diff --git a/ash/wm/panels/panel_frame_view.cc b/ash/wm/panels/panel_frame_view.cc
index 733af9ad..87e6f34 100644
--- a/ash/wm/panels/panel_frame_view.cc
+++ b/ash/wm/panels/panel_frame_view.cc
@@ -32,6 +32,11 @@
 PanelFrameView::~PanelFrameView() {
 }
 
+void PanelFrameView::SetFrameColors(SkColor active_frame_color,
+                                    SkColor inactive_frame_color) {
+  header_painter_->SetFrameColors(active_frame_color, inactive_frame_color);
+}
+
 const char* PanelFrameView::GetClassName() const {
   return kViewClassName;
 }
diff --git a/ash/wm/panels/panel_frame_view.h b/ash/wm/panels/panel_frame_view.h
index f4ba33be..d51a72a 100644
--- a/ash/wm/panels/panel_frame_view.h
+++ b/ash/wm/panels/panel_frame_view.h
@@ -31,6 +31,10 @@
   PanelFrameView(views::Widget* frame, FrameType frame_type);
   ~PanelFrameView() override;
 
+  // Sets the active and inactive frame colors. Note the inactive frame color
+  // will have some transparency added when the frame is drawn.
+  void SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color);
+
   // Overridden from views::View:
   const char* GetClassName() const override;
 
diff --git a/build/android/gyp/create_java_binary_script.py b/build/android/gyp/create_java_binary_script.py
index b73144b8..324361d4 100755
--- a/build/android/gyp/create_java_binary_script.py
+++ b/build/android/gyp/create_java_binary_script.py
@@ -30,13 +30,15 @@
 
 self_dir = os.path.dirname(__file__)
 classpath = [{classpath}]
-extra_java_args = {extra_java_args}
+bootclasspath = [{bootclasspath}]
 extra_program_args = {extra_program_args}
 if os.getcwd() != self_dir:
   offset = os.path.relpath(self_dir, os.getcwd())
   classpath = [os.path.join(offset, p) for p in classpath]
+  bootclasspath = [os.path.join(offset, p) for p in bootclasspath]
 java_cmd = ["java"]
-java_cmd.extend(extra_java_args)
+if bootclasspath:
+    java_cmd.append("-Xbootclasspath/p:" + ":".join(bootclasspath))
 java_cmd.extend(
     ["-classpath", ":".join(classpath), "-enableassertions", \"{main_class}\"])
 java_cmd.extend(extra_program_args)
@@ -52,28 +54,28 @@
   parser.add_option('--jar-path', help='Path to the main jar.')
   parser.add_option('--main-class',
       help='Name of the java class with the "main" entry point.')
-  parser.add_option('--classpath', action='append',
+  parser.add_option('--classpath', action='append', default=[],
       help='Classpath for running the jar.')
-  parser.add_option('--extra-java-args',
-      help='Extra args passed to the "java" cmd')
+  parser.add_option('--bootclasspath', action='append', default=[],
+      help='zip/jar files to add to bootclasspath for java cmd.')
   options, extra_program_args = parser.parse_args(argv)
 
   classpath = [options.jar_path]
   for cp_arg in options.classpath:
     classpath += build_utils.ParseGypList(cp_arg)
 
-  if options.extra_java_args:
-    extra_java_args = build_utils.ParseGypList(options.extra_java_args)
-  else:
-    extra_java_args = []
+  bootclasspath = []
+  for bootcp_arg in options.bootclasspath:
+    bootclasspath += build_utils.ParseGypList(bootcp_arg)
 
   run_dir = os.path.dirname(options.output)
   classpath = [os.path.relpath(p, run_dir) for p in classpath]
 
   with open(options.output, 'w') as script:
     script.write(script_template.format(
-      extra_java_args=repr(extra_java_args),
       classpath=('"%s"' % '", "'.join(classpath)),
+      bootclasspath=('"%s"' % '", "'.join(bootclasspath)
+                     if bootclasspath else ''),
       main_class=options.main_class,
       extra_program_args=repr(extra_program_args)))
 
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 95a2420..57b3a1b 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -166,10 +166,10 @@
     if (defined(invoker.wrapper_script_args)) {
       args += [ "--" ] + invoker.wrapper_script_args
     }
-    if (defined(invoker.extra_java_args)) {
+    if (defined(invoker.bootclasspath)) {
       args += [
-        "--extra-java-args",
-        invoker.extra_java_args,
+        "--bootclasspath",
+        invoker.bootclasspath,
       ]
     }
   }
@@ -1033,7 +1033,7 @@
     java_binary_script(binary_script_target_name) {
       forward_variables_from(invoker,
                              [
-                               "extra_java_args",
+                               "bootclasspath",
                                "main_class",
                                "wrapper_script_args",
                              ])
@@ -1383,7 +1383,7 @@
     java_binary_script("${_template_name}__java_binary_script") {
       forward_variables_from(invoker,
                              [
-                               "extra_java_args",
+                               "bootclasspath",
                                "main_class",
                                "wrapper_script_args",
                              ])
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index c9e88ac..4d14ff7 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -1893,9 +1893,6 @@
 
     accumulated_surface_state->push_back(AccumulatedSurfaceState(layer));
 
-    // Don't clip if the layer has copy requests.
-    if (layer->HasCopyRequest())
-      subtree_is_clipped_by_surface_bounds = false;
     render_surface->SetIsClipped(subtree_is_clipped_by_surface_bounds);
     if (!subtree_is_clipped_by_surface_bounds) {
       render_surface->SetClipRect(gfx::Rect());
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 9e8786a9..5ecd1b8 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -5448,13 +5448,13 @@
   inputs.can_adjust_raster_scales = true;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
-  // We should have two render surface, as the others are clipped out.
-  ASSERT_EQ(2u, render_surface_layer_list.size());
+  // We should have one render surface, as the others are clipped out.
+  ASSERT_EQ(1u, render_surface_layer_list.size());
   EXPECT_EQ(root->id(), render_surface_layer_list.at(0)->id());
 
-  // The root render surface should only have 2 contributing layer, since the
+  // The root render surface should only have 1 contributing layer, since the
   // other layers are empty/clipped away.
-  ASSERT_EQ(2u, root->render_surface()->layer_list().size());
+  ASSERT_EQ(1u, root->render_surface()->layer_list().size());
   EXPECT_EQ(root->id(), root->render_surface()->layer_list().at(0)->id());
 }
 
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index 0ddc7b7..802a014 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -473,10 +473,10 @@
   }
 
   void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
-    // We should still get the content even if the copy requested layer was
-    // completely clipped away.
+    // We should still get a callback with no output if the copy requested layer
+    // was completely clipped away.
     EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
-    EXPECT_EQ(gfx::Size(10, 10).ToString(), result->size().ToString());
+    EXPECT_EQ(gfx::Size().ToString(), result->size().ToString());
     EndTest();
   }
 
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index 435503c..2f1d954 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -101,9 +101,7 @@
   bool is_root = !layer->parent();
 
   // Whether we have an ancestor clip that we might need to apply.
-  // Don't apply ancestor clip when the layer has copy requests.
-  bool ancestor_clips_subtree =
-      (is_root || parent->data.layers_are_clipped) && !layer->HasCopyRequest();
+  bool ancestor_clips_subtree = is_root || parent->data.layers_are_clipped;
 
   bool layers_are_clipped = false;
   bool has_unclipped_surface = false;
@@ -122,6 +120,7 @@
       // of its own, but clips from ancestor nodes don't need to be considered
       // when computing clip rects or visibility.
       has_unclipped_surface = true;
+      DCHECK(!parent->data.applies_local_clip);
     }
     // A surface with unclipped descendants cannot be clipped by its ancestor
     // clip at draw time since the unclipped descendants aren't affected by the
diff --git a/chrome/VERSION b/chrome/VERSION
index 0035e287..c104260 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=48
 MINOR=0
-BUILD=2555
+BUILD=2556
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
index c5c1564..df3d8bb8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
@@ -7,6 +7,7 @@
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.preference.PreferenceManager;
+import android.util.Base64;
 import android.util.Log;
 
 import org.chromium.base.ThreadUtils;
@@ -219,6 +220,45 @@
         }
     }
 
+    // TODO(agulenko): Move this piece of code to a separate class.
+
+    private static final String VARIATIONS_FIRST_RUN_SEED_BASE64 = "variations_seed_base64";
+    private static final String VARIATIONS_FIRST_RUN_SEED_SIGNATURE = "variations_seed_signature";
+    private static final String VARIATIONS_FIRST_RUN_SEED_COUNTRY = "variations_seed_country";
+
+    private static String getVariationsFirstRunSeedPref(Context context, String prefName) {
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        return prefs.getString(prefName, "");
+    }
+
+    public static void setVariationsFirstRunSeed(
+            Context context, byte[] rawSeed, String signature, String country) {
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        prefs.edit()
+                .putString(VARIATIONS_FIRST_RUN_SEED_BASE64,
+                        Base64.encodeToString(rawSeed, Base64.NO_WRAP))
+                .putString(VARIATIONS_FIRST_RUN_SEED_SIGNATURE, signature)
+                .putString(VARIATIONS_FIRST_RUN_SEED_COUNTRY, country)
+                .apply();
+    }
+
+    @CalledByNative
+    private static byte[] getVariationsFirstRunSeedData(Context context) {
+        return Base64.decode(
+                getVariationsFirstRunSeedPref(context, VARIATIONS_FIRST_RUN_SEED_BASE64),
+                Base64.NO_WRAP);
+    }
+
+    @CalledByNative
+    private static String getVariationsFirstRunSeedSignature(Context context) {
+        return getVariationsFirstRunSeedPref(context, VARIATIONS_FIRST_RUN_SEED_SIGNATURE);
+    }
+
+    @CalledByNative
+    private static String getVariationsFirstRunSeedCountry(Context context) {
+        return getVariationsFirstRunSeedPref(context, VARIATIONS_FIRST_RUN_SEED_COUNTRY);
+    }
+
     public boolean isAcceptCookiesEnabled() {
         return nativeGetAcceptCookiesEnabled();
     }
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc
index 5b5f4b5..96e721b 100644
--- a/chrome/browser/android/preferences/pref_service_bridge.cc
+++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -5,13 +5,16 @@
 #include "chrome/browser/android/preferences/pref_service_bridge.h"
 
 #include <jni.h>
+#include <vector>
 
 #include "base/android/build_info.h"
 #include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/android/jni_weak_ref.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
@@ -36,6 +39,7 @@
 #include "components/signin/core/common/signin_pref_names.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/translate/core/common/translate_pref_names.h"
+#include "components/variations/pref_names.h"
 #include "components/version_info/version_info.h"
 #include "components/web_resource/web_resource_pref_names.h"
 #include "content/public/browser/browser_thread.h"
@@ -47,6 +51,7 @@
 using base::android::CheckException;
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::GetApplicationContext;
 using base::android::ScopedJavaLocalRef;
 using base::android::ScopedJavaGlobalRef;
 using content::BrowserThread;
@@ -111,6 +116,14 @@
   return GetOriginalProfile()->GetPrefs();
 }
 
+std::string JavaByteArrayToString(JNIEnv* env, jbyteArray byte_array) {
+  if (!byte_array)
+    return std::string();
+  std::vector<uint8> array_data;
+  base::android::JavaByteArrayToByteVector(env, byte_array, &array_data);
+  return std::string(array_data.begin(), array_data.end());
+}
+
 }  // namespace
 
 // ----------------------------------------------------------------------------
@@ -948,3 +961,22 @@
 
   return ConvertJavaStringToUTF8(android_permission);
 }
+
+// static
+void PrefServiceBridge::GetVariationsFirstRunSeed(std::string* seed_data,
+                                                  std::string* seed_signature,
+                                                  std::string* seed_country) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jbyteArray> j_seed_data =
+      Java_PrefServiceBridge_getVariationsFirstRunSeedData(
+          env, GetApplicationContext());
+  ScopedJavaLocalRef<jstring> j_seed_signature =
+      Java_PrefServiceBridge_getVariationsFirstRunSeedSignature(
+          env, GetApplicationContext());
+  ScopedJavaLocalRef<jstring> j_seed_country =
+      Java_PrefServiceBridge_getVariationsFirstRunSeedCountry(
+          env, GetApplicationContext());
+  *seed_data = JavaByteArrayToString(env, j_seed_data.obj());
+  *seed_signature = ConvertJavaStringToUTF8(j_seed_signature);
+  *seed_country = ConvertJavaStringToUTF8(j_seed_country);
+}
diff --git a/chrome/browser/android/preferences/pref_service_bridge.h b/chrome/browser/android/preferences/pref_service_bridge.h
index 656a0fec..282364b 100644
--- a/chrome/browser/android/preferences/pref_service_bridge.h
+++ b/chrome/browser/android/preferences/pref_service_bridge.h
@@ -26,6 +26,11 @@
   // ContentSettingsType specified (or an empty string if no permission exists).
   static std::string GetAndroidPermissionForContentSetting(
       ContentSettingsType content_type);
+
+  // Return the first run seed data pulled from the Java side of application.
+  static void GetVariationsFirstRunSeed(std::string* seed_data,
+                                        std::string* seed_signature,
+                                        std::string* seed_country);
 };
 
 #endif  // CHROME_BROWSER_ANDROID_PREFERENCES_PREF_SERVICE_BRIDGE_H_
diff --git a/chrome/browser/devtools/BUILD.gn b/chrome/browser/devtools/BUILD.gn
index b1a1eed8..9b8f6ea 100644
--- a/chrome/browser/devtools/BUILD.gn
+++ b/chrome/browser/devtools/BUILD.gn
@@ -121,6 +121,8 @@
       "devtools_file_helper.h",
       "devtools_file_system_indexer.cc",
       "devtools_file_system_indexer.h",
+      "devtools_file_watcher.cc",
+      "devtools_file_watcher.h",
       "devtools_target_impl.cc",
       "devtools_target_impl.h",
       "devtools_targets_ui.cc",
diff --git a/chrome/browser/devtools/devtools_file_helper.cc b/chrome/browser/devtools/devtools_file_helper.cc
index 361d739..d3a9312ba 100644
--- a/chrome/browser/devtools/devtools_file_helper.cc
+++ b/chrome/browser/devtools/devtools_file_helper.cc
@@ -17,6 +17,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/value_conversions.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/devtools/devtools_file_watcher.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/profiles/profile.h"
@@ -212,9 +213,14 @@
   pref_change_registrar_.Add(prefs::kDevToolsFileSystemPaths,
       base::Bind(&DevToolsFileHelper::FileSystemPathsSettingChanged,
                  base::Unretained(this)));
+  file_watcher_.reset(new DevToolsFileWatcher(
+      base::Bind(&DevToolsFileHelper::FilePathsChanged,
+                 weak_factory_.GetWeakPtr())));
 }
 
 DevToolsFileHelper::~DevToolsFileHelper() {
+  BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE,
+                            file_watcher_.release());
 }
 
 void DevToolsFileHelper::Save(const std::string& url,
@@ -392,6 +398,9 @@
                                                    file_system_id,
                                                    file_system_path);
     file_systems.push_back(filesystem);
+    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+                            Bind(&DevToolsFileWatcher::AddWatch,
+                                 base::Unretained(file_watcher_.get()), path));
   }
   return file_systems;
 }
@@ -426,12 +435,26 @@
                                                      file_system_id,
                                                      file_system_path);
       delegate_->FileSystemAdded(filesystem);
+      BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+                              Bind(&DevToolsFileWatcher::AddWatch,
+                                   base::Unretained(file_watcher_.get()),
+                                   path));
     } else {
       remaining.erase(file_system_path);
     }
     file_system_paths_.insert(file_system_path);
   }
 
-  for (auto file_system_path : remaining)
+  for (auto file_system_path : remaining) {
     delegate_->FileSystemRemoved(file_system_path);
+    base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path);
+    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+                            Bind(&DevToolsFileWatcher::RemoveWatch,
+                                 base::Unretained(file_watcher_.get()), path));
+  }
+}
+
+void DevToolsFileHelper::FilePathsChanged(
+    const std::vector<std::string>& paths) {
+  delegate_->FilePathsChanged(paths);
 }
diff --git a/chrome/browser/devtools/devtools_file_helper.h b/chrome/browser/devtools/devtools_file_helper.h
index d7f63c30..550a19d 100644
--- a/chrome/browser/devtools/devtools_file_helper.h
+++ b/chrome/browser/devtools/devtools_file_helper.h
@@ -17,6 +17,7 @@
 #include "base/prefs/pref_change_registrar.h"
 #include "base/strings/string16.h"
 
+class DevToolsFileWatcher;
 class Profile;
 
 namespace base {
@@ -45,6 +46,7 @@
     virtual ~Delegate() {}
     virtual void FileSystemAdded(const FileSystem& file_system) = 0;
     virtual void FileSystemRemoved(const std::string& file_system_path) = 0;
+    virtual void FilePathsChanged(const std::vector<std::string>& paths) = 0;
   };
 
   DevToolsFileHelper(content::WebContents* web_contents, Profile* profile,
@@ -129,6 +131,7 @@
       const base::FilePath& path,
       bool allowed);
   void FileSystemPathsSettingChanged();
+  void FilePathsChanged(const std::vector<std::string>& paths);
 
   content::WebContents* web_contents_;
   Profile* profile_;
@@ -137,6 +140,7 @@
   PathsMap saved_files_;
   PrefChangeRegistrar pref_change_registrar_;
   std::set<std::string> file_system_paths_;
+  scoped_ptr<DevToolsFileWatcher> file_watcher_;
   base::WeakPtrFactory<DevToolsFileHelper> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(DevToolsFileHelper);
 };
diff --git a/chrome/browser/devtools/devtools_file_watcher.cc b/chrome/browser/devtools/devtools_file_watcher.cc
new file mode 100644
index 0000000..bfc4906
--- /dev/null
+++ b/chrome/browser/devtools/devtools_file_watcher.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/devtools/devtools_file_watcher.h"
+
+#include <map>
+#include <set>
+
+#include "base/bind.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_path_watcher.h"
+#include "base/memory/ref_counted.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+static int kFirstThrottleTimeout = 10;
+static int kDefaultThrottleTimeout = 200;
+
+// DevToolsFileWatcher::SharedFileWatcher --------------------------------------
+
+class DevToolsFileWatcher::SharedFileWatcher :
+    public base::RefCounted<SharedFileWatcher> {
+ public:
+  SharedFileWatcher();
+
+  void AddListener(DevToolsFileWatcher* watcher);
+  void RemoveListener(DevToolsFileWatcher* watcher);
+  void AddWatch(const base::FilePath& path);
+  void RemoveWatch(const base::FilePath& path);
+
+ private:
+  friend class base::RefCounted<
+      DevToolsFileWatcher::SharedFileWatcher>;
+  ~SharedFileWatcher();
+
+  void DirectoryChanged(const base::FilePath& path, bool error);
+  void DispatchNotifications();
+
+  std::vector<DevToolsFileWatcher*> listeners_;
+  std::map<base::FilePath, scoped_ptr<base::FilePathWatcher>> watchers_;
+  using FilePathTimesMap = std::map<base::FilePath, base::Time>;
+  FilePathTimesMap file_path_times_;
+  std::set<base::FilePath> pending_paths_;
+  base::Time last_event_time_;
+  base::TimeDelta last_dispatch_cost_;
+};
+
+DevToolsFileWatcher::SharedFileWatcher::SharedFileWatcher()
+    : last_dispatch_cost_(
+          base::TimeDelta::FromMilliseconds(kDefaultThrottleTimeout)) {
+  DevToolsFileWatcher::s_shared_watcher_ = this;
+}
+
+DevToolsFileWatcher::SharedFileWatcher::~SharedFileWatcher() {
+  DevToolsFileWatcher::s_shared_watcher_ = nullptr;
+}
+
+void DevToolsFileWatcher::SharedFileWatcher::AddListener(
+    DevToolsFileWatcher* watcher) {
+  listeners_.push_back(watcher);
+}
+
+void DevToolsFileWatcher::SharedFileWatcher::RemoveListener(
+    DevToolsFileWatcher* watcher) {
+  auto it = std::find(listeners_.begin(), listeners_.end(), watcher);
+  listeners_.erase(it);
+}
+
+void DevToolsFileWatcher::SharedFileWatcher::AddWatch(
+    const base::FilePath& path) {
+  if (watchers_.find(path) != watchers_.end())
+    return;
+  if (!base::FilePathWatcher::RecursiveWatchAvailable())
+    return;
+  watchers_[path].reset(new base::FilePathWatcher());
+  bool success = watchers_[path]->Watch(
+      path, true,
+      base::Bind(&SharedFileWatcher::DirectoryChanged, base::Unretained(this)));
+  if (!success)
+    return;
+
+  base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES);
+  base::FilePath file_path = enumerator.Next();
+  while (!file_path.empty()) {
+    base::FileEnumerator::FileInfo file_info = enumerator.GetInfo();
+    file_path_times_[file_path] = file_info.GetLastModifiedTime();
+    file_path = enumerator.Next();
+  }
+}
+
+void DevToolsFileWatcher::SharedFileWatcher::RemoveWatch(
+    const base::FilePath& path) {
+  watchers_.erase(path);
+}
+
+void DevToolsFileWatcher::SharedFileWatcher::DirectoryChanged(
+    const base::FilePath& path,
+    bool error) {
+  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  pending_paths_.insert(path);
+  if (pending_paths_.size() > 1)
+    return;  // PostDelayedTask is already pending.
+
+  base::Time now = base::Time::Now();
+  // Quickly dispatch first chunk.
+  base::TimeDelta shedule_for =
+      now - last_event_time_ > last_dispatch_cost_ ?
+          base::TimeDelta::FromMilliseconds(kFirstThrottleTimeout) :
+          last_dispatch_cost_ * 2;
+
+  BrowserThread::PostDelayedTask(
+      BrowserThread::FILE, FROM_HERE,
+      base::Bind(&DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications,
+                 this), shedule_for);
+  last_event_time_ = now;
+}
+
+void DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications() {
+  base::Time start = base::Time::Now();
+  std::vector<std::string> changed_paths;
+  for (auto path : pending_paths_) {
+    base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES);
+    base::FilePath file_path = enumerator.Next();
+    while (!file_path.empty()) {
+      base::FileEnumerator::FileInfo file_info = enumerator.GetInfo();
+      base::Time new_time = file_info.GetLastModifiedTime();
+      if (file_path_times_[file_path] != new_time) {
+        file_path_times_[file_path] = new_time;
+        changed_paths.push_back(file_path.AsUTF8Unsafe());
+      }
+      file_path = enumerator.Next();
+    }
+  }
+  pending_paths_.clear();
+
+  for (auto watcher : listeners_) {
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                            base::Bind(watcher->callback_, changed_paths));
+  }
+  last_dispatch_cost_ = base::Time::Now() - start;
+}
+
+// static
+DevToolsFileWatcher::SharedFileWatcher*
+DevToolsFileWatcher::s_shared_watcher_ = nullptr;
+
+// DevToolsFileWatcher ---------------------------------------------------------
+
+DevToolsFileWatcher::DevToolsFileWatcher(const WatchCallback& callback)
+    : callback_(callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+                          base::Bind(&DevToolsFileWatcher::InitSharedWatcher,
+                                     base::Unretained(this)));
+}
+
+DevToolsFileWatcher::~DevToolsFileWatcher() {
+  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  shared_watcher_->RemoveListener(this);
+}
+
+void DevToolsFileWatcher::InitSharedWatcher() {
+  if (!DevToolsFileWatcher::s_shared_watcher_)
+    new SharedFileWatcher();
+  shared_watcher_ = DevToolsFileWatcher::s_shared_watcher_;
+  shared_watcher_->AddListener(this);
+}
+
+void DevToolsFileWatcher::AddWatch(const base::FilePath& path) {
+  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  shared_watcher_->AddWatch(path);
+}
+
+void DevToolsFileWatcher::RemoveWatch(const base::FilePath& path) {
+  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  shared_watcher_->RemoveWatch(path);
+}
diff --git a/chrome/browser/devtools/devtools_file_watcher.h b/chrome/browser/devtools/devtools_file_watcher.h
new file mode 100644
index 0000000..b753af4
--- /dev/null
+++ b/chrome/browser/devtools/devtools_file_watcher.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_FILE_WATCHER_H_
+#define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_FILE_WATCHER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+
+namespace base {
+class FilePath;
+class FilePathWatcher;
+}
+
+class DevToolsFileWatcher {
+ public:
+  using WatchCallback = base::Callback<void(const std::vector<std::string>&)>;
+  explicit DevToolsFileWatcher(const WatchCallback& callback);
+  ~DevToolsFileWatcher();
+
+  void AddWatch(const base::FilePath& path);
+  void RemoveWatch(const base::FilePath& path);
+
+ private:
+  class SharedFileWatcher;
+  static SharedFileWatcher* s_shared_watcher_;
+
+  void InitSharedWatcher();
+  void FileChanged(const base::FilePath&, int);
+
+  scoped_refptr<SharedFileWatcher> shared_watcher_;
+  WatchCallback callback_;
+  DISALLOW_COPY_AND_ASSIGN(DevToolsFileWatcher);
+};
+
+#endif  // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_FILE_WATCHER_H_
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index 1cb42bd..66ff96fb 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -14,6 +14,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/devtools/devtools_file_watcher.h"
 #include "chrome/browser/devtools/devtools_protocol.h"
 #include "chrome/browser/devtools/devtools_target_impl.h"
 #include "chrome/browser/devtools/global_confirm_info_bar.h"
@@ -995,6 +996,15 @@
                      &file_system_path_value, NULL, NULL);
 }
 
+void DevToolsUIBindings::FilePathsChanged(
+    const std::vector<std::string>& file_paths) {
+  base::ListValue list;
+  for (auto path : file_paths)
+    list.AppendString(path);
+  CallClientFunction("DevToolsAPI.fileSystemFilesChanged",
+                     &list, NULL, NULL);
+}
+
 void DevToolsUIBindings::IndexingTotalWorkCalculated(
     int request_id,
     const std::string& file_system_path,
diff --git a/chrome/browser/devtools/devtools_ui_bindings.h b/chrome/browser/devtools/devtools_ui_bindings.h
index e9486924..e44545b3 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.h
+++ b/chrome/browser/devtools/devtools_ui_bindings.h
@@ -173,6 +173,7 @@
   void FileSystemAdded(
       const DevToolsFileHelper::FileSystem& file_system) override;
   void FileSystemRemoved(const std::string& file_system_path) override;
+  void FilePathsChanged(const std::vector<std::string>& file_paths) override;
 
   // DevToolsFileHelper callbacks.
   void FileSavedAs(const std::string& url);
diff --git a/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc b/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc
index 50d24d6..0d6a8508 100644
--- a/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc
+++ b/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/lazy_instance.h"
 #include "base/memory/linked_ptr.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/local_discovery/privet_http.h"
 #include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h"
 #include "chrome/browser/local_discovery/privetv3_session.h"
diff --git a/chrome/browser/metrics/variations/chrome_variations_service_client.cc b/chrome/browser/metrics/variations/chrome_variations_service_client.cc
index ed7ceff..8e6b4be 100644
--- a/chrome/browser/metrics/variations/chrome_variations_service_client.cc
+++ b/chrome/browser/metrics/variations/chrome_variations_service_client.cc
@@ -10,6 +10,10 @@
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_thread.h"
 
+#if defined(OS_ANDROID)
+#include "chrome/browser/android/preferences/pref_service_bridge.h"
+#endif  // OS_ANDROID
+
 #if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
 #include "chrome/browser/upgrade_detector_impl.h"
 #endif
@@ -79,6 +83,15 @@
 #endif
 }
 
+variations::VariationsFirstRunSeedCallback
+ChromeVariationsServiceClient::GetVariationsFirstRunSeedCallback() {
+#if defined(OS_ANDROID)
+  return base::Bind(&PrefServiceBridge::GetVariationsFirstRunSeed);
+#else   // OS_ANDROID
+  return variations::VariationsFirstRunSeedCallback();
+#endif  // OS_ANDROID
+}
+
 void ChromeVariationsServiceClient::OnInitialStartup() {
 #if defined(OS_WIN)
   StartGoogleUpdateRegistrySync();
diff --git a/chrome/browser/metrics/variations/chrome_variations_service_client.h b/chrome/browser/metrics/variations/chrome_variations_service_client.h
index 8abe72ef..d38b170 100644
--- a/chrome/browser/metrics/variations/chrome_variations_service_client.h
+++ b/chrome/browser/metrics/variations/chrome_variations_service_client.h
@@ -5,8 +5,12 @@
 #ifndef CHROME_BROWSER_METRICS_VARIATIONS_CHROME_VARIATIONS_SERVICE_CLIENT_H_
 #define CHROME_BROWSER_METRICS_VARIATIONS_CHROME_VARIATIONS_SERVICE_CLIENT_H_
 
+#include <string>
+
 #include "base/basictypes.h"
+#include "base/bind.h"
 #include "components/variations/service/variations_service_client.h"
+#include "components/variations/variations_seed_store.h"
 
 #if defined(OS_WIN)
 #include "chrome/browser/metrics/variations/variations_registry_syncer_win.h"
@@ -30,6 +34,8 @@
   version_info::Channel GetChannel() override;
   bool OverridesRestrictParameter(std::string* parameter) override;
   void OnInitialStartup() override;
+  variations::VariationsFirstRunSeedCallback GetVariationsFirstRunSeedCallback()
+      override;
 
  private:
 #if defined(OS_WIN)
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
index 2adfb24e..5c6dad7 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
@@ -325,9 +325,11 @@
       return CreateNonStandardAppFrame();
 
     if (app_window()->window_type_is_panel()) {
-      views::NonClientFrameView* frame_view =
+      ash::PanelFrameView* frame_view =
           new ash::PanelFrameView(widget, ash::PanelFrameView::FRAME_ASH);
       frame_view->set_context_menu_controller(this);
+      if (HasFrameColor())
+        frame_view->SetFrameColors(ActiveFrameColor(), InactiveFrameColor());
       return frame_view;
     }
 
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index c2d651c..c2cc048a 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -1129,8 +1129,12 @@
 }
 
 void Tab::PaintTabBackground(gfx::Canvas* canvas) {
+  const int kActiveTabFillId = IDR_THEME_TOOLBAR;
+  const bool has_custom_image =
+      GetThemeProvider()->HasCustomImage(kActiveTabFillId);
   if (IsActive()) {
-    PaintActiveTabBackground(canvas);
+    PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId,
+                                  has_custom_image, 0);
   } else {
     if (pinned_title_change_animation_ &&
         pinned_title_change_animation_->is_animating())
@@ -1142,7 +1146,8 @@
     if (throb_value > 0) {
       canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff),
                              GetLocalBounds());
-      PaintActiveTabBackground(canvas);
+      PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId,
+                                    has_custom_image, 0);
       canvas->Restore();
     }
   }
@@ -1174,98 +1179,74 @@
 }
 
 void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas) {
-  int tab_id, frame_id;
-  GetTabIdAndFrameId(GetWidget(), &tab_id, &frame_id);
-  // HasCustomImage() is only true if the theme provides the image. However,
-  // even if the theme does not provide a tab background, the theme machinery
-  // will make one if given a frame image.
-  ui::ThemeProvider* theme_provider = GetThemeProvider();
-  const bool has_custom_image = theme_provider->HasCustomImage(tab_id) ||
-      (frame_id != 0 && theme_provider->HasCustomImage(frame_id));
-
+  bool has_custom_image;
+  int fill_id = controller_->GetBackgroundResourceId(&has_custom_image);
   // Explicitly map the id so we cache correctly.
   const chrome::HostDesktopType host_desktop_type = GetHostDesktopType(this);
-  tab_id = chrome::MapThemeImage(host_desktop_type, tab_id);
+  fill_id = chrome::MapThemeImage(host_desktop_type, fill_id);
+
+  // If the theme is providing a custom background image, then its top edge
+  // should be at the top of the tab. Otherwise, we assume that the background
+  // image is a composited foreground + frame image.
+  const int y_offset = GetThemeProvider()->HasCustomImage(fill_id) ?
+      0 : background_offset_.y();
 
   // We only cache the image when it's the default image and we're not hovered,
   // to avoid caching a background image that isn't the same for all tabs.
   if (!has_custom_image && !hover_controller_.ShouldDraw()) {
     ui::ScaleFactor scale_factor =
         ui::GetSupportedScaleFactor(canvas->image_scale());
-    gfx::ImageSkia cached_image(GetCachedImage(tab_id, size(), scale_factor));
+    gfx::ImageSkia cached_image(GetCachedImage(fill_id, size(), scale_factor));
     if (cached_image.width() == 0) {
       gfx::Canvas tmp_canvas(size(), canvas->image_scale(), false);
-      PaintInactiveTabBackgroundUsingResourceId(&tmp_canvas, tab_id);
+      PaintTabBackgroundUsingFillId(&tmp_canvas, false, fill_id, false,
+                                    y_offset);
       cached_image = gfx::ImageSkia(tmp_canvas.ExtractImageRep());
-      SetCachedImage(tab_id, scale_factor, cached_image);
+      SetCachedImage(fill_id, scale_factor, cached_image);
     }
     canvas->DrawImageInt(cached_image, 0, 0);
   } else {
-    PaintInactiveTabBackgroundUsingResourceId(canvas, tab_id);
+    PaintTabBackgroundUsingFillId(canvas, false, fill_id, has_custom_image,
+                                  y_offset);
   }
 }
 
-void Tab::PaintInactiveTabBackgroundUsingResourceId(gfx::Canvas* canvas,
-                                                    int tab_id) {
-  gfx::ImageSkia* tab_background =
-      GetThemeProvider()->GetImageSkiaNamed(tab_id);
+void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* canvas,
+                                        bool is_active,
+                                        int fill_id,
+                                        bool has_custom_image,
+                                        int y_offset) {
+  gfx::ImageSkia* fill_image = GetThemeProvider()->GetImageSkiaNamed(fill_id);
   // The tab image needs to be lined up with the background image
   // so that it feels partially transparent.  These offsets represent the tab
   // position within the frame background image.
   const int x_offset = GetMirroredX() + background_offset_.x();
 
-  // If the theme is providing a custom background image, then its top edge
-  // should be at the top of the tab. Otherwise, we assume that the background
-  // image is a composited foreground + frame image.
-  const int y_offset = GetThemeProvider()->HasCustomImage(tab_id) ?
-      0 : background_offset_.y();
+  const SkScalar radius = SkFloatToScalar(width() / 3.f);
+  const bool draw_hover =
+      !is_active && hover_controller_.ShouldDraw() && radius > 0;
+  SkPoint hover_location(PointToSkPoint(hover_controller_.location()));
+  const SkAlpha hover_alpha = hover_controller_.GetAlpha();
 
-  const gfx::Insets tab_insets(GetLayoutInsets(TAB));
-  // Don't draw over the toolbar, but do include the 1 px divider stroke at the
-  // bottom.
-  const int toolbar_overlap = tab_insets.bottom() - 1;
+  if (draw_hover) {
+    // Draw everything to a temporary canvas so we can extract an image for use
+    // in masking the hover glow.
+    gfx::Canvas background_canvas(size(), canvas->image_scale(), false);
+    PaintTabFill(&background_canvas, fill_image, x_offset, y_offset, is_active);
+    gfx::ImageSkia background_image(background_canvas.ExtractImageRep());
+    canvas->DrawImageInt(background_image, 0, 0);
 
-  // Draw everything to a temporary canvas so we can extract an image for use in
-  // masking the hover glow.
-  gfx::Canvas background_canvas(size(), canvas->image_scale(), false);
-
-  // Draw left edge.
-  gfx::ImageSkia tab_l = gfx::ImageSkiaOperations::CreateTiledImage(
-      *tab_background, x_offset, y_offset, mask_images_.l_width, height());
-  gfx::ImageSkia theme_l =
-      gfx::ImageSkiaOperations::CreateMaskedImage(tab_l, *mask_images_.image_l);
-  background_canvas.DrawImageInt(
-      theme_l, 0, 0, theme_l.width(), theme_l.height() - toolbar_overlap, 0, 0,
-      theme_l.width(), theme_l.height() - toolbar_overlap, false);
-
-  // Draw right edge.
-  gfx::ImageSkia tab_r = gfx::ImageSkiaOperations::CreateTiledImage(
-      *tab_background, x_offset + width() - mask_images_.r_width, y_offset,
-      mask_images_.r_width, height());
-  gfx::ImageSkia theme_r =
-      gfx::ImageSkiaOperations::CreateMaskedImage(tab_r, *mask_images_.image_r);
-  background_canvas.DrawImageInt(theme_r, 0, 0, theme_r.width(),
-                                 theme_r.height() - toolbar_overlap,
-                                 width() - theme_r.width(), 0, theme_r.width(),
-                                 theme_r.height() - toolbar_overlap, false);
-
-  // Draw center.  Instead of masking out the top portion we simply skip over
-  // it by incrementing by the top padding, since it's a simple rectangle.
-  background_canvas.TileImageInt(
-      *tab_background, x_offset + mask_images_.l_width,
-      y_offset + tab_insets.top(), mask_images_.l_width, tab_insets.top(),
-      width() - mask_images_.l_width - mask_images_.r_width,
-      height() - tab_insets.top() - toolbar_overlap);
-
-  gfx::ImageSkia background_image(background_canvas.ExtractImageRep());
-  canvas->DrawImageInt(background_image, 0, 0);
-
-  if (!GetThemeProvider()->HasCustomImage(tab_id) &&
-      hover_controller_.ShouldDraw())
-    hover_controller_.Draw(canvas, background_image);
+    gfx::Canvas hover_canvas(size(), canvas->image_scale(), false);
+    DrawHighlight(&hover_canvas, hover_location, radius, hover_alpha);
+    gfx::ImageSkia result = gfx::ImageSkiaOperations::CreateMaskedImage(
+        gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image);
+    canvas->DrawImageInt(result, 0, 0);
+  } else {
+    PaintTabFill(canvas, fill_image, x_offset, y_offset, is_active);
+  }
 
   // Now draw the stroke, highlights, and shadows around the tab edge.
-  TabImages* stroke_images = &inactive_images_;
+  TabImages* stroke_images = is_active ? &active_images_ : &inactive_images_;
   canvas->DrawImageInt(*stroke_images->image_l, 0, 0);
   canvas->TileImageInt(
       *stroke_images->image_c, stroke_images->l_width, 0,
@@ -1274,47 +1255,43 @@
                        width() - stroke_images->r_width, 0);
 }
 
-void Tab::PaintActiveTabBackground(gfx::Canvas* canvas) {
-  gfx::ImageSkia* tab_background =
-      GetThemeProvider()->GetImageSkiaNamed(IDR_THEME_TOOLBAR);
-  int x_offset = GetMirroredX() + background_offset_.x();
-
+void Tab::PaintTabFill(gfx::Canvas* canvas,
+                       gfx::ImageSkia* fill_image,
+                       int x_offset,
+                       int y_offset,
+                       bool is_active) {
   const gfx::Insets tab_insets(GetLayoutInsets(TAB));
+  // If this isn't the foreground tab, don't draw over the toolbar, but do
+  // include the 1 px divider stroke at the bottom.
+  const int toolbar_overlap = is_active ? 0 : (tab_insets.bottom() - 1);
 
   // Draw left edge.
   gfx::ImageSkia tab_l = gfx::ImageSkiaOperations::CreateTiledImage(
-      *tab_background, x_offset, 0, mask_images_.l_width, height());
+      *fill_image, x_offset, y_offset, mask_images_.l_width, height());
   gfx::ImageSkia theme_l =
       gfx::ImageSkiaOperations::CreateMaskedImage(tab_l, *mask_images_.image_l);
   canvas->DrawImageInt(
-      theme_l, 0, 0, theme_l.width(), theme_l.height(), 0, 0, theme_l.width(),
-      theme_l.height(), false);
+      theme_l, 0, 0, theme_l.width(), theme_l.height() - toolbar_overlap, 0, 0,
+      theme_l.width(), theme_l.height() - toolbar_overlap, false);
 
   // Draw right edge.
   gfx::ImageSkia tab_r = gfx::ImageSkiaOperations::CreateTiledImage(
-      *tab_background, x_offset + width() - mask_images_.r_width, 0,
+      *fill_image, x_offset + width() - mask_images_.r_width, y_offset,
       mask_images_.r_width, height());
   gfx::ImageSkia theme_r =
       gfx::ImageSkiaOperations::CreateMaskedImage(tab_r, *mask_images_.image_r);
-  canvas->DrawImageInt(theme_r, 0, 0, theme_r.width(), theme_r.height(),
+  canvas->DrawImageInt(theme_r, 0, 0, theme_r.width(),
+                       theme_r.height() - toolbar_overlap,
                        width() - theme_r.width(), 0, theme_r.width(),
-                       theme_r.height(), false);
+                       theme_r.height() - toolbar_overlap, false);
 
   // Draw center.  Instead of masking out the top portion we simply skip over it
   // by incrementing by the top padding, since it's a simple rectangle.
-  canvas->TileImageInt(*tab_background, x_offset + mask_images_.l_width,
-                       tab_insets.top(), mask_images_.l_width, tab_insets.top(),
+  canvas->TileImageInt(*fill_image, x_offset + mask_images_.l_width,
+                       y_offset + tab_insets.top(), mask_images_.l_width,
+                       tab_insets.top(),
                        width() - mask_images_.l_width - mask_images_.r_width,
-                       height() - tab_insets.top());
-
-  // Now draw the stroke, highlights, and shadows around the tab edge.
-  TabImages* stroke_images = &active_images_;
-  canvas->DrawImageInt(*stroke_images->image_l, 0, 0);
-  canvas->TileImageInt(
-      *stroke_images->image_c, stroke_images->l_width, 0,
-      width() - stroke_images->l_width - stroke_images->r_width, height());
-  canvas->DrawImageInt(*stroke_images->image_r,
-                       width() - stroke_images->r_width, 0);
+                       height() - tab_insets.top() - toolbar_overlap);
 }
 
 void Tab::PaintIcon(gfx::Canvas* canvas) {
@@ -1507,22 +1484,6 @@
       main_bar_left, 0, main_bar_right - main_bar_left, kImmersiveBarHeight);
 }
 
-void Tab::GetTabIdAndFrameId(views::Widget* widget,
-                             int* tab_id,
-                             int* frame_id) const {
-  if (widget &&
-      widget->GetTopLevelWidget()->ShouldWindowContentsBeTransparent()) {
-    *tab_id = IDR_THEME_TAB_BACKGROUND_V;
-    *frame_id = 0;
-  } else if (data().incognito) {
-    *tab_id = IDR_THEME_TAB_BACKGROUND_INCOGNITO;
-    *frame_id = IDR_THEME_FRAME_INCOGNITO;
-  } else {
-    *tab_id = IDR_THEME_TAB_BACKGROUND;
-    *frame_id = IDR_THEME_FRAME;
-  }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Tab, private static:
 
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index be601119..38ea62c 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -239,9 +239,16 @@
   void PaintTabBackground(gfx::Canvas* canvas);
   void PaintInactiveTabBackgroundWithTitleChange(gfx::Canvas* canvas);
   void PaintInactiveTabBackground(gfx::Canvas* canvas);
-  void PaintInactiveTabBackgroundUsingResourceId(gfx::Canvas* canvas,
-                                                 int tab_id);
-  void PaintActiveTabBackground(gfx::Canvas* canvas);
+  void PaintTabBackgroundUsingFillId(gfx::Canvas* canvas,
+                                     bool is_active,
+                                     int fill_id,
+                                     bool has_custom_image,
+                                     int y_offset);
+  void PaintTabFill(gfx::Canvas* canvas,
+                    gfx::ImageSkia* fill_image,
+                    int x_offset,
+                    int y_offset,
+                    bool is_active);
 
   // Paints the favicon, mirrored for RTL if needed.
   void PaintIcon(gfx::Canvas* canvas);
@@ -291,11 +298,6 @@
   // Returns the rectangle for the light bar in immersive mode.
   gfx::Rect GetImmersiveBarRect() const;
 
-  // Gets the tab id and frame id.
-  void GetTabIdAndFrameId(views::Widget* widget,
-                          int* tab_id,
-                          int* frame_id) const;
-
   // Performs a one-time initialization of static resources such as tab images.
   static void InitTabResources();
 
diff --git a/chrome/browser/ui/views/tabs/tab_controller.h b/chrome/browser/ui/views/tabs/tab_controller.h
index 23de038..f8485e07 100644
--- a/chrome/browser/ui/views/tabs/tab_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_controller.h
@@ -96,6 +96,11 @@
   // Returns true if tabs painted in the rectangular light-bar style.
   virtual bool IsImmersiveStyle() const = 0;
 
+  // Returns the resource ID for the image to use as the tab background.
+  // |custom_image| is an outparam set to true if either the tab or the frame
+  // background images have been customized; see implementation comments.
+  virtual int GetBackgroundResourceId(bool* custom_image) const = 0;
+
   // Adds private information to the tab's accessibility state.
   virtual void UpdateTabAccessibilityState(const Tab* tab,
                                         ui::AXViewState* state) = 0;
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index da4e53b1..5fe10f19 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -398,11 +398,8 @@
                              double hover_value,
                              float scale,
                              gfx::Canvas* canvas) const {
-  int bg_id = IDR_THEME_TAB_BACKGROUND_V;
-  if (!GetWidget()->ShouldWindowContentsBeTransparent()) {
-    bg_id = tab_strip_->controller()->IsIncognito() ?
-        IDR_THEME_TAB_BACKGROUND_INCOGNITO : IDR_THEME_TAB_BACKGROUND;
-  }
+  bool custom_image;
+  const int bg_id = tab_strip_->GetBackgroundResourceId(&custom_image);
 
   // Draw the fill background image.
   const gfx::Size size(GetNewTabButtonSize());
@@ -1208,6 +1205,28 @@
   return immersive_style_;
 }
 
+int TabStrip::GetBackgroundResourceId(bool* custom_image) const {
+  ui::ThemeProvider* theme_provider = GetThemeProvider();
+
+  if (GetWidget()->ShouldWindowContentsBeTransparent()) {
+    const int kBackgroundIdGlass = IDR_THEME_TAB_BACKGROUND_V;
+    *custom_image = theme_provider->HasCustomImage(kBackgroundIdGlass);
+    return kBackgroundIdGlass;
+  }
+
+  // If a custom theme does not provide a replacement tab background, but does
+  // provide a replacement frame image, HasCustomImage() on the tab background
+  // ID will return false, but the theme provider will make a custom image from
+  // the frame image.
+  const bool incognito = controller()->IsIncognito();
+  const int id = incognito ?
+      IDR_THEME_TAB_BACKGROUND_INCOGNITO : IDR_THEME_TAB_BACKGROUND;
+  *custom_image = theme_provider->HasCustomImage(id) ||
+      theme_provider->HasCustomImage(
+          incognito ? IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME);
+  return id;
+}
+
 void TabStrip::UpdateTabAccessibilityState(const Tab* tab,
                                            ui::AXViewState* state) {
   state->count = tab_count();
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index 4f62593..9bd8882 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -231,6 +231,7 @@
                          const ui::MouseEvent& event) override;
   bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) override;
   bool IsImmersiveStyle() const override;
+  int GetBackgroundResourceId(bool* custom_image) const override;
   void UpdateTabAccessibilityState(const Tab* tab,
                                    ui::AXViewState* state) override;
 
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc
index 621fbca..27dacf94 100644
--- a/chrome/browser/ui/views/tabs/tab_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/browser/ui/views/tabs/media_indicator_button.h"
 #include "chrome/browser/ui/views/tabs/tab_controller.h"
+#include "grit/theme_resources.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/models/list_selection_model.h"
 #include "ui/views/controls/button/image_button.h"
@@ -60,6 +61,10 @@
                          const ui::MouseEvent& event) override {}
   bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) override { return true; }
   bool IsImmersiveStyle() const override { return immersive_style_; }
+  int GetBackgroundResourceId(bool* custom_image) const override {
+    *custom_image = false;
+    return IDR_THEME_TAB_BACKGROUND;
+  }
   void UpdateTabAccessibilityState(const Tab* tab,
                                    ui::AXViewState* state) override{};
 
diff --git a/chrome/chrome_debugger.gypi b/chrome/chrome_debugger.gypi
index 3a717779..50f17ab 100644
--- a/chrome/chrome_debugger.gypi
+++ b/chrome/chrome_debugger.gypi
@@ -101,6 +101,8 @@
             'browser/devtools/devtools_file_helper.h',
             'browser/devtools/devtools_file_system_indexer.cc',
             'browser/devtools/devtools_file_system_indexer.h',
+            'browser/devtools/devtools_file_watcher.cc',
+            'browser/devtools/devtools_file_watcher.h',
             'browser/devtools/devtools_target_impl.cc',
             'browser/devtools/devtools_target_impl.h',
             'browser/devtools/devtools_targets_ui.cc',
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index 7ee2509..816c2195 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -316,8 +316,8 @@
     const base::DictionaryValue& params,
     scoped_ptr<base::Value>* value) {
   std::string name;
-  if (!params.GetString("name", &name) || name.empty())
-    return Status(kUnknownError, "'name' must be a nonempty string");
+  if (!params.GetString("name", &name))
+    return Status(kUnknownError, "'name' must be a string");
 
   std::list<std::string> web_view_ids;
   Status status = session->chrome->GetWebViewIds(&web_view_ids);
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index 268a5b2..d66f80e5 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -33,6 +33,7 @@
     "//crypto",
     "//crypto:platform",
     "//google_apis",
+    "//ipc",
     "//third_party/icu",
     "//third_party/libxml",
     "//third_party/protobuf:protobuf_lite",
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 6558c09..9ab9baf 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-7609.0.0
\ No newline at end of file
+7611.0.0
\ No newline at end of file
diff --git a/chromeos/arc/OWNERS b/chromeos/arc/OWNERS
new file mode 100644
index 0000000..e67f9dff
--- /dev/null
+++ b/chromeos/arc/OWNERS
@@ -0,0 +1,3 @@
+elijahtaylor@chromium.org
+lhchavez@chromium.org
+dgreid@chromium.org
diff --git a/chromeos/arc/bridge/common/OWNERS b/chromeos/arc/bridge/common/OWNERS
new file mode 100644
index 0000000..78ef284
--- /dev/null
+++ b/chromeos/arc/bridge/common/OWNERS
@@ -0,0 +1,12 @@
+ # Changes to IPC messages require a security review to avoid introducing
+ # new sandbox escapes.
+ per-file *_messages*.h=set noparent
+ per-file *_messages*.h=dcheng@chromium.org
+ per-file *_messages*.h=inferno@chromium.org
+ per-file *_messages*.h=jln@chromium.org
+ per-file *_messages*.h=jschuh@chromium.org
+ per-file *_messages*.h=kenrb@chromium.org
+ per-file *_messages*.h=mkwst@chromium.org
+ per-file *_messages*.h=nasko@chromium.org
+ per-file *_messages*.h=tsepez@chromium.org
+ per-file *_messages*.h=wfh@chromium.org
diff --git a/chromeos/arc/bridge/common/arc_host_messages.h b/chromeos/arc/bridge/common/arc_host_messages.h
new file mode 100644
index 0000000..a04efd2
--- /dev/null
+++ b/chromeos/arc/bridge/common/arc_host_messages.h
@@ -0,0 +1,12 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Messages sent from the host to the ARC instance
+// Multiply-included message file, hence no include guard.
+
+#include "ipc/ipc_message_macros.h"
+
+#define IPC_MESSAGE_START ArcInstanceHostMsgStart
+
+IPC_MESSAGE_CONTROL0(ArcInstanceHostMsg_InstanceReady)
diff --git a/chromeos/arc/bridge/common/arc_instance_messages.h b/chromeos/arc/bridge/common/arc_instance_messages.h
new file mode 100644
index 0000000..607718d1
--- /dev/null
+++ b/chromeos/arc/bridge/common/arc_instance_messages.h
@@ -0,0 +1,24 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Messages sent from the ARC instance to the host
+// Multiply-included message file, hence no include guard.
+
+#include <stdint.h>
+
+#include "base/file_descriptor_posix.h"
+#include "ipc/ipc_message_macros.h"
+
+#define IPC_MESSAGE_START ArcInstanceMsgStart
+
+// Registers a virtual input device on the container side.
+// |name| is the device name, like "Chrome OS Keyboard".
+// |device_type| is the device type, like "keyboard".
+// The virtual device will be reading 'struct input_event's from |fd|.  The
+// ownership of |fd| will be transferred to the receiver, so the sender must
+// not close it.
+IPC_MESSAGE_CONTROL3(ArcInstanceMsg_RegisterInputDevice,
+                     std::string, /* name */
+                     std::string, /* device_type */
+                     base::FileDescriptor /* fd */)
diff --git a/chromeos/arc/bridge/common/arc_message_generator.cc b/chromeos/arc/bridge/common/arc_message_generator.cc
new file mode 100644
index 0000000..910d433f
--- /dev/null
+++ b/chromeos/arc/bridge/common/arc_message_generator.cc
@@ -0,0 +1,33 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Get basic type definitions.
+#define IPC_MESSAGE_IMPL
+#include "arc_message_generator.h"
+
+// Generate constructors.
+#include "ipc/struct_constructor_macros.h"
+#include "arc_message_generator.h"
+
+// Generate destructors.
+#include "ipc/struct_destructor_macros.h"
+#include "arc_message_generator.h"
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#include "arc_message_generator.h"
+}  // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#include "arc_message_generator.h"
+}  // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#include "arc_message_generator.h"
+}  // namespace IPC
diff --git a/chromeos/arc/bridge/common/arc_message_generator.h b/chromeos/arc/bridge/common/arc_message_generator.h
new file mode 100644
index 0000000..2b302a6
--- /dev/null
+++ b/chromeos/arc/bridge/common/arc_message_generator.h
@@ -0,0 +1,9 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Multiply-included message file, hence no include guard.
+
+// Not using the full path since this is also expected to be compiled in ARC.
+#include "arc_host_messages.h"
+#include "arc_instance_messages.h"
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp
index d2f05119..2f93d9ed 100644
--- a/chromeos/chromeos.gyp
+++ b/chromeos/chromeos.gyp
@@ -13,6 +13,7 @@
       'accelerometer/accelerometer_types.h',
       'app_mode/kiosk_oem_manifest_parser.cc',
       'app_mode/kiosk_oem_manifest_parser.h',
+      'arc/bridge/common/arc_message_generator.cc',
       'attestation/attestation_constants.cc',
       'attestation/attestation_constants.h',
       'attestation/attestation_flow.cc',
@@ -478,6 +479,7 @@
         '../crypto/crypto.gyp:crypto',
         '../dbus/dbus.gyp:dbus',
         '../google_apis/google_apis.gyp:google_apis',
+        '../ipc/ipc.gyp:ipc',
         '../net/net.gyp:net',
         '../third_party/icu/icu.gyp:icui18n',
         '../third_party/libxml/libxml.gyp:libxml',
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.cc b/components/autofill/content/browser/content_autofill_driver_factory.cc
index d19bd574..565c58b 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory.cc
+++ b/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -57,11 +57,7 @@
                  base::Unretained(this)));
 }
 
-ContentAutofillDriverFactory::~ContentAutofillDriverFactory() {
-  STLDeleteContainerPairSecondPointers(frame_driver_map_.begin(),
-                                       frame_driver_map_.end());
-  frame_driver_map_.clear();
-}
+ContentAutofillDriverFactory::~ContentAutofillDriverFactory() {}
 
 ContentAutofillDriver* ContentAutofillDriverFactory::DriverForFrame(
     content::RenderFrameHost* render_frame_host) {
@@ -72,19 +68,19 @@
 bool ContentAutofillDriverFactory::OnMessageReceived(
     const IPC::Message& message,
     content::RenderFrameHost* render_frame_host) {
-  return frame_driver_map_[render_frame_host]->HandleMessage(message);
+  return frame_driver_map_.find(render_frame_host)
+      ->second->HandleMessage(message);
 }
 
 void ContentAutofillDriverFactory::RenderFrameCreated(
     content::RenderFrameHost* render_frame_host) {
   // RenderFrameCreated is called more than once for the main frame.
-  if (!frame_driver_map_[render_frame_host])
+  if (!ContainsKey(frame_driver_map_, render_frame_host))
     CreateDriverForFrame(render_frame_host);
 }
 
 void ContentAutofillDriverFactory::RenderFrameDeleted(
     content::RenderFrameHost* render_frame_host) {
-  delete frame_driver_map_[render_frame_host];
   frame_driver_map_.erase(render_frame_host);
 }
 
@@ -92,7 +88,7 @@
     content::RenderFrameHost* rfh,
     const content::LoadCommittedDetails& details,
     const content::FrameNavigateParams& params) {
-  frame_driver_map_[rfh]->DidNavigateFrame(details, params);
+  frame_driver_map_.find(rfh)->second->DidNavigateFrame(details, params);
 }
 
 void ContentAutofillDriverFactory::NavigationEntryCommitted(
@@ -106,9 +102,11 @@
 
 void ContentAutofillDriverFactory::CreateDriverForFrame(
     content::RenderFrameHost* render_frame_host) {
-  DCHECK(!frame_driver_map_[render_frame_host]);
-  frame_driver_map_[render_frame_host] = new ContentAutofillDriver(
-      render_frame_host, client_, app_locale_, enable_download_manager_);
+  DCHECK(!ContainsKey(frame_driver_map_, render_frame_host));
+  frame_driver_map_.set(
+      render_frame_host,
+      make_scoped_ptr(new ContentAutofillDriver(
+          render_frame_host, client_, app_locale_, enable_download_manager_)));
 }
 
 }  // namespace autofill
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.h b/components/autofill/content/browser/content_autofill_driver_factory.h
index c0b1aa1..95f8df6 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory.h
+++ b/components/autofill/content/browser/content_autofill_driver_factory.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/containers/scoped_ptr_map.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/supports_user_data.h"
 #include "components/autofill/content/browser/request_autocomplete_manager.h"
@@ -74,7 +75,8 @@
   std::string app_locale_;
   AutofillManager::AutofillDownloadManagerState enable_download_manager_;
 
-  std::map<content::RenderFrameHost*, ContentAutofillDriver*> frame_driver_map_;
+  base::ScopedPtrMap<content::RenderFrameHost*,
+                     scoped_ptr<ContentAutofillDriver>> frame_driver_map_;
 };
 
 }  // namespace autofill
diff --git a/components/mus/example/wm/BUILD.gn b/components/mus/example/wm/BUILD.gn
index faf1b6c..82df07e 100644
--- a/components/mus/example/wm/BUILD.gn
+++ b/components/mus/example/wm/BUILD.gn
@@ -22,6 +22,10 @@
     "layout_manager.h",
     "move_loop.cc",
     "move_loop.h",
+    "non_client_frame_controller.cc",
+    "non_client_frame_controller.h",
+    "non_client_frame_view_impl.cc",
+    "non_client_frame_view_impl.h",
     "property_util.cc",
     "property_util.h",
     "shelf_layout.cc",
@@ -42,6 +46,10 @@
     "//mojo/application/public/cpp",
     "//mojo/common:common_base",
     "//mojo/converters/geometry",
+    "//skia",
+    "//ui/mojo/init",
+    "//ui/views",
+    "//ui/views/mus",
   ]
 }
 
@@ -53,11 +61,14 @@
   deps = [
     ":example_wm_lib",
     "//mojo/application/public/cpp",
+    "//ui/views/mus:resources",
   ]
 
   data_deps = [
     "//components/mus",
   ]
+
+  resources = [ "$root_out_dir/views_mus_resources.pak" ]
 }
 
 mojo_native_application("apptests") {
diff --git a/components/mus/example/wm/move_loop.cc b/components/mus/example/wm/move_loop.cc
index 28e33bc..926855e9 100644
--- a/components/mus/example/wm/move_loop.cc
+++ b/components/mus/example/wm/move_loop.cc
@@ -31,6 +31,12 @@
                mus::mojom::EVENT_FLAGS_RIGHT_MOUSE_BUTTON));
 }
 
+gfx::Rect ClientAreaBounds(const mus::Window* window) {
+  gfx::Rect client_area(window->bounds().size());
+  client_area.Inset(window->client_area());
+  return client_area;
+}
+
 }  // namespace
 
 MoveLoop::~MoveLoop() {
@@ -44,7 +50,7 @@
   DCHECK_EQ(event.action, mus::mojom::EVENT_TYPE_POINTER_DOWN);
   const gfx::Point location(EventLocationToPoint(event));
   if (!gfx::Rect(target->bounds().size()).Contains(location) ||
-      target->client_area().Contains(location)) {
+      ClientAreaBounds(target).Contains(location)) {
     return nullptr;
   }
 
@@ -123,16 +129,17 @@
       kResizeSize *
       std::max(1.f, target->viewport_metrics().device_pixel_ratio));
 
-  if (location.x() < target->client_area().x())
+  const gfx::Rect client_area(ClientAreaBounds(target));
+  if (location.x() < client_area.x())
     *h_loc = HorizontalLocation::LEFT;
-  else if (location.x() >= target->client_area().right())
+  else if (location.x() >= client_area.right())
     *h_loc = HorizontalLocation::RIGHT;
   else
     *h_loc = HorizontalLocation::OTHER;
 
   if (location.y() < resize_size)
     *v_loc = VerticalLocation::TOP;
-  else if (location.y() >= target->client_area().bottom())
+  else if (location.y() >= client_area.bottom())
     *v_loc = VerticalLocation::BOTTOM;
   else
     *v_loc = VerticalLocation::OTHER;
diff --git a/components/mus/example/wm/move_loop_unittest.cc b/components/mus/example/wm/move_loop_unittest.cc
index 175e6cf8..13229a4 100644
--- a/components/mus/example/wm/move_loop_unittest.cc
+++ b/components/mus/example/wm/move_loop_unittest.cc
@@ -22,10 +22,9 @@
   if (window->bounds().IsEmpty())
     window->SetBounds(gfx::Rect(100, 200, 300, 400));
 
-  gfx::Rect client_area(window->bounds().size());
-  client_area.Inset(MoveLoop::kResizeSize, MoveLoop::kResizeSize + 10,
-                    MoveLoop::kResizeSize, MoveLoop::kResizeSize);
-  window->SetClientArea(client_area);
+  window->SetClientArea(
+      gfx::Insets(MoveLoop::kResizeSize + 10, MoveLoop::kResizeSize,
+                  MoveLoop::kResizeSize, MoveLoop::kResizeSize));
 }
 
 mus::mojom::EventPtr CreatePointerDownEvent(const gfx::Point& location) {
diff --git a/components/mus/example/wm/non_client_frame_controller.cc b/components/mus/example/wm/non_client_frame_controller.cc
new file mode 100644
index 0000000..8cd5add
--- /dev/null
+++ b/components/mus/example/wm/non_client_frame_controller.cc
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/mus/example/wm/non_client_frame_controller.h"
+
+#include "components/mus/example/wm/non_client_frame_view_impl.h"
+#include "components/mus/public/cpp/window.h"
+#include "ui/views/mus/native_widget_mus.h"
+#include "ui/views/widget/widget.h"
+
+namespace {
+
+class WmNativeWidgetMus : public views::NativeWidgetMus {
+ public:
+  WmNativeWidgetMus(views::internal::NativeWidgetDelegate* delegate,
+                    mojo::Shell* shell,
+                    mus::Window* window)
+      : NativeWidgetMus(delegate,
+                        shell,
+                        window,
+                        mus::mojom::SURFACE_TYPE_UNDERLAY) {}
+  ~WmNativeWidgetMus() override {}
+
+  // NativeWidgetMus:
+  views::NonClientFrameView* CreateNonClientFrameView() override {
+    NonClientFrameViewImpl* frame_view = new NonClientFrameViewImpl(window());
+    frame_view->Init(
+        static_cast<views::internal::NativeWidgetPrivate*>(this)->GetWidget());
+    return frame_view;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WmNativeWidgetMus);
+};
+
+}  // namespace
+
+NonClientFrameController::NonClientFrameController(mojo::Shell* shell,
+                                                   mus::Window* window) {
+  views::Widget* widget = new views::Widget;
+  views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
+  params.delegate = this;
+  params.native_widget = new WmNativeWidgetMus(widget, shell, window);
+  widget->Init(params);
+  widget->Show();
+}
+
+NonClientFrameController::~NonClientFrameController() {}
+
+views::View* NonClientFrameController::GetContentsView() {
+  return this;
+}
diff --git a/components/mus/example/wm/non_client_frame_controller.h b/components/mus/example/wm/non_client_frame_controller.h
new file mode 100644
index 0000000..914f7eb
--- /dev/null
+++ b/components/mus/example/wm/non_client_frame_controller.h
@@ -0,0 +1,34 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_MUS_EXAMPLE_WM_NON_CLIENT_FRAME_CONTROLLER_H_
+#define COMPONENTS_MUS_EXAMPLE_WM_NON_CLIENT_FRAME_CONTROLLER_H_
+
+#include "base/macros.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace mojo {
+class Shell;
+}
+
+namespace mus {
+class Window;
+}
+
+// Provides the non-client frame for mus Windows.
+class NonClientFrameController : public views::WidgetDelegateView {
+ public:
+  // NonClientFrameController deletes itself when |window| is destroyed.
+  NonClientFrameController(mojo::Shell* shell, mus::Window* window);
+
+ private:
+  ~NonClientFrameController() override;
+
+  // views::WidgetDelegateView:
+  views::View* GetContentsView() override;
+
+  DISALLOW_COPY_AND_ASSIGN(NonClientFrameController);
+};
+
+#endif  // COMPONENTS_MUS_EXAMPLE_WM_NON_CLIENT_FRAME_CONTROLLER_H_
diff --git a/components/mus/example/wm/non_client_frame_view_impl.cc b/components/mus/example/wm/non_client_frame_view_impl.cc
new file mode 100644
index 0000000..7ca7a223
--- /dev/null
+++ b/components/mus/example/wm/non_client_frame_view_impl.cc
@@ -0,0 +1,58 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/mus/example/wm/non_client_frame_view_impl.h"
+
+#include "components/mus/public/cpp/window.h"
+#include "ui/compositor/paint_recorder.h"
+#include "ui/gfx/canvas.h"
+
+NonClientFrameViewImpl::NonClientFrameViewImpl(mus::Window* window)
+    : window_(window) {
+  window_->AddObserver(this);
+}
+
+NonClientFrameViewImpl::~NonClientFrameViewImpl() {
+  if (window_)
+    window_->RemoveObserver(this);
+}
+
+gfx::Rect NonClientFrameViewImpl::GetBoundsForClientView() const {
+  gfx::Rect result(GetLocalBounds());
+  result.Inset(window_->client_area());
+  return result;
+}
+
+void NonClientFrameViewImpl::OnPaint(gfx::Canvas* canvas) {
+  canvas->Save();
+  CustomFrameView::OnPaint(canvas);
+  canvas->Restore();
+
+  // The client app draws the client area. Make ours totally transparent so
+  // we only see the client apps client area.
+  canvas->FillRect(GetBoundsForClientView(), SK_ColorBLACK,
+                   SkXfermode::kSrc_Mode);
+}
+
+void NonClientFrameViewImpl::PaintChildren(const ui::PaintContext& context) {
+  CustomFrameView::PaintChildren(context);
+
+  // The client app draws the client area. Make ours totally transparent so
+  // we only see the client apps client area.
+  ui::PaintRecorder recorder(context, size(), &paint_cache_);
+  recorder.canvas()->FillRect(GetBoundsForClientView(), SK_ColorBLACK,
+                              SkXfermode::kSrc_Mode);
+}
+
+void NonClientFrameViewImpl::OnWindowClientAreaChanged(
+    mus::Window* window,
+    const gfx::Insets& old_client_area) {
+  Layout();
+  SchedulePaint();
+}
+
+void NonClientFrameViewImpl::OnWindowDestroyed(mus::Window* window) {
+  window_->RemoveObserver(this);
+  window_ = nullptr;
+}
diff --git a/components/mus/example/wm/non_client_frame_view_impl.h b/components/mus/example/wm/non_client_frame_view_impl.h
new file mode 100644
index 0000000..b5a9d319
--- /dev/null
+++ b/components/mus/example/wm/non_client_frame_view_impl.h
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_MUS_EXAMPLE_WM_NON_CLIENT_FRAME_VIEW_IMPL_H_
+#define COMPONENTS_MUS_EXAMPLE_WM_NON_CLIENT_FRAME_VIEW_IMPL_H_
+
+#include "base/macros.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "ui/compositor/paint_cache.h"
+#include "ui/views/window/custom_frame_view.h"
+
+class NonClientFrameViewImpl : public views::CustomFrameView,
+                               public mus::WindowObserver {
+ public:
+  explicit NonClientFrameViewImpl(mus::Window* window);
+  ~NonClientFrameViewImpl() override;
+
+ private:
+  // CustomFrameView:
+  gfx::Rect GetBoundsForClientView() const override;
+  void OnPaint(gfx::Canvas* canvas) override;
+  void PaintChildren(const ui::PaintContext& context) override;
+
+  // mus::WindowObserver:
+  void OnWindowClientAreaChanged(mus::Window* window,
+                                 const gfx::Insets& old_client_area) override;
+  void OnWindowDestroyed(mus::Window* window) override;
+
+ private:
+  mus::Window* window_;
+  ui::PaintCache paint_cache_;
+
+  DISALLOW_COPY_AND_ASSIGN(NonClientFrameViewImpl);
+};
+
+#endif  // COMPONENTS_MUS_EXAMPLE_WM_NON_CLIENT_FRAME_VIEW_IMPL_H_
diff --git a/components/mus/example/wm/window_manager_application.cc b/components/mus/example/wm/window_manager_application.cc
index f5cfee7d..67e56ee 100644
--- a/components/mus/example/wm/window_manager_application.cc
+++ b/components/mus/example/wm/window_manager_application.cc
@@ -13,9 +13,12 @@
 #include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/mus/public/cpp/window_tree_host_factory.h"
 #include "mojo/application/public/cpp/application_connection.h"
+#include "ui/mojo/init/ui_init.h"
+#include "ui/views/mus/aura_init.h"
+#include "ui/views/mus/display_converter.h"
 
 WindowManagerApplication::WindowManagerApplication()
-    : root_(nullptr), window_count_(0) {}
+    : root_(nullptr), window_count_(0), app_(nullptr) {}
 WindowManagerApplication::~WindowManagerApplication() {}
 
 mus::Window* WindowManagerApplication::GetWindowForContainer(
@@ -30,6 +33,7 @@
 }
 
 void WindowManagerApplication::Initialize(mojo::ApplicationImpl* app) {
+  app_ = app;
   mus::mojom::WindowManagerPtr window_manager;
   requests_.push_back(new mojo::InterfaceRequest<mus::mojom::WindowManager>(
       mojo::GetProxy(&window_manager)));
@@ -54,6 +58,10 @@
       GetWindowForContainer(ash::mojom::CONTAINER_USER_WINDOWS)));
 
   window_manager_.reset(new WindowManagerImpl(this));
+
+  ui_init_.reset(new ui::mojo::UIInit(views::GetDisplaysFromWindow(root)));
+  aura_init_.reset(new views::AuraInit(app_, "views_mus_resources.pak"));
+
   for (auto request : requests_)
     window_manager_binding_.AddBinding(window_manager_.get(), request->Pass());
   requests_.clear();
diff --git a/components/mus/example/wm/window_manager_application.h b/components/mus/example/wm/window_manager_application.h
index 65be459..635e1004 100644
--- a/components/mus/example/wm/window_manager_application.h
+++ b/components/mus/example/wm/window_manager_application.h
@@ -21,9 +21,18 @@
 class BackgroundLayout;
 class ShelfLayout;
 class WindowLayout;
-
 class WindowManagerImpl;
 
+namespace ui {
+namespace mojo {
+class UIInit;
+}
+}
+
+namespace views {
+class AuraInit;
+}
+
 class WindowManagerApplication
     : public mojo::ApplicationDelegate,
       public mus::WindowObserver,
@@ -41,6 +50,8 @@
   mus::Window* GetWindowForContainer(ash::mojom::Container container);
   mus::Window* GetWindowById(mus::Id id);
 
+  mojo::ApplicationImpl* app() { return app_; }
+
  private:
   // ApplicationDelegate:
   void Initialize(mojo::ApplicationImpl* app) override;
@@ -66,8 +77,13 @@
   mus::Window* root_;
   int window_count_;
 
+  mojo::ApplicationImpl* app_;
+
   mus::mojom::WindowTreeHostPtr host_;
 
+  scoped_ptr<ui::mojo::UIInit> ui_init_;
+  scoped_ptr<views::AuraInit> aura_init_;
+
   // |window_manager_| is created once OnEmbed() is called. Until that time
   // |requests_| stores any pending WindowManager interface requests.
   scoped_ptr<WindowManagerImpl> window_manager_;
diff --git a/components/mus/example/wm/window_manager_impl.cc b/components/mus/example/wm/window_manager_impl.cc
index 9525f26..6039472 100644
--- a/components/mus/example/wm/window_manager_impl.cc
+++ b/components/mus/example/wm/window_manager_impl.cc
@@ -5,6 +5,7 @@
 #include "components/mus/example/wm/window_manager_impl.h"
 
 #include "components/mus/example/wm/move_loop.h"
+#include "components/mus/example/wm/non_client_frame_controller.h"
 #include "components/mus/example/wm/property_util.h"
 #include "components/mus/example/wm/public/interfaces/container.mojom.h"
 #include "components/mus/example/wm/window_manager_application.h"
@@ -14,6 +15,7 @@
 #include "components/mus/public/cpp/window_property.h"
 #include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/mus/public/interfaces/input_events.mojom.h"
+#include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
 
 namespace {
@@ -73,6 +75,9 @@
   child_window->Embed(client.Pass());
   child_window->AddObserver(this);
 
+  // NonClientFrameController deletes itself when the window is destroyed.
+  new NonClientFrameController(state_->app()->shell(), child_window);
+
   state_->IncrementWindowCount();
 }
 
@@ -105,18 +110,36 @@
   callback.Run(mus::mojom::WINDOW_MANAGER_ERROR_CODE_SUCCESS);
 }
 
-void WindowManagerImpl::GetDisplays(const GetDisplaysCallback& callback) {
-  mojo::Array<mus::mojom::DisplayPtr> displays(1);
-  displays[0] = mus::mojom::Display::New();
-  displays[0]->id = 2001;
-  displays[0]->bounds = mojo::Rect::New();
-  displays[0]->bounds->y = 0;
-  displays[0]->bounds->width = state_->root()->bounds().width();
-  displays[0]->bounds->height = state_->root()->bounds().width();
-  displays[0]->work_area = displays[0]->bounds.Clone();
-  displays[0]->device_pixel_ratio =
+void WindowManagerImpl::GetConfig(const GetConfigCallback& callback) {
+  mus::mojom::WindowManagerConfigPtr config(
+      mus::mojom::WindowManagerConfig::New());
+  config->displays = mojo::Array<mus::mojom::DisplayPtr>::New(1);
+  config->displays[0] = mus::mojom::Display::New();
+  config->displays[0]->id = 2001;
+  config->displays[0]->bounds = mojo::Rect::New();
+  config->displays[0]->bounds->y = 0;
+  config->displays[0]->bounds->width = state_->root()->bounds().width();
+  config->displays[0]->bounds->height = state_->root()->bounds().width();
+  config->displays[0]->work_area = config->displays[0]->bounds.Clone();
+  config->displays[0]->device_pixel_ratio =
       state_->root()->viewport_metrics().device_pixel_ratio;
-  callback.Run(displays.Pass());
+
+  // The insets are roughly what is needed by CustomFrameView. The expectation
+  // is at some point we'll write our own NonClientFrameView and get the insets
+  // from it.
+  config->normal_client_area_insets = mojo::Insets::New();
+  config->normal_client_area_insets->top = 23;
+  config->normal_client_area_insets->left = 5;
+  config->normal_client_area_insets->right = 5;
+  config->normal_client_area_insets->bottom = 5;
+
+  config->maximized_client_area_insets = mojo::Insets::New();
+  config->maximized_client_area_insets->top = 21;
+  config->maximized_client_area_insets->left = 0;
+  config->maximized_client_area_insets->right = 0;
+  config->maximized_client_area_insets->bottom = 0;
+
+  callback.Run(config.Pass());
 }
 
 void WindowManagerImpl::OnWindowDestroyed(mus::Window* window) {
diff --git a/components/mus/example/wm/window_manager_impl.h b/components/mus/example/wm/window_manager_impl.h
index 5551a47..3df0aa2 100644
--- a/components/mus/example/wm/window_manager_impl.h
+++ b/components/mus/example/wm/window_manager_impl.h
@@ -39,7 +39,7 @@
   void SetShowState(mus::Id window_id,
                     mus::mojom::ShowState show_state,
                     const WindowManagerErrorCodeCallback& callback) override;
-  void GetDisplays(const GetDisplaysCallback& callback) override;
+  void GetConfig(const GetConfigCallback& callback) override;
 
   // mus::WindowObserver:
   void OnWindowDestroyed(mus::Window* window) override;
diff --git a/components/mus/public/cpp/lib/window.cc b/components/mus/public/cpp/lib/window.cc
index 13f5009..a8cd5219 100644
--- a/components/mus/public/cpp/lib/window.cc
+++ b/components/mus/public/cpp/lib/window.cc
@@ -214,7 +214,7 @@
   LocalSetBounds(bounds_, bounds);
 }
 
-void Window::SetClientArea(const gfx::Rect& client_area) {
+void Window::SetClientArea(const gfx::Insets& client_area) {
   if (!OwnsWindow(connection_, this) && !IsConnectionRoot(this))
     return;
 
@@ -535,13 +535,11 @@
   // the bounds.
   DCHECK(!OwnsWindow(connection_, this) || old_bounds == bounds_);
   ScopedSetBoundsNotifier notifier(this, old_bounds, new_bounds);
-  if (bounds_.size() != new_bounds.size())
-    client_area_ = gfx::Rect(new_bounds.size());
   bounds_ = new_bounds;
 }
 
-void Window::LocalSetClientArea(const gfx::Rect& new_client_area) {
-  const gfx::Rect old_client_area = client_area_;
+void Window::LocalSetClientArea(const gfx::Insets& new_client_area) {
+  const gfx::Insets old_client_area = client_area_;
   client_area_ = new_client_area;
   FOR_EACH_OBSERVER(WindowObserver, observers_,
                     OnWindowClientAreaChanged(this, old_client_area));
diff --git a/components/mus/public/cpp/lib/window_private.h b/components/mus/public/cpp/lib/window_private.h
index 4f9b57f..d566a60 100644
--- a/components/mus/public/cpp/lib/window_private.h
+++ b/components/mus/public/cpp/lib/window_private.h
@@ -54,7 +54,7 @@
                       const gfx::Rect& new_bounds) {
     window_->LocalSetBounds(old_bounds, new_bounds);
   }
-  void LocalSetClientArea(const gfx::Rect& new_client_area) {
+  void LocalSetClientArea(const gfx::Insets& new_client_area) {
     window_->LocalSetClientArea(new_client_area);
   }
   void LocalSetDrawn(bool drawn) { window_->LocalSetDrawn(drawn); }
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.cc b/components/mus/public/cpp/lib/window_tree_client_impl.cc
index fff7f2d..b869e442 100644
--- a/components/mus/public/cpp/lib/window_tree_client_impl.cc
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.cc
@@ -15,6 +15,7 @@
 #include "mojo/application/public/cpp/service_provider_impl.h"
 #include "mojo/application/public/interfaces/service_provider.mojom.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
+#include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace mus {
@@ -182,9 +183,9 @@
 }
 
 void WindowTreeClientImpl::SetClientArea(Id window_id,
-                                         const gfx::Rect& client_area) {
+                                         const gfx::Insets& client_area) {
   DCHECK(tree_);
-  tree_->SetClientArea(window_id, mojo::Rect::From(client_area));
+  tree_->SetClientArea(window_id, mojo::Insets::From(client_area));
 }
 
 void WindowTreeClientImpl::SetFocus(Id window_id) {
@@ -361,12 +362,13 @@
       .LocalSetBounds(old_bounds.To<gfx::Rect>(), new_bounds.To<gfx::Rect>());
 }
 
-void WindowTreeClientImpl::OnClientAreaChanged(uint32_t window_id,
-                                               mojo::RectPtr old_client_area,
-                                               mojo::RectPtr new_client_area) {
+void WindowTreeClientImpl::OnClientAreaChanged(
+    uint32_t window_id,
+    mojo::InsetsPtr old_client_area,
+    mojo::InsetsPtr new_client_area) {
   Window* window = GetWindowById(window_id);
   if (window)
-    WindowPrivate(window).LocalSetClientArea(new_client_area.To<gfx::Rect>());
+    WindowPrivate(window).LocalSetClientArea(new_client_area.To<gfx::Insets>());
 }
 
 namespace {
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.h b/components/mus/public/cpp/lib/window_tree_client_impl.h
index c6ce955b..4b8baeac 100644
--- a/components/mus/public/cpp/lib/window_tree_client_impl.h
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.h
@@ -12,6 +12,7 @@
 #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
 
 namespace gfx {
+class Insets;
 class Size;
 }
 
@@ -52,7 +53,7 @@
   bool OwnsWindow(Id id) const;
 
   void SetBounds(Id window_id, const gfx::Rect& bounds);
-  void SetClientArea(Id window_id, const gfx::Rect& client_area);
+  void SetClientArea(Id window_id, const gfx::Insets& client_area);
   void SetFocus(Id window_id);
   void SetVisible(Id window_id, bool visible);
   void SetProperty(Id window_id,
@@ -123,8 +124,8 @@
                              mojo::RectPtr old_bounds,
                              mojo::RectPtr new_bounds) override;
   void OnClientAreaChanged(uint32_t window_id,
-                           mojo::RectPtr old_client_area,
-                           mojo::RectPtr new_client_area) override;
+                           mojo::InsetsPtr old_client_area,
+                           mojo::InsetsPtr new_client_area) override;
   void OnWindowViewportMetricsChanged(
       mojom::ViewportMetricsPtr old_metrics,
       mojom::ViewportMetricsPtr new_metrics) override;
diff --git a/components/mus/public/cpp/window.h b/components/mus/public/cpp/window.h
index 1e4f1d6..f3e39e8a 100644
--- a/components/mus/public/cpp/window.h
+++ b/components/mus/public/cpp/window.h
@@ -17,6 +17,7 @@
 #include "mojo/application/public/interfaces/service_provider.mojom.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/array.h"
 #include "third_party/mojo/src/mojo/public/cpp/system/macros.h"
+#include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace gfx {
@@ -63,8 +64,8 @@
   const gfx::Rect& bounds() const { return bounds_; }
   void SetBounds(const gfx::Rect& bounds);
 
-  const gfx::Rect& client_area() const { return client_area_; }
-  void SetClientArea(const gfx::Rect& client_area);
+  const gfx::Insets& client_area() const { return client_area_; }
+  void SetClientArea(const gfx::Insets& new_client_area);
 
   // Visibility (also see IsDrawn()). When created windows are hidden.
   bool visible() const { return visible_; }
@@ -199,7 +200,7 @@
   // Returns true if the order actually changed.
   bool LocalReorder(Window* relative, mojom::OrderDirection direction);
   void LocalSetBounds(const gfx::Rect& old_bounds, const gfx::Rect& new_bounds);
-  void LocalSetClientArea(const gfx::Rect& new_client_area);
+  void LocalSetClientArea(const gfx::Insets& new_client_area);
   void LocalSetViewportMetrics(const mojom::ViewportMetrics& old_metrics,
                                const mojom::ViewportMetrics& new_metrics);
   void LocalSetDrawn(bool drawn);
@@ -231,7 +232,7 @@
   base::ObserverList<WindowObserver> observers_;
 
   gfx::Rect bounds_;
-  gfx::Rect client_area_;
+  gfx::Insets client_area_;
 
   mojom::ViewportMetricsPtr viewport_metrics_;
 
diff --git a/components/mus/public/cpp/window_observer.h b/components/mus/public/cpp/window_observer.h
index 91fd666..979428ad 100644
--- a/components/mus/public/cpp/window_observer.h
+++ b/components/mus/public/cpp/window_observer.h
@@ -55,7 +55,7 @@
                                      const gfx::Rect& old_bounds,
                                      const gfx::Rect& new_bounds) {}
   virtual void OnWindowClientAreaChanged(Window* window,
-                                         const gfx::Rect& old_client_area) {}
+                                         const gfx::Insets& old_client_area) {}
 
   virtual void OnWindowViewportMetricsChanged(
       Window* window,
diff --git a/components/mus/public/interfaces/window_manager.mojom b/components/mus/public/interfaces/window_manager.mojom
index c7881f4..140e455a 100644
--- a/components/mus/public/interfaces/window_manager.mojom
+++ b/components/mus/public/interfaces/window_manager.mojom
@@ -8,6 +8,12 @@
 import "components/mus/public/interfaces/window_tree.mojom";
 import "ui/mojo/geometry/geometry.mojom";
 
+struct WindowManagerConfig {
+  array<Display> displays;
+  mojo.Insets normal_client_area_insets;
+  mojo.Insets maximized_client_area_insets;
+};
+
 // Represents a core interface that should be implemented by any window manager
 // built on top of Mus.
 // For security reasons, methods that take window_ids can only pass window ids
@@ -35,5 +41,5 @@
   SetShowState(uint32 window_id, ShowState show_state) =>
       (WindowManagerErrorCode result);
 
-  GetDisplays() => (array<Display> displays);
+  GetConfig() => (WindowManagerConfig config);
 };
diff --git a/components/mus/public/interfaces/window_tree.mojom b/components/mus/public/interfaces/window_tree.mojom
index 345f571..67a2f3a 100644
--- a/components/mus/public/interfaces/window_tree.mojom
+++ b/components/mus/public/interfaces/window_tree.mojom
@@ -90,9 +90,8 @@
   // Sets the specified bounds of the specified window.
   SetWindowBounds(uint32 window_id, mojo.Rect bounds) => (bool success);
 
-  // Sets the client area of the specified window. Areas outside the client
-  // area are treated specially.
-  SetClientArea(uint32 window_id, mojo.Rect rect);
+  // Sets the insets of the client area of the specified window.
+  SetClientArea(uint32 window_id, mojo.Insets insets);
 
   // Sets the visibility of the specified window to |visible|. Connections are
   // allowed to change the visibility of any window they have created, as well
@@ -197,7 +196,6 @@
       (WindowManagerErrorCode result);
   SetShowState(uint32 window_id, ShowState show_state) =>
       (WindowManagerErrorCode result);
-  GetDisplays() => (array<Display> displays);
 };
 
 // Changes to windows are not sent to the connection that originated the
@@ -231,8 +229,8 @@
                         mojo.Rect new_bounds);
 
   OnClientAreaChanged(uint32 window_id,
-                      mojo.Rect old_client_area,
-                      mojo.Rect new_client_area);
+                      mojo.Insets old_client_area,
+                      mojo.Insets new_client_area);
 
   // Invoked when the viewport metrics for the window have changed.
   // Clients are expected to propagate this to the window tree.
diff --git a/components/mus/ws/connection_manager.cc b/components/mus/ws/connection_manager.cc
index e4ee980..ede74e9 100644
--- a/components/mus/ws/connection_manager.cc
+++ b/components/mus/ws/connection_manager.cc
@@ -255,8 +255,8 @@
 
 void ConnectionManager::ProcessClientAreaChanged(
     const ServerWindow* window,
-    const gfx::Rect& old_client_area,
-    const gfx::Rect& new_client_area) {
+    const gfx::Insets& old_client_area,
+    const gfx::Insets& new_client_area) {
   for (auto& pair : connection_map_) {
     pair.second->service()->ProcessClientAreaChanged(
         window, old_client_area, new_client_area, IsChangeSource(pair.first));
@@ -387,8 +387,8 @@
 
 void ConnectionManager::OnWindowClientAreaChanged(
     ServerWindow* window,
-    const gfx::Rect& old_client_area,
-    const gfx::Rect& new_client_area) {
+    const gfx::Insets& old_client_area,
+    const gfx::Insets& new_client_area) {
   if (in_destructor_)
     return;
 
diff --git a/components/mus/ws/connection_manager.h b/components/mus/ws/connection_manager.h
index 088bd1a..4fca836e 100644
--- a/components/mus/ws/connection_manager.h
+++ b/components/mus/ws/connection_manager.h
@@ -160,8 +160,8 @@
                                   const gfx::Rect& old_bounds,
                                   const gfx::Rect& new_bounds);
   void ProcessClientAreaChanged(const ServerWindow* window,
-                                const gfx::Rect& old_client_area,
-                                const gfx::Rect& new_client_area);
+                                const gfx::Insets& old_client_area,
+                                const gfx::Insets& new_client_area);
   void ProcessViewportMetricsChanged(const mojom::ViewportMetrics& old_metrics,
                                      const mojom::ViewportMetrics& new_metrics);
   void ProcessWillChangeWindowHierarchy(const ServerWindow* window,
@@ -216,8 +216,8 @@
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override;
   void OnWindowClientAreaChanged(ServerWindow* window,
-                                 const gfx::Rect& old_client_area,
-                                 const gfx::Rect& new_client_area) override;
+                                 const gfx::Insets& old_client_area,
+                                 const gfx::Insets& new_client_area) override;
   void OnWindowReordered(ServerWindow* window,
                          ServerWindow* relative,
                          mojom::OrderDirection direction) override;
diff --git a/components/mus/ws/event_dispatcher.cc b/components/mus/ws/event_dispatcher.cc
index aa06ec4..2df70ca 100644
--- a/components/mus/ws/event_dispatcher.cc
+++ b/components/mus/ws/event_dispatcher.cc
@@ -34,8 +34,12 @@
 
 bool IsLocationInNonclientArea(const ServerWindow* target,
                                const gfx::Point& location) {
-  return target->parent() &&
-         !target->client_area().Contains(location);
+  if (!target->parent())
+    return false;
+
+  gfx::Rect client_area(target->bounds().size());
+  client_area.Inset(target->client_area());
+  return !client_area.Contains(location);
 }
 
 gfx::Point EventLocationToPoint(const mojom::Event& event) {
diff --git a/components/mus/ws/event_dispatcher_unittest.cc b/components/mus/ws/event_dispatcher_unittest.cc
index 2dec66c..2cfbf29 100644
--- a/components/mus/ws/event_dispatcher_unittest.cc
+++ b/components/mus/ws/event_dispatcher_unittest.cc
@@ -303,7 +303,7 @@
   root.SetBounds(gfx::Rect(0, 0, 100, 100));
   child.SetBounds(gfx::Rect(10, 10, 20, 20));
 
-  child.SetClientArea(gfx::Rect(5, 5, 10, 10));
+  child.SetClientArea(gfx::Insets(5, 5, 5, 5));
 
   TestEventDispatcherDelegate event_dispatcher_delegate(&root);
   EventDispatcher dispatcher(&event_dispatcher_delegate);
diff --git a/components/mus/ws/server_window.cc b/components/mus/ws/server_window.cc
index 49a4d91..b0348d40 100644
--- a/components/mus/ws/server_window.cc
+++ b/components/mus/ws/server_window.cc
@@ -122,26 +122,20 @@
 
   // TODO(fsamuel): figure out how will this work with CompositorFrames.
 
-  // |client_area_| is relative to the bounds. If the size of bounds change
-  // we have to reset the client area. We assume any size change is quicky
-  // followed by a client area change.
-  if (bounds_.size() != bounds.size())
-    client_area_ = gfx::Rect(bounds.size());
-
   const gfx::Rect old_bounds = bounds_;
   bounds_ = bounds;
   FOR_EACH_OBSERVER(ServerWindowObserver, observers_,
                     OnWindowBoundsChanged(this, old_bounds, bounds));
 }
 
-void ServerWindow::SetClientArea(const gfx::Rect& bounds) {
-  if (client_area_ == bounds)
+void ServerWindow::SetClientArea(const gfx::Insets& insets) {
+  if (client_area_ == insets)
     return;
 
-  const gfx::Rect old_client_area = client_area_;
-  client_area_ = bounds;
+  const gfx::Insets old_client_area = client_area_;
+  client_area_ = insets;
   FOR_EACH_OBSERVER(ServerWindowObserver, observers_,
-                    OnWindowClientAreaChanged(this, old_client_area, bounds));
+                    OnWindowClientAreaChanged(this, old_client_area, insets));
 }
 
 const ServerWindow* ServerWindow::GetRoot() const {
diff --git a/components/mus/ws/server_window.h b/components/mus/ws/server_window.h
index 0fa7810c..614c082 100644
--- a/components/mus/ws/server_window.h
+++ b/components/mus/ws/server_window.h
@@ -15,12 +15,12 @@
 #include "components/mus/ws/ids.h"
 #include "components/mus/ws/server_window_surface.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
+#include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/transform.h"
 #include "ui/platform_window/text_input_state.h"
 
 namespace mus {
-
 namespace ws {
 
 class ServerWindowDelegate;
@@ -66,8 +66,8 @@
   // area to fill the whole bounds.
   void SetBounds(const gfx::Rect& bounds);
 
-  const gfx::Rect& client_area() const { return client_area_; }
-  void SetClientArea(const gfx::Rect& bounds);
+  const gfx::Insets& client_area() const { return client_area_; }
+  void SetClientArea(const gfx::Insets& insets);
 
   const ServerWindow* parent() const { return parent_; }
   ServerWindow* parent() { return parent_; }
@@ -137,7 +137,7 @@
   Windows children_;
   bool visible_;
   gfx::Rect bounds_;
-  gfx::Rect client_area_;
+  gfx::Insets client_area_;
   scoped_ptr<ServerWindowSurfaceManager> surface_manager_;
   float opacity_;
   gfx::Transform transform_;
@@ -151,7 +151,6 @@
 };
 
 }  // namespace ws
-
 }  // namespace mus
 
 #endif  // COMPONENTS_MUS_WS_SERVER_WINDOW_H_
diff --git a/components/mus/ws/server_window_observer.h b/components/mus/ws/server_window_observer.h
index f963ceb..be51d04 100644
--- a/components/mus/ws/server_window_observer.h
+++ b/components/mus/ws/server_window_observer.h
@@ -8,6 +8,7 @@
 #include "components/mus/public/interfaces/mus_constants.mojom.h"
 
 namespace gfx {
+class Insets;
 class Rect;
 }
 
@@ -46,8 +47,8 @@
                                      const gfx::Rect& new_bounds) {}
 
   virtual void OnWindowClientAreaChanged(ServerWindow* window,
-                                         const gfx::Rect& old_client_area,
-                                         const gfx::Rect& new_client_area) {}
+                                         const gfx::Insets& old_client_area,
+                                         const gfx::Insets& new_client_area) {}
 
   virtual void OnWindowReordered(ServerWindow* window,
                                  ServerWindow* relative,
diff --git a/components/mus/ws/window_manager_client_apptest.cc b/components/mus/ws/window_manager_client_apptest.cc
index b204b6cd..6105047 100644
--- a/components/mus/ws/window_manager_client_apptest.cc
+++ b/components/mus/ws/window_manager_client_apptest.cc
@@ -61,7 +61,7 @@
  private:
   // Overridden from WindowObserver:
   void OnWindowClientAreaChanged(Window* window,
-                                 const gfx::Rect& old_client_area) override {
+                                 const gfx::Insets& old_client_area) override {
     DCHECK_EQ(window, window_);
     EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
   }
@@ -879,16 +879,16 @@
   WindowTreeConnection* embedded_connection = Embed(embed_window).connection;
 
   // Verify change from embedded makes it to parent.
-  embedded_connection->GetRoot()->SetClientArea(gfx::Rect(1, 2, 3, 4));
+  embedded_connection->GetRoot()->SetClientArea(gfx::Insets(1, 2, 3, 4));
   ASSERT_TRUE(WaitForClientAreaToChange(embed_window));
-  EXPECT_TRUE(gfx::Rect(1, 2, 3, 4) == embed_window->client_area());
+  EXPECT_TRUE(gfx::Insets(1, 2, 3, 4) == embed_window->client_area());
 
-  // Verify bounds change results in resetting client area in embedded.
+  // Changing bounds shouldn't effect client area.
   embed_window->SetBounds(gfx::Rect(21, 22, 23, 24));
   WaitForBoundsToChange(embedded_connection->GetRoot());
   EXPECT_TRUE(gfx::Rect(21, 22, 23, 24) ==
               embedded_connection->GetRoot()->bounds());
-  EXPECT_TRUE(gfx::Rect(0, 0, 23, 24) ==
+  EXPECT_TRUE(gfx::Insets(1, 2, 3, 4) ==
               embedded_connection->GetRoot()->client_area());
 }
 
diff --git a/components/mus/ws/window_tree_apptest.cc b/components/mus/ws/window_tree_apptest.cc
index 46862937..3cc0ca0 100644
--- a/components/mus/ws/window_tree_apptest.cc
+++ b/components/mus/ws/window_tree_apptest.cc
@@ -330,8 +330,8 @@
                                      new_bounds.Pass());
   }
   void OnClientAreaChanged(uint32_t window_id,
-                           mojo::RectPtr old_client_area,
-                           mojo::RectPtr new_client_area) override {}
+                           mojo::InsetsPtr old_client_area,
+                           mojo::InsetsPtr new_client_area) override {}
   void OnWindowViewportMetricsChanged(ViewportMetricsPtr old_metrics,
                                       ViewportMetricsPtr new_metrics) override {
     // Don't track the metrics as they are available at an indeterministic time
diff --git a/components/mus/ws/window_tree_impl.cc b/components/mus/ws/window_tree_impl.cc
index 38740b9..d8872fd 100644
--- a/components/mus/ws/window_tree_impl.cc
+++ b/components/mus/ws/window_tree_impl.cc
@@ -187,15 +187,16 @@
                                   Rect::From(new_bounds));
 }
 
-void WindowTreeImpl::ProcessClientAreaChanged(const ServerWindow* window,
-                                              const gfx::Rect& old_client_area,
-                                              const gfx::Rect& new_client_area,
-                                              bool originated_change) {
+void WindowTreeImpl::ProcessClientAreaChanged(
+    const ServerWindow* window,
+    const gfx::Insets& old_client_area,
+    const gfx::Insets& new_client_area,
+    bool originated_change) {
   if (originated_change || !IsWindowKnown(window))
     return;
   client()->OnClientAreaChanged(WindowIdToTransportId(window->id()),
-                                Rect::From(old_client_area),
-                                Rect::From(new_client_area));
+                                mojo::Insets::From(old_client_area),
+                                mojo::Insets::From(new_client_area));
 }
 
 void WindowTreeImpl::ProcessViewportMetricsChanged(
@@ -702,16 +703,14 @@
   }
 }
 
-void WindowTreeImpl::SetClientArea(Id transport_window_id, mojo::RectPtr rect) {
+void WindowTreeImpl::SetClientArea(Id transport_window_id,
+                                   mojo::InsetsPtr insets) {
   ServerWindow* window =
       GetWindow(WindowIdFromTransportId(transport_window_id));
   if (!window || !access_policy_->CanSetClientArea(window))
     return;
 
-  if (rect.is_null())
-    window->SetClientArea(gfx::Rect(window->bounds().size()));
-  else
-    window->SetClientArea(rect.To<gfx::Rect>());
+  window->SetClientArea(insets.To<gfx::Insets>());
 }
 
 void WindowTreeImpl::Embed(Id transport_window_id,
@@ -758,13 +757,6 @@
   GetHost()->window_manager()->SetShowState(window_id, show_state, callback);
 }
 
-void WindowTreeImpl::GetDisplays(const GetDisplaysCallback& callback) {
-  if (!GetHost() || !GetHost()->window_manager())
-    return;
-
-  GetHost()->window_manager()->GetDisplays(callback);
-}
-
 bool WindowTreeImpl::IsRootForAccessPolicy(const WindowId& id) const {
   return IsRoot(id);
 }
diff --git a/components/mus/ws/window_tree_impl.h b/components/mus/ws/window_tree_impl.h
index c38486e..c8c7f8c 100644
--- a/components/mus/ws/window_tree_impl.h
+++ b/components/mus/ws/window_tree_impl.h
@@ -19,6 +19,7 @@
 #include "components/mus/ws/ids.h"
 
 namespace gfx {
+class Insets;
 class Rect;
 }
 
@@ -91,8 +92,8 @@
                                   const gfx::Rect& new_bounds,
                                   bool originated_change);
   void ProcessClientAreaChanged(const ServerWindow* window,
-                                const gfx::Rect& old_client_area,
-                                const gfx::Rect& new_client_area,
+                                const gfx::Insets& old_client_area,
+                                const gfx::Insets& new_client_area,
                                 bool originated_change);
   void ProcessViewportMetricsChanged(const mojom::ViewportMetrics& old_metrics,
                                      const mojom::ViewportMetrics& new_metrics,
@@ -220,14 +221,13 @@
   void SetImeVisibility(Id transport_window_id,
                         bool visible,
                         mojo::TextInputStatePtr state) override;
-  void SetClientArea(Id transport_window_id, mojo::RectPtr rect) override;
+  void SetClientArea(Id transport_window_id, mojo::InsetsPtr insets) override;
   void SetPreferredSize(uint32_t window_id,
                         mojo::SizePtr size,
                         const SetPreferredSizeCallback& callback) override;
   void SetShowState(uint32_t window_id,
                     mus::mojom::ShowState show_state,
                     const SetShowStateCallback& callback) override;
-  void GetDisplays(const GetDisplaysCallback& callback) override;
 
   // AccessPolicyDelegate:
   bool IsRootForAccessPolicy(const WindowId& id) const override;
diff --git a/components/mus/ws/window_tree_unittest.cc b/components/mus/ws/window_tree_unittest.cc
index 399a38ca..19cdff1 100644
--- a/components/mus/ws/window_tree_unittest.cc
+++ b/components/mus/ws/window_tree_unittest.cc
@@ -77,8 +77,8 @@
                                    new_bounds.Pass());
   }
   void OnClientAreaChanged(uint32_t window_id,
-                           mojo::RectPtr old_client_area,
-                           mojo::RectPtr new_client_area) override {}
+                           mojo::InsetsPtr old_client_area,
+                           mojo::InsetsPtr new_client_area) override {}
   void OnWindowViewportMetricsChanged(
       mojom::ViewportMetricsPtr old_metrics,
       mojom::ViewportMetricsPtr new_metrics) override {
diff --git a/components/test_runner/test_runner.cc b/components/test_runner/test_runner.cc
index 996cd35..2ffbee56 100644
--- a/components/test_runner/test_runner.cc
+++ b/components/test_runner/test_runner.cc
@@ -7,6 +7,7 @@
 #include <limits>
 
 #include "base/logging.h"
+#include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "components/test_runner/mock_credential_manager_client.h"
 #include "components/test_runner/mock_web_speech_recognizer.h"
@@ -39,6 +40,7 @@
 #include "third_party/WebKit/public/web/WebInputElement.h"
 #include "third_party/WebKit/public/web/WebKit.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "third_party/WebKit/public/web/WebPageImportanceSignals.h"
 #include "third_party/WebKit/public/web/WebScriptSource.h"
 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
 #include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
@@ -258,6 +260,7 @@
   void WaitUntilExternalURLLoad();
   void DumpDragImage();
   void DumpNavigationPolicy();
+  void DumpPageImportanceSignals();
   void ShowWebInspector(gin::Arguments* args);
   void CloseWebInspector();
   bool IsChooserShown();
@@ -524,6 +527,8 @@
       .SetMethod("dumpDragImage", &TestRunnerBindings::DumpDragImage)
       .SetMethod("dumpNavigationPolicy",
                  &TestRunnerBindings::DumpNavigationPolicy)
+      .SetMethod("dumpPageImportanceSignals",
+                 &TestRunnerBindings::DumpPageImportanceSignals)
       .SetMethod("showWebInspector", &TestRunnerBindings::ShowWebInspector)
       .SetMethod("closeWebInspector", &TestRunnerBindings::CloseWebInspector)
       .SetMethod("isChooserShown", &TestRunnerBindings::IsChooserShown)
@@ -1270,6 +1275,11 @@
     runner_->DumpNavigationPolicy();
 }
 
+void TestRunnerBindings::DumpPageImportanceSignals() {
+  if (runner_)
+    runner_->DumpPageImportanceSignals();
+}
+
 void TestRunnerBindings::ShowWebInspector(gin::Arguments* args) {
   if (runner_) {
     std::string settings;
@@ -2789,6 +2799,22 @@
   dump_navigation_policy_ = true;
 }
 
+void TestRunner::DumpPageImportanceSignals() {
+  blink::WebPageImportanceSignals* signals =
+    web_view_->pageImportanceSignals();
+  if (!signals)
+    return;
+
+  std::string message = base::StringPrintf(
+      "WebPageImportanceSignals:\n"
+      "  hadFormInteraction: %s\n"
+      "  issuedNonGetFetchFromScript: %s\n",
+      signals->hadFormInteraction() ? "true" : "false",
+      signals->issuedNonGetFetchFromScript() ? "true" : "false");
+  if (delegate_)
+    delegate_->PrintMessage(message);
+}
+
 void TestRunner::CloseWebInspector() {
   delegate_->CloseDevTools();
 }
diff --git a/components/test_runner/test_runner.h b/components/test_runner/test_runner.h
index 1b03a30..f459954 100644
--- a/components/test_runner/test_runner.h
+++ b/components/test_runner/test_runner.h
@@ -478,6 +478,9 @@
   // policy passed to the decidePolicyForNavigation callback.
   void DumpNavigationPolicy();
 
+  // Dump current PageImportanceSignals for the page.
+  void DumpPageImportanceSignals();
+
   ///////////////////////////////////////////////////////////////////////////
   // Methods interacting with the WebTestProxy
 
diff --git a/components/variations.gypi b/components/variations.gypi
index d1fc8c6..4d9ce3f 100644
--- a/components/variations.gypi
+++ b/components/variations.gypi
@@ -113,6 +113,7 @@
         'variations/service/variations_service.cc',
         'variations/service/variations_service.h',
         'variations/service/variations_service_client.h',
+        'variations/service/variations_service_client.cc',
       ],
     },
     {
diff --git a/components/variations/service/BUILD.gn b/components/variations/service/BUILD.gn
index c6cf5b11..a1fa0a2 100644
--- a/components/variations/service/BUILD.gn
+++ b/components/variations/service/BUILD.gn
@@ -8,6 +8,7 @@
     "ui_string_overrider.h",
     "variations_service.cc",
     "variations_service.h",
+    "variations_service_client.cc",
     "variations_service_client.h",
   ]
 
diff --git a/components/variations/service/variations_service.cc b/components/variations/service/variations_service.cc
index 8d3ced5c..2c19983 100644
--- a/components/variations/service/variations_service.cc
+++ b/components/variations/service/variations_service.cc
@@ -4,6 +4,8 @@
 
 #include "components/variations/service/variations_service.h"
 
+#include <vector>
+
 #include "base/build_time.h"
 #include "base/command_line.h"
 #include "base/metrics/histogram.h"
@@ -288,6 +290,8 @@
   DCHECK(resource_request_allowed_notifier_.get());
 
   resource_request_allowed_notifier_->Init(this);
+  seed_store_.SetVariationsFirstRunSeedCallback(
+      client_->GetVariationsFirstRunSeedCallback());
 }
 
 VariationsService::~VariationsService() {
diff --git a/components/variations/service/variations_service_client.cc b/components/variations/service/variations_service_client.cc
new file mode 100644
index 0000000..688bb1f
--- /dev/null
+++ b/components/variations/service/variations_service_client.cc
@@ -0,0 +1,14 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/variations/service/variations_service_client.h"
+
+namespace variations {
+
+VariationsFirstRunSeedCallback
+VariationsServiceClient::GetVariationsFirstRunSeedCallback() {
+  return VariationsFirstRunSeedCallback();
+}
+
+}  // namespace variations
diff --git a/components/variations/service/variations_service_client.h b/components/variations/service/variations_service_client.h
index b3758a6..fabaee83 100644
--- a/components/variations/service/variations_service_client.h
+++ b/components/variations/service/variations_service_client.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/strings/string16.h"
 #include "base/version.h"
+#include "components/variations/variations_seed_store.h"
 #include "components/version_info/version_info.h"
 
 namespace base {
@@ -59,6 +60,10 @@
 
   // Called from VariationsService::PerformPreMainMessageLoopStartup().
   virtual void OnInitialStartup() {}
+
+  // Get callback for pulling variations first run seed from Java applicaton
+  // in Chrome for Android.
+  virtual VariationsFirstRunSeedCallback GetVariationsFirstRunSeedCallback();
 };
 
 }  // namespace variations
diff --git a/components/variations/variations_seed_store.cc b/components/variations/variations_seed_store.cc
index 89e1af2..edd3df3 100644
--- a/components/variations/variations_seed_store.cc
+++ b/components/variations/variations_seed_store.cc
@@ -152,6 +152,11 @@
 bool VariationsSeedStore::LoadSeed(variations::VariationsSeed* seed) {
   invalid_base64_signature_.clear();
 
+#if defined(OS_ANDROID)
+  if (!local_state_->HasPrefPath(prefs::kVariationsSeedSignature))
+    ImportFirstRunJavaSeed();
+#endif  // OS_ANDROID
+
   std::string seed_data;
   if (!ReadSeedData(&seed_data))
     return false;
@@ -336,6 +341,36 @@
   local_state_->ClearPref(prefs::kVariationsSeedSignature);
 }
 
+#if defined(OS_ANDROID)
+void VariationsSeedStore::ImportFirstRunJavaSeed() {
+  DVLOG(1) << "Importing first run seed from Java preferences.";
+  std::string seed_data;
+  std::string seed_signature;
+  std::string seed_country;
+  if (!get_variations_first_run_seed_.is_null()) {
+    get_variations_first_run_seed_.Run(&seed_data, &seed_signature,
+                                       &seed_country);
+  }
+
+  if (seed_data.empty()) {
+    // TODO(agulenko): add a new UMA histogram for the state of failing
+    // to import seed from Java preferences during Chrome first run.
+    return;
+  }
+
+  // TODO(agulenko): Pull actual time from the response.
+  base::Time current_time = base::Time::Now();
+
+  // TODO(agulenko): Support gzip compressed seed.
+  if (!StoreSeedData(seed_data, seed_signature, seed_country, current_time,
+                     false, false, nullptr)) {
+    LOG(WARNING) << "First run variations seed is invalid.";
+    return;
+  }
+  // TODO(agulenko): Clear Java prefs.
+}
+#endif  // OS_ANDROID
+
 bool VariationsSeedStore::ReadSeedData(std::string* seed_data) {
   std::string base64_seed_data =
       local_state_->GetString(prefs::kVariationsCompressedSeed);
diff --git a/components/variations/variations_seed_store.h b/components/variations/variations_seed_store.h
index cc743d88..42a6a59 100644
--- a/components/variations/variations_seed_store.h
+++ b/components/variations/variations_seed_store.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/time/time.h"
@@ -20,6 +21,9 @@
 
 namespace variations {
 
+typedef base::Callback<void(std::string*, std::string*, std::string*)>
+    VariationsFirstRunSeedCallback;
+
 // VariationsSeedStore is a helper class for reading and writing the variations
 // seed from Local State.
 class VariationsSeedStore {
@@ -75,6 +79,13 @@
   // Registers Local State prefs used by this class.
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
+  // Registers callback for pulling variations first run seed from Java side
+  // in Chrome for Android.
+  void SetVariationsFirstRunSeedCallback(
+      const VariationsFirstRunSeedCallback& callback) {
+    get_variations_first_run_seed_ = callback;
+  }
+
  protected:
   // Note: UMA histogram enum - don't re-order or remove entries.
   enum VerifySignatureResult {
@@ -103,6 +114,12 @@
   // Clears all prefs related to variations seed storage.
   void ClearPrefs();
 
+#if defined(OS_ANDROID)
+  // Imports the variations seed data from Java side during the first
+  // Chrome for Android run.
+  void ImportFirstRunJavaSeed();
+#endif  // OS_ANDROID
+
   // Reads the variations seed data from prefs; returns true on success.
   bool ReadSeedData(std::string* seed_data);
 
@@ -134,6 +151,8 @@
   // Keeps track of an invalid signature.
   std::string invalid_base64_signature_;
 
+  VariationsFirstRunSeedCallback get_variations_first_run_seed_;
+
   DISALLOW_COPY_AND_ASSIGN(VariationsSeedStore);
 };
 
diff --git a/content/browser/bluetooth/bluetooth_dispatcher_host.cc b/content/browser/bluetooth/bluetooth_dispatcher_host.cc
index 8c6c7d8..bc13e95 100644
--- a/content/browser/bluetooth/bluetooth_dispatcher_host.cc
+++ b/content/browser/bluetooth/bluetooth_dispatcher_host.cc
@@ -944,14 +944,18 @@
     VLOG(1) << "\t" << uuid.canonical_value();
 
   content::BluetoothDevice device_ipc(
-      device->GetAddress(),         // id
-      device->GetName(),            // name
-      device->GetBluetoothClass(),  // device_class
-      device->GetVendorIDSource(),  // vendor_id_source
-      device->GetVendorID(),        // vendor_id
-      device->GetProductID(),       // product_id
-      device->GetDeviceID(),        // product_version
-      device->IsPaired(),           // paired
+      device->GetAddress(),  // id
+      device->GetName(),     // name
+      content::BluetoothDevice::ValidatePower(
+          device->GetInquiryTxPower()),  // tx_power
+      content::BluetoothDevice::ValidatePower(
+          device->GetInquiryRSSI()),  // rssi
+      device->GetBluetoothClass(),    // device_class
+      device->GetVendorIDSource(),    // vendor_id_source
+      device->GetVendorID(),          // vendor_id
+      device->GetProductID(),         // product_id
+      device->GetDeviceID(),          // product_version
+      device->IsPaired(),             // paired
       content::BluetoothDevice::UUIDsFromBluetoothUUIDs(
           device->GetUUIDs()));  // uuids
   RecordRequestDeviceOutcome(UMARequestDeviceOutcome::SUCCESS);
diff --git a/content/common/bluetooth/bluetooth_device.cc b/content/common/bluetooth/bluetooth_device.cc
index baf930c..ece3ce4d 100644
--- a/content/common/bluetooth/bluetooth_device.cc
+++ b/content/common/bluetooth/bluetooth_device.cc
@@ -11,6 +11,8 @@
 BluetoothDevice::BluetoothDevice()
     : id(""),
       name(base::string16()),
+      tx_power(device::BluetoothDevice::kUnknownPower),
+      rssi(device::BluetoothDevice::kUnknownPower),
       device_class(0),
       vendor_id_source(
           device::BluetoothDevice::VendorIDSource::VENDOR_ID_UNKNOWN),
@@ -23,6 +25,8 @@
 BluetoothDevice::BluetoothDevice(
     const std::string& id,
     const base::string16& name,
+    int8_t tx_power,
+    int8_t rssi,
     uint32 device_class,
     device::BluetoothDevice::VendorIDSource vendor_id_source,
     uint16 vendor_id,
@@ -32,6 +36,8 @@
     const std::vector<std::string>& uuids)
     : id(id),
       name(name),
+      tx_power(tx_power),
+      rssi(rssi),
       device_class(device_class),
       vendor_id_source(vendor_id_source),
       vendor_id(vendor_id),
@@ -53,4 +59,10 @@
   return uuids;
 }
 
+// static
+int8_t BluetoothDevice::ValidatePower(int16_t power) {
+  return ((power < -127) || (power > 127)) ? BluetoothDevice::kUnknownPower
+                                           : power;
+}
+
 }  // namespace content
diff --git a/content/common/bluetooth/bluetooth_device.h b/content/common/bluetooth/bluetooth_device.h
index 73aef99..575f43a 100644
--- a/content/common/bluetooth/bluetooth_device.h
+++ b/content/common/bluetooth/bluetooth_device.h
@@ -20,6 +20,8 @@
   BluetoothDevice();
   BluetoothDevice(const std::string& id,
                   const base::string16& name,
+                  int8_t tx_power,
+                  int8_t rssi,
                   uint32 device_class,
                   device::BluetoothDevice::VendorIDSource vendor_id_source,
                   uint16 vendor_id,
@@ -31,9 +33,18 @@
 
   static std::vector<std::string> UUIDsFromBluetoothUUIDs(
       const device::BluetoothDevice::UUIDList& uuid_list);
+  // 127 is used as Unknown Power. According to the Bluetooth spec valid powers
+  // are between [-127, 127]. Anything outside this range will be considered
+  // Unknown Power.
+  static int8_t ValidatePower(int16_t power);
+  // TODO(ortuno): RSSI Unknown and Tx Power Unknown should have different
+  // values. Add kUnknownTxPower when implemented: http://crbug.com/551572
+  const static int8_t kUnknownPower = 127;
 
   std::string id;
   base::string16 name;
+  int8_t tx_power;
+  int8_t rssi;
   uint32 device_class;
   device::BluetoothDevice::VendorIDSource vendor_id_source;
   uint16 vendor_id;
diff --git a/content/common/bluetooth/bluetooth_messages.h b/content/common/bluetooth/bluetooth_messages.h
index 85100ff..b7518c1 100644
--- a/content/common/bluetooth/bluetooth_messages.h
+++ b/content/common/bluetooth/bluetooth_messages.h
@@ -92,6 +92,8 @@
 IPC_STRUCT_TRAITS_BEGIN(content::BluetoothDevice)
   IPC_STRUCT_TRAITS_MEMBER(id)
   IPC_STRUCT_TRAITS_MEMBER(name)
+  IPC_STRUCT_TRAITS_MEMBER(tx_power)
+  IPC_STRUCT_TRAITS_MEMBER(rssi)
   IPC_STRUCT_TRAITS_MEMBER(device_class)
   IPC_STRUCT_TRAITS_MEMBER(vendor_id_source)
   IPC_STRUCT_TRAITS_MEMBER(vendor_id)
diff --git a/content/renderer/bluetooth/bluetooth_dispatcher.cc b/content/renderer/bluetooth/bluetooth_dispatcher.cc
index a5097d8..5687bf7 100644
--- a/content/renderer/bluetooth/bluetooth_dispatcher.cc
+++ b/content/renderer/bluetooth/bluetooth_dispatcher.cc
@@ -551,9 +551,9 @@
   pending_requests_.Lookup(request_id)
       ->onSuccess(blink::adoptWebPtr(new WebBluetoothDevice(
           WebString::fromUTF8(device.id), WebString(device.name),
-          device.device_class, GetWebVendorIdSource(device.vendor_id_source),
-          device.vendor_id, device.product_id, device.product_version,
-          device.paired, uuids)));
+          device.tx_power, device.rssi, device.device_class,
+          GetWebVendorIdSource(device.vendor_id_source), device.vendor_id,
+          device.product_id, device.product_version, device.paired, uuids)));
   pending_requests_.Remove(request_id);
 }
 
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
index 054fb95..fc35b28 100644
--- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
+++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
@@ -8,6 +8,9 @@
 #include "base/bind_helpers.h"
 #include "base/format_macros.h"
 #include "base/location.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/thread_task_runner_handle.h"
 #include "device/bluetooth/bluetooth_adapter.h"
@@ -20,6 +23,7 @@
 #include "device/bluetooth/test/mock_bluetooth_gatt_notify_session.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
+using base::StringPiece;
 using device::BluetoothAdapter;
 using device::BluetoothDevice;
 using device::BluetoothGattCharacteristic;
@@ -62,6 +66,10 @@
 const char kBodySensorLocation[] = "2a38";
 const char kDeviceNameUUID[] = "2a00";
 
+const int kDefaultTxPower = -10;  // TxPower of a device broadcasting at 0.1mW.
+const int kDefaultRssi = -51;     // RSSI at 1m from a device broadcasting at
+                                  // 0.1mW.
+
 // Invokes Run() on the k-th argument of the function with no arguments.
 ACTION_TEMPLATE(RunCallback,
                 HAS_1_TEMPLATE_PARAMS(int, k),
@@ -143,6 +151,40 @@
   else if (fake_adapter_name == "")
     return NULL;
 
+  if (base::StartsWith(fake_adapter_name, "PowerValueAdapter",
+                       base::CompareCase::SENSITIVE)) {
+    std::vector<StringPiece> args =
+        base::SplitStringPiece(fake_adapter_name, ":", base::KEEP_WHITESPACE,
+                               base::SPLIT_WANT_NONEMPTY);
+    DCHECK(args[0] == "PowerValueAdapter");
+    DCHECK(args.size() == 3) << "Should contain AdapterName:TxPower:RSSI";
+
+    int tx_power;
+    base::StringToInt(args[1], &tx_power);
+    DCHECK(tx_power >= INT8_MIN && tx_power <= INT8_MAX)
+        << "Must be between [-128, 127]";
+    int rssi;
+    base::StringToInt(args[2], &rssi);
+    DCHECK(rssi >= INT8_MIN && rssi <= INT8_MAX)
+        << "Must be between [-128, 127]";
+    return GetPowerValueAdapter(tx_power, rssi);
+  }
+
+  if (base::StartsWith(fake_adapter_name, "PowerPresenceAdapter",
+                       base::CompareCase::SENSITIVE)) {
+    std::vector<StringPiece> args =
+        base::SplitStringPiece(fake_adapter_name, ":", base::KEEP_WHITESPACE,
+                               base::SPLIT_WANT_NONEMPTY);
+    DCHECK(args[0] == "PowerPresenceAdapter");
+    DCHECK(args.size() == 3)
+        << "Should contain AdapterName:TxPowerPresent:RSSIPResent";
+    DCHECK(args[1] == "true" || args[1] == "false");
+    DCHECK(args[2] == "true" || args[2] == "false");
+
+    return GetPowerPresenceAdapter(args[1] == "true" /* tx_power_present */,
+                                   args[2] == "true" /* rssi_present */);
+  }
+
   NOTREACHED() << fake_adapter_name;
   return NULL;
 }
@@ -257,6 +299,35 @@
 
 // static
 scoped_refptr<NiceMockBluetoothAdapter>
+LayoutTestBluetoothAdapterProvider::GetPowerValueAdapter(int8_t tx_power,
+                                                         int8_t rssi) {
+  scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
+  scoped_ptr<NiceMockBluetoothDevice> device(GetHeartRateDevice(adapter.get()));
+
+  ON_CALL(*device, GetInquiryTxPower()).WillByDefault(Return(tx_power));
+  ON_CALL(*device, GetInquiryRSSI()).WillByDefault(Return(rssi));
+
+  adapter->AddMockDevice(device.Pass());
+
+  return adapter;
+}
+
+// static
+scoped_refptr<NiceMockBluetoothAdapter>
+LayoutTestBluetoothAdapterProvider::GetPowerPresenceAdapter(
+    bool tx_power_present,
+    bool rssi_present) {
+  // TODO(ortuno): RSSI Unknown and Tx Power Unknown should have different
+  // values. Add kUnknownTxPower when implemented: http://crbug.com/551572
+  int tx_power =
+      tx_power_present ? kDefaultTxPower : BluetoothDevice::kUnknownPower;
+  int rssi = rssi_present ? kDefaultRssi : BluetoothDevice::kUnknownPower;
+
+  return GetPowerValueAdapter(tx_power, rssi);
+}
+
+// static
+scoped_refptr<NiceMockBluetoothAdapter>
 LayoutTestBluetoothAdapterProvider::GetGlucoseHeartRateAdapter() {
   scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
 
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
index ca23237..39431b26 100644
--- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
+++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
@@ -114,6 +114,32 @@
   static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
   GetEmptyAdapter();
 
+  // |PowerValueAdapter|(tx_power, rssi)
+  // Inherits from |EmptyAdapter|
+  // Internal Structure:
+  //  - |HeartRateDevice|
+  //    - Mock Functions:
+  //      - GetInquiryTxPower(): Returns tx_power
+  //      - GetInquiryRSSI(): Returns rssi
+  static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
+  GetPowerValueAdapter(int8_t tx_power, int8_t rssi);
+
+  // |PowerPresenceAdapter|(tx_power_present, rssi_present)
+  // Inherits from |EmptyAdapter|
+  // Internal Structure:
+  //  - |HeartRateDevice|
+  //    - Mock Functions:
+  //      - GetInquiryTxPower(): If tx_power_present is true, returns -10,
+  //        the TxPower of a device broadcasting at 0.1mW. Otherwise
+  //        returns 127 which denotes a missing Tx Power.
+  //        TODO(ortuno): Change 127 to -128 when Tx Power Unknown value gets
+  //        fixed: http://crbug.com/551572
+  //      - GetInquiryRSSI(): If rssi_present is true returns -51,
+  //        the RSSI at 1m from a device broadcasting at 0.1mW. Otherwise
+  //        returns 127 which denotes a missing RSSI.
+  static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
+  GetPowerPresenceAdapter(bool tx_power_present, bool rssi_present);
+
   // |GlucoseHeartRateAdapter|
   // Inherits from |EmptyAdapter|
   // Devices added:
diff --git a/ios/chrome/browser/chrome_switches.cc b/ios/chrome/browser/chrome_switches.cc
index 4af3f01..ae18f94 100644
--- a/ios/chrome/browser/chrome_switches.cc
+++ b/ios/chrome/browser/chrome_switches.cc
@@ -12,17 +12,68 @@
 // all work out.
 // -----------------------------------------------------------------------------
 
+// Disables Contextual Search.
+const char kDisableContextualSearch[] = "disable-contextual-search";
+
+// Disables a workaround for fast inset updates for UIWebView.scrollView.
+const char kDisableIOSFastWebScrollViewInsets[] =
+    "disable-fast-web-scroll-view-insets";
+
+// Disable password generation for iOS.
+const char kDisableIOSPasswordGeneration[] = "disable-ios-password-generation";
+
+// Disable showing available password credentials in the keyboard accessory
+// view when focused on form fields.
+const char kDisableIOSPasswordSuggestions[] =
+    "disable-ios-password-suggestions";
+
 // Disables the use of WKWebView instead of UIWebView.
 const char kDisableIOSWKWebView[] = "disable-wkwebview";
 
+// Disables support for keyboard commands.
+const char kDisableKeyboardCommands[] = "disable-keyboard-commands";
+
+// Disables NTP favicons.
+const char kDisableNTPFavicons[] = "disable-ntp-favicons";
+
+// Disable auto-reload of error pages if offline.
+const char kDisableOfflineAutoReload[] = "disable-offline-auto-reload";
+
+// Disables the tab switcher.
+const char kDisableTabSwitcher[] = "disable-tab-switcher";
+
+// Enables Contextual Search.
+const char kEnableContextualSearch[] = "enable-contextual-search";
+
+// Enable the experimental Credential Manager JavaScript API.
+const char kEnableCredentialManagerAPI[] = "enable-credential-manager-api";
+
+// Enables a workaround for fast inset updates for UIWebView.scrollView.
+const char kEnableIOSFastWebScrollViewInsets[] =
+    "enable-fast-web-scroll-view-insets";
+
+// Enables support for Handoff from Chrome on iOS to the default browser of
+// other Apple devices.
+const char kEnableIOSHandoffToOtherDevices[] =
+    "enable-ios-handoff-to-other-devices";
+
+// Enable password generation for iOS.
+const char kEnableIOSPasswordGeneration[] = "enable-ios-password-generation";
+
 // Enables the use of WKWebView instead of UIWebView.
 const char kEnableIOSWKWebView[] = "enable-wkwebview";
 
+// Enables NTP favicons.
+const char kEnableNTPFavicons[] = "enable-ntp-favicons";
+
+// Enable auto-reload of error pages if offline.
+const char kEnableOfflineAutoReload[] = "enable-offline-auto-reload";
+
 // Enables context-sensitive reader mode button in the toolbar.
 const char kEnableReaderModeToolbarIcon[] = "enable-reader-mode-toolbar-icon";
 
-// Disables support for keyboard commands.
-const char kDisableKeyboardCommands[] = "disable-keyboard-commands";
+// Enables the tab switcher.
+const char kEnableTabSwitcher[] = "enable-tab-switcher";
 
 // Enables the recording of metrics reports but disables reporting. In contrast
 // to kDisableMetrics, this executes all the code that a normal client would
@@ -31,4 +82,7 @@
 // performance tests.
 const char kIOSMetricsRecordingOnly[] = "metrics-recording-only";
 
+// A string used to override the default user agent with a custom one.
+const char kUserAgent[] = "user-agent";
+
 }  // namespace switches
diff --git a/ios/chrome/browser/chrome_switches.h b/ios/chrome/browser/chrome_switches.h
index e6df544c..f1c590ef 100644
--- a/ios/chrome/browser/chrome_switches.h
+++ b/ios/chrome/browser/chrome_switches.h
@@ -9,11 +9,29 @@
 
 namespace switches {
 
+extern const char kDisableContextualSearch[];
+extern const char kDisableIOSFastWebScrollViewInsets[];
+extern const char kDisableIOSPasswordGeneration[];
+extern const char kDisableIOSPasswordSuggestions[];
 extern const char kDisableIOSWKWebView[];
-extern const char kEnableIOSWKWebView[];
-extern const char kEnableReaderModeToolbarIcon[];
 extern const char kDisableKeyboardCommands[];
+extern const char kDisableNTPFavicons[];
+extern const char kDisableOfflineAutoReload[];
+extern const char kDisableTabSwitcher[];
+
+extern const char kEnableContextualSearch[];
+extern const char kEnableCredentialManagerAPI[];
+extern const char kEnableIOSFastWebScrollViewInsets[];
+extern const char kEnableIOSHandoffToOtherDevices[];
+extern const char kEnableIOSPasswordGeneration[];
+extern const char kEnableIOSWKWebView[];
+extern const char kEnableNTPFavicons[];
+extern const char kEnableOfflineAutoReload[];
+extern const char kEnableReaderModeToolbarIcon[];
+extern const char kEnableTabSwitcher[];
+
 extern const char kIOSMetricsRecordingOnly[];
+extern const char kUserAgent[];
 
 }  // namespace switches
 
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h
index 9edcfa5e..8acdd7c1 100644
--- a/ipc/ipc_message_start.h
+++ b/ipc/ipc_message_start.h
@@ -129,6 +129,8 @@
   PageLoadMetricsMsgStart,
   MemoryMsgStart,
   IPCTestMsgStart,
+  ArcInstanceMsgStart,
+  ArcInstanceHostMsgStart,
   LastIPCMsgStart  // Must come last.
 };
 
diff --git a/mandoline/ui/common/BUILD.gn b/mandoline/ui/common/BUILD.gn
deleted file mode 100644
index a695e43..0000000
--- a/mandoline/ui/common/BUILD.gn
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("common") {
-  sources = [
-    "util.cc",
-    "util.h",
-  ]
-
-  deps = [
-    "//components/mus/public/cpp",
-    "//mojo/converters/geometry",
-    "//ui/gfx",
-    "//ui/gfx/geometry",
-  ]
-}
diff --git a/mandoline/ui/desktop_ui/BUILD.gn b/mandoline/ui/desktop_ui/BUILD.gn
index 916683a..255419a 100644
--- a/mandoline/ui/desktop_ui/BUILD.gn
+++ b/mandoline/ui/desktop_ui/BUILD.gn
@@ -39,7 +39,6 @@
     "//base",
     "//components/web_view/public/cpp",
     "//components/web_view/public/interfaces",
-    "//mandoline/ui/common",
     "//mojo/application/public/cpp:sources",
     "//mojo/common:common_base",
     "//mojo/converters/geometry",
diff --git a/mandoline/ui/desktop_ui/browser_window.cc b/mandoline/ui/desktop_ui/browser_window.cc
index 59d82ef2..4b4e698 100644
--- a/mandoline/ui/desktop_ui/browser_window.cc
+++ b/mandoline/ui/desktop_ui/browser_window.cc
@@ -12,7 +12,6 @@
 #include "components/mus/public/cpp/event_matcher.h"
 #include "components/mus/public/cpp/scoped_window_ptr.h"
 #include "components/mus/public/cpp/window_tree_host_factory.h"
-#include "mandoline/ui/common/util.h"
 #include "mandoline/ui/desktop_ui/browser_commands.h"
 #include "mandoline/ui/desktop_ui/browser_manager.h"
 #include "mandoline/ui/desktop_ui/find_bar_view.h"
@@ -27,6 +26,7 @@
 #include "ui/views/background.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/mus/aura_init.h"
+#include "ui/views/mus/display_converter.h"
 #include "ui/views/mus/native_widget_view_manager.h"
 #include "ui/views/widget/widget_delegate.h"
 
@@ -392,7 +392,7 @@
 void BrowserWindow::Init(mus::Window* root) {
   DCHECK_GT(root->viewport_metrics().device_pixel_ratio, 0);
   if (!aura_init_) {
-    ui_init_.reset(new ui::mojo::UIInit(GetDisplaysFromWindow(root)));
+    ui_init_.reset(new ui::mojo::UIInit(views::GetDisplaysFromWindow(root)));
     aura_init_.reset(new views::AuraInit(app_, "mandoline_ui.pak"));
   }
 
diff --git a/mandoline/ui/omnibox/BUILD.gn b/mandoline/ui/omnibox/BUILD.gn
index 9e95dbd..76530b9 100644
--- a/mandoline/ui/omnibox/BUILD.gn
+++ b/mandoline/ui/omnibox/BUILD.gn
@@ -28,7 +28,6 @@
     "//base",
     "//components/mus/public/cpp",
     "//components/url_formatter",
-    "//mandoline/ui/common",
     "//mandoline/ui/desktop_ui/public/interfaces",
     "//mojo/application/public/cpp:sources",
     "//mojo/common",
diff --git a/mandoline/ui/omnibox/omnibox_application.cc b/mandoline/ui/omnibox/omnibox_application.cc
index 7dffe081..3a17170 100644
--- a/mandoline/ui/omnibox/omnibox_application.cc
+++ b/mandoline/ui/omnibox/omnibox_application.cc
@@ -10,7 +10,6 @@
 #include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/mus/public/cpp/window_tree_delegate.h"
 #include "components/url_formatter/url_fixer.h"
-#include "mandoline/ui/common/util.h"
 #include "mandoline/ui/desktop_ui/public/interfaces/view_embedder.mojom.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/common/common_type_converters.h"
@@ -20,6 +19,7 @@
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/layout/layout_manager.h"
 #include "ui/views/mus/aura_init.h"
+#include "ui/views/mus/display_converter.h"
 #include "ui/views/mus/native_widget_view_manager.h"
 #include "ui/views/widget/widget_delegate.h"
 
@@ -119,7 +119,7 @@
   root_ = root;
 
   if (!aura_init_.get()) {
-    ui_init_.reset(new ui::mojo::UIInit(GetDisplaysFromWindow(root_)));
+    ui_init_.reset(new ui::mojo::UIInit(views::GetDisplaysFromWindow(root_)));
     aura_init_.reset(new views::AuraInit(app_, "mandoline_ui.pak"));
     edit_ = new views::Textfield;
     edit_->set_controller(this);
diff --git a/media/BUILD.gn b/media/BUILD.gn
index f15e5903..514d40f 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -165,6 +165,10 @@
     "capture/video/win/video_capture_device_win.h",
     "cdm/aes_decryptor.cc",
     "cdm/aes_decryptor.h",
+    "cdm/cdm_adapter.cc",
+    "cdm/cdm_adapter.h",
+    "cdm/cdm_adapter_impl.cc",
+    "cdm/cdm_adapter_impl.h",
     "cdm/default_cdm_factory.cc",
     "cdm/default_cdm_factory.h",
     "cdm/json_web_key.cc",
@@ -175,6 +179,8 @@
     "cdm/player_tracker_impl.h",
     "cdm/proxy_decryptor.cc",
     "cdm/proxy_decryptor.h",
+    "cdm/supported_cdm_versions.cc",
+    "cdm/supported_cdm_versions.h",
     "ffmpeg/ffmpeg_deleters.h",
     "filters/audio_clock.cc",
     "filters/audio_clock.h",
diff --git a/media/cdm/cdm_adapter.cc b/media/cdm/cdm_adapter.cc
new file mode 100644
index 0000000..94791cf0
--- /dev/null
+++ b/media/cdm/cdm_adapter.cc
@@ -0,0 +1,93 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/cdm/cdm_adapter.h"
+
+#include "base/logging.h"
+#include "media/cdm/cdm_adapter_impl.h"
+
+namespace media {
+
+CdmAdapter::CdmAdapter() {}
+
+CdmAdapter::~CdmAdapter() {}
+
+void CdmAdapter::Initialize(
+    const std::string& key_system,
+    const base::FilePath& cdm_path,
+    const CdmConfig& cdm_config,
+    const SessionMessageCB& session_message_cb,
+    const SessionClosedCB& session_closed_cb,
+    const LegacySessionErrorCB& legacy_session_error_cb,
+    const SessionKeysChangeCB& session_keys_change_cb,
+    const SessionExpirationUpdateCB& session_expiration_update_cb,
+    scoped_ptr<SimpleCdmPromise> promise) {
+  DCHECK(!key_system.empty());
+  DCHECK(!session_message_cb.is_null());
+  DCHECK(!session_closed_cb.is_null());
+  DCHECK(!legacy_session_error_cb.is_null());
+  DCHECK(!session_keys_change_cb.is_null());
+  DCHECK(!session_expiration_update_cb.is_null());
+
+  scoped_refptr<CdmAdapterImpl> cdm = new CdmAdapterImpl();
+  cdm->Initialize(key_system, cdm_path, cdm_config, session_message_cb,
+                  session_closed_cb, legacy_session_error_cb,
+                  session_keys_change_cb, session_expiration_update_cb,
+                  promise.Pass());
+  cdm_ = cdm.Pass();
+}
+
+void CdmAdapter::SetServerCertificate(const std::vector<uint8_t>& certificate,
+                                      scoped_ptr<SimpleCdmPromise> promise) {
+  DCHECK(cdm_);
+  cdm_->SetServerCertificate(certificate, promise.Pass());
+}
+
+void CdmAdapter::CreateSessionAndGenerateRequest(
+    SessionType session_type,
+    EmeInitDataType init_data_type,
+    const std::vector<uint8_t>& init_data,
+    scoped_ptr<NewSessionCdmPromise> promise) {
+  DCHECK(cdm_);
+  return cdm_->CreateSessionAndGenerateRequest(session_type, init_data_type,
+                                               init_data, promise.Pass());
+}
+
+void CdmAdapter::LoadSession(SessionType session_type,
+                             const std::string& session_id,
+                             scoped_ptr<NewSessionCdmPromise> promise) {
+  DCHECK(cdm_);
+  DCHECK(!session_id.empty());
+  return cdm_->LoadSession(session_type, session_id, promise.Pass());
+}
+
+void CdmAdapter::UpdateSession(const std::string& session_id,
+                               const std::vector<uint8_t>& response,
+                               scoped_ptr<SimpleCdmPromise> promise) {
+  DCHECK(cdm_);
+  DCHECK(!session_id.empty());
+  DCHECK(!response.empty());
+  return cdm_->UpdateSession(session_id, response, promise.Pass());
+}
+
+void CdmAdapter::CloseSession(const std::string& session_id,
+                              scoped_ptr<SimpleCdmPromise> promise) {
+  DCHECK(cdm_);
+  DCHECK(!session_id.empty());
+  return cdm_->CloseSession(session_id, promise.Pass());
+}
+
+void CdmAdapter::RemoveSession(const std::string& session_id,
+                               scoped_ptr<SimpleCdmPromise> promise) {
+  DCHECK(cdm_);
+  DCHECK(!session_id.empty());
+  return cdm_->RemoveSession(session_id, promise.Pass());
+}
+
+CdmContext* CdmAdapter::GetCdmContext() {
+  DCHECK(cdm_);
+  return cdm_->GetCdmContext();
+}
+
+}  // namespace media
diff --git a/media/cdm/cdm_adapter.h b/media/cdm/cdm_adapter.h
new file mode 100644
index 0000000..b304fb3
--- /dev/null
+++ b/media/cdm/cdm_adapter.h
@@ -0,0 +1,69 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_CDM_CDM_ADAPTER_H_
+#define MEDIA_CDM_CDM_ADAPTER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "media/base/cdm_config.h"
+#include "media/base/media_export.h"
+#include "media/base/media_keys.h"
+
+namespace media {
+
+// Due to windows warning C4275 (should not export a class that inherits from
+// a non-exported class), this class exists as a wrapper for CdmAdapterImpl.
+class MEDIA_EXPORT CdmAdapter : public MediaKeys {
+ public:
+  CdmAdapter();
+
+  // Load the CDM using |cdm_path| and initialize it using |key_system| and
+  // |cdm_config|. Callbacks will be used for events generated by the CDM.
+  // |promise| is resolved if the CDM is loaded and initialized correctly,
+  // otherwise it is rejected.
+  void Initialize(const std::string& key_system,
+                  const base::FilePath& cdm_path,
+                  const CdmConfig& cdm_config,
+                  const SessionMessageCB& session_message_cb,
+                  const SessionClosedCB& session_closed_cb,
+                  const LegacySessionErrorCB& legacy_session_error_cb,
+                  const SessionKeysChangeCB& session_keys_change_cb,
+                  const SessionExpirationUpdateCB& session_expiration_update_cb,
+                  scoped_ptr<SimpleCdmPromise> promise);
+
+  // MediaKeys implementation.
+  void SetServerCertificate(const std::vector<uint8_t>& certificate,
+                            scoped_ptr<SimpleCdmPromise> promise) override;
+  void CreateSessionAndGenerateRequest(
+      SessionType session_type,
+      EmeInitDataType init_data_type,
+      const std::vector<uint8_t>& init_data,
+      scoped_ptr<NewSessionCdmPromise> promise) override;
+  void LoadSession(SessionType session_type,
+                   const std::string& session_id,
+                   scoped_ptr<NewSessionCdmPromise> promise) override;
+  void UpdateSession(const std::string& session_id,
+                     const std::vector<uint8_t>& response,
+                     scoped_ptr<SimpleCdmPromise> promise) override;
+  void CloseSession(const std::string& session_id,
+                    scoped_ptr<SimpleCdmPromise> promise) override;
+  void RemoveSession(const std::string& session_id,
+                     scoped_ptr<SimpleCdmPromise> promise) override;
+  CdmContext* GetCdmContext() override;
+
+ private:
+  ~CdmAdapter() final;
+
+  scoped_refptr<MediaKeys> cdm_;
+  DISALLOW_COPY_AND_ASSIGN(CdmAdapter);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CDM_CDM_ADAPTER_H_
diff --git a/media/cdm/cdm_adapter_impl.cc b/media/cdm/cdm_adapter_impl.cc
new file mode 100644
index 0000000..aabd1fa8
--- /dev/null
+++ b/media/cdm/cdm_adapter_impl.cc
@@ -0,0 +1,479 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/cdm/cdm_adapter_impl.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "media/base/cdm_context.h"
+#include "media/base/cdm_key_information.h"
+#include "media/base/limits.h"
+#include "media/cdm/cdm_wrapper.h"
+
+namespace media {
+
+namespace {
+
+cdm::SessionType MediaSessionTypeToCdmSessionType(
+    MediaKeys::SessionType session_type) {
+  switch (session_type) {
+    case MediaKeys::TEMPORARY_SESSION:
+      return cdm::kTemporary;
+    case MediaKeys::PERSISTENT_LICENSE_SESSION:
+      return cdm::kPersistentLicense;
+    case MediaKeys::PERSISTENT_RELEASE_MESSAGE_SESSION:
+      return cdm::kPersistentKeyRelease;
+  }
+
+  NOTREACHED();
+  return cdm::kTemporary;
+}
+
+cdm::InitDataType MediaInitDataTypeToCdmInitDataType(
+    EmeInitDataType init_data_type) {
+  switch (init_data_type) {
+    case EmeInitDataType::CENC:
+      return cdm::kCenc;
+    case EmeInitDataType::KEYIDS:
+      return cdm::kKeyIds;
+    case EmeInitDataType::WEBM:
+      return cdm::kWebM;
+    case EmeInitDataType::UNKNOWN:
+      break;
+  }
+
+  NOTREACHED();
+  return cdm::kKeyIds;
+}
+
+MediaKeys::Exception CdmErrorTypeToMediaExceptionType(cdm::Error error) {
+  switch (error) {
+    case cdm::kNotSupportedError:
+      return MediaKeys::NOT_SUPPORTED_ERROR;
+    case cdm::kInvalidStateError:
+      return MediaKeys::INVALID_STATE_ERROR;
+    case cdm::kInvalidAccessError:
+      return MediaKeys::INVALID_ACCESS_ERROR;
+    case cdm::kQuotaExceededError:
+      return MediaKeys::QUOTA_EXCEEDED_ERROR;
+    case cdm::kUnknownError:
+      return MediaKeys::UNKNOWN_ERROR;
+    case cdm::kClientError:
+      return MediaKeys::CLIENT_ERROR;
+    case cdm::kOutputError:
+      return MediaKeys::OUTPUT_ERROR;
+  }
+
+  NOTREACHED();
+  return MediaKeys::UNKNOWN_ERROR;
+}
+
+MediaKeys::MessageType CdmMessageTypeToMediaMessageType(
+    cdm::MessageType message_type) {
+  switch (message_type) {
+    case cdm::kLicenseRequest:
+      return MediaKeys::LICENSE_REQUEST;
+    case cdm::kLicenseRenewal:
+      return MediaKeys::LICENSE_RENEWAL;
+    case cdm::kLicenseRelease:
+      return MediaKeys::LICENSE_RELEASE;
+  }
+
+  NOTREACHED();
+  return MediaKeys::LICENSE_REQUEST;
+}
+
+CdmKeyInformation::KeyStatus CdmKeyStatusToCdmKeyInformationKeyStatus(
+    cdm::KeyStatus status) {
+  switch (status) {
+    case cdm::kUsable:
+      return CdmKeyInformation::USABLE;
+    case cdm::kInternalError:
+      return CdmKeyInformation::INTERNAL_ERROR;
+    case cdm::kExpired:
+      return CdmKeyInformation::EXPIRED;
+    case cdm::kOutputRestricted:
+      return CdmKeyInformation::OUTPUT_RESTRICTED;
+    case cdm::kOutputDownscaled:
+      return CdmKeyInformation::OUTPUT_DOWNSCALED;
+    case cdm::kStatusPending:
+      return CdmKeyInformation::KEY_STATUS_PENDING;
+    case cdm::kReleased:
+      return CdmKeyInformation::RELEASED;
+  }
+
+  NOTREACHED();
+  return CdmKeyInformation::INTERNAL_ERROR;
+}
+
+static void* GetCdmHost(int host_interface_version, void* user_data) {
+  if (!host_interface_version || !user_data)
+    return nullptr;
+
+  static_assert(
+      cdm::ContentDecryptionModule::Host::kVersion == cdm::Host_8::kVersion,
+      "update the code below");
+
+  // Ensure IsSupportedCdmHostVersion matches implementation of this function.
+  // Always update this DCHECK when updating this function.
+  // If this check fails, update this function and DCHECK or update
+  // IsSupportedCdmHostVersion.
+
+  DCHECK(
+      // Future version is not supported.
+      !IsSupportedCdmHostVersion(cdm::Host_8::kVersion + 1) &&
+      // Current version is supported.
+      IsSupportedCdmHostVersion(cdm::Host_8::kVersion) &&
+      // Include all previous supported versions (if any) here.
+      IsSupportedCdmHostVersion(cdm::Host_7::kVersion) &&
+      // One older than the oldest supported version is not supported.
+      !IsSupportedCdmHostVersion(cdm::Host_7::kVersion - 1));
+  DCHECK(IsSupportedCdmHostVersion(host_interface_version));
+
+  CdmAdapterImpl* cdm_adapter = static_cast<CdmAdapterImpl*>(user_data);
+  DVLOG(1) << "Create CDM Host with version " << host_interface_version;
+  switch (host_interface_version) {
+    case cdm::Host_8::kVersion:
+      return static_cast<cdm::Host_8*>(cdm_adapter);
+    case cdm::Host_7::kVersion:
+      return static_cast<cdm::Host_7*>(cdm_adapter);
+    default:
+      NOTREACHED();
+      return nullptr;
+  }
+}
+
+}  // namespace
+
+CdmAdapterImpl::CdmAdapterImpl()
+    : task_runner_(base::ThreadTaskRunnerHandle::Get()), weak_factory_(this) {}
+
+CdmAdapterImpl::~CdmAdapterImpl() {}
+
+CdmWrapper* CdmAdapterImpl::CreateCdmInstance(const std::string& key_system,
+                                              const base::FilePath& cdm_path) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  // TODO(jrummell): We need to call INITIALIZE_CDM_MODULE() and
+  // DeinitializeCdmModule(). However, that should only be done once for the
+  // library.
+  base::NativeLibraryLoadError error;
+  library_.Reset(base::LoadNativeLibrary(cdm_path, &error));
+  if (!library_.is_valid()) {
+    DVLOG(1) << "CDM instance for " + key_system + " could not be created. "
+             << error.ToString();
+    return nullptr;
+  }
+
+  CreateCdmFunc create_cdm_func = reinterpret_cast<CreateCdmFunc>(
+      library_.GetFunctionPointer("CreateCdmInstance"));
+  if (!create_cdm_func) {
+    DVLOG(1) << "No CreateCdmInstance() in library for " + key_system;
+    return nullptr;
+  }
+
+  CdmWrapper* cdm = CdmWrapper::Create(create_cdm_func, key_system.data(),
+                                       key_system.size(), GetCdmHost, this);
+
+  DVLOG(1) << "CDM instance for " + key_system + (cdm ? "" : " could not be") +
+                  " created.";
+  return cdm;
+}
+
+void CdmAdapterImpl::Initialize(
+    const std::string& key_system,
+    const base::FilePath& cdm_path,
+    const CdmConfig& cdm_config,
+    const SessionMessageCB& session_message_cb,
+    const SessionClosedCB& session_closed_cb,
+    const LegacySessionErrorCB& legacy_session_error_cb,
+    const SessionKeysChangeCB& session_keys_change_cb,
+    const SessionExpirationUpdateCB& session_expiration_update_cb,
+    scoped_ptr<SimpleCdmPromise> promise) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(!key_system.empty());
+  DCHECK(key_system_.empty());
+  DCHECK(!session_message_cb.is_null());
+  DCHECK(!session_closed_cb.is_null());
+  DCHECK(!legacy_session_error_cb.is_null());
+  DCHECK(!session_keys_change_cb.is_null());
+  DCHECK(!session_expiration_update_cb.is_null());
+
+  session_message_cb_ = session_message_cb;
+  session_closed_cb_ = session_closed_cb;
+  legacy_session_error_cb_ = legacy_session_error_cb;
+  session_keys_change_cb_ = session_keys_change_cb;
+  session_expiration_update_cb_ = session_expiration_update_cb;
+
+  cdm_.reset(CreateCdmInstance(key_system, cdm_path));
+  if (!cdm_) {
+    promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0,
+                    "Unable to create CDM.");
+    return;
+  }
+
+  key_system_ = key_system;
+  cdm_config_ = cdm_config;
+  cdm_->Initialize(cdm_config_.allow_distinctive_identifier,
+                   cdm_config_.allow_persistent_state);
+  promise->resolve();
+}
+
+void CdmAdapterImpl::SetServerCertificate(
+    const std::vector<uint8_t>& certificate,
+    scoped_ptr<SimpleCdmPromise> promise) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  if (certificate.size() < limits::kMinCertificateLength ||
+      certificate.size() > limits::kMaxCertificateLength) {
+    promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0,
+                    "Incorrect certificate.");
+    return;
+  }
+
+  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
+  cdm_->SetServerCertificate(promise_id, vector_as_array(&certificate),
+                             certificate.size());
+}
+
+void CdmAdapterImpl::CreateSessionAndGenerateRequest(
+    SessionType session_type,
+    EmeInitDataType init_data_type,
+    const std::vector<uint8_t>& init_data,
+    scoped_ptr<NewSessionCdmPromise> promise) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
+  cdm_->CreateSessionAndGenerateRequest(
+      promise_id, MediaSessionTypeToCdmSessionType(session_type),
+      MediaInitDataTypeToCdmInitDataType(init_data_type),
+      vector_as_array(&init_data), init_data.size());
+}
+
+void CdmAdapterImpl::LoadSession(SessionType session_type,
+                                 const std::string& session_id,
+                                 scoped_ptr<NewSessionCdmPromise> promise) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
+  cdm_->LoadSession(promise_id, MediaSessionTypeToCdmSessionType(session_type),
+                    session_id.data(), session_id.size());
+}
+
+void CdmAdapterImpl::UpdateSession(const std::string& session_id,
+                                   const std::vector<uint8_t>& response,
+                                   scoped_ptr<SimpleCdmPromise> promise) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(!session_id.empty());
+  DCHECK(!response.empty());
+
+  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
+  cdm_->UpdateSession(promise_id, session_id.data(), session_id.size(),
+                      vector_as_array(&response), response.size());
+}
+
+void CdmAdapterImpl::CloseSession(const std::string& session_id,
+                                  scoped_ptr<SimpleCdmPromise> promise) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(!session_id.empty());
+
+  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
+  cdm_->CloseSession(promise_id, session_id.data(), session_id.size());
+}
+
+void CdmAdapterImpl::RemoveSession(const std::string& session_id,
+                                   scoped_ptr<SimpleCdmPromise> promise) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(!session_id.empty());
+
+  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
+  cdm_->RemoveSession(promise_id, session_id.data(), session_id.size());
+}
+
+CdmContext* CdmAdapterImpl::GetCdmContext() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  // TODO(jrummell): Support the Decryptor interface.
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+cdm::Buffer* CdmAdapterImpl::Allocate(uint32_t capacity) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  // TODO(jrummell): Figure out how memory should be passed around when
+  // decrypting.
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+void CdmAdapterImpl::SetTimer(int64_t delay_ms, void* context) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  task_runner_->PostDelayedTask(FROM_HERE,
+                                base::Bind(&CdmAdapterImpl::TimerExpired,
+                                           weak_factory_.GetWeakPtr(), context),
+                                base::TimeDelta::FromMilliseconds(delay_ms));
+}
+
+void CdmAdapterImpl::TimerExpired(void* context) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  cdm_->TimerExpired(context);
+}
+
+cdm::Time CdmAdapterImpl::GetCurrentWallTime() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  return base::Time::Now().ToDoubleT();
+}
+
+void CdmAdapterImpl::OnResolvePromise(uint32_t promise_id) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  cdm_promise_adapter_.ResolvePromise(promise_id);
+}
+
+void CdmAdapterImpl::OnResolveNewSessionPromise(uint32_t promise_id,
+                                                const char* session_id,
+                                                uint32_t session_id_size) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  cdm_promise_adapter_.ResolvePromise(promise_id,
+                                      std::string(session_id, session_id_size));
+}
+
+void CdmAdapterImpl::OnRejectPromise(uint32_t promise_id,
+                                     cdm::Error error,
+                                     uint32_t system_code,
+                                     const char* error_message,
+                                     uint32_t error_message_size) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  cdm_promise_adapter_.RejectPromise(
+      promise_id, CdmErrorTypeToMediaExceptionType(error), system_code,
+      std::string(error_message, error_message_size));
+}
+
+void CdmAdapterImpl::OnSessionMessage(const char* session_id,
+                                      uint32_t session_id_size,
+                                      cdm::MessageType message_type,
+                                      const char* message,
+                                      uint32_t message_size,
+                                      const char* legacy_destination_url,
+                                      uint32_t legacy_destination_url_size) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(legacy_destination_url_size == 0 ||
+         message_type != cdm::MessageType::kLicenseRequest);
+
+  GURL verified_gurl =
+      GURL(std::string(legacy_destination_url, legacy_destination_url_size));
+  if (!verified_gurl.is_valid()) {
+    DLOG(WARNING) << "SessionMessage legacy_destination_url is invalid : "
+                  << verified_gurl.possibly_invalid_spec();
+    verified_gurl = GURL::EmptyGURL();  // Replace invalid destination_url.
+  }
+
+  const uint8_t* message_ptr = reinterpret_cast<const uint8*>(message);
+  session_message_cb_.Run(
+      std::string(session_id, session_id_size),
+      CdmMessageTypeToMediaMessageType(message_type),
+      std::vector<uint8_t>(message_ptr, message_ptr + message_size),
+      verified_gurl);
+}
+
+void CdmAdapterImpl::OnSessionKeysChange(const char* session_id,
+                                         uint32_t session_id_size,
+                                         bool has_additional_usable_key,
+                                         const cdm::KeyInformation* keys_info,
+                                         uint32_t keys_info_count) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  CdmKeysInfo keys;
+  keys.reserve(keys_info_count);
+  for (uint32_t i = 0; i < keys_info_count; ++i) {
+    const auto& info = keys_info[i];
+    keys.push_back(new CdmKeyInformation(
+        info.key_id, info.key_id_size,
+        CdmKeyStatusToCdmKeyInformationKeyStatus(info.status),
+        info.system_code));
+  }
+
+  session_keys_change_cb_.Run(std::string(session_id, session_id_size),
+                              has_additional_usable_key, keys.Pass());
+}
+
+void CdmAdapterImpl::OnExpirationChange(const char* session_id,
+                                        uint32_t session_id_size,
+                                        cdm::Time new_expiry_time) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  session_expiration_update_cb_.Run(std::string(session_id, session_id_size),
+                                    base::Time::FromDoubleT(new_expiry_time));
+}
+
+void CdmAdapterImpl::OnSessionClosed(const char* session_id,
+                                     uint32_t session_id_size) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  session_closed_cb_.Run(std::string(session_id, session_id_size));
+}
+
+void CdmAdapterImpl::OnLegacySessionError(const char* session_id,
+                                          uint32_t session_id_size,
+                                          cdm::Error error,
+                                          uint32_t system_code,
+                                          const char* error_message,
+                                          uint32_t error_message_size) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  legacy_session_error_cb_.Run(std::string(session_id, session_id_size),
+                               CdmErrorTypeToMediaExceptionType(error),
+                               system_code,
+                               std::string(error_message, error_message_size));
+}
+
+void CdmAdapterImpl::SendPlatformChallenge(const char* service_id,
+                                           uint32_t service_id_size,
+                                           const char* challenge,
+                                           uint32_t challenge_size) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  // TODO(jrummell): If platform verification is available, use it.
+  NOTIMPLEMENTED();
+  cdm::PlatformChallengeResponse platform_challenge_response = {};
+  cdm_->OnPlatformChallengeResponse(platform_challenge_response);
+}
+
+void CdmAdapterImpl::EnableOutputProtection(uint32_t desired_protection_mask) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  // TODO(jrummell): If output protection is available, use it.
+  NOTIMPLEMENTED();
+}
+
+void CdmAdapterImpl::QueryOutputProtectionStatus() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  // TODO(jrummell): If output protection is available, use it.
+  NOTIMPLEMENTED();
+  cdm_->OnQueryOutputProtectionStatus(cdm::kQueryFailed, 0, 0);
+}
+
+void CdmAdapterImpl::OnDeferredInitializationDone(cdm::StreamType stream_type,
+                                                  cdm::Status decoder_status) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  // Not initializing a decoder, so this should never happen.
+  NOTREACHED();
+}
+
+// The CDM owns the returned object and must call FileIO::Close() to release it.
+cdm::FileIO* CdmAdapterImpl::CreateFileIO(cdm::FileIOClient* client) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  // TODO(jrummell): This should use the mojo FileIO client.
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+}  // namespace media
diff --git a/media/cdm/cdm_adapter_impl.h b/media/cdm/cdm_adapter_impl.h
new file mode 100644
index 0000000..41b091c
--- /dev/null
+++ b/media/cdm/cdm_adapter_impl.h
@@ -0,0 +1,153 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_CDM_CDM_ADAPTER_IMPL_H_
+#define MEDIA_CDM_CDM_ADAPTER_IMPL_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/scoped_native_library.h"
+#include "base/threading/thread.h"
+#include "media/base/cdm_config.h"
+#include "media/base/cdm_promise_adapter.h"
+#include "media/base/media_keys.h"
+#include "media/cdm/api/content_decryption_module.h"
+
+namespace media {
+
+class CdmWrapper;
+
+class CdmAdapterImpl : public MediaKeys,
+                       public cdm::Host_7,
+                       public cdm::Host_8 {
+ public:
+  CdmAdapterImpl();
+
+  // Load the CDM using |cdm_path| and initialize it using |key_system| and
+  // |cdm_config|. Callbacks will be used for events generated by the CDM.
+  // |promise| is resolved if the CDM is loaded and initialized correctly,
+  // otherwise it is rejected.
+  void Initialize(const std::string& key_system,
+                  const base::FilePath& cdm_path,
+                  const CdmConfig& cdm_config,
+                  const SessionMessageCB& session_message_cb,
+                  const SessionClosedCB& session_closed_cb,
+                  const LegacySessionErrorCB& legacy_session_error_cb,
+                  const SessionKeysChangeCB& session_keys_change_cb,
+                  const SessionExpirationUpdateCB& session_expiration_update_cb,
+                  scoped_ptr<SimpleCdmPromise> promise);
+
+  // MediaKeys implementation.
+  void SetServerCertificate(const std::vector<uint8_t>& certificate,
+                            scoped_ptr<SimpleCdmPromise> promise) override;
+  void CreateSessionAndGenerateRequest(
+      SessionType session_type,
+      EmeInitDataType init_data_type,
+      const std::vector<uint8_t>& init_data,
+      scoped_ptr<NewSessionCdmPromise> promise) override;
+  void LoadSession(SessionType session_type,
+                   const std::string& session_id,
+                   scoped_ptr<NewSessionCdmPromise> promise) override;
+  void UpdateSession(const std::string& session_id,
+                     const std::vector<uint8_t>& response,
+                     scoped_ptr<SimpleCdmPromise> promise) override;
+  void CloseSession(const std::string& session_id,
+                    scoped_ptr<SimpleCdmPromise> promise) override;
+  void RemoveSession(const std::string& session_id,
+                     scoped_ptr<SimpleCdmPromise> promise) override;
+  CdmContext* GetCdmContext() override;
+
+  // cdm::Host_7 and cdm::Host_8 implementation.
+  cdm::Buffer* Allocate(uint32_t capacity) override;
+  void SetTimer(int64_t delay_ms, void* context) override;
+  cdm::Time GetCurrentWallTime() override;
+  void OnResolveNewSessionPromise(uint32_t promise_id,
+                                  const char* session_id,
+                                  uint32_t session_id_size) override;
+  void OnResolvePromise(uint32_t promise_id) override;
+  void OnRejectPromise(uint32_t promise_id,
+                       cdm::Error error,
+                       uint32_t system_code,
+                       const char* error_message,
+                       uint32_t error_message_size) override;
+  void OnSessionMessage(const char* session_id,
+                        uint32_t session_id_size,
+                        cdm::MessageType message_type,
+                        const char* message,
+                        uint32_t message_size,
+                        const char* legacy_destination_url,
+                        uint32_t legacy_destination_url_size) override;
+  void OnSessionKeysChange(const char* session_id,
+                           uint32_t session_id_size,
+                           bool has_additional_usable_key,
+                           const cdm::KeyInformation* keys_info,
+                           uint32_t keys_info_count) override;
+  void OnExpirationChange(const char* session_id,
+                          uint32_t session_id_size,
+                          cdm::Time new_expiry_time) override;
+  void OnSessionClosed(const char* session_id,
+                       uint32_t session_id_size) override;
+  void OnLegacySessionError(const char* session_id,
+                            uint32_t session_id_size,
+                            cdm::Error error,
+                            uint32_t system_code,
+                            const char* error_message,
+                            uint32_t error_message_size) override;
+  void SendPlatformChallenge(const char* service_id,
+                             uint32_t service_id_size,
+                             const char* challenge,
+                             uint32_t challenge_size) override;
+  void EnableOutputProtection(uint32_t desired_protection_mask) override;
+  void QueryOutputProtectionStatus() override;
+  void OnDeferredInitializationDone(cdm::StreamType stream_type,
+                                    cdm::Status decoder_status) override;
+  cdm::FileIO* CreateFileIO(cdm::FileIOClient* client) override;
+
+ private:
+  ~CdmAdapterImpl() final;
+
+  // Create an instance of the |key_system| CDM contained in |cdm_path|.
+  // Caller owns the returned pointer. On error (unable to load, does not
+  // support |key_system|, does not support an supported interface, etc.)
+  // NULL will be returned.
+  CdmWrapper* CreateCdmInstance(const std::string& key_system,
+                                const base::FilePath& cdm_path);
+
+  // Helper for SetTimer().
+  void TimerExpired(void* context);
+
+  // Keep a reference to the CDM.
+  base::ScopedNativeLibrary library_;
+
+  // Used to keep track of promises while the CDM is processing the request.
+  CdmPromiseAdapter cdm_promise_adapter_;
+
+  scoped_ptr<CdmWrapper> cdm_;
+  std::string key_system_;
+  CdmConfig cdm_config_;
+
+  // Callbacks for firing session events.
+  SessionMessageCB session_message_cb_;
+  SessionClosedCB session_closed_cb_;
+  LegacySessionErrorCB legacy_session_error_cb_;
+  SessionKeysChangeCB session_keys_change_cb_;
+  SessionExpirationUpdateCB session_expiration_update_cb_;
+
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  // NOTE: Weak pointers must be invalidated before all other member variables.
+  base::WeakPtrFactory<CdmAdapterImpl> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CdmAdapterImpl);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CDM_CDM_ADAPTER_IMPL_H_
diff --git a/media/cdm/cdm_wrapper.h b/media/cdm/cdm_wrapper.h
index c8fe54d..f5aef43 100644
--- a/media/cdm/cdm_wrapper.h
+++ b/media/cdm/cdm_wrapper.h
@@ -12,6 +12,7 @@
 #include "media/cdm/supported_cdm_versions.h"
 
 #if defined(USE_PPAPI_CDM_ADAPTER)
+// When building the ppapi adapter do not include any non-trivial base/ headers.
 #include "ppapi/cpp/logging.h"
 #define PLATFORM_DCHECK PP_DCHECK
 #else
@@ -21,6 +22,19 @@
 
 namespace media {
 
+// Returns a pointer to the requested CDM upon success.
+// Returns NULL if an error occurs or the requested |cdm_interface_version| or
+// |key_system| is not supported or another error occurs.
+// The caller should cast the returned pointer to the type matching
+// |cdm_interface_version|.
+// Caller retains ownership of arguments and must call Destroy() on the returned
+// object.
+typedef void* (*CreateCdmFunc)(int cdm_interface_version,
+                               const char* key_system,
+                               uint32_t key_system_size,
+                               GetCdmHostFunc get_cdm_host_func,
+                               void* user_data);
+
 // CdmWrapper wraps different versions of ContentDecryptionModule interfaces and
 // exposes a common interface to the caller.
 //
@@ -36,7 +50,8 @@
 // (just a shim layer in most cases), everything is done in this header file.
 class CdmWrapper {
  public:
-  static CdmWrapper* Create(const char* key_system,
+  static CdmWrapper* Create(CreateCdmFunc create_cdm_func,
+                            const char* key_system,
                             uint32_t key_system_size,
                             GetCdmHostFunc get_cdm_host_func,
                             void* user_data);
@@ -103,15 +118,16 @@
 template <class CdmInterface>
 class CdmWrapperImpl : public CdmWrapper {
  public:
-  static CdmWrapper* Create(const char* key_system,
+  static CdmWrapper* Create(CreateCdmFunc create_cdm_func,
+                            const char* key_system,
                             uint32_t key_system_size,
                             GetCdmHostFunc get_cdm_host_func,
                             void* user_data) {
     void* cdm_instance =
-        ::CreateCdmInstance(CdmInterface::kVersion, key_system, key_system_size,
-                            get_cdm_host_func, user_data);
+        create_cdm_func(CdmInterface::kVersion, key_system, key_system_size,
+                        get_cdm_host_func, user_data);
     if (!cdm_instance)
-      return NULL;
+      return nullptr;
 
     return new CdmWrapperImpl<CdmInterface>(
         static_cast<CdmInterface*>(cdm_instance));
@@ -256,7 +272,8 @@
       init_data_type_as_string.length(), init_data, init_data_size);
 }
 
-CdmWrapper* CdmWrapper::Create(const char* key_system,
+CdmWrapper* CdmWrapper::Create(CreateCdmFunc create_cdm_func,
+                               const char* key_system,
                                uint32_t key_system_size,
                                GetCdmHostFunc get_cdm_host_func,
                                void* user_data) {
@@ -280,13 +297,15 @@
   // Try to create the CDM using the latest CDM interface version.
   CdmWrapper* cdm_wrapper =
       CdmWrapperImpl<cdm::ContentDecryptionModule>::Create(
-          key_system, key_system_size, get_cdm_host_func, user_data);
+          create_cdm_func, key_system, key_system_size, get_cdm_host_func,
+          user_data);
 
   // If |cdm_wrapper| is NULL, try to create the CDM using older supported
   // versions of the CDM interface here.
   if (!cdm_wrapper) {
     cdm_wrapper = CdmWrapperImpl<cdm::ContentDecryptionModule_7>::Create(
-        key_system, key_system_size, get_cdm_host_func, user_data);
+        create_cdm_func, key_system, key_system_size, get_cdm_host_func,
+        user_data);
   }
 
   return cdm_wrapper;
diff --git a/media/cdm/ppapi/ppapi_cdm_adapter.cc b/media/cdm/ppapi/ppapi_cdm_adapter.cc
index e4fa9e43..e90a2f6 100644
--- a/media/cdm/ppapi/ppapi_cdm_adapter.cc
+++ b/media/cdm/ppapi/ppapi_cdm_adapter.cc
@@ -341,8 +341,10 @@
 PpapiCdmAdapter::~PpapiCdmAdapter() {}
 
 CdmWrapper* PpapiCdmAdapter::CreateCdmInstance(const std::string& key_system) {
-  CdmWrapper* cdm = CdmWrapper::Create(key_system.data(), key_system.size(),
-                                       GetCdmHost, this);
+  // The Pepper plugin will be staticly linked to the CDM, so pass the plugin's
+  // CreateCdmInstance() to CdmWrapper.
+  CdmWrapper* cdm = CdmWrapper::Create(::CreateCdmInstance, key_system.data(),
+                                       key_system.size(), GetCdmHost, this);
 
   const std::string message = "CDM instance for " + key_system +
                               (cdm ? "" : " could not be") + " created.";
diff --git a/media/cdm/ppapi/ppapi_cdm_adapter.h b/media/cdm/ppapi/ppapi_cdm_adapter.h
index 7d1527dd..470bc9a5 100644
--- a/media/cdm/ppapi/ppapi_cdm_adapter.h
+++ b/media/cdm/ppapi/ppapi_cdm_adapter.h
@@ -165,6 +165,9 @@
     std::string legacy_destination_url;
   };
 
+  // Create an instance of the |key_system| CDM. Caller owns the returned
+  // pointer. On error (unable to load CDM, does not support |key_system|,
+  // does not support an supported interface, etc.) NULL will be returned.
   CdmWrapper* CreateCdmInstance(const std::string& key_system);
 
   // <code>PPB_ContentDecryptor_Private</code> dispatchers. These are passed to
diff --git a/media/media.gyp b/media/media.gyp
index dc23002a4..75f6e91 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -488,6 +488,10 @@
         'capture/video/win/video_capture_device_win.h',
         'cdm/aes_decryptor.cc',
         'cdm/aes_decryptor.h',
+        'cdm/cdm_adapter.cc',
+        'cdm/cdm_adapter.h',
+        'cdm/cdm_adapter_impl.cc',
+        'cdm/cdm_adapter_impl.h',
         'cdm/default_cdm_factory.cc',
         'cdm/default_cdm_factory.h',
         'cdm/json_web_key.cc',
diff --git a/media/midi/midi_manager_win.cc b/media/midi/midi_manager_win.cc
index 4adedbb..efab827 100644
--- a/media/midi/midi_manager_win.cc
+++ b/media/midi/midi_manager_win.cc
@@ -428,7 +428,7 @@
   ~MidiServiceWinImpl() final {
     // Start() and Stop() of the threads, and AddDevicesChangeObserver() and
     // RemoveDevicesChangeObserver() should be called on the same thread.
-    CHECK(thread_checker_.CalledOnValidThread());
+    DCHECK(thread_checker_.CalledOnValidThread());
 
     destructor_started = true;
     base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this);
@@ -482,7 +482,7 @@
   void InitializeAsync(MidiServiceWinDelegate* delegate) final {
     // Start() and Stop() of the threads, and AddDevicesChangeObserver() and
     // RemoveDevicesChangeObserver() should be called on the same thread.
-    CHECK(thread_checker_.CalledOnValidThread());
+    DCHECK(thread_checker_.CalledOnValidThread());
 
     delegate_ = delegate;
 
@@ -539,7 +539,7 @@
 
   // base::SystemMonitor::DevicesChangedObserver overrides:
   void OnDevicesChanged(base::SystemMonitor::DeviceType device_type) final {
-    CHECK(thread_checker_.CalledOnValidThread());
+    DCHECK(thread_checker_.CalledOnValidThread());
     if (destructor_started)
       return;
 
@@ -1120,7 +1120,6 @@
 }
 
 MidiManagerWin::~MidiManagerWin() {
-  midi_service_.reset();
 }
 
 void MidiManagerWin::StartInitialization() {
@@ -1129,6 +1128,10 @@
   midi_service_->InitializeAsync(this);
 }
 
+void MidiManagerWin::Finalize() {
+  midi_service_.reset();
+}
+
 void MidiManagerWin::DispatchSendMidiData(MidiManagerClient* client,
                                           uint32 port_index,
                                           const std::vector<uint8>& data,
diff --git a/media/midi/midi_manager_win.h b/media/midi/midi_manager_win.h
index dbee7e15..b54f9d18 100644
--- a/media/midi/midi_manager_win.h
+++ b/media/midi/midi_manager_win.h
@@ -47,6 +47,7 @@
 
   // MidiManager overrides:
   void StartInitialization() final;
+  void Finalize() final;
   void DispatchSendMidiData(MidiManagerClient* client,
                             uint32 port_index,
                             const std::vector<uint8>& data,
diff --git a/mojo/converters/geometry/geometry_type_converters.cc b/mojo/converters/geometry/geometry_type_converters.cc
index 00f4f343..c918d01 100644
--- a/mojo/converters/geometry/geometry_type_converters.cc
+++ b/mojo/converters/geometry/geometry_type_converters.cc
@@ -115,4 +115,39 @@
   return gfx::Size(input.width, input.height);
 }
 
+// static
+Insets TypeConverter<Insets, gfx::Insets>::Convert(const gfx::Insets& input) {
+  Insets insets;
+  insets.top = input.top();
+  insets.left = input.left();
+  insets.bottom = input.bottom();
+  insets.right = input.right();
+  return insets;
+}
+
+// static
+gfx::Insets TypeConverter<gfx::Insets, Insets>::Convert(const Insets& input) {
+  return gfx::Insets(input.top, input.left, input.bottom, input.right);
+}
+
+// static
+InsetsPtr TypeConverter<InsetsPtr, gfx::Insets>::Convert(
+    const gfx::Insets& input) {
+  InsetsPtr insets(Insets::New());
+  insets->top = input.top();
+  insets->left = input.left();
+  insets->bottom = input.bottom();
+  insets->right = input.right();
+  return insets.Pass();
+}
+
+// static
+gfx::Insets TypeConverter<gfx::Insets, InsetsPtr>::Convert(
+    const InsetsPtr& input) {
+  if (input.is_null())
+    return gfx::Insets();
+
+  return gfx::Insets(input->top, input->left, input->bottom, input->right);
+}
+
 }  // namespace mojo
diff --git a/mojo/converters/geometry/geometry_type_converters.h b/mojo/converters/geometry/geometry_type_converters.h
index d3d8fd2..f90aba7 100644
--- a/mojo/converters/geometry/geometry_type_converters.h
+++ b/mojo/converters/geometry/geometry_type_converters.h
@@ -6,6 +6,7 @@
 #define MOJO_CONVERTERS_GEOMETRY_GEOMETRY_TYPE_CONVERTERS_H_
 
 #include "mojo/converters/geometry/mojo_geometry_export.h"
+#include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/point_f.h"
 #include "ui/gfx/geometry/rect.h"
@@ -78,6 +79,24 @@
   static gfx::Size Convert(const Size& input);
 };
 
+template <>
+struct MOJO_GEOMETRY_EXPORT TypeConverter<Insets, gfx::Insets> {
+  static Insets Convert(const gfx::Insets& input);
+};
+template <>
+struct MOJO_GEOMETRY_EXPORT TypeConverter<gfx::Insets, Insets> {
+  static gfx::Insets Convert(const Insets& input);
+};
+
+template <>
+struct MOJO_GEOMETRY_EXPORT TypeConverter<InsetsPtr, gfx::Insets> {
+  static InsetsPtr Convert(const gfx::Insets& input);
+};
+template <>
+struct MOJO_GEOMETRY_EXPORT TypeConverter<gfx::Insets, InsetsPtr> {
+  static gfx::Insets Convert(const InsetsPtr& input);
+};
+
 }  // namespace mojo
 
 #endif  // MOJO_CONVERTERS_GEOMETRY_GEOMETRY_TYPE_CONVERTERS_H_
diff --git a/third_party/WebKit/LayoutTests/bluetooth/advertising-data.html b/third_party/WebKit/LayoutTests/bluetooth/advertising-data.html
new file mode 100644
index 0000000..703ab815
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/bluetooth/advertising-data.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="resources/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+
+test(function(t) { assert_true(window.testRunner instanceof Object); t.done(); },
+     'window.testRunner is required for the following tests.');
+// Tests that we are handling values returned from the underlying platform
+// correctly. Only meant to be used by chromium.
+[{
+  name: 'Tx Power too low must result in nulled txPower.',
+  tx_power: -128,
+  expected_tx_power: null,
+  rssi: 0,
+  expected_rssi: 0
+}, {
+  name: 'RSSI too low must result in nulled rssi.',
+  tx_power: 0,
+  expected_tx_power: 0,
+  rssi: -128,
+  expected_rssi: null
+}, {
+  name: 'Low Tx Power should appear in adData.',
+  tx_power: -127,
+  expected_tx_power: -127,
+  rssi: 0,
+  expected_rssi: 0
+}, {
+  name: 'Low RSSI should appear in adData.',
+  tx_power: 0,
+  expected_tx_power: 0,
+  rssi: -127,
+  expected_rssi: -127
+}, {
+  name: 'High Tx Power should appear in adData.',
+  // TODO(ortuno): According to the Bluetooth Spec Supplement, 127 is the
+  // the hightest possible valid value for Tx Power. Change to 127 when
+  // fixed: http://crbug.com/551572
+  tx_power: 126,
+  expected_tx_power: 126,
+  rssi: 0,
+  expected_rssi: 0
+}, {
+  name: 'High RSSI should appear in adData.',
+  tx_power: 0,
+  expected_tx_power: 0,
+  rssi: 126,
+  expected_rssi: 126
+}, {
+  // TODO(ortuno): Remove this test since 127 is both a valid Tx Power
+  // and the max value of a int8.
+  // http://crbug.com/551572
+  name: 'Tx Power too high must result in nulled txPower.',
+  tx_power: 127,
+  expected_tx_power: null,
+  rssi: 0,
+  expected_rssi: 0
+}, {
+  name: 'RSSI too high must result in nulled rssi.',
+  tx_power: 0,
+  expected_tx_power: 0,
+  rssi: 127,
+  expected_rssi: null
+}].forEach(power_test => {
+  promise_test(() => {
+    testRunner.setBluetoothMockDataSet('PowerValueAdapter:' +
+                                       power_test.tx_power +  ':' +
+                                       power_test.rssi);
+    return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
+      .then(device => {
+        let adv_data = device.adData;
+        assert_equals(adv_data.txPower, power_test.expected_tx_power);
+        assert_equals(adv_data.rssi, power_test.expected_rssi);
+      });
+  }, power_test.name);
+});
+
+// Tests for all platforms.
+[{
+  name: 'TxPower not present, RSSI not present.',
+  tx_power_present: false,
+  rssi_present: false
+}, {
+  name: 'TxPower not present, RSSI present.',
+  tx_power_present: false,
+  rssi_present: true
+}, {
+  name: 'TxPower present, RSSI not present.',
+  tx_power_present: true,
+  rssi_present: false,
+}, {
+  name: 'TxPower present, RSSI present.',
+  tx_power_present: true,
+  rssi_present: true
+}].forEach(power_test => {
+  promise_test(() => {
+    testRunner.setBluetoothMockDataSet('PowerPresenceAdapter:' +
+                                       power_test.tx_power_present + ':' +
+                                       power_test.rssi_present);
+    return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
+      .then(device => {
+        let adv_data = device.adData;
+        let expected_tx_power = power_test.tx_power_present ?
+                              -10 /* broadcasting at 0.1mW */
+                              : null;
+        let expected_rssi = power_test.rssi_present ?
+                          -51 /* power at 1m from device broadcasting at 0.1mW */
+                          : null;
+        assert_equals(adv_data.txPower, expected_tx_power);
+        assert_equals(adv_data.rssi, expected_rssi);
+      });
+  }, power_test.name)
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/text/first-letter-bad-line-boxes-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/text/first-letter-bad-line-boxes-crash-expected.txt
index fd703d5..bbfaf90 100644
--- a/third_party/WebKit/LayoutTests/fast/text/first-letter-bad-line-boxes-crash-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/text/first-letter-bad-line-boxes-crash-expected.txt
@@ -3,6 +3,7 @@
 CONSOLE WARNING: We don't execute document.execCommand() this time, because it is called recursively.
 \\\\\\m{VVVVVVVVVVVVVVV<};<WWWWW
 
- \\\\\\m{VVVVVVVVVVVVVVV<};<WWWWW
+ Te\\\\\\m{VVVVVVVVVVVVVVV<};<WWWWW
 xt
 
+
diff --git a/third_party/WebKit/LayoutTests/fast/text/insert-text-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/text/insert-text-crash-expected.txt
index 6902cf2..d5bb3cf6 100644
--- a/third_party/WebKit/LayoutTests/fast/text/insert-text-crash-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/text/insert-text-crash-expected.txt
@@ -1,4 +1,4 @@
 CONSOLE WARNING: We don't execute document.execCommand() this time, because it is called recursively.
 CONSOLE WARNING: SVG's SMIL animations (<animate>, <set>, etc.) are deprecated and will be removed. Please use CSS animations or Web animations instead.
-a:ca:ce#@::l@::l
+a:ce#@:a:ce#@::l:l
 Test passes if it does not CRASH.
diff --git a/third_party/WebKit/LayoutTests/http/tests/fetch/window/pageimportancesignals-expected.txt b/third_party/WebKit/LayoutTests/http/tests/fetch/window/pageimportancesignals-expected.txt
new file mode 100644
index 0000000..f062130
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/fetch/window/pageimportancesignals-expected.txt
@@ -0,0 +1,17 @@
+CONSOLE MESSAGE: line 12: Testing script initiated GET fetch.
+WebPageImportanceSignals:
+  hadFormInteraction: false
+  issuedNonGetFetchFromScript: false
+CONSOLE MESSAGE: line 28: Testing script initiated POST fetch.
+WebPageImportanceSignals:
+  hadFormInteraction: false
+  issuedNonGetFetchFromScript: true
+PageImportanceSignals should be recorded after script initiated non-GET fetch.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/fetch/window/pageimportancesignals.html b/third_party/WebKit/LayoutTests/http/tests/fetch/window/pageimportancesignals.html
new file mode 100644
index 0000000..fc272ad
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/fetch/window/pageimportancesignals.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<script src="/js-test-resources/js-test.js"></script>
+<script>
+description("PageImportanceSignals should be recorded after script initiated non-GET fetch.");
+window.jsTestIsAsync = true;
+
+function parseJSON(response) {
+  return response.json;
+}
+
+function test1() {
+  console.log("Testing script initiated GET fetch.");
+  window.fetch("../resources/simple.json")
+    .then(parseJSON)
+    .then(function(data) {
+      if (window.testRunner)
+          window.testRunner.dumpPageImportanceSignals();
+
+      test2();
+    })
+    .catch(function(error) {
+      testFailed("fetch failed: "+error);
+      finishJSTest();
+    });
+}
+
+function test2() {
+  console.log("Testing script initiated POST fetch.");
+  window.fetch("../resources/simple.json", { method: "POST" })
+    .then(parseJSON)
+    .then(function(data) {
+      if (window.testRunner)
+          window.testRunner.dumpPageImportanceSignals();
+
+      finishJSTest();
+    })
+    .catch(function() {
+      testFailed("fetch failed: "+error);
+      finishJSTest();
+    });
+}
+
+test1();
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/usecounter.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/usecounter.js
new file mode 100644
index 0000000..bc89a96f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/usecounter.js
@@ -0,0 +1,5 @@
+function isUseCounted(frame) {
+  var ServiceWorkerControlledPage = 990;  // From UseCounter.h
+  return frame.contentWindow.internals.isUseCounted(
+      frame.contentDocument, ServiceWorkerControlledPage);
+}
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-claim.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-claim.html
new file mode 100644
index 0000000..93cba0a7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-claim.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<title>Service Worker: UseCounter for page controlled-on-claim</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../resources/test-helpers.js"></script>
+<script src="resources/usecounter.js"></script>
+<script>
+
+promise_test(function(t) {
+    var url = '../resources/claim-worker.js';
+    var scope = '../resources/blank.html?usecounter-on-claim';
+    var worker;
+    var frame;
+
+    return service_worker_unregister(t, scope)
+      .then(function() { return with_iframe(scope); })
+      .then(function(f) {
+          frame = f;
+          add_completion_callback(function() { frame.remove(); });
+          var w = frame.contentWindow;
+          assert_equals(w.navigator.serviceWorker.controller, null);
+          assert_false(isUseCounted(frame),
+                       'should not be counted as controlled yet');
+          return navigator.serviceWorker.register(url, {scope: scope});
+        })
+      .then(function(registration) {
+          add_completion_callback(function() { registration.unregister(); });
+          worker = registration.installing;
+          return wait_for_state(t, worker, 'activated');
+        })
+      .then(function() {
+          var w = frame.contentWindow;
+          var saw_controllerchanged = new Promise(function(resolve) {
+              w.navigator.serviceWorker.oncontrollerchange = resolve;
+            });
+          var channel = new MessageChannel();
+          var saw_message = new Promise(function(resolve) {
+              channel.port1.onmessage = t.step_func(function(e) {
+                  assert_equals(e.data, 'PASS', 'claim() should fulfill');
+                  resolve();
+                });
+            });
+          worker.postMessage({port: channel.port2}, [channel.port2]);
+          return Promise.all([saw_controllerchanged, saw_message]);
+        })
+      .then(function() {
+          var w = frame.contentWindow;
+          var controller = w.navigator.serviceWorker.controller;
+          assert_true(controller instanceof w.ServiceWorker);
+          assert_true(isUseCounted(frame),
+                      'should be counted as controlled after claim()');
+        });
+  }, 'usecounter is counted upon claim() after registration');
+
+</script>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-load.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-load.html
new file mode 100644
index 0000000..3788ac01
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-load.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>Service Worker: UseCounter for page controlled-on-load</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../resources/test-helpers.js"></script>
+<script src="resources/usecounter.js"></script>
+<script>
+
+promise_test(function(t) {
+    var url = 'resources/empty-worker.js';
+    var scope = 'resources/blank.html?on-load';
+
+    return service_worker_unregister_and_register(t, url, scope)
+      .then(function(registration) {
+          add_completion_callback(function() { registration.unregister(); });
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope) })
+      .then(function(frame) {
+          add_completion_callback(function() { frame.remove(); });
+          var w = frame.contentWindow;
+          var controller = w.navigator.serviceWorker.controller;
+          assert_true(controller instanceof w.ServiceWorker);
+          assert_true(isUseCounted(frame), 'should be counted as controlled');
+        });
+  }, 'usecounter is counted for a controlled document');
+
+</script>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-reload.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-reload.html
new file mode 100644
index 0000000..874dd46
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-reload.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<title>Service Worker: UseCounter for page controlled-on-reload</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../resources/test-helpers.js"></script>
+<script src="resources/usecounter.js"></script>
+<script>
+
+promise_test(function(t) {
+    var url = 'resources/empty-worker.js';
+    var scope = 'resources/blank.html?on-reload';
+    var frame;
+
+    return service_worker_unregister(t, scope)
+      .then(function() { return with_iframe(scope); })
+      .then(function(f) {
+          frame = f;
+          add_completion_callback(function() { frame.remove(); });
+          var w = frame.contentWindow;
+          assert_equals(w.navigator.serviceWorker.controller, null);
+          assert_false(isUseCounted(frame),
+                       'should not be counted as controlled yet');
+          return navigator.serviceWorker.register(url, {scope: scope});
+        })
+      .then(function(registration) {
+          add_completion_callback(function() { registration.unregister(); });
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          var w = frame.contentWindow;
+          assert_equals(w.navigator.serviceWorker.controller, null);
+          return new Promise(function(resolve) {
+              frame.onload = function() { resolve(); }
+              w.location.reload();
+            });
+        })
+      .then(function() {
+          var w = frame.contentWindow;
+          var controller = w.navigator.serviceWorker.controller;
+          assert_true(controller instanceof w.ServiceWorker);
+          assert_true(isUseCounted(frame),
+                      'should be counted as controlled after reload()');
+        });
+  }, 'usecounter is counted upon reload after registration');
+
+</script>
+</html>
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 70d1d6b..cc69615 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -289,6 +289,10 @@
 interface BlobEvent : Event
     getter data
     method constructor
+interface BluetoothAdvertisingData
+    getter rssi
+    getter txPower
+    method constructor
 interface BluetoothCharacteristicProperties
     getter authenticatedSignedWrites
     getter broadcast
@@ -301,6 +305,7 @@
     getter writeWithoutResponse
     method constructor
 interface BluetoothDevice
+    getter adData
     getter deviceClass
     getter id
     getter instanceID
diff --git a/third_party/WebKit/Source/core/css/CSSSelectorList.cpp b/third_party/WebKit/Source/core/css/CSSSelectorList.cpp
index ba3f0f0..ab68f70 100644
--- a/third_party/WebKit/Source/core/css/CSSSelectorList.cpp
+++ b/third_party/WebKit/Source/core/css/CSSSelectorList.cpp
@@ -175,13 +175,13 @@
     }
 };
 
-bool CSSSelectorList::hasShadowDistributedAt(size_t index) const
+bool CSSSelectorList::selectorHasShadowDistributed(size_t index) const
 {
     SelectorHasShadowDistributed functor;
     return forEachTagSelector(functor, selectorAt(index));
 }
 
-class SelectorCrossesTreeScopes {
+class SelectorUsesDeepCombinatorOrShadowPseudo {
 public:
     bool operator()(const CSSSelector& selector)
     {
@@ -189,9 +189,9 @@
     }
 };
 
-bool CSSSelectorList::selectorCrossesTreeScopes(size_t index) const
+bool CSSSelectorList::selectorUsesDeepCombinatorOrShadowPseudo(size_t index) const
 {
-    SelectorCrossesTreeScopes functor;
+    SelectorUsesDeepCombinatorOrShadowPseudo functor;
     return forEachTagSelector(functor, selectorAt(index));
 }
 
diff --git a/third_party/WebKit/Source/core/css/CSSSelectorList.h b/third_party/WebKit/Source/core/css/CSSSelectorList.h
index 0c1ec08..d37148d 100644
--- a/third_party/WebKit/Source/core/css/CSSSelectorList.h
+++ b/third_party/WebKit/Source/core/css/CSSSelectorList.h
@@ -63,9 +63,10 @@
 
     bool selectorNeedsUpdatedDistribution(size_t index) const;
 
-    // TODO(esprehn): These methods are confusing and incorrectly named.
-    bool hasShadowDistributedAt(size_t index) const;
-    bool selectorCrossesTreeScopes(size_t index) const;
+    // TODO(kochi): "ShadowDistributed" means the selector has ::content pseudo element.
+    // Once ::slotted is introduced, come up with more readable name.
+    bool selectorHasShadowDistributed(size_t index) const;
+    bool selectorUsesDeepCombinatorOrShadowPseudo(size_t index) const;
 
     String selectorsText() const;
 
diff --git a/third_party/WebKit/Source/core/css/FontFace.idl b/third_party/WebKit/Source/core/css/FontFace.idl
index 37e45c4..e847005 100644
--- a/third_party/WebKit/Source/core/css/FontFace.idl
+++ b/third_party/WebKit/Source/core/css/FontFace.idl
@@ -43,6 +43,7 @@
     // FIXME: This should be (DOMString or BinaryData), where BinaryData is typedef of (ArrayBuffer or ArrayBufferView)
     Constructor(DOMString family, (DOMString or ArrayBuffer or ArrayBufferView) source, optional FontFaceDescriptors descriptors),
     ConstructorCallWith=ExecutionContext,
+    MeasureAs=FontFaceConstructor,
     WillBeGarbageCollected,
 ] interface FontFace {
     [RaisesException=Setter, SetterCallWith=ExecutionContext] attribute DOMString family;
diff --git a/third_party/WebKit/Source/core/css/RuleSet.cpp b/third_party/WebKit/Source/core/css/RuleSet.cpp
index 5bcdaf0..b37c2b0 100644
--- a/third_party/WebKit/Source/core/css/RuleSet.cpp
+++ b/third_party/WebKit/Source/core/css/RuleSet.cpp
@@ -259,9 +259,9 @@
 
             const CSSSelectorList& selectorList = styleRule->selectorList();
             for (size_t selectorIndex = 0; selectorIndex != kNotFound; selectorIndex = selectorList.indexOfNextSelectorAfter(selectorIndex)) {
-                if (selectorList.selectorCrossesTreeScopes(selectorIndex)) {
-                    m_treeBoundaryCrossingRules.append(MinimalRuleData(styleRule, selectorIndex, addRuleFlags));
-                } else if (selectorList.hasShadowDistributedAt(selectorIndex)) {
+                if (selectorList.selectorUsesDeepCombinatorOrShadowPseudo(selectorIndex)) {
+                    m_deepCombinatorOrShadowPseudoRules.append(MinimalRuleData(styleRule, selectorIndex, addRuleFlags));
+                } else if (selectorList.selectorHasShadowDistributed(selectorIndex)) {
                     m_shadowDistributedRules.append(MinimalRuleData(styleRule, selectorIndex, addRuleFlags));
                 } else {
                     addRule(styleRule, selectorIndex, addRuleFlags);
@@ -341,7 +341,7 @@
     m_viewportRules.shrinkToFit();
     m_fontFaceRules.shrinkToFit();
     m_keyframesRules.shrinkToFit();
-    m_treeBoundaryCrossingRules.shrinkToFit();
+    m_deepCombinatorOrShadowPseudoRules.shrinkToFit();
     m_shadowDistributedRules.shrinkToFit();
 }
 
@@ -382,7 +382,7 @@
     visitor->trace(m_viewportRules);
     visitor->trace(m_fontFaceRules);
     visitor->trace(m_keyframesRules);
-    visitor->trace(m_treeBoundaryCrossingRules);
+    visitor->trace(m_deepCombinatorOrShadowPseudoRules);
     visitor->trace(m_shadowDistributedRules);
     visitor->trace(m_viewportDependentMediaQueryResults);
     visitor->trace(m_pendingRules);
diff --git a/third_party/WebKit/Source/core/css/RuleSet.h b/third_party/WebKit/Source/core/css/RuleSet.h
index abf096a..203d177 100644
--- a/third_party/WebKit/Source/core/css/RuleSet.h
+++ b/third_party/WebKit/Source/core/css/RuleSet.h
@@ -144,7 +144,7 @@
     const WillBeHeapVector<RawPtrWillBeMember<StyleRuleViewport>>& viewportRules() const { ASSERT(!m_pendingRules); return m_viewportRules; }
     const WillBeHeapVector<RawPtrWillBeMember<StyleRuleFontFace>>& fontFaceRules() const { return m_fontFaceRules; }
     const WillBeHeapVector<RawPtrWillBeMember<StyleRuleKeyframes>>& keyframesRules() const { return m_keyframesRules; }
-    const WillBeHeapVector<MinimalRuleData>& treeBoundaryCrossingRules() const { return m_treeBoundaryCrossingRules; }
+    const WillBeHeapVector<MinimalRuleData>& deepCombinatorOrShadowPseudoRules() const { return m_deepCombinatorOrShadowPseudoRules; }
     const WillBeHeapVector<MinimalRuleData>& shadowDistributedRules() const { return m_shadowDistributedRules; }
     const MediaQueryResultList& viewportDependentMediaQueryResults() const { return m_viewportDependentMediaQueryResults; }
 
@@ -220,7 +220,9 @@
     WillBeHeapVector<RawPtrWillBeMember<StyleRuleViewport>> m_viewportRules;
     WillBeHeapVector<RawPtrWillBeMember<StyleRuleFontFace>> m_fontFaceRules;
     WillBeHeapVector<RawPtrWillBeMember<StyleRuleKeyframes>> m_keyframesRules;
-    WillBeHeapVector<MinimalRuleData> m_treeBoundaryCrossingRules;
+    WillBeHeapVector<MinimalRuleData> m_deepCombinatorOrShadowPseudoRules;
+    // TODO(kochi): "shadowDistributed" means the selector has ::content pseudo element.
+    // Once ::slotted is introduced, come up with more readable name.
     WillBeHeapVector<MinimalRuleData> m_shadowDistributedRules;
 
     MediaQueryResultList m_viewportDependentMediaQueryResults;
diff --git a/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.cpp
index f2bb5fe..e42cae5 100644
--- a/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.cpp
@@ -207,14 +207,14 @@
 void ScopedStyleResolver::addTreeBoundaryCrossingRules(const RuleSet& authorRules, CSSStyleSheet* parentStyleSheet, unsigned sheetIndex)
 {
     bool isDocumentScope = treeScope().rootNode().isDocumentNode();
-    if (authorRules.treeBoundaryCrossingRules().isEmpty() && (isDocumentScope || authorRules.shadowDistributedRules().isEmpty()))
+    if (authorRules.deepCombinatorOrShadowPseudoRules().isEmpty() && (isDocumentScope || authorRules.shadowDistributedRules().isEmpty()))
         return;
 
-    if (!authorRules.treeBoundaryCrossingRules().isEmpty())
+    if (!authorRules.deepCombinatorOrShadowPseudoRules().isEmpty())
         m_hasDeepOrShadowSelector = true;
 
     OwnPtrWillBeRawPtr<RuleSet> ruleSetForScope = RuleSet::create();
-    addRules(ruleSetForScope.get(), authorRules.treeBoundaryCrossingRules());
+    addRules(ruleSetForScope.get(), authorRules.deepCombinatorOrShadowPseudoRules());
 
     if (!isDocumentScope)
         addRules(ruleSetForScope.get(), authorRules.shadowDistributedRules());
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index 50e0821e..ce58a2e 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -1439,8 +1439,7 @@
 String Node::debugName() const
 {
     StringBuilder name;
-    name.append(nodeName());
-
+    name.append(debugNodeName());
     if (isElementNode()) {
         const Element& thisElement = toElement(*this);
         if (thisElement.hasID()) {
@@ -1459,10 +1458,14 @@
             name.append('\'');
         }
     }
-
     return name.toString();
 }
 
+String Node::debugNodeName() const
+{
+    return nodeName();
+}
+
 #ifndef NDEBUG
 
 static void appendAttributeDesc(const Node* node, StringBuilder& stringBuilder, const QualifiedName& name, const char* attrDesc)
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h
index dbc4db9..3d58ac8 100644
--- a/third_party/WebKit/Source/core/dom/Node.h
+++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -579,6 +579,8 @@
     //
     virtual void removedFrom(ContainerNode* insertionPoint);
 
+    // FIXME(dominicc): This method is not debug-only--it is used by
+    // Tracing--rename it to something indicative.
     String debugName() const;
 
 #ifndef NDEBUG
@@ -787,6 +789,13 @@
 #endif
     bool hasTreeSharedParent() const { return !!parentOrShadowHostNode(); }
 
+    // Gets nodeName without caching AtomicStrings. Used by
+    // debugName. Compositor may call debugName from the "impl" thread
+    // during "commit". The main thread is stopped at that time, but
+    // it is not safe to cache AtomicStrings because those are
+    // per-thread.
+    virtual String debugNodeName() const;
+
     enum EditableLevel { Editable, RichlyEditable };
     bool hasEditableStyle(EditableLevel, UserSelectAllTreatment = UserSelectAllIsAlwaysNonEditable) const;
     bool isEditableToAccessibility(EditableLevel) const;
diff --git a/third_party/WebKit/Source/core/dom/SelectorQuery.cpp b/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
index 1f929dd..4b47147 100644
--- a/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
+++ b/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
@@ -106,13 +106,13 @@
     for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector))
         selectorCount++;
 
-    m_crossesTreeBoundary = false;
+    m_usesDeepCombinatorOrShadowPseudo = false;
     m_needsUpdatedDistribution = false;
     m_selectors.reserveInitialCapacity(selectorCount);
     unsigned index = 0;
     for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector), ++index) {
         m_selectors.uncheckedAppend(selector);
-        m_crossesTreeBoundary |= selectorList.selectorCrossesTreeScopes(index);
+        m_usesDeepCombinatorOrShadowPseudo |= selectorList.selectorUsesDeepCombinatorOrShadowPseudo(index);
         m_needsUpdatedDistribution |= selectorList.selectorNeedsUpdatedDistribution(index);
     }
 }
@@ -213,7 +213,7 @@
 
 inline bool SelectorDataList::canUseFastQuery(const ContainerNode& rootNode) const
 {
-    if (m_crossesTreeBoundary)
+    if (m_usesDeepCombinatorOrShadowPseudo)
         return false;
     if (m_needsUpdatedDistribution)
         return false;
@@ -455,7 +455,7 @@
     if (!canUseFastQuery(rootNode)) {
         if (m_needsUpdatedDistribution)
             rootNode.updateDistribution();
-        if (m_crossesTreeBoundary) {
+        if (m_usesDeepCombinatorOrShadowPseudo) {
             executeSlowTraversingShadowTree<SelectorQueryTrait>(rootNode, output);
         } else {
             executeSlow<SelectorQueryTrait>(rootNode, output);
diff --git a/third_party/WebKit/Source/core/dom/SelectorQuery.h b/third_party/WebKit/Source/core/dom/SelectorQuery.h
index 08e8639..172fecd 100644
--- a/third_party/WebKit/Source/core/dom/SelectorQuery.h
+++ b/third_party/WebKit/Source/core/dom/SelectorQuery.h
@@ -81,7 +81,7 @@
     const CSSSelector* selectorForIdLookup(const CSSSelector&) const;
 
     Vector<const CSSSelector*> m_selectors;
-    bool m_crossesTreeBoundary : 1;
+    bool m_usesDeepCombinatorOrShadowPseudo : 1;
     bool m_needsUpdatedDistribution : 1;
 };
 
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
index 7328a36..a51beb24 100644
--- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -29,6 +29,7 @@
 #include "core/HTMLNames.h"
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
+#include "core/dom/FirstLetterPseudoElement.h"
 #include "core/dom/NodeTraversal.h"
 #include "core/dom/Text.h"
 #include "core/editing/EditingUtilities.h"
@@ -51,6 +52,7 @@
 #include "core/layout/LayoutBlockFlow.h"
 #include "core/layout/LayoutInline.h"
 #include "core/layout/LayoutObject.h"
+#include "core/layout/LayoutTextFragment.h"
 #include "core/layout/LayoutView.h"
 #include "core/layout/line/InlineIterator.h"
 #include "core/layout/line/InlineTextBox.h"
@@ -2149,6 +2151,32 @@
     return VisiblePosition();
 }
 
+// TODO(yosin): We should use |associatedLayoutObjectOf()| in "VisibleUnits.cpp"
+// where it takes |LayoutObject| from |Position|.
+static LayoutObject* associatedLayoutObjectOf(const Node& node, int offsetInNode)
+{
+    ASSERT(offsetInNode >= 0);
+    LayoutObject* layoutObject = node.layoutObject();
+    if (!node.isTextNode() || !layoutObject || !toLayoutText(layoutObject)->isTextFragment())
+        return layoutObject;
+    LayoutTextFragment* layoutTextFragment = toLayoutTextFragment(layoutObject);
+    if (layoutTextFragment->isRemainingTextLayoutObject()) {
+        if (static_cast<unsigned>(offsetInNode) >= layoutTextFragment->start())
+            return layoutObject;
+        LayoutObject* firstLetterLayoutObject = layoutTextFragment->firstLetterPseudoElement()->layoutObject();
+        if (!firstLetterLayoutObject)
+            return nullptr;
+        // TODO(yosin): We're not sure when |firstLetterLayoutObject| has
+        // multiple child layout object.
+        ASSERT(firstLetterLayoutObject->slowFirstChild() == firstLetterLayoutObject->slowLastChild());
+        return firstLetterLayoutObject->slowFirstChild();
+    }
+    // TODO(yosin): We should rename |LayoutTextFramge::length()| instead of
+    // |end()|, once |LayoutTextFramge| has it. See http://crbug.com/545789
+    ASSERT(static_cast<unsigned>(offsetInNode) <= layoutTextFragment->start() + layoutTextFragment->fragmentLength());
+    return layoutTextFragment;
+}
+
 template <typename Strategy>
 static bool inRenderedText(const PositionTemplate<Strategy>& position)
 {
@@ -2156,22 +2184,23 @@
     if (!anchorNode || !anchorNode->isTextNode())
         return false;
 
-    LayoutObject* layoutObject = anchorNode->layoutObject();
+    const int offsetInNode = position.computeEditingOffset();
+    LayoutObject* layoutObject = associatedLayoutObjectOf(*anchorNode, offsetInNode);
     if (!layoutObject)
         return false;
 
-    const int offsetInNode = position.computeEditingOffset();
     LayoutText* textLayoutObject = toLayoutText(layoutObject);
+    const int textOffset = offsetInNode - textLayoutObject->textStartOffset();
     for (InlineTextBox *box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) {
-        if (offsetInNode < static_cast<int>(box->start()) && !textLayoutObject->containsReversedText()) {
+        if (textOffset < static_cast<int>(box->start()) && !textLayoutObject->containsReversedText()) {
             // The offset we're looking for is before this node
             // this means the offset must be in content that is
             // not laid out. Return false.
             return false;
         }
-        if (box->containsCaretOffset(offsetInNode)) {
+        if (box->containsCaretOffset(textOffset)) {
             // Return false for offsets inside composed characters.
-            return offsetInNode == 0 || offsetInNode == textLayoutObject->nextOffset(textLayoutObject->previousOffset(offsetInNode));
+            return textOffset == 0 || textOffset == textLayoutObject->nextOffset(textLayoutObject->previousOffset(textOffset));
         }
     }
 
@@ -2406,7 +2435,7 @@
             return lastVisible.deprecatedComputePosition();
 
         // skip position in non-laid out or invisible node
-        LayoutObject* layoutObject = currentNode->layoutObject();
+        LayoutObject* layoutObject = associatedLayoutObjectOf(*currentNode, currentPos.offsetInLeafNode());
         if (!layoutObject || layoutObject->style()->visibility() != VISIBLE)
             continue;
 
@@ -2433,19 +2462,33 @@
 
         // return current position if it is in laid out text
         if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox()) {
+            LayoutText* const textLayoutObject = toLayoutText(layoutObject);
+            const unsigned textStartOffset = textLayoutObject->textStartOffset();
             if (currentNode != startNode) {
                 // This assertion fires in layout tests in the case-transform.html test because
                 // of a mix-up between offsets in the text in the DOM tree with text in the
                 // layout tree which can have a different length due to case transformation.
                 // Until we resolve that, disable this so we can run the layout tests!
                 // ASSERT(currentOffset >= layoutObject->caretMaxOffset());
-                return PositionTemplate<Strategy>(currentNode, layoutObject->caretMaxOffset());
+                return PositionTemplate<Strategy>(currentNode, layoutObject->caretMaxOffset() + textStartOffset);
             }
 
-            unsigned textOffset = currentPos.offsetInLeafNode();
-            LayoutText* textLayoutObject = toLayoutText(layoutObject);
+            // Map offset in DOM node to offset in InlineBox.
+            ASSERT(currentPos.offsetInLeafNode() >= static_cast<int>(textStartOffset));
+            const unsigned textOffset = currentPos.offsetInLeafNode() - textStartOffset;
             InlineTextBox* lastTextBox = textLayoutObject->lastTextBox();
             for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) {
+                if (textOffset == box->start()) {
+                    if (textLayoutObject->isTextFragment() && toLayoutTextFragment(layoutObject)->isRemainingTextLayoutObject()) {
+                        // |currentPos| is at start of remaining text of
+                        // |Text| node with :first-letter.
+                        ASSERT(currentPos.offsetInLeafNode() >= 1);
+                        LayoutObject* firstLetterLayoutObject = toLayoutTextFragment(layoutObject)->firstLetterPseudoElement()->layoutObject();
+                        if (firstLetterLayoutObject && firstLetterLayoutObject->style()->visibility() == VISIBLE)
+                            return currentPos.computePosition();
+                    }
+                    continue;
+                }
                 if (textOffset <= box->start() + box->len()) {
                     if (textOffset > box->start())
                         return currentPos.computePosition();
@@ -2543,7 +2586,7 @@
             return lastVisible.deprecatedComputePosition();
 
         // skip position in non-laid out or invisible node
-        LayoutObject* layoutObject = currentNode->layoutObject();
+        LayoutObject* layoutObject = associatedLayoutObjectOf(*currentNode, currentPos.offsetInLeafNode());
         if (!layoutObject || layoutObject->style()->visibility() != VISIBLE)
             continue;
 
@@ -2565,13 +2608,16 @@
 
         // return current position if it is in laid out text
         if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox()) {
+            LayoutText* const textLayoutObject = toLayoutText(layoutObject);
+            const unsigned textStartOffset = textLayoutObject->textStartOffset();
             if (currentNode != startNode) {
                 ASSERT(currentPos.atStartOfNode());
-                return PositionTemplate<Strategy>(currentNode, layoutObject->caretMinOffset());
+                return PositionTemplate<Strategy>(currentNode, layoutObject->caretMinOffset() + textStartOffset);
             }
 
-            unsigned textOffset = currentPos.offsetInLeafNode();
-            LayoutText* textLayoutObject = toLayoutText(layoutObject);
+            // Map offset in DOM node to offset in InlineBox.
+            ASSERT(currentPos.offsetInLeafNode() >= static_cast<int>(textStartOffset));
+            const unsigned textOffset = currentPos.offsetInLeafNode() - textStartOffset;
             InlineTextBox* lastTextBox = textLayoutObject->lastTextBox();
             for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) {
                 if (textOffset <= box->end()) {
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnitsTest.cpp b/third_party/WebKit/Source/core/editing/VisibleUnitsTest.cpp
index 3079616..75a7a8d 100644
--- a/third_party/WebKit/Source/core/editing/VisibleUnitsTest.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleUnitsTest.cpp
@@ -762,6 +762,28 @@
     EXPECT_EQ(PositionInComposedTree::lastPositionInNode(host.get()), mostForwardCaretPosition(PositionInComposedTree::afterNode(host.get())));
 }
 
+TEST_F(VisibleUnitsTest, mostBackwardCaretPositionFirstLetter)
+{
+    // Note: first-letter pseudo element contains letter and punctuations.
+    const char* bodyContent = "<style>p:first-letter {color:red;}</style><p id=sample> (2)45 </p>";
+    setBodyContent(bodyContent);
+    updateLayoutAndStyleForPainting();
+
+    Node* sample = document().getElementById("sample")->firstChild();
+
+    EXPECT_EQ(Position(sample->parentNode(), 0), mostBackwardCaretPosition(Position(sample, 0)));
+    EXPECT_EQ(Position(sample->parentNode(), 0), mostBackwardCaretPosition(Position(sample, 1)));
+    EXPECT_EQ(Position(sample, 2), mostBackwardCaretPosition(Position(sample, 2)));
+    EXPECT_EQ(Position(sample, 3), mostBackwardCaretPosition(Position(sample, 3)));
+    EXPECT_EQ(Position(sample, 4), mostBackwardCaretPosition(Position(sample, 4)));
+    EXPECT_EQ(Position(sample, 5), mostBackwardCaretPosition(Position(sample, 5)));
+    EXPECT_EQ(Position(sample, 6), mostBackwardCaretPosition(Position(sample, 6)));
+    EXPECT_EQ(Position(sample, 6), mostBackwardCaretPosition(Position(sample, 7)));
+    EXPECT_EQ(Position(sample, 6), mostBackwardCaretPosition(Position::lastPositionInNode(sample->parentNode())));
+    EXPECT_EQ(Position(sample, 6), mostBackwardCaretPosition(Position::afterNode(sample->parentNode())));
+    EXPECT_EQ(Position::lastPositionInNode(document().body()), mostBackwardCaretPosition(Position::lastPositionInNode(document().body())));
+}
+
 TEST_F(VisibleUnitsTest, mostForwardCaretPositionAfterAnchor)
 {
     const char* bodyContent = "<p id='host'><b id='one'>1</b></p>";
@@ -778,6 +800,28 @@
     EXPECT_EQ(PositionInComposedTree(three->firstChild(), 3), mostBackwardCaretPosition(PositionInComposedTree::afterNode(host.get())));
 }
 
+TEST_F(VisibleUnitsTest, mostForwardCaretPositionFirstLetter)
+{
+    // Note: first-letter pseudo element contains letter and punctuations.
+    const char* bodyContent = "<style>p:first-letter {color:red;}</style><p id=sample> (2)45 </p>";
+    setBodyContent(bodyContent);
+    updateLayoutAndStyleForPainting();
+
+    Node* sample = document().getElementById("sample")->firstChild();
+
+    EXPECT_EQ(Position(document().body(), 0), mostForwardCaretPosition(Position::firstPositionInNode(document().body())));
+    EXPECT_EQ(Position(sample, 1), mostForwardCaretPosition(Position::beforeNode(sample->parentNode())));
+    EXPECT_EQ(Position(sample, 1), mostForwardCaretPosition(Position::firstPositionInNode(sample->parentNode())));
+    EXPECT_EQ(Position(sample, 1), mostForwardCaretPosition(Position(sample, 0)));
+    EXPECT_EQ(Position(sample, 1), mostForwardCaretPosition(Position(sample, 1)));
+    EXPECT_EQ(Position(sample, 2), mostForwardCaretPosition(Position(sample, 2)));
+    EXPECT_EQ(Position(sample, 3), mostForwardCaretPosition(Position(sample, 3)));
+    EXPECT_EQ(Position(sample, 4), mostForwardCaretPosition(Position(sample, 4)));
+    EXPECT_EQ(Position(sample, 5), mostForwardCaretPosition(Position(sample, 5)));
+    EXPECT_EQ(Position(sample, 7), mostForwardCaretPosition(Position(sample, 6)));
+    EXPECT_EQ(Position(sample, 7), mostForwardCaretPosition(Position(sample, 7)));
+}
+
 TEST_F(VisibleUnitsTest, nextPositionOf)
 {
     const char* bodyContent = "<b id=zero>0</b><p id=host><b id=one>1</b><b id=two>22</b></p><b id=three>333</b>";
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index b7de419d..f600654 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -861,6 +861,8 @@
         HTMLLabelElementFormContentAttribute = 986,
         DeviceOrientationAbsoluteInsecureOrigin = 987,
         DeviceOrientationAbsoluteSecureOrigin = 988,
+        FontFaceConstructor = 989,
+        ServiceWorkerControlledPage = 990,
 
         // Add new features immediately above this line. Don't change assigned
         // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/html/HTMLElement.cpp b/third_party/WebKit/Source/core/html/HTMLElement.cpp
index fb1a964..c85256a 100644
--- a/third_party/WebKit/Source/core/html/HTMLElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLElement.cpp
@@ -72,8 +72,21 @@
 
 DEFINE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLElement);
 
+String HTMLElement::debugNodeName() const
+{
+    if (document().isHTMLDocument()) {
+        return tagQName().hasPrefix()
+            ? Element::nodeName().upper()
+            : tagQName().localName().upper();
+    }
+    return Element::nodeName();
+}
+
 String HTMLElement::nodeName() const
 {
+    // localNameUpper may intern and cache an AtomicString.
+    RELEASE_ASSERT(isMainThread());
+
     // FIXME: Would be nice to have an atomicstring lookup based off uppercase
     // chars that does not have to copy the string on a hit in the hash.
     // FIXME: We should have a way to detect XHTML elements and replace the hasPrefix() check with it.
diff --git a/third_party/WebKit/Source/core/html/HTMLElement.h b/third_party/WebKit/Source/core/html/HTMLElement.h
index 333cd66b..eeb2c34 100644
--- a/third_party/WebKit/Source/core/html/HTMLElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLElement.h
@@ -121,6 +121,7 @@
     void calculateAndAdjustDirectionality();
 
 private:
+    String debugNodeName() const final;
     String nodeName() const final;
 
     bool isHTMLElement() const = delete; // This will catch anyone doing an unnecessary check.
diff --git a/third_party/WebKit/Source/core/layout/LayoutTextFragment.h b/third_party/WebKit/Source/core/layout/LayoutTextFragment.h
index d5e0368..d4c6198 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTextFragment.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTextFragment.h
@@ -44,6 +44,7 @@
     bool canBeSelectionLeaf() const override { return node() && node()->hasEditableStyle(); }
 
     unsigned start() const { return m_start; }
+    unsigned fragmentLength() const { return m_fragmentLength; }
 
     unsigned textStartOffset() const override { return start(); }
 
@@ -80,7 +81,6 @@
 
     Text* associatedTextNode() const;
     void updateHitTestResult(HitTestResult&, const LayoutPoint&) override;
-    unsigned fragmentLength() const { return m_fragmentLength; }
 
     unsigned m_start;
     unsigned m_fragmentLength;
diff --git a/third_party/WebKit/Source/devtools/devtools.gypi b/third_party/WebKit/Source/devtools/devtools.gypi
index 3a4f6dd..82c2807 100644
--- a/third_party/WebKit/Source/devtools/devtools.gypi
+++ b/third_party/WebKit/Source/devtools/devtools.gypi
@@ -192,7 +192,6 @@
             'front_end/bindings/SASSSourceMapping.js',
             'front_end/bindings/StylesSourceMapping.js',
             'front_end/bindings/TempFile.js',
-            'front_end/bindings/WorkspaceController.js',
         ],
         'devtools_platform_js_files': [
             'front_end/platform/DOMExtension.js',
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js b/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js
index d4e51a1..d8e69f0e 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js
@@ -39,6 +39,7 @@
     this._workspace = workspace;
     this._isolatedFileSystemManager.addEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemAdded, this._fileSystemAdded, this);
     this._isolatedFileSystemManager.addEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemRemoved, this._fileSystemRemoved, this);
+    this._isolatedFileSystemManager.addEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemFilesChanged, this._fileSystemFilesChanged, this);
     /** @type {!Map.<string, !WebInspector.FileSystemWorkspaceBinding.FileSystem>} */
     this._boundFileSystems = new Map();
 
@@ -98,6 +99,22 @@
     },
 
     /**
+     * @param {!WebInspector.Event} event
+     */
+    _fileSystemFilesChanged: function(event)
+    {
+        var paths = /** @type {!Array<string>} */ (event.data);
+        for (var path of paths) {
+            var normalizedPath = WebInspector.IsolatedFileSystem.normalizePath(path);
+            for (var key of this._boundFileSystems.keys()) {
+                if (!normalizedPath.startsWith(key))
+                    continue;
+                this._boundFileSystems.get(key)._fileChanged(normalizedPath.substr(key.length + 1));
+            }
+        }
+    },
+
+    /**
      * @param {string} projectId
      * @return {string}
      */
@@ -233,7 +250,7 @@
 
     this._projectId = WebInspector.FileSystemWorkspaceBinding.projectId(this._fileSystem.path());
     console.assert(!this._workspace.project(this._projectId));
-    this._workspace.addProject(this._projectId, this);
+    this._project = this._workspace.addProject(this._projectId, this);
     this.populate();
 }
 
@@ -617,6 +634,19 @@
         this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileRemoved, path);
     },
 
+    /**
+     * @param {string} path
+     */
+    _fileChanged: function(path)
+    {
+        var uiSourceCode = this._project.uiSourceCode(path);
+        if (!uiSourceCode) {
+            this._addFile(path);
+            return;
+        }
+        this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileChanged, path);
+    },
+
     dispose: function()
     {
         this._workspace.removeProject(this._projectId);
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/WorkspaceController.js b/third_party/WebKit/Source/devtools/front_end/bindings/WorkspaceController.js
deleted file mode 100644
index 495aee6..0000000
--- a/third_party/WebKit/Source/devtools/front_end/bindings/WorkspaceController.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * 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.
- */
-
-/**
- * @constructor
- * @suppressGlobalPropertiesCheck
- */
-WebInspector.WorkspaceController = function(workspace)
-{
-    this._workspace = workspace;
-    // Only for main window.
-    window.addEventListener("focus", this._windowFocused.bind(this), false);
-    this._fileSystemRefreshThrottler = new WebInspector.Throttler(1000);
-}
-
-WebInspector.WorkspaceController.prototype = {
-    /**
-     * @param {!Event} event
-     */
-    _windowFocused: function(event)
-    {
-        this._fileSystemRefreshThrottler.schedule(refreshFileSystems.bind(this));
-
-        /**
-         * @this {WebInspector.WorkspaceController}
-         */
-        function refreshFileSystems()
-        {
-            var barrier = new CallbackBarrier();
-            var projects = this._workspace.projects();
-            for (var i = 0; i < projects.length; ++i)
-                projects[i].refresh("/", barrier.createCallback());
-            return barrier.donePromise();
-        }
-    }
-}
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/module.json b/third_party/WebKit/Source/devtools/front_end/bindings/module.json
index a7da14c..4f2b5be 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/module.json
@@ -19,7 +19,6 @@
         "PresentationConsoleMessageHelper.js",
         "ResourceUtils.js",
         "TempFile.js",
-        "WorkspaceController.js",
         "ContentScriptProjectDecorator.js"
     ]
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
index 8c28906..df94691 100644
--- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
+++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
@@ -45,8 +45,6 @@
 
     /** @type {!Array.<!WebInspector.DataGrid>} */
     this._dataGrids = [];
-    /** @type {!Map.<!WebInspector.DataGrid, ?Element>} */
-    this._dataGridParents = new Map();
 
     /** @type {!Object.<string, function(!WebInspector.RemoteObject, !Element, boolean=)>} */
     this._customFormatters = {
@@ -88,12 +86,8 @@
      */
     wasShown: function()
     {
-        for (var i = 0; this._dataGrids && i < this._dataGrids.length; ++i) {
-            var dataGrid = this._dataGrids[i];
-            var parentElement = this._dataGridParents.get(dataGrid) || null;
-            parentElement.appendChild(dataGrid.element);
-            dataGrid.updateWidths();
-        }
+        for (var i = 0; this._dataGrids && i < this._dataGrids.length; ++i)
+            this._dataGrids[i].updateWidths();
         this._isVisible = true;
     },
 
@@ -108,22 +102,10 @@
     /**
      * @override
      */
-    cacheFastHeight: function()
-    {
-        this._cachedHeight = this.contentElement().offsetHeight;
-    },
-
-    /**
-     * @override
-     */
     willHide: function()
     {
         this._isVisible = false;
-        for (var i = 0; this._dataGrids && i < this._dataGrids.length; ++i) {
-            var dataGrid = this._dataGrids[i];
-            this._dataGridParents.set(dataGrid, dataGrid.element.parentElement);
-            dataGrid.element.remove();
-        }
+        this._cachedHeight = this.contentElement().offsetHeight;
     },
 
     /**
@@ -607,8 +589,8 @@
         columnNames.unshift(WebInspector.UIString("(index)"));
         var dataGrid = WebInspector.SortableDataGrid.create(columnNames, flatValues);
         dataGrid.renderInline();
+        dataGridContainer.appendChild(dataGrid.element);
         this._dataGrids.push(dataGrid);
-        this._dataGridParents.set(dataGrid, dataGridContainer);
         return element;
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/devtools.js b/third_party/WebKit/Source/devtools/front_end/devtools.js
index 671aac0f..000b533fa 100644
--- a/third_party/WebKit/Source/devtools/front_end/devtools.js
+++ b/third_party/WebKit/Source/devtools/front_end/devtools.js
@@ -176,6 +176,11 @@
         this._dispatchOnInspectorFrontendAPI("fileSystemAdded", ["", fileSystem]);
     },
 
+    fileSystemFilesChanged: function(path)
+    {
+        this._dispatchOnInspectorFrontendAPI("fileSystemFilesChanged", [path]);
+    },
+
     /**
      * @param {number} requestId
      * @param {string} fileSystemPath
diff --git a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js
index 34f2075..4b38146 100644
--- a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js
+++ b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js
@@ -42,6 +42,7 @@
     FileSystemsLoaded: "fileSystemsLoaded",
     FileSystemRemoved: "fileSystemRemoved",
     FileSystemAdded: "fileSystemAdded",
+    FileSystemFilesChanged: "fileSystemFilesChanged",
     FrontendAPIAttached: "frontendAPIAttached",
     FrontendAPIDetached: "frontendAPIDetached",
     IndexingTotalWorkCalculated: "indexingTotalWorkCalculated",
@@ -73,6 +74,7 @@
     [InspectorFrontendHostAPI.Events.FileSystemsLoaded, ["fileSystems"]],
     [InspectorFrontendHostAPI.Events.FileSystemRemoved, ["fileSystemPath"]],
     [InspectorFrontendHostAPI.Events.FileSystemAdded, ["errorMessage", "fileSystem"]],
+    [InspectorFrontendHostAPI.Events.FileSystemFilesChanged, ["paths"]],
     [InspectorFrontendHostAPI.Events.FrontendAPIAttached, ["frontendAPIAttached"]],
     [InspectorFrontendHostAPI.Events.FrontendAPIDetached, ["frontendAPIDetached"]],
     [InspectorFrontendHostAPI.Events.IndexingTotalWorkCalculated, ["requestId", "fileSystemPath", "totalWork"]],
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js
index 41ea1365..2c7918e 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/Main.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -230,7 +230,6 @@
         WebInspector.openAnchorLocationRegistry.registerHandler(autoselectPanel, function() { return false; });
         WebInspector.Linkifier.setLinkHandler(new WebInspector.HandlerRegistry.LinkHandler());
 
-        new WebInspector.WorkspaceController(WebInspector.workspace);
         new WebInspector.Main.PauseListener();
         new WebInspector.Main.InspectedNodeRevealer();
         new WebInspector.NetworkPanelIndicator();
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/timelineStatusDialog.css b/third_party/WebKit/Source/devtools/front_end/timeline/timelineStatusDialog.css
index e5ffd8b..83a6023 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/timelineStatusDialog.css
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/timelineStatusDialog.css
@@ -15,9 +15,11 @@
     margin-top: -1px;
 }
 
-.timeline-status-dialog div {
+.timeline-status-dialog > div {
     margin: 2px;
     height: 14px;
+    display: flex;
+    align-items: baseline;
 }
 
 .timeline-status-dialog ::before {
@@ -57,7 +59,7 @@
 }
 
 .timeline-status-dialog .stop-button {
-    text-align: center;
     margin-top: 8px;
     height: 100%;
+    align-self: center;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js b/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js
index 943aba3f..b9de04d 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js
@@ -94,8 +94,6 @@
  */
 WebInspector.ViewportElement = function() { }
 WebInspector.ViewportElement.prototype = {
-    cacheFastHeight: function() { },
-
     willHide: function() { },
 
     wasShown: function() { },
@@ -120,11 +118,6 @@
     /**
      * @override
      */
-    cacheFastHeight: function() { },
-
-    /**
-     * @override
-     */
     willHide: function() { },
 
     /**
@@ -223,10 +216,17 @@
         var itemCount = this._provider.itemCount();
         if (!itemCount)
             return;
+        var firstVisibleIndex = this._firstVisibleIndex;
+        var lastVisibleIndex = this._lastVisibleIndex;
+        var height = 0;
         this._cumulativeHeights = new Int32Array(itemCount);
-        this._cumulativeHeights[0] = this._provider.fastHeight(0);
-        for (var i = 1; i < itemCount; ++i)
-            this._cumulativeHeights[i] = this._cumulativeHeights[i - 1] + this._provider.fastHeight(i);
+        for (var i = 0; i < itemCount; ++i) {
+            if (firstVisibleIndex <= i && i <= lastVisibleIndex)
+                height += this._renderedItems[i - firstVisibleIndex].element().offsetHeight;
+            else
+                height += this._provider.fastHeight(i);
+            this._cumulativeHeights[i] = height;
+        }
     },
 
     /**
@@ -376,8 +376,6 @@
         var itemCount = this._provider.itemCount();
         if (!itemCount) {
             for (var i = 0; i < this._renderedItems.length; ++i)
-                this._renderedItems[i].cacheFastHeight();
-            for (var i = 0; i < this._renderedItems.length; ++i)
                 this._renderedItems[i].willHide();
             this._renderedItems = [];
             this._contentElement.removeChildren();
@@ -399,9 +397,8 @@
         if (this._cumulativeHeights && itemCount !== this._cumulativeHeights.length)
             delete this._cumulativeHeights;
         for (var i = 0; i < this._renderedItems.length; ++i) {
-            this._renderedItems[i].cacheFastHeight();
             // Tolerate 1-pixel error due to double-to-integer rounding errors.
-            if (this._cumulativeHeights && Math.abs(this._cachedItemHeight(this._firstVisibleIndex + i) - this._provider.fastHeight(i + this._firstVisibleIndex)) > 1)
+            if (this._cumulativeHeights && Math.abs(this._cachedItemHeight(this._firstVisibleIndex + i) - this._renderedItems[i].element().offsetHeight) > 1)
                 delete this._cumulativeHeights;
         }
         this._rebuildCumulativeHeightsIfNeeded();
@@ -421,16 +418,22 @@
         var topGapHeight = this._cumulativeHeights[this._firstVisibleIndex - 1] || 0;
         var bottomGapHeight = this._cumulativeHeights[this._cumulativeHeights.length - 1] - this._cumulativeHeights[this._lastVisibleIndex];
 
-        this._topGapElement.style.height = topGapHeight + "px";
-        this._bottomGapElement.style.height = bottomGapHeight + "px";
-        this._topGapElement._active = !!topGapHeight;
-        this._bottomGapElement._active = !!bottomGapHeight;
+        /**
+         * @this {WebInspector.ViewportControl}
+         */
+        function prepare()
+        {
+            this._topGapElement.style.height = topGapHeight + "px";
+            this._bottomGapElement.style.height = bottomGapHeight + "px";
+            this._topGapElement._active = !!topGapHeight;
+            this._bottomGapElement._active = !!bottomGapHeight;
+            this._contentElement.style.setProperty("height", "10000000px");
+        }
 
-        this._contentElement.style.setProperty("height", "10000000px");
         if (isInvalidating)
-            this._fullViewportUpdate();
+            this._fullViewportUpdate(prepare.bind(this));
         else
-            this._partialViewportUpdate(oldFirstVisibleIndex, oldLastVisibleIndex);
+            this._partialViewportUpdate(oldFirstVisibleIndex, oldLastVisibleIndex, prepare.bind(this));
         this._contentElement.style.removeProperty("height");
         // Should be the last call in the method as it might force layout.
         if (shouldRestoreSelection)
@@ -439,25 +442,31 @@
             this.element.scrollTop = this.element.scrollHeight;
     },
 
-    _fullViewportUpdate: function()
+    /**
+     * @param {function()} prepare
+     */
+    _fullViewportUpdate: function(prepare)
     {
         for (var i = 0; i < this._renderedItems.length; ++i)
             this._renderedItems[i].willHide();
+        prepare();
         this._renderedItems = [];
         this._contentElement.removeChildren();
         for (var i = this._firstVisibleIndex; i <= this._lastVisibleIndex; ++i) {
             var viewportElement = this._providerElement(i);
             this._contentElement.appendChild(viewportElement.element());
             this._renderedItems.push(viewportElement);
-            viewportElement.wasShown();
         }
+        for (var i = 0; i < this._renderedItems.length; ++i)
+            this._renderedItems[i].wasShown();
     },
 
     /**
      * @param {number} oldFirstVisibleIndex
      * @param {number} oldLastVisibleIndex
+     * @param {function()} prepare
      */
-    _partialViewportUpdate: function(oldFirstVisibleIndex, oldLastVisibleIndex)
+    _partialViewportUpdate: function(oldFirstVisibleIndex, oldLastVisibleIndex, prepare)
     {
         var willBeHidden = [];
         for (var i = 0; i < this._renderedItems.length; ++i) {
@@ -467,22 +476,26 @@
         }
         for (var i = 0; i < willBeHidden.length; ++i)
             willBeHidden[i].willHide();
+        prepare();
         for (var i = 0; i < willBeHidden.length; ++i)
             willBeHidden[i].element().remove();
 
         this._renderedItems = [];
         var anchor = this._contentElement.firstChild;
+        var wasShown = [];
         for (var i = this._firstVisibleIndex; i <= this._lastVisibleIndex; ++i) {
             var viewportElement = this._providerElement(i);
             var element = viewportElement.element();
             if (element !== anchor) {
                 this._contentElement.insertBefore(element, anchor);
-                viewportElement.wasShown();
+                wasShown.push(viewportElement);
             } else {
                 anchor = anchor.nextSibling;
             }
             this._renderedItems.push(viewportElement);
         }
+        for (var i = 0; i < wasShown.length; ++i)
+            wasShown[i].wasShown();
     },
 
     /**
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js
index f26ac30..5869e611 100644
--- a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js
@@ -40,6 +40,7 @@
     InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemsLoaded, this._onFileSystemsLoaded, this);
     InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemRemoved, this._onFileSystemRemoved, this);
     InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemAdded, this._onFileSystemAdded, this);
+    InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemFilesChanged, this._onFileSystemFilesChanged, this);
 
     this._initExcludePatterSetting();
 }
@@ -51,6 +52,7 @@
     FileSystemAdded: "FileSystemAdded",
     FileSystemRemoved: "FileSystemRemoved",
     FileSystemsLoaded: "FileSystemsLoaded",
+    FileSystemFilesChanged: "FileSystemFilesChanged",
     ExcludedFolderAdded: "ExcludedFolderAdded",
     ExcludedFolderRemoved: "ExcludedFolderRemoved"
 }
@@ -156,6 +158,14 @@
     },
 
     /**
+     * @param {!WebInspector.Event} event
+     */
+    _onFileSystemFilesChanged: function(event)
+    {
+        this.dispatchEventToListeners(WebInspector.IsolatedFileSystemManager.Events.FileSystemFilesChanged, event.data);
+    },
+
+    /**
      * @param {string} fileSystemPath
      */
     _fileSystemRemoved: function(fileSystemPath)
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js b/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js
index 9f0b8a9..10de8f5 100644
--- a/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js
+++ b/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js
@@ -85,6 +85,7 @@
 WebInspector.ProjectDelegate.Events = {
     FileAdded: "FileAdded",
     FileRemoved: "FileRemoved",
+    FileChanged: "FileChanged"
 }
 
 WebInspector.ProjectDelegate.prototype = {
@@ -208,6 +209,7 @@
     this._displayName = this._projectDelegate.displayName();
     projectDelegate.addEventListener(WebInspector.ProjectDelegate.Events.FileAdded, this._fileAdded, this);
     projectDelegate.addEventListener(WebInspector.ProjectDelegate.Events.FileRemoved, this._fileRemoved, this);
+    projectDelegate.addEventListener(WebInspector.ProjectDelegate.Events.FileChanged, this._fileChanged, this);
 }
 
 /**
@@ -298,6 +300,17 @@
     },
 
     /**
+     * @param {!WebInspector.Event} event
+     */
+    _fileChanged: function(event)
+    {
+        var path = /** @type {string} */ (event.data);
+        var uiSourceCode = this.uiSourceCode(path);
+        if (uiSourceCode && uiSourceCode.contentLoaded())
+            uiSourceCode.checkContentUpdated();
+    },
+
+    /**
      * @param {string} path
      */
     _removeFile: function(path)
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.cpp
new file mode 100644
index 0000000..89d94fd
--- /dev/null
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.cpp
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "modules/bluetooth/BluetoothAdvertisingData.h"
+
+namespace blink {
+
+namespace {
+// TODO(ortuno): RSSI Unknown and Tx Power Unknown should have different
+// values. Add kUnknownTxPower when implemented: http://crbug.com/551572
+const int kUnknownPower = 127;
+} // namespace
+
+BluetoothAdvertisingData* BluetoothAdvertisingData::create(int8_t txPower, int8_t rssi)
+{
+    return new BluetoothAdvertisingData(txPower, rssi);
+}
+
+int8_t BluetoothAdvertisingData::txPower(bool& isNull)
+{
+    if (m_txPower == kUnknownPower) {
+        isNull = true;
+    }
+    return m_txPower;
+}
+
+int8_t BluetoothAdvertisingData::rssi(bool& isNull)
+{
+    if (m_rssi == kUnknownPower) {
+        isNull = true;
+    }
+    return m_rssi;
+}
+
+BluetoothAdvertisingData::BluetoothAdvertisingData(int8_t txPower, int8_t rssi)
+    : m_txPower(txPower)
+    , m_rssi(rssi)
+{
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.h
new file mode 100644
index 0000000..4aef9b8
--- /dev/null
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.h
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BluetoothAdvertisingData_h
+#define BluetoothAdvertisingData_h
+
+#include "bindings/core/v8/ScriptWrappable.h"
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+// Represents the data a BLE device is advertising.
+class BluetoothAdvertisingData final
+    : public GarbageCollected<BluetoothAdvertisingData>
+    , public ScriptWrappable {
+    DEFINE_WRAPPERTYPEINFO();
+public:
+    static BluetoothAdvertisingData* create(int8_t txPower, int8_t rssi);
+
+    // IDL exposed interface:
+    int8_t txPower(bool& isNull);
+    int8_t rssi(bool& isNull);
+
+    // Interface required by garbage collection.
+    DEFINE_INLINE_TRACE() { }
+
+private:
+    explicit BluetoothAdvertisingData(int8_t txPower, int8_t rssi);
+
+    int8_t m_txPower;
+    int8_t m_rssi;
+};
+
+} // namespace blink
+
+#endif // BluetoothAdvertisingData_h
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.idl b/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.idl
new file mode 100644
index 0000000..6e0454d0
--- /dev/null
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.idl
@@ -0,0 +1,18 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothadvertisingdata
+
+// Implement BluetoothAdvertisingData interface: http://crbug.com/542756
+
+[
+    GarbageCollected,
+    RuntimeEnabled=WebBluetooth,
+] interface BluetoothAdvertisingData {
+    // readonly attribute unsigned short? appearance;
+    readonly attribute byte? txPower;
+    readonly attribute byte? rssi;
+    // readonly attribute ManufacturerDataMap manufacturerData;
+    // readonly attribute ServiceDataMap  serviceData;
+};
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp
index da50dfd4..2129c98 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp
@@ -19,6 +19,8 @@
 
 BluetoothDevice::BluetoothDevice(PassOwnPtr<WebBluetoothDevice> webDevice)
     : m_webDevice(webDevice)
+    , m_adData(BluetoothAdvertisingData::create(m_webDevice->txPower,
+        m_webDevice->rssi))
 {
 }
 
@@ -28,6 +30,11 @@
     return new BluetoothDevice(webDevice);
 }
 
+DEFINE_TRACE(BluetoothDevice)
+{
+    visitor->trace(m_adData);
+}
+
 unsigned BluetoothDevice::deviceClass(bool& isNull)
 {
     isNull = false;
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.h
index 096cda7..a0ec5db 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.h
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.h
@@ -6,6 +6,7 @@
 #define BluetoothDevice_h
 
 #include "bindings/core/v8/ScriptWrappable.h"
+#include "modules/bluetooth/BluetoothAdvertisingData.h"
 #include "platform/heap/Heap.h"
 #include "public/platform/modules/bluetooth/WebBluetoothDevice.h"
 #include "wtf/OwnPtr.h"
@@ -38,11 +39,12 @@
     static BluetoothDevice* take(ScriptPromiseResolver*, PassOwnPtr<WebBluetoothDevice>);
 
     // Interface required by Garbage Collection:
-    DEFINE_INLINE_TRACE() { }
+    DECLARE_VIRTUAL_TRACE();
 
     // IDL exposed interface:
     String id() { return m_webDevice->id; }
     String name() { return m_webDevice->name; }
+    BluetoothAdvertisingData* adData() { return m_adData; }
     unsigned deviceClass(bool& isNull);
     String vendorIDSource();
     unsigned vendorID(bool& isNull);
@@ -53,6 +55,7 @@
 
 private:
     OwnPtr<WebBluetoothDevice> m_webDevice;
+    Member<BluetoothAdvertisingData> m_adData;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.idl b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.idl
index 03c25e06..86ad3a9 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.idl
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.idl
@@ -22,7 +22,7 @@
     [DeprecateAs=BluetoothDeviceInstanceId, ImplementedAs=id] readonly attribute DOMString instanceID;
     readonly    attribute DOMString id;
     readonly    attribute DOMString?                 name;
-//    readonly    attribute BluetoothAdvertisingData   adData;
+    readonly    attribute BluetoothAdvertisingData   adData;
     readonly    attribute unsigned long?             deviceClass;
     readonly    attribute VendorIDSource?            vendorIDSource;
     readonly    attribute unsigned long?             vendorID;
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.idl b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.idl
index b830fb9..e385a17 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.idl
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.idl
@@ -58,7 +58,7 @@
 
     // compositing
     attribute unrestricted float globalAlpha; // (default 1.0)
-    [TreatNullAs=NullString] attribute DOMString globalCompositeOperation; // (default source-over)
+    attribute DOMString globalCompositeOperation; // (default source-over)
     [RuntimeEnabled=ExperimentalCanvasFeatures] attribute DOMString filter; // (default 'none') 
 
     // image smoothing
@@ -77,7 +77,7 @@
     attribute unrestricted float shadowOffsetX;
     attribute unrestricted float shadowOffsetY;
     attribute unrestricted float shadowBlur;
-    [TreatNullAs=NullString] attribute DOMString shadowColor;
+    attribute DOMString shadowColor;
 
     // rects
     void clearRect(unrestricted float x, unrestricted float y, unrestricted float width, unrestricted float height);
@@ -133,8 +133,8 @@
     // FIXME: factor out to CanvasDrawingStyles
     // line caps/joins
     attribute unrestricted float lineWidth; // (default 1)
-    [TreatNullAs=NullString] attribute DOMString lineCap; // "butt", "round", "square" (default "butt")
-    [TreatNullAs=NullString] attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter")
+    attribute DOMString lineCap; // "butt", "round", "square" (default "butt")
+    attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter")
     attribute unrestricted float miterLimit; // (default 10)
 
     // dashed lines
diff --git a/third_party/WebKit/Source/modules/modules.gypi b/third_party/WebKit/Source/modules/modules.gypi
index 0c4d52c5..09e47ff09 100644
--- a/third_party/WebKit/Source/modules/modules.gypi
+++ b/third_party/WebKit/Source/modules/modules.gypi
@@ -24,6 +24,7 @@
       'background_sync/SyncRegistration.idl',
       'battery/BatteryManager.idl',
       'bluetooth/Bluetooth.idl',
+      'bluetooth/BluetoothAdvertisingData.idl',
       'bluetooth/BluetoothDevice.idl',
       'bluetooth/BluetoothCharacteristicProperties.idl',
       'bluetooth/BluetoothGATTCharacteristic.idl',
@@ -792,6 +793,8 @@
       'bluetooth/ConvertWebVectorToArrayBuffer.cpp',
       'bluetooth/ConvertWebVectorToArrayBuffer.h',
       'bluetooth/Bluetooth.cpp',
+      'bluetooth/BluetoothAdvertisingData.cpp',
+      'bluetooth/BluetoothAdvertisingData.h',
       'bluetooth/BluetoothCharacteristicProperties.cpp',
       'bluetooth/BluetoothCharacteristicProperties.h',
       'bluetooth/BluetoothDevice.cpp',
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
index 09518f7..136a0850 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
@@ -42,6 +42,7 @@
 #include "core/dom/ExecutionContext.h"
 #include "core/dom/MessagePort.h"
 #include "core/frame/LocalDOMWindow.h"
+#include "core/frame/UseCounter.h"
 #include "modules/EventTargetModules.h"
 #include "modules/serviceworkers/ServiceWorker.h"
 #include "modules/serviceworkers/ServiceWorkerContainerClient.h"
@@ -358,6 +359,8 @@
     if (!executionContext())
         return;
     m_controller = ServiceWorker::from(executionContext(), handle.release());
+    if (m_controller)
+        UseCounter::count(executionContext(), UseCounter::ServiceWorkerControlledPage);
     if (shouldNotifyControllerChange)
         dispatchEvent(Event::create(EventTypeNames::controllerchange));
 }
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h
index 76534e5..e2d97b5 100644
--- a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h
+++ b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h
@@ -20,6 +20,8 @@
 
     WebBluetoothDevice(const WebString& id,
         const WebString& name,
+        int8_t txPower,
+        int8_t rssi,
         int32_t deviceClass,
         VendorIDSource vendorIDSource,
         uint16_t vendorID,
@@ -29,6 +31,8 @@
         const WebVector<WebString>& uuids)
         : id(id)
         , name(name)
+        , txPower(txPower)
+        , rssi(rssi)
         , deviceClass(deviceClass)
         , vendorIDSource(vendorIDSource)
         , vendorID(vendorID)
@@ -42,6 +46,10 @@
     // Members corresponding to BluetoothDevice attributes as specified in IDL.
     const WebString id;
     const WebString name;
+    // Powers:
+    // A value of 127 denotes an invalid power.
+    const int8_t txPower;
+    const int8_t rssi;
     const int32_t deviceClass;
     const VendorIDSource vendorIDSource;
     const uint16_t vendorID;
diff --git a/third_party/errorprone/BUILD.gn b/third_party/errorprone/BUILD.gn
index 8274bfb..6795c5a 100644
--- a/third_party/errorprone/BUILD.gn
+++ b/third_party/errorprone/BUILD.gn
@@ -37,5 +37,5 @@
   main_class = "com.google.errorprone.ErrorProneCompiler"
 
   # TODO(mikecase): Remove this extra arg when the bots are on jdk8 or higher.
-  extra_java_args = "-Xbootclasspath/p:$target_gen_dir/javac_java.jar"
+  bootclasspath = "$target_gen_dir/javac_java.jar"
 }
diff --git a/third_party/errorprone/errorprone.gyp b/third_party/errorprone/errorprone.gyp
index 4a1f6a1..67de7684 100644
--- a/third_party/errorprone/errorprone.gyp
+++ b/third_party/errorprone/errorprone.gyp
@@ -84,7 +84,7 @@
             'python', '<(DEPTH)/build/android/gyp/create_java_binary_script.py',
             '--output', '<(PRODUCT_DIR)/bin.java/chromium_errorprone',
             # TODO(mikecase): Remove this extra arg when the bots are on jdk8 or higher.
-            '--extra-java-args', '-Xbootclasspath/p:<(PRODUCT_DIR)/lib.java/javac_jar.jar',
+            '--bootclasspath', '<(PRODUCT_DIR)/lib.java/javac_jar.jar',
             '--jar-path=<(jar_path)',
             '--classpath=>@(input_jars_paths)',
             '--main-class=com.google.errorprone.ErrorProneCompiler',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index dd13c31..c06c07b 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -61313,6 +61313,7 @@
   <int value="986" label="HTMLLabelElementFormContentAttribute"/>
   <int value="987" label="DeviceOrientationAbsoluteInsecureOrigin"/>
   <int value="988" label="DeviceOrientationAbsoluteSecureOrigin"/>
+  <int value="989" label="FontFaceConstructor"/>
 </enum>
 
 <enum name="FetchRequestMode" type="int">
diff --git a/tools/telemetry/telemetry/util/statistics.py b/tools/telemetry/telemetry/util/statistics.py
index 9867f45..381c6b4 100644
--- a/tools/telemetry/telemetry/util/statistics.py
+++ b/tools/telemetry/telemetry/util/statistics.py
@@ -87,26 +87,41 @@
       count_less.append(len(samples))
       count_less_equal.append(len(samples))
 
-  # Iterate over the intervals defined by any pair of locations.
-  for i in xrange(0, len(locations)):
-    for j in xrange(i+1, len(locations)):
-      # Length of interval
-      length = locations[j] - locations[i]
+  # Compute discrepancy as max(overshoot, -undershoot), where
+  # overshoot = max(count_closed(i, j)/N - length(i, j)) for all i < j,
+  # undershoot = min(count_open(i, j)/N - length(i, j)) for all i < j,
+  # N = len(samples),
+  # count_closed(i, j) is the number of points between i and j including ends,
+  # count_open(i, j) is the number of points between i and j excluding ends,
+  # length(i, j) is locations[i] - locations[j].
 
-      # Local discrepancy for closed interval
-      count_closed = count_less_equal[j] - count_less[i]
-      local_discrepancy_closed = abs(float(count_closed) *
-                                     inv_sample_count - length)
-      max_local_discrepancy = max(local_discrepancy_closed,
-                                  max_local_discrepancy)
+  # The following algorithm is modification of Kadane's algorithm,
+  # see https://en.wikipedia.org/wiki/Maximum_subarray_problem.
 
-      # Local discrepancy for open interval
-      count_open = count_less[j] - count_less_equal[i]
-      local_discrepancy_open = abs(float(count_open) *
-                                   inv_sample_count - length)
-      max_local_discrepancy = max(local_discrepancy_open,
-                                  max_local_discrepancy)
+  # The maximum of (count_closed(k, i-1)/N - length(k, i-1)) for any k < i-1.
+  max_diff = 0
+  # The minimum of (count_open(k, i-1)/N - length(k, i-1)) for any k < i-1.
+  min_diff = 0
+  for i in xrange(1, len(locations)):
+    length = locations[i] - locations[i - 1]
+    count_closed = count_less_equal[i] - count_less[i - 1]
+    count_open = count_less[i] - count_less_equal[i - 1]
+    # Number of points that are added if we extend a closed range that
+    # ends at location (i-1).
+    count_closed_increment = count_less_equal[i] - count_less_equal[i - 1]
+    # Number of points that are added if we extend an open range that
+    # ends at location (i-1).
+    count_open_increment = count_less[i] - count_less[i - 1]
 
+    # Either extend the previous optimal range or start a new one.
+    max_diff = max(
+        float(count_closed_increment) * inv_sample_count - length + max_diff,
+        float(count_closed) * inv_sample_count - length)
+    min_diff = min(
+        float(count_open_increment) * inv_sample_count - length + min_diff,
+        float(count_open) * inv_sample_count - length)
+
+    max_local_discrepancy = max(max_diff, -min_diff, max_local_discrepancy)
   return max_local_discrepancy
 
 
diff --git a/ui/file_manager/audio_player/css/audio_player.css b/ui/file_manager/audio_player/css/audio_player.css
index 56accad..06c01630 100644
--- a/ui/file_manager/audio_player/css/audio_player.css
+++ b/ui/file_manager/audio_player/css/audio_player.css
@@ -23,6 +23,7 @@
 }
 
 div.audio-player {
+  border-top: 4px solid white;
   color: #3d3d3d;
   cursor: default;
   flex: 1 1 auto;
diff --git a/ui/file_manager/audio_player/js/audio_player.js b/ui/file_manager/audio_player/js/audio_player.js
index fea6cd4..ea5fd26 100644
--- a/ui/file_manager/audio_player/js/audio_player.js
+++ b/ui/file_manager/audio_player/js/audio_player.js
@@ -329,7 +329,7 @@
  * @type {number}
  * @const
  */
-AudioPlayer.HEADER_HEIGHT = 33;  // 32px + border 1px
+AudioPlayer.HEADER_HEIGHT = 36;  // 32px + border 4px
 
 /**
  * Track height in pixels.
diff --git a/ui/file_manager/audio_player/js/background.js b/ui/file_manager/audio_player/js/background.js
index 6177c7a..587c0816 100644
--- a/ui/file_manager/audio_player/js/background.js
+++ b/ui/file_manager/audio_player/js/background.js
@@ -21,10 +21,13 @@
 var audioPlayerCreateOptions = {
   id: 'audio-player',
   type: 'panel',
-  minHeight: 48 + 96,  // 48px: track, 96px: controller
+  minHeight: 4 + 48 + 96,  // 4px: border-top, 48px: track, 96px: controller
   minWidth: 280,
-  height: 48 + 96,  // collapsed
-  width: 280
+  height: 4 + 48 + 96,  // collapsed
+  width: 280,
+  frame: {
+    color: '#fafafa'
+  }
 };
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
index c82d88c..38a38415 100644
--- a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
+++ b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
@@ -287,9 +287,6 @@
     this.cache_.put(url, thumbnail);
     this.dispatchThumbnailLoaded_(index, thumbnail);
     this.continue_();
-  }.bind(this), function() {
-    delete this.active_[url];
-    this.continue_();
   }.bind(this));
 };
 
@@ -337,13 +334,13 @@
   /** @type {string}*/
   event.fileUrl = thumbnail.fileUrl;
 
-  /** @type {string} */
+  /** @type {?string} */
   event.dataUrl = thumbnail.dataUrl;
 
-  /** @type {number} */
+  /** @type {?number} */
   event.width = thumbnail.width;
 
-  /** @type {number}*/
+  /** @type {?number}*/
   event.height = thumbnail.height;
 
   return event;
@@ -352,9 +349,9 @@
 /**
  * A class to represent thumbnail data.
  * @param {string} fileUrl File url of an original image.
- * @param {string} dataUrl Data url of thumbnail.
- * @param {number} width Width of thumbnail.
- * @param {number} height Height of thumbnail.
+ * @param {?string} dataUrl Data url of thumbnail.
+ * @param {?number} width Width of thumbnail.
+ * @param {?number} height Height of thumbnail.
  * @constructor
  * @struct
  */
@@ -365,17 +362,17 @@
   this.fileUrl = fileUrl;
 
   /**
-   * @const {string}
+   * @const {?string}
    */
   this.dataUrl = dataUrl;
 
   /**
-   * @const {number}
+   * @const {?number}
    */
   this.width = width;
 
   /**
-   * @const {number}
+   * @const {?number}
    */
   this.height = height;
 
@@ -405,21 +402,34 @@
 };
 
 /**
+ * Minimum delay of milliseconds before another retry for fetching a thumbnmail
+ * from EXIF after failing with an IO error. In milliseconds.
+ *
+ * @type {number}
+ */
+ListThumbnailLoader.Task.EXIF_IO_ERROR_DELAY = 3000;
+
+/**
  * Fetches thumbnail.
  *
  * @return {!Promise<!ListThumbnailLoader.ThumbnailData>} A promise which is
- *     resolved when thumbnail is fetched.
+ *     resolved when thumbnail data is fetched with either a success or an
+ *     error.
  */
 ListThumbnailLoader.Task.prototype.fetch = function() {
+  var ioError = false;
   return this.thumbnailModel_.get([this.entry_]).then(function(metadatas) {
     // When it failed to read exif header with an IO error, do not generate
     // thumbnail at this time since it may success in the second try. If it
     // failed to read at 0 byte, it would be an IO error.
     if (metadatas[0].thumbnail.urlError &&
         metadatas[0].thumbnail.urlError.errorDescription ===
-            'Error: Unexpected EOF @0')
-      throw metadatas[0].thumbnail.urlError;
-
+            'Error: Unexpected EOF @0') {
+      ioError = true;
+      return Promise.reject();
+    }
+    return metadatas[0];
+  }.bind(this)).then(function(metadata) {
     var loadTargets = [
       ThumbnailLoader.LoadTarget.CONTENT_METADATA,
       ThumbnailLoader.LoadTarget.EXTERNAL_METADATA
@@ -436,11 +446,25 @@
     }
 
     return new this.thumbnailLoaderConstructor_(
-        this.entry_, ThumbnailLoader.LoaderType.IMAGE, metadatas[0],
+        this.entry_, ThumbnailLoader.LoaderType.IMAGE, metadata,
         undefined /* opt_mediaType */, loadTargets)
         .loadAsDataUrl(ThumbnailLoader.FillMode.OVER_FILL);
   }.bind(this)).then(function(result) {
     return new ListThumbnailLoader.ThumbnailData(
         this.entry_.toURL(), result.data, result.width, result.height);
+  }.bind(this)).catch(function() {
+    // If an error happens during generating of a thumbnail, then return
+    // an empty object, so we don't retry the thumbnail over and over
+    // again.
+    var thumbnailData = new ListThumbnailLoader.ThumbnailData(
+          this.entry_.toURL(), null, null, null);
+    if (ioError) {
+      // If fetching a thumbnail from EXIF fails due to an IO error, then try to
+      // refetch it in the future, but not earlier than in 3 second.
+      setTimeout(function() {
+        thumbnailData.outdated = true;
+      }, ListThumbnailLoader.Task.EXIF_IO_ERROR_DELAY);
+    }
+    return thumbnailData;
   }.bind(this));
 };
diff --git a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js
index b5ee6f45..bb35917 100644
--- a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js
@@ -44,6 +44,8 @@
 var listThumbnailLoader;
 var getCallbacks;
 var thumbnailLoadedEvents;
+var thumbnailModel;
+var metadataModel;
 var fileListModel;
 var directoryModel;
 var currentVolumeType;
@@ -67,7 +69,7 @@
   MockThumbnailLoader.testImageHeight = 160;
 
   getCallbacks = {};
-  var thumbnailModel = {
+  thumbnailModel = {
     get: function(entries) {
       return new Promise(function(fulfill) {
         getCallbacks[getKeyOfGetCallback_(entries)] = fulfill;
@@ -75,7 +77,7 @@
     }
   };
 
-  var metadataModel = {
+  metadataModel = {
     get: function() {},
     getCache: function(entries, names) {
       return [{}];
@@ -375,3 +377,41 @@
 
   assertEquals(2, Object.keys(getCallbacks).length);
 }
+
+/**
+ * Test case for EXIF IO error and retrying logic.
+ */
+function testExifIOError(callback) {
+  var task = new ListThumbnailLoader.Task(
+      entry1,
+      // Mocking volume manager.
+      {
+        getVolumeInfo: function(entry) {
+          return { volumeType: currentVolumeType };
+        }
+      },
+      // Mocking thumbnail model.
+      {
+        get: function(entries) {
+          return Promise.resolve([{
+            thumbnail: {
+              urlError: {
+                errorDescription: 'Error: Unexpected EOF @0'
+              }
+            }
+          }]);
+        }
+      },
+      function() {
+        // Thumbnails should be fetched only from EXIF on IO error.
+        assertTrue(false);
+      });
+
+  return reportPromise(task.fetch().then(function(thumbnailData) {
+    assertEquals(null, thumbnailData.dataUrl);
+    assertFalse(thumbnailData.outdated);
+    return waitUntil(function() {
+      return thumbnailData.outdated;
+    });
+  }), callback);
+}
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
index 135af6f..8eff43d 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
@@ -151,16 +151,23 @@
     if (box) {
       var mimeType = this.metadataModel_.getCache(
           [entry], ['contentMimeType'])[0].contentMimeType;
-      FileGrid.setThumbnailImage_(
-          assertInstanceof(box, HTMLDivElement),
-          entry,
-          event.dataUrl,
-          event.width,
-          event.height,
-          /* should animate */ true,
-          mimeType);
+      if (!event.dataUrl) {
+        FileGrid.clearThumbnailImage_(
+            assertInstanceof(box, HTMLDivElement));
+        FileGrid.setGenericThumbnail_(
+            assertInstanceof(box, HTMLDivElement), entry);
+      } else {
+        FileGrid.setThumbnailImage_(
+            assertInstanceof(box, HTMLDivElement),
+            entry,
+            assert(event.dataUrl),
+            assert(event.width),
+            assert(event.height),
+            /* should animate */ true,
+            mimeType);
+      }
     }
-    listItem.classList.toggle('thumbnail-loaded', true);
+    listItem.classList.toggle('thumbnail-loaded', !!event.dataUrl);
   }
 };
 
@@ -582,14 +589,15 @@
   }
 
   if (entry.isDirectory) {
-    box.setAttribute('generic-thumbnail', 'folder');
+    FileGrid.setGenericThumbnail_(box, entry);
     return;
   }
 
-  // Set thumbnail if it's already in cache.
-  if (this.listThumbnailLoader_ &&
-      this.listThumbnailLoader_.getThumbnailFromCache(entry)) {
-    var thumbnailData = this.listThumbnailLoader_.getThumbnailFromCache(entry);
+  // Set thumbnail if it's already in cache, and the thumbnail data is not
+  // empty.
+  var thumbnailData = this.listThumbnailLoader_ ?
+      this.listThumbnailLoader_.getThumbnailFromCache(entry) : null;
+  if (thumbnailData && thumbnailData.dataUrl) {
     var mimeType = this.metadataModel_.getCache(
         [entry], ['contentMimeType'])[0].contentMimeType;
     FileGrid.setThumbnailImage_(
@@ -602,8 +610,7 @@
         mimeType);
     li.classList.toggle('thumbnail-loaded', true);
   } else {
-    var mediaType = FileType.getMediaType(entry);
-    box.setAttribute('generic-thumbnail', mediaType);
+    FileGrid.setGenericThumbnail_(box, entry);
     li.classList.toggle('thumbnail-loaded', false);
   }
   var mimeType = this.metadataModel_.getCache(
@@ -652,11 +659,11 @@
 /**
  * Sets thumbnail image to the box.
  * @param {!HTMLDivElement} box A div element to hold thumbnails.
- * @param {Entry!} entry An entry of the thumbnail.
+ * @param {!Entry} entry An entry of the thumbnail.
  * @param {string} dataUrl Data url of thumbnail.
  * @param {number} width Width of thumbnail.
  * @param {number} height Height of thumbnail.
- * @param {boolean} shouldAnimate Whether the thumbanil is shown with animation
+ * @param {boolean} shouldAnimate Whether the thumbnail is shown with animation
  *     or not.
  * @param {string=} opt_mimeType Optional mime type for the image.
  * @private
@@ -692,6 +699,34 @@
 };
 
 /**
+ * Clears thumbnail image from the box.
+ * @param {!HTMLDivElement} box A div element to hold thumbnails.
+ * @private
+ */
+FileGrid.clearThumbnailImage_ = function(box) {
+  var oldThumbnails = box.querySelectorAll('.thumbnail');
+  for (var i = 0; i < oldThumbnails.length; i++) {
+    box.removeChild(oldThumbnails[i]);
+  }
+  return;
+};
+
+/**
+ * Sets a generic thumbnail on the box.
+ * @param {!HTMLDivElement} box A div element to hold thumbnails.
+ * @param {!Entry} entry An entry of the thumbnail.
+ * @private
+ */
+FileGrid.setGenericThumbnail_ = function(box, entry) {
+  if (entry.isDirectory) {
+    box.setAttribute('generic-thumbnail', 'folder');
+  } else {
+    var mediaType = FileType.getMediaType(entry);
+    box.setAttribute('generic-thumbnail', mediaType);
+  }
+};
+
+/**
  * Applies cloud import history badges as appropriate for the Entry.
  *
  * @param {!FileEntry} entry
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
index 0545025..1764273 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -526,9 +526,14 @@
   if (listItem) {
     var box = listItem.querySelector('.detail-thumbnail');
     if (box) {
-      this.setThumbnailImage_(
-          assertInstanceof(box, HTMLDivElement), event.dataUrl,
-          true /* with animation */);
+      if (event.dataUrl) {
+        this.setThumbnailImage_(
+            assertInstanceof(box, HTMLDivElement), event.dataUrl,
+            true /* with animation */);
+      } else {
+        this.clearThumbnailImage_(
+            assertInstanceof(box, HTMLDivElement));
+      }
     }
   }
 };
@@ -965,8 +970,9 @@
   box.className = 'detail-thumbnail';
 
   // Set thumbnail if it's already in cache.
-  if (this.listThumbnailLoader_ &&
-      this.listThumbnailLoader_.getThumbnailFromCache(entry)) {
+  var thumbnailData = this.listThumbnailLoader_ ?
+      this.listThumbnailLoader_.getThumbnailFromCache(entry) : null;
+  if (thumbnailData && thumbnailData.dataUrl) {
     this.setThumbnailImage_(
         box, this.listThumbnailLoader_.getThumbnailFromCache(entry).dataUrl,
         false /* without animation */);
@@ -1007,6 +1013,19 @@
 };
 
 /**
+ * Clears thumbnail image from the box.
+ * @param {!HTMLDivElement} box Detail thumbnail div element.
+ * @private
+ */
+FileTable.prototype.clearThumbnailImage_ = function(box) {
+  var oldThumbnails = box.querySelectorAll('.thumbnail');
+
+  for (var i = 0; i < oldThumbnails.length; i++) {
+    box.removeChild(oldThumbnails[i]);
+  }
+};
+
+/**
  * Renders the selection checkmark in the detail table.
  * @return {!HTMLDivElement} Created element.
  * @private
diff --git a/ui/gl/angle_platform_impl.cc b/ui/gl/angle_platform_impl.cc
index 1f1085b5..4f979ca 100644
--- a/ui/gl/angle_platform_impl.cc
+++ b/ui/gl/angle_platform_impl.cc
@@ -37,10 +37,6 @@
   LOG(WARNING) << warningMessage;
 }
 
-void ANGLEPlatformImpl::logInfo(const char* infoMessage) {
-  LOG(INFO) << infoMessage;
-}
-
 angle::Platform::TraceEventHandle ANGLEPlatformImpl::addTraceEvent(
     char phase,
     const unsigned char* category_group_enabled,
diff --git a/ui/gl/angle_platform_impl.h b/ui/gl/angle_platform_impl.h
index 61dd0fb..0783f2cb 100644
--- a/ui/gl/angle_platform_impl.h
+++ b/ui/gl/angle_platform_impl.h
@@ -24,7 +24,6 @@
   double monotonicallyIncreasingTime() override;
   void logError(const char* errorMessage) override;
   void logWarning(const char* warningMessage) override;
-  void logInfo(const char* infoMessage) override;
   const unsigned char* getTraceCategoryEnabledFlag(
       const char* category_group) override;
   TraceEventHandle addTraceEvent(char phase,
diff --git a/ui/mojo/geometry/geometry.mojom b/ui/mojo/geometry/geometry.mojom
index 62bc6c8e..95a4336 100644
--- a/ui/mojo/geometry/geometry.mojom
+++ b/ui/mojo/geometry/geometry.mojom
@@ -37,3 +37,10 @@
   // Row major order.
   array<float, 16> matrix;
 };
+
+struct Insets {
+  int32 top;
+  int32 left;
+  int32 bottom;
+  int32 right;
+};
diff --git a/ui/views/controls/glow_hover_controller.cc b/ui/views/controls/glow_hover_controller.cc
index 5ce23fa..d621cea9 100644
--- a/ui/views/controls/glow_hover_controller.cc
+++ b/ui/views/controls/glow_hover_controller.cc
@@ -4,10 +4,6 @@
 
 #include "ui/views/controls/glow_hover_controller.h"
 
-#include "third_party/skia/include/effects/SkGradientShader.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/image/image_skia_operations.h"
 #include "ui/views/view.h"
 
 namespace views {
@@ -72,49 +68,13 @@
   return animation_.GetCurrentValue();
 }
 
-bool GlowHoverController::ShouldDraw() const {
-  return animation_.IsShowing() || animation_.is_animating();
+SkAlpha GlowHoverController::GetAlpha() const {
+  return static_cast<SkAlpha>(gfx::ToFlooredInt(
+      0.5 + animation_.CurrentValueBetween(0., 255 * opacity_scale_)));
 }
 
-void GlowHoverController::Draw(gfx::Canvas* canvas,
-                               const gfx::ImageSkia& mask_image) const {
-  if (!ShouldDraw())
-    return;
-
-  // Draw a radial gradient to hover_canvas.
-  gfx::Canvas hover_canvas(gfx::Size(mask_image.width(), mask_image.height()),
-                           canvas->image_scale(),
-                           false);
-
-  // Draw a radial gradient to hover_canvas.
-  int radius = view_->width() / 3;
-
-  SkPoint center_point;
-  center_point.iset(location_.x(), location_.y());
-  SkColor colors[2];
-  int hover_alpha =
-      static_cast<int>(255 * opacity_scale_ * animation_.GetCurrentValue());
-  colors[0] = SkColorSetARGB(hover_alpha, 255, 255, 255);
-  colors[1] = SkColorSetARGB(0, 255, 255, 255);
-  skia::RefPtr<SkShader> shader = skia::AdoptRef(
-      SkGradientShader::CreateRadial(
-          center_point, SkIntToScalar(radius), colors, NULL, 2,
-          SkShader::kClamp_TileMode));
-  // Shader can end up null when radius = 0.
-  // If so, this results in default full tab glow behavior.
-  if (shader) {
-    SkPaint paint;
-    paint.setStyle(SkPaint::kFill_Style);
-    paint.setAntiAlias(true);
-    paint.setShader(shader.get());
-    hover_canvas.DrawRect(gfx::Rect(location_.x() - radius,
-                                    location_.y() - radius,
-                                    radius * 2, radius * 2), paint);
-  }
-  gfx::ImageSkia result = gfx::ImageSkiaOperations::CreateMaskedImage(
-      gfx::ImageSkia(hover_canvas.ExtractImageRep()), mask_image);
-  canvas->DrawImageInt(result, (view_->width() - mask_image.width()) / 2,
-                       (view_->height() - mask_image.height()) / 2);
+bool GlowHoverController::ShouldDraw() const {
+  return animation_.IsShowing() || animation_.is_animating();
 }
 
 void GlowHoverController::AnimationEnded(const gfx::Animation* animation) {
diff --git a/ui/views/controls/glow_hover_controller.h b/ui/views/controls/glow_hover_controller.h
index 6be5ae7..00bf528 100644
--- a/ui/views/controls/glow_hover_controller.h
+++ b/ui/views/controls/glow_hover_controller.h
@@ -44,6 +44,8 @@
   // constructor.
   void SetLocation(const gfx::Point& location);
 
+  const gfx::Point& location() const { return location_; }
+
   // Initiates showing the hover.
   void Show(Style style);
 
@@ -56,14 +58,12 @@
   // Returns the value of the animation.
   double GetAnimationValue() const;
 
+  SkAlpha GetAlpha() const;
+
   // Returns true if there is something to be drawn. Use this instead of
   // invoking Draw() if creating |mask_image| is expensive.
   bool ShouldDraw() const;
 
-  // If the hover is currently visible it is drawn to the supplied canvas.
-  // |mask_image| is used to determine what parts of the canvas to draw on.
-  void Draw(gfx::Canvas* canvas, const gfx::ImageSkia& mask_image) const;
-
   // gfx::AnimationDelegate overrides:
   void AnimationEnded(const gfx::Animation* animation) override;
   void AnimationProgressed(const gfx::Animation* animation) override;
diff --git a/ui/views/mus/BUILD.gn b/ui/views/mus/BUILD.gn
index fa6741f..1384128 100644
--- a/ui/views/mus/BUILD.gn
+++ b/ui/views/mus/BUILD.gn
@@ -8,6 +8,8 @@
   sources = [
     "aura_init.cc",
     "aura_init.h",
+    "display_converter.cc",
+    "display_converter.h",
     "input_method_mus.cc",
     "input_method_mus.h",
     "native_widget_mus.cc",
@@ -18,6 +20,7 @@
     "surface_binding.h",
     "surface_context_factory.cc",
     "surface_context_factory.h",
+    "window_manager_client_area_insets.h",
     "window_manager_connection.cc",
     "window_manager_connection.h",
     "window_tree_host_mus.cc",
@@ -53,6 +56,8 @@
     "//ui/compositor",
     "//ui/events",
     "//ui/events:events_base",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
     "//ui/gl",
     "//ui/mojo/ime:interfaces_cpp_sources",
     "//ui/mojo/init",
diff --git a/mandoline/ui/common/util.cc b/ui/views/mus/display_converter.cc
similarity index 88%
rename from mandoline/ui/common/util.cc
rename to ui/views/mus/display_converter.cc
index 2ef16046..954aad7 100644
--- a/mandoline/ui/common/util.cc
+++ b/ui/views/mus/display_converter.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mandoline/ui/common/util.h"
+#include "ui/views/mus/display_converter.h"
 
 #include "components/mus/public/cpp/window.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
 
-namespace mandoline {
+namespace views {
 
 std::vector<gfx::Display> GetDisplaysFromWindow(mus::Window* window) {
   static int64 synthesized_display_id = 2000;
@@ -21,4 +21,4 @@
   return displays;
 }
 
-}  // namespace mandoline
+}  // namespace views
diff --git a/mandoline/ui/common/util.h b/ui/views/mus/display_converter.h
similarity index 64%
rename from mandoline/ui/common/util.h
rename to ui/views/mus/display_converter.h
index 63e88b5..a747455 100644
--- a/mandoline/ui/common/util.h
+++ b/ui/views/mus/display_converter.h
@@ -2,20 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MANDOLINE_UI_COMMON_UTIL_H_
-#define MANDOLINE_UI_COMMON_UTIL_H_
+#ifndef UI_VIEWS_MUS_DISPLAY_CONVERTER_H_
+#define UI_VIEWS_MUS_DISPLAY_CONVERTER_H_
 
 #include <vector>
+
 #include "ui/gfx/display.h"
 
 namespace mus {
 class Window;
 }
 
-namespace mandoline {
+namespace views {
 
 std::vector<gfx::Display> GetDisplaysFromWindow(mus::Window* window);
 
-}  // namespace mandoline
+}  // namespace views
 
-#endif  // MANDOLINE_UI_COMMON_UTIL_H_
\ No newline at end of file
+#endif  // UI_VIEWS_MUS_DISPLAY_CONVERTER_H_
diff --git a/ui/views/mus/native_widget_mus.cc b/ui/views/mus/native_widget_mus.cc
index f9b43d3..507e83f 100644
--- a/ui/views/mus/native_widget_mus.cc
+++ b/ui/views/mus/native_widget_mus.cc
@@ -10,9 +10,15 @@
 #include "ui/aura/client/default_capture_client.h"
 #include "ui/aura/layout_manager.h"
 #include "ui/aura/window.h"
+#include "ui/base/hit_test.h"
+#include "ui/compositor/clip_transform_recorder.h"
+#include "ui/compositor/paint_recorder.h"
+#include "ui/gfx/canvas.h"
 #include "ui/native_theme/native_theme_aura.h"
+#include "ui/views/mus/window_manager_client_area_insets.h"
 #include "ui/views/mus/window_tree_host_mus.h"
 #include "ui/views/widget/widget_delegate.h"
+#include "ui/views/window/custom_frame_view.h"
 #include "ui/wm/core/base_focus_rules.h"
 #include "ui/wm/core/capture_controller.h"
 #include "ui/wm/core/focus_controller.h"
@@ -20,6 +26,8 @@
 namespace views {
 namespace {
 
+WindowManagerClientAreaInsets* window_manager_client_area_insets = nullptr;
+
 // TODO: figure out what this should be.
 class FocusRulesImpl : public wm::BaseFocusRules {
  public:
@@ -61,6 +69,60 @@
   DISALLOW_COPY_AND_ASSIGN(ContentWindowLayoutManager);
 };
 
+// As the window manager renderers the non-client decorations this class does
+// very little but honor the client area insets from the window manager.
+class ClientSideNonClientFrameView : public NonClientFrameView {
+ public:
+  explicit ClientSideNonClientFrameView(views::Widget* widget)
+      : widget_(widget) {}
+  ~ClientSideNonClientFrameView() override {}
+
+ private:
+  // Returns the default values of client area insets from the window manager.
+  static gfx::Insets GetDefaultWindowManagerInsets(bool is_maximized) {
+    if (!window_manager_client_area_insets)
+      return gfx::Insets();
+    return is_maximized ? window_manager_client_area_insets->maximized_insets
+                        : window_manager_client_area_insets->normal_insets;
+  }
+
+  // NonClientFrameView:
+  gfx::Rect GetBoundsForClientView() const override {
+    gfx::Rect result(GetLocalBounds());
+    result.Inset(GetDefaultWindowManagerInsets(widget_->IsMaximized()));
+    return result;
+  }
+  gfx::Rect GetWindowBoundsForClientBounds(
+      const gfx::Rect& client_bounds) const override {
+    const gfx::Insets insets(
+        GetDefaultWindowManagerInsets(widget_->IsMaximized()));
+    return gfx::Rect(client_bounds.x() - insets.left(),
+                     client_bounds.y() - insets.top(),
+                     client_bounds.width() + insets.width(),
+                     client_bounds.height() + insets.height());
+  }
+  int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
+  void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {
+    // The window manager provides the shape; do nothing.
+  }
+  void ResetWindowControls() override {
+    // TODO(sky): push to wm?
+  }
+  void UpdateWindowIcon() override {
+    // NOTIMPLEMENTED();
+  }
+  void UpdateWindowTitle() override {
+    // NOTIMPLEMENTED();
+  }
+  void SizeConstraintsChanged() override {
+    // NOTIMPLEMENTED();
+  }
+
+  views::Widget* widget_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClientSideNonClientFrameView);
+};
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -78,6 +140,15 @@
       content_(new aura::Window(this)) {}
 NativeWidgetMus::~NativeWidgetMus() {}
 
+// static
+void NativeWidgetMus::SetWindowManagerClientAreaInsets(
+    const WindowManagerClientAreaInsets& insets) {
+  delete window_manager_client_area_insets;
+  // This is called early on, so we don't bother trying to relayout existing
+  // NativeWidgetMus. When we support restarting the WM we'll need to do that.
+  window_manager_client_area_insets = new WindowManagerClientAreaInsets(insets);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // NativeWidgetMus, private:
 
@@ -87,12 +158,20 @@
   if (!non_client_view || !non_client_view->client_view())
     return;
 
-  window_->SetClientArea(non_client_view->client_view()->bounds());
+  const gfx::Rect client_area_rect(non_client_view->client_view()->bounds());
+  window_->SetClientArea(gfx::Insets(
+      client_area_rect.y(), client_area_rect.x(),
+      non_client_view->bounds().height() - client_area_rect.bottom(),
+      non_client_view->bounds().width() - client_area_rect.right()));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // NativeWidgetMus, internal::NativeWidgetPrivate implementation:
 
+NonClientFrameView* NativeWidgetMus::CreateNonClientFrameView() {
+  return new ClientSideNonClientFrameView(GetWidget());
+}
+
 void NativeWidgetMus::InitNativeWidget(const Widget::InitParams& params) {
   window_tree_host_.reset(
       new WindowTreeHostMus(shell_, window_, surface_type_));
@@ -119,11 +198,6 @@
   // TODO(beng): much else, see [Desktop]NativeWidgetAura.
 }
 
-NonClientFrameView* NativeWidgetMus::CreateNonClientFrameView() {
-  // NOTIMPLEMENTED();
-  return nullptr;
-}
-
 bool NativeWidgetMus::ShouldUseNativeFrame() const {
   // NOTIMPLEMENTED();
   return false;
@@ -386,7 +460,7 @@
 }
 
 void NativeWidgetMus::SchedulePaintInRect(const gfx::Rect& rect) {
-  // NOTIMPLEMENTED();
+  content_->SchedulePaintInRect(rect);
 }
 
 void NativeWidgetMus::SetCursor(gfx::NativeCursor cursor) {
diff --git a/ui/views/mus/native_widget_mus.h b/ui/views/mus/native_widget_mus.h
index 61df1cc..dbfbba0 100644
--- a/ui/views/mus/native_widget_mus.h
+++ b/ui/views/mus/native_widget_mus.h
@@ -23,6 +23,10 @@
 
 namespace mus {
 class Window;
+
+namespace mojom {
+class WindowManager;
+}
 }
 
 namespace wm {
@@ -30,6 +34,7 @@
 }
 
 namespace views {
+struct WindowManagerClientAreaInsets;
 class WindowTreeHostMus;
 
 // An implementation of NativeWidget that binds to a mus::Window. Because Aura
@@ -47,12 +52,22 @@
                   mus::mojom::SurfaceType surface_type);
   ~NativeWidgetMus() override;
 
+  // Sets the insets for the client area. These values come from the window
+  // manager.
+  static void SetWindowManagerClientAreaInsets(
+      const WindowManagerClientAreaInsets& insets);
+
+  mus::Window* window() { return window_; }
+
+ protected:
+  // internal::NativeWidgetPrivate:
+  NonClientFrameView* CreateNonClientFrameView() override;
+
  private:
   void UpdateClientAreaInWindowManager();
 
   // internal::NativeWidgetPrivate:
   void InitNativeWidget(const Widget::InitParams& params) override;
-  NonClientFrameView* CreateNonClientFrameView() override;
   bool ShouldUseNativeFrame() const override;
   bool ShouldWindowContentsBeTransparent() const override;
   void FrameTypeChanged() override;
diff --git a/ui/views/mus/window_manager_client_area_insets.h b/ui/views/mus/window_manager_client_area_insets.h
new file mode 100644
index 0000000..20a27f6
--- /dev/null
+++ b/ui/views/mus/window_manager_client_area_insets.h
@@ -0,0 +1,19 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_MUS_WINDOW_MANAGER_CLIENT_AREA_INSETS_H_
+#define UI_VIEWS_MUS_WINDOW_MANAGER_CLIENT_AREA_INSETS_H_
+
+#include "ui/gfx/geometry/insets.h"
+
+namespace views {
+
+struct WindowManagerClientAreaInsets {
+  gfx::Insets normal_insets;
+  gfx::Insets maximized_insets;
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_MUS_WINDOW_MANAGER_CLIENT_AREA_INSETS_H_
diff --git a/ui/views/mus/window_manager_connection.cc b/ui/views/mus/window_manager_connection.cc
index b46ac10..006a8b3 100644
--- a/ui/views/mus/window_manager_connection.cc
+++ b/ui/views/mus/window_manager_connection.cc
@@ -17,6 +17,7 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/mojo/init/ui_init.h"
 #include "ui/views/mus/native_widget_mus.h"
+#include "ui/views/mus/window_manager_client_area_insets.h"
 #include "ui/views/views_delegate.h"
 
 namespace mojo {
@@ -58,6 +59,8 @@
 
 }  // namespace mojo
 
+namespace views {
+
 namespace {
 
 using WindowManagerConnectionPtr =
@@ -69,18 +72,23 @@
 
 std::vector<gfx::Display> GetDisplaysFromWindowManager(
     mus::mojom::WindowManagerPtr* window_manager) {
+  WindowManagerClientAreaInsets client_insets;
   std::vector<gfx::Display> displays;
-  (*window_manager)->GetDisplays(
-      [&displays](mojo::Array<mus::mojom::DisplayPtr> mojom_displays) {
-        displays = mojom_displays.To<std::vector<gfx::Display>>();
+  (*window_manager)
+      ->GetConfig([&displays,
+                   &client_insets](mus::mojom::WindowManagerConfigPtr results) {
+        displays = results->displays.To<std::vector<gfx::Display>>();
+        client_insets.normal_insets =
+            results->normal_client_area_insets.To<gfx::Insets>();
+        client_insets.maximized_insets =
+            results->maximized_client_area_insets.To<gfx::Insets>();
       });
   CHECK(window_manager->WaitForIncomingResponse());
+  NativeWidgetMus::SetWindowManagerClientAreaInsets(client_insets);
   return displays;
 }
 
-}
-
-namespace views {
+}  // namespace
 
 // static
 void WindowManagerConnection::Create(
diff --git a/ui/views/window/non_client_view.h b/ui/views/window/non_client_view.h
index 762ccf1..4efde57b 100644
--- a/ui/views/window/non_client_view.h
+++ b/ui/views/window/non_client_view.h
@@ -73,12 +73,19 @@
   // the parent NonClientView because that makes it more difficult to calculate
   // hittests for regions that are partially obscured by the ClientView, e.g.
   // HTSYSMENU.
+  // Return value is one of the windows HT constants (see ui/base/hit_test.h).
   virtual int NonClientHitTest(const gfx::Point& point) = 0;
+
+  // Used to make the hosting widget shaped (non-rectangular). For a
+  // rectangular window do nothing. For a shaped window update |window_mask|
+  // accordingly. |size| is the size of the widget.
   virtual void GetWindowMask(const gfx::Size& size,
                              gfx::Path* window_mask) = 0;
   virtual void ResetWindowControls() = 0;
   virtual void UpdateWindowIcon() = 0;
   virtual void UpdateWindowTitle() = 0;
+
+  // Whether the widget can be resized or maximized has changed.
   virtual void SizeConstraintsChanged() = 0;
 
   // View: