diff --git a/DEPS b/DEPS
index b55419f21..29b2300 100644
--- a/DEPS
+++ b/DEPS
@@ -78,7 +78,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '1fa9c434fc0dbe28342c28b7d08cb9361f80c4e2',
+  'skia_revision': '92c7fa6b009b3ea4e93ca179153f837c2d9d7962',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -134,7 +134,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '5626f3590eea9631f90a98549c73334577994819',
+  'catapult_revision': '3b3f9e1e789dbed2726dcd3c97d9dcd080ca7f23',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index 72031e2..8801722d 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -2316,30 +2316,6 @@
   Shell::Get()->SetCursorCompositingEnabled(false);
 }
 
-TEST_F(DisplayManagerTest, HardwareMirrorDetection) {
-  // Disable restoring mirror mode to prevent interference from previous
-  // display configuration.
-  display_manager()->set_disable_restoring_mirror_mode_for_test(true);
-
-  UpdateDisplay("500x500,400x400");
-  EXPECT_FALSE(display_manager()->GetCurrentDisplayLayout().mirrored);
-  EXPECT_EQ(2, display::Screen::GetScreen()->GetNumDisplays());
-  EXPECT_EQ(2U, display_manager()->num_connected_displays());
-
-  // Hardware mirroring.
-  UpdateDisplay("1+0-500x500,1+0-500x500");
-  EXPECT_TRUE(display_manager()->GetCurrentDisplayLayout().mirrored);
-  EXPECT_EQ(1, display::Screen::GetScreen()->GetNumDisplays());
-  EXPECT_EQ(2U, display_manager()->num_connected_displays());
-
-  UpdateDisplay("500x500,500x500");
-  EXPECT_FALSE(display_manager()->GetCurrentDisplayLayout().mirrored);
-  EXPECT_EQ(2, display::Screen::GetScreen()->GetNumDisplays());
-  EXPECT_EQ(2U, display_manager()->num_connected_displays());
-
-  display_manager()->set_disable_restoring_mirror_mode_for_test(false);
-}
-
 TEST_F(DisplayManagerTest, InvertLayout) {
   EXPECT_EQ("left, 0",
             display::DisplayPlacement(display::DisplayPlacement::RIGHT, 0)
@@ -2553,7 +2529,6 @@
   display::DisplayIdList list = display::test::CreateDisplayIdList2(1, 2);
   display::DisplayLayoutBuilder builder(
       display_manager()->layout_store()->GetRegisteredDisplayLayout(list));
-  builder.SetMirrored(false);
   display_manager()->layout_store()->RegisterLayoutForDisplayIdList(
       list, builder.Build());
   d2.SetBounds(gfx::Rect(0, 500, 500, 500));
@@ -3497,9 +3472,8 @@
 
   const display::DisplayIdList current_list =
       display_manager()->GetCurrentDisplayIdList();
-  display_manager()->layout_store()->UpdateMultiDisplayState(
-      current_list, true /* mirrored */, false /* unified */);
-  EXPECT_FALSE(display_manager()->GetCurrentDisplayLayout().mirrored);
+  display_manager()->layout_store()->UpdateDefaultUnified(current_list,
+                                                          false /* unified */);
   EXPECT_EQ(display::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR,
             observer.GetStateForDisplayIds(outputs));
 
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc
index cca2c80e..f911d96 100644
--- a/ash/display/window_tree_host_manager.cc
+++ b/ash/display/window_tree_host_manager.cc
@@ -718,8 +718,7 @@
     display::DisplayIdList list = display_manager->GetCurrentDisplayIdList();
     const display::DisplayLayout& layout =
         layout_store->GetRegisteredDisplayLayout(list);
-    layout_store->UpdateMultiDisplayState(
-        list, display_manager->IsInMirrorMode(), layout.default_unified);
+    layout_store->UpdateDefaultUnified(list, layout.default_unified);
     if (display::Screen::GetScreen()->GetNumDisplays() > 1) {
       SetPrimaryDisplayId(layout.primary_id == display::kInvalidDisplayId
                               ? list[0]
diff --git a/chrome/browser/chromeos/display/display_preferences_unittest.cc b/chrome/browser/chromeos/display/display_preferences_unittest.cc
index 53483ed1..1ff00147 100644
--- a/chrome/browser/chromeos/display/display_preferences_unittest.cc
+++ b/chrome/browser/chromeos/display/display_preferences_unittest.cc
@@ -48,7 +48,6 @@
 namespace chromeos {
 namespace {
 const char kPrimaryIdKey[] = "primary-id";
-const char kMirroredKey[] = "mirrored";
 const char kPositionKey[] = "position";
 const char kOffsetKey[] = "offset";
 const char kPlacementDisplayIdKey[] = "placement.display_id";
@@ -384,10 +383,6 @@
   EXPECT_EQ(dummy_layout->placement_list[0].offset,
             stored_layout.placement_list[0].offset);
 
-  bool mirrored = true;
-  EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored));
-  EXPECT_FALSE(mirrored);
-
   const base::ListValue* external_display_mirror_info =
       local_state()->GetList(prefs::kExternalDisplayMirrorInfo);
   EXPECT_EQ(0U, external_display_mirror_info->GetSize());
@@ -499,9 +494,6 @@
   if (true)
     return;
 
-  mirrored = true;
-  EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored));
-  EXPECT_FALSE(mirrored);
   std::string primary_id_str;
   EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str));
   EXPECT_EQ(base::Int64ToString(id2), primary_id_str);
@@ -526,9 +518,6 @@
   EXPECT_TRUE(layout_value->GetString(kPlacementParentDisplayIdKey, &id));
   EXPECT_EQ(base::Int64ToString(id2), id);
 
-  mirrored = false;
-  EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored));
-  EXPECT_TRUE(mirrored);
   EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str));
   EXPECT_EQ(base::Int64ToString(id2), primary_id_str);
 
@@ -565,9 +554,6 @@
   EXPECT_EQ("right", position);
   EXPECT_TRUE(layout_value->GetInteger(kOffsetKey, &offset));
   EXPECT_EQ(0, offset);
-  mirrored = true;
-  EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored));
-  EXPECT_FALSE(mirrored);
   EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str));
   EXPECT_EQ(base::Int64ToString(id1), primary_id_str);
 
@@ -591,9 +577,6 @@
   EXPECT_EQ("right", position);
   EXPECT_TRUE(layout_value->GetInteger(kOffsetKey, &offset));
   EXPECT_EQ(0, offset);
-  mirrored = true;
-  EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored));
-  EXPECT_FALSE(mirrored);
   EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str));
   EXPECT_EQ(base::Int64ToString(id1), primary_id_str);
 
@@ -1038,7 +1021,6 @@
   display::DisplayLayout stored_layout;
   EXPECT_TRUE(display::JsonToDisplayLayout(*new_value, &stored_layout));
   EXPECT_TRUE(stored_layout.default_unified);
-  EXPECT_FALSE(stored_layout.mirrored);
 
   const base::DictionaryValue* displays =
       local_state()->GetDictionary(prefs::kDisplayProperties);
@@ -1060,14 +1042,12 @@
       display::DisplayIdListToString(list), &new_value));
   EXPECT_TRUE(display::JsonToDisplayLayout(*new_value, &stored_layout));
   EXPECT_TRUE(stored_layout.default_unified);
-  EXPECT_TRUE(stored_layout.mirrored);
 
   display_manager()->SetMirrorMode(false);
   ASSERT_TRUE(secondary_displays->GetDictionary(
       display::DisplayIdListToString(list), &new_value));
   EXPECT_TRUE(display::JsonToDisplayLayout(*new_value, &stored_layout));
   EXPECT_TRUE(stored_layout.default_unified);
-  EXPECT_FALSE(stored_layout.mirrored);
 
   // Exit unified mode.
   display_manager()->SetDefaultMultiDisplayModeForCurrentDisplays(
@@ -1076,7 +1056,6 @@
       display::DisplayIdListToString(list), &new_value));
   EXPECT_TRUE(display::JsonToDisplayLayout(*new_value, &stored_layout));
   EXPECT_FALSE(stored_layout.default_unified);
-  EXPECT_FALSE(stored_layout.mirrored);
 }
 
 TEST_F(DisplayPreferencesTest, RestoreUnifiedMode) {
@@ -1215,11 +1194,6 @@
   // Make sure the mirror mode is not saved in the preference.
   display::DisplayIdList list = display_manager()->GetCurrentDisplayIdList();
   ASSERT_EQ(2u, list.size());
-  base::Value* value;
-  EXPECT_TRUE(GetDisplayPropertyFromList(list, "mirrored", &value));
-  bool mirrored;
-  EXPECT_TRUE(value->GetAsBoolean(&mirrored));
-  EXPECT_FALSE(mirrored);
 
   // Exiting the tablet mode should exit mirror mode.
   controller->EnableTabletModeWindowManager(false);
diff --git a/chrome/browser/extensions/active_tab_unittest.cc b/chrome/browser/extensions/active_tab_unittest.cc
index f043480a..819217e3 100644
--- a/chrome/browser/extensions/active_tab_unittest.cc
+++ b/chrome/browser/extensions/active_tab_unittest.cc
@@ -446,7 +446,7 @@
 #if defined(OS_CHROMEOS)
 // Test that the platform delegate is being set and the permission is prompted
 // for.
-TEST_F(ActiveTabTest, DelegateIsSet) {
+TEST_F(ActiveTabTest, DISABLED_DelegateIsSet) {
   // Necessary to prevent instantiation of ProfileSyncService, which messes with
   // our signin state below.
   base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kDisableSync);
diff --git a/chrome/browser/printing/pdf_to_emf_converter.cc b/chrome/browser/printing/pdf_to_emf_converter.cc
index c90ded9..b2e4d2b 100644
--- a/chrome/browser/printing/pdf_to_emf_converter.cc
+++ b/chrome/browser/printing/pdf_to_emf_converter.cc
@@ -8,6 +8,7 @@
 #include <windows.h>
 
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -262,10 +263,6 @@
   void OnTempFileReady(GetPageCallbackData* callback_data,
                        ScopedTempFile temp_file);
 
-  // Additional message handler needed for Pdf to Emf
-  void OnPreCacheFontCharacters(const LOGFONT& log_font,
-                                const base::string16& characters);
-
   scoped_refptr<RefCountedTempDir> temp_dir_;
 
   PdfRenderSettings settings_;
@@ -560,37 +557,6 @@
   Stop();
 }
 
-void PdfConverterImpl::OnPreCacheFontCharacters(const LOGFONT& font,
-                                                const base::string16& str) {
-  // TODO(scottmg): pdf/ppapi still require the renderer to be able to precache
-  // GDI fonts (http://crbug.com/383227), even when using DirectWrite.
-  // Eventually this shouldn't be added and should be moved to
-  // FontCacheDispatcher too. http://crbug.com/356346.
-
-  // First, comments from FontCacheDispatcher::OnPreCacheFont do apply here too.
-  // Except that for True Type fonts,
-  // GetTextMetrics will not load the font in memory.
-  // The only way windows seem to load properly, it is to create a similar
-  // device (like the one in which we print), then do an ExtTextOut,
-  // as we do in the printing thread, which is sandboxed.
-  HDC hdc = CreateEnhMetaFile(nullptr, nullptr, nullptr, nullptr);
-  HFONT font_handle = CreateFontIndirect(&font);
-  DCHECK(font_handle != nullptr);
-
-  HGDIOBJ old_font = SelectObject(hdc, font_handle);
-  DCHECK(old_font != nullptr);
-
-  ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, str.c_str(), str.length(), nullptr);
-
-  SelectObject(hdc, old_font);
-  DeleteObject(font_handle);
-
-  HENHMETAFILE metafile = CloseEnhMetaFile(hdc);
-
-  if (metafile)
-    DeleteEnhMetaFile(metafile);
-}
-
 }  // namespace
 
 PdfConverter::~PdfConverter() = default;
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/background.js b/chrome/browser/resources/chromeos/chromevox/chromevox/background/background.js
index 381a28d..0bae33d 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/background.js
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/background.js
@@ -10,7 +10,6 @@
 
 goog.require('ChromeVoxState');
 goog.require('Msgs');
-goog.require('constants');
 goog.require('cvox.AbstractEarcons');
 goog.require('cvox.BrailleBackground');
 goog.require('cvox.BrailleCaptionsBackground');
@@ -88,7 +87,7 @@
     cvox.BrailleCaptionsBackground.setActive(!!value);
   } else if (pref == 'position') {
     cvox.ChromeVox.position =
-        /** @type {Object<string, constants.Point>} */ (JSON.parse(
+        /** @type {Object<string, cvox.Point>} */ (JSON.parse(
             /** @type {string} */ (value)));
   }
   window['prefs'].setPref(pref, value);
diff --git a/chrome/browser/resources/chromeos/chromevox/common/chromevox.js b/chrome/browser/resources/chromeos/chromevox/common/chromevox.js
index 37cb604f..1dcb41b 100644
--- a/chrome/browser/resources/chromeos/chromevox/common/chromevox.js
+++ b/chrome/browser/resources/chromeos/chromevox/common/chromevox.js
@@ -9,7 +9,6 @@
  */
 
 goog.provide('cvox.ChromeVox');
-goog.require('constants');
 
 // Forward declarations.
 // TODO (stoarca): Put these in a separate file and pass that
@@ -133,7 +132,11 @@
  */
 cvox.ChromeVox.keyEcho = {};
 /**
- * @type {Object<string, constants.Point>}
+ * @typedef {{x: number, y: number}}
+ */
+cvox.Point;
+/**
+ * @type {Object<string, cvox.Point>}
  */
 cvox.ChromeVox.position = {};
 /**
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
index 5be61ec..e05adba 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
@@ -144,7 +144,7 @@
  * @return {boolean}
  */
 AutomationPredicate.visitedLink = function(node) {
-  return node.state[State.VISITED];
+  return node.state.visited;
 };
 
 /**
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
index 7f439ca1..903c414 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
@@ -259,7 +259,7 @@
  * with respect to their parents, the hit test considers all children before
  * their parents when looking for a matching node.
  * @param {AutomationNode} node Subtree to search.
- * @param {constants.Point} point
+ * @param {cvox.Point} point
  * @return {AutomationNode}
  */
 AutomationUtil.hitTest = function(node, point) {
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/constants.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/constants.js
index 6d44861..762ca88e 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/constants.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/constants.js
@@ -21,12 +21,6 @@
 };
 
 /**
- * Represents a point.
- * @typedef {{x: (number), y: (number)}}
- */
-constants.Point;
-
-/**
  * If a node contains more characters than this, it should not be visited during
  * object navigation.
  *
diff --git a/chrome/browser/resources/chromeos/select_to_speak/BUILD.gn b/chrome/browser/resources/chromeos/select_to_speak/BUILD.gn
index e0a5937fc..a30ce42d 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/BUILD.gn
+++ b/chrome/browser/resources/chromeos/select_to_speak/BUILD.gn
@@ -26,10 +26,6 @@
   mode = "copy"
   dest_dir = select_to_speak_out_dir
   sources = [
-    "../chromevox/cvox2/background/automation_predicate.js",
-    "../chromevox/cvox2/background/automation_util.js",
-    "../chromevox/cvox2/background/constants.js",
-    "../chromevox/cvox2/background/tree_walker.js",
     "checked.png",
     "options.css",
     "options.html",
diff --git a/chrome/browser/resources/chromeos/select_to_speak/closure_shim.js b/chrome/browser/resources/chromeos/select_to_speak/closure_shim.js
deleted file mode 100644
index e04ffc8..0000000
--- a/chrome/browser/resources/chromeos/select_to_speak/closure_shim.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * Provides a shim to allow select-to-speak to use closure files.
- */
-
-var goog = {};
-
-goog.provide = function(n) {
-  window[n] = {};
-};
-
-goog.require = function() {};
-
-goog.scope = function(c) {
-  c();
-};
diff --git a/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp b/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp
index 4284ec0..a581105 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp
+++ b/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp
@@ -6,8 +6,6 @@
     {
       'target_name': 'select_to_speak',
       'dependencies': [
-        '../chromevox/cvox2/background/constants',
-        '../chromevox/cvox2/background/automation_util',
 	'externs',
 	'paragraph_utils',
 	'<(EXTERNS_GYP):accessibility_private',
@@ -42,43 +40,5 @@
        ],
        'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
-    {
-      'target_name': '../chromevox/cvox2/background/automation_util',
-      'dependencies': [
-	'../chromevox/cvox2/background/automation_predicate',
-	'../chromevox/cvox2/background/tree_walker',
-	'../chromevox/cvox2/background/constants',
-	'<(EXTERNS_GYP):automation',
-	'<(EXTERNS_GYP):chrome_extensions',
-      ],
-      'includes':  ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': '../chromevox/cvox2/background/tree_walker',
-      'dependencies': [
-	'../chromevox/cvox2/background/automation_predicate',
-	'../chromevox/cvox2/background/constants',
-	'<(EXTERNS_GYP):automation',
-	'<(EXTERNS_GYP):chrome_extensions',
-      ],
-      'includes':  ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': '../chromevox/cvox2/background/automation_predicate',
-      'dependencies': [
-	'../chromevox/cvox2/background/constants',
-	'<(EXTERNS_GYP):automation',
-	'<(EXTERNS_GYP):chrome_extensions',
-      ],
-      'includes':  ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': '../chromevox/cvox2/background/constants',
-      'includes':  ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'closure_shim',
-      'includes':  ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
   ],
 }
diff --git a/chrome/browser/resources/chromeos/select_to_speak/manifest.json.jinja2 b/chrome/browser/resources/chromeos/select_to_speak/manifest.json.jinja2
index 3461a8fc..e0b3ef43 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/select_to_speak/manifest.json.jinja2
@@ -11,11 +11,6 @@
 {% endif %}
   "background": {
     "scripts": [
-      "closure_shim.js",
-      "constants.js",
-      "automation_predicate.js",
-      "tree_walker.js",
-      "automation_util.js",
       "paragraph_utils.js",
       "select_to_speak.js",
       "select_to_speak_main.js"
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
index a918a77..90d091e 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
@@ -4,7 +4,11 @@
 
 #include "chrome/browser/ui/webui/extensions/extension_settings_browsertest.h"
 
+#include <string>
+
 #include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/extensions/unpacked_installer.h"
 #include "chrome/browser/profiles/profile.h"
@@ -12,6 +16,10 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/web_contents_sizer.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test_utils.h"
 #include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_system.h"
 
@@ -58,9 +66,12 @@
       test_data_dir_.AppendASCII("platform_apps").AppendASCII("minimal")));
 }
 
-void ExtensionSettingsUIBrowserTest::InstallExtensionWithInPageOptions() {
-  EXPECT_TRUE(
-      InstallExtension(test_data_dir_.AppendASCII("options_page_in_view")));
+const extensions::Extension*
+ExtensionSettingsUIBrowserTest::InstallExtensionWithInPageOptions() {
+  const extensions::Extension* extension =
+      InstallExtension(test_data_dir_.AppendASCII("options_page_in_view"));
+  EXPECT_TRUE(extension);
+  return extension;
 }
 
 void ExtensionSettingsUIBrowserTest::AddManagedPolicyProvider() {
@@ -92,3 +103,59 @@
   loader.set_ignore_manifest_warnings(true);
   return loader.LoadExtension(path).get();
 }
+
+// Tests that viewing a source of the options page works fine.
+// This is a regression test for https://crbug.com/796080.
+IN_PROC_BROWSER_TEST_F(ExtensionSettingsUIBrowserTest, ViewSource) {
+  // Navigate to an in-page (guest-view-based) extension options page
+  // and grab the WebContents hosting the options page.
+  const extensions::Extension* extension = InstallExtensionWithInPageOptions();
+  GURL options_url("chrome://extensions/?options=" + extension->id());
+  content::WebContents* options_contents = nullptr;
+  {
+    content::WebContentsAddedObserver options_contents_added_observer;
+    ui_test_utils::NavigateToURL(browser(), options_url);
+    options_contents = options_contents_added_observer.GetWebContents();
+  }
+  ASSERT_TRUE(options_contents);
+  content::WaitForLoadStop(options_contents);
+  EXPECT_EQ(extension->GetResourceURL("options.html"),
+            options_contents->GetLastCommittedURL());
+
+  // Open the view-source of the options page.
+  int old_tabs_count = browser()->tab_strip_model()->count();
+  content::WebContentsAddedObserver view_source_contents_added_observer;
+  options_contents->GetMainFrame()->ViewSource();
+  content::WebContents* view_source_contents =
+      view_source_contents_added_observer.GetWebContents();
+  ASSERT_TRUE(view_source_contents);
+  content::WaitForLoadStop(view_source_contents);
+
+  // Verify that the view-source is present in the tab-strip.
+  int new_tabs_count = browser()->tab_strip_model()->count();
+  EXPECT_EQ(new_tabs_count, old_tabs_count + 1);
+  EXPECT_EQ(view_source_contents,
+            browser()->tab_strip_model()->GetActiveWebContents());
+
+  // Verify the contents of the view-source tab.
+  std::string actual_source_text;
+  std::string view_source_extraction_script = R"(
+      output = "";
+      document.querySelectorAll(".line-content").forEach(function(elem) {
+          output += elem.innerText;
+      });
+      domAutomationController.send(output); )";
+  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+      view_source_contents, view_source_extraction_script,
+      &actual_source_text));
+  base::FilePath source_path =
+      test_data_dir().AppendASCII("options_page_in_view/options.html");
+  std::string expected_source_text;
+  {
+    base::ScopedAllowBlockingForTesting scoped_allow_blocking;
+    EXPECT_TRUE(base::ReadFileToString(source_path, &expected_source_text));
+  }
+  EXPECT_TRUE(
+      base::RemoveChars(expected_source_text, "\n", &expected_source_text));
+  EXPECT_EQ(expected_source_text, actual_source_text);
+}
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
index a971fcbc..6a2a64c 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
@@ -39,7 +39,9 @@
 
   void InstallPlatformApp();
 
-  void InstallExtensionWithInPageOptions();
+  // Installs chrome/test/data/extensions/options_page_in_view extension
+  // and returns it back to the caller.  Can return null upon failure.
+  const extensions::Extension* InstallExtensionWithInPageOptions();
 
   void AddManagedPolicyProvider();
 
@@ -51,6 +53,8 @@
   // Shrinks the web contents view in order to ensure vertical overflow.
   void ShrinkWebContentsView();
 
+  const base::FilePath& test_data_dir() { return test_data_dir_; }
+
  private:
   const extensions::Extension* InstallExtension(const base::FilePath& path);
 
diff --git a/chrome/service/service_utility_process_host.cc b/chrome/service/service_utility_process_host.cc
index e54e6cd..e991854 100644
--- a/chrome/service/service_utility_process_host.cc
+++ b/chrome/service/service_utility_process_host.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -24,7 +25,6 @@
 #include "base/task_runner_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/win/win_util.h"
-#include "build/build_config.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_utility_printing_messages.h"
 #include "content/public/common/child_process_host.h"
@@ -95,8 +95,7 @@
 
 class ServiceUtilityProcessHost::PdfToEmfState {
  public:
-  explicit PdfToEmfState(ServiceUtilityProcessHost* host)
-      : host_(host), page_count_(0), current_page_(0), pages_in_progress_(0) {}
+  explicit PdfToEmfState(ServiceUtilityProcessHost* host) : host_(host) {}
   ~PdfToEmfState() { Stop(); }
 
   bool Start(base::File pdf_file,
@@ -162,11 +161,11 @@
   }
 
   base::ScopedTempDir temp_dir_;
-  ServiceUtilityProcessHost* host_;
+  ServiceUtilityProcessHost* const host_;
   base::queue<base::File> emf_files_;
-  int page_count_;
-  int current_page_;
-  int pages_in_progress_;
+  int page_count_ = 0;
+  int current_page_ = 0;
+  int pages_in_progress_ = 0;
 };
 
 ServiceUtilityProcessHost::ServiceUtilityProcessHost(
@@ -196,7 +195,7 @@
   DCHECK(!waiting_for_reply_);
   waiting_for_reply_ = true;
 
-  pdf_to_emf_state_.reset(new PdfToEmfState(this));
+  pdf_to_emf_state_ = std::make_unique<PdfToEmfState>(this);
   return pdf_to_emf_state_->Start(std::move(pdf_file), render_settings);
 }
 
@@ -388,12 +387,10 @@
 void ServiceUtilityProcessHost::OnPDFToEmfFinished(bool success) {
   if (!waiting_for_reply_)
     return;
+
   waiting_for_reply_ = false;
-  if (success) {
-    ReportUmaEvent(SERVICE_UTILITY_METAFILE_SUCCEEDED);
-  } else {
-    ReportUmaEvent(SERVICE_UTILITY_METAFILE_FAILED);
-  }
+  ReportUmaEvent(success ? SERVICE_UTILITY_METAFILE_SUCCEEDED
+                         : SERVICE_UTILITY_METAFILE_FAILED);
   client_task_runner_->PostTask(
       FROM_HERE, base::Bind(&Client::OnRenderPDFPagesToMetafileDone,
                             client_.get(), success));
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc
index a261ebdc..eb2bc32 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -26,7 +26,7 @@
 namespace {
 
 void TransformEventTouchPositions(blink::WebTouchEvent* event,
-                                  const gfx::Vector2d& delta) {
+                                  const gfx::Vector2dF& delta) {
   for (unsigned i = 0; i < event->touches_length; ++i) {
     event->touches[i].SetPositionInWidget(
         event->touches[i].PositionInWidget().x + delta.x(),
@@ -233,20 +233,6 @@
 
 RenderWidgetHostViewBase* RenderWidgetHostInputEventRouter::FindViewAtLocation(
     RenderWidgetHostViewBase* root_view,
-    const gfx::Point& point,
-    const gfx::Point& point_in_screen,
-    viz::EventSource source,
-    gfx::Point* transformed_point) const {
-  gfx::PointF temp_point(*transformed_point);
-  RenderWidgetHostViewBase* view =
-      FindViewAtLocation(root_view, gfx::PointF(point),
-                         gfx::PointF(point_in_screen), source, &temp_point);
-  *transformed_point = gfx::ToFlooredPoint(temp_point);
-  return view;
-}
-
-RenderWidgetHostViewBase* RenderWidgetHostInputEventRouter::FindViewAtLocation(
-    RenderWidgetHostViewBase* root_view,
     const gfx::PointF& point,
     const gfx::PointF& point_in_screen,
     viz::EventSource source,
@@ -365,8 +351,7 @@
       wheel_target_.target = FindViewAtLocation(
           root_view, event->PositionInWidget(), event->PositionInScreen(),
           viz::EventSource::MOUSE, &transformed_point);
-      wheel_target_.delta =
-          gfx::ToFlooredVector2d(transformed_point - event->PositionInWidget());
+      wheel_target_.delta = transformed_point - event->PositionInWidget();
       target = wheel_target_.target;
     } else {
       if (wheel_target_.target) {
@@ -494,10 +479,10 @@
         // Since this is the first touch, it defines the target for the rest
         // of this sequence.
         DCHECK(!touch_target_.target);
-        gfx::Point transformed_point;
-        gfx::Point original_point(event->touches[0].PositionInWidget().x,
-                                  event->touches[0].PositionInWidget().y);
-        gfx::Point original_point_in_screen(
+        gfx::PointF transformed_point;
+        gfx::PointF original_point(event->touches[0].PositionInWidget().x,
+                                   event->touches[0].PositionInWidget().y);
+        gfx::PointF original_point_in_screen(
             event->touches[0].PositionInScreen().x,
             event->touches[0].PositionInScreen().y);
         touch_target_.target = FindViewAtLocation(
@@ -1018,9 +1003,9 @@
   // gesture start, then the target must be recalculated.
   if (event->unique_touch_event_id == 0 ||
       (no_matching_id && is_gesture_start)) {
-    gfx::Point transformed_point;
-    gfx::Point original_point(event->x, event->y);
-    gfx::Point original_point_in_screen(event->global_x, event->global_y);
+    gfx::PointF transformed_point;
+    gfx::PointF original_point(event->x, event->y);
+    gfx::PointF original_point_in_screen(event->global_x, event->global_y);
     touchscreen_gesture_target_.target =
         FindViewAtLocation(root_view, original_point, original_point_in_screen,
                            viz::EventSource::TOUCH, &transformed_point);
@@ -1059,9 +1044,9 @@
 
   if (event->GetType() == blink::WebInputEvent::kGesturePinchBegin ||
       event->GetType() == blink::WebInputEvent::kGestureFlingStart) {
-    gfx::Point transformed_point;
-    gfx::Point original_point(event->x, event->y);
-    gfx::Point original_point_in_screen(event->global_x, event->global_y);
+    gfx::PointF transformed_point;
+    gfx::PointF original_point(event->x, event->y);
+    gfx::PointF original_point_in_screen(event->global_x, event->global_y);
     touchpad_gesture_target_.target =
         FindViewAtLocation(root_view, original_point, original_point_in_screen,
                            viz::EventSource::TOUCH, &transformed_point);
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.h b/content/browser/renderer_host/render_widget_host_input_event_router.h
index 7b8a2c8..b4b5d33 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.h
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -124,7 +124,7 @@
                                                  viz::FrameSinkIdHash>;
   struct TargetData {
     RenderWidgetHostViewBase* target;
-    gfx::Vector2d delta;
+    gfx::Vector2dF delta;
 
     TargetData() : target(nullptr) {}
   };
@@ -138,13 +138,6 @@
 
   RenderWidgetHostViewBase* FindViewAtLocation(
       RenderWidgetHostViewBase* root_view,
-      const gfx::Point& point,
-      const gfx::Point& point_in_screen,
-      viz::EventSource source,
-      gfx::Point* transformed_point) const;
-
-  RenderWidgetHostViewBase* FindViewAtLocation(
-      RenderWidgetHostViewBase* root_view,
       const gfx::PointF& point,
       const gfx::PointF& point_in_screen,
       viz::EventSource source,
diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.cc b/extensions/browser/guest_view/extension_options/extension_options_guest.cc
index 259fcba..1a74872 100644
--- a/extensions/browser/guest_view/extension_options/extension_options_guest.cc
+++ b/extensions/browser/guest_view/extension_options/extension_options_guest.cc
@@ -152,6 +152,20 @@
       options.ToValue()));
 }
 
+void ExtensionOptionsGuest::AddNewContents(WebContents* source,
+                                           WebContents* new_contents,
+                                           WindowOpenDisposition disposition,
+                                           const gfx::Rect& initial_rect,
+                                           bool user_gesture,
+                                           bool* was_blocked) {
+  if (!attached() || !embedder_web_contents()->GetDelegate())
+    return;
+
+  embedder_web_contents()->GetDelegate()->AddNewContents(
+      source, new_contents, disposition, initial_rect, user_gesture,
+      was_blocked);
+}
+
 WebContents* ExtensionOptionsGuest::OpenURLFromTab(
     WebContents* source,
     const content::OpenURLParams& params) {
diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.h b/extensions/browser/guest_view/extension_options/extension_options_guest.h
index ed9e3bb..12250fc1 100644
--- a/extensions/browser/guest_view/extension_options/extension_options_guest.h
+++ b/extensions/browser/guest_view/extension_options/extension_options_guest.h
@@ -7,6 +7,8 @@
 
 #include <stdint.h>
 
+#include <memory>
+
 #include "base/macros.h"
 #include "components/guest_view/browser/guest_view.h"
 #include "extensions/browser/guest_view/extension_options/extension_options_guest_delegate.h"
@@ -36,6 +38,12 @@
   void OnPreferredSizeChanged(const gfx::Size& pref_size) final;
 
   // content::WebContentsDelegate implementation.
+  void AddNewContents(content::WebContents* source,
+                      content::WebContents* new_contents,
+                      WindowOpenDisposition disposition,
+                      const gfx::Rect& initial_rect,
+                      bool user_gesture,
+                      bool* was_blocked) final;
   content::WebContents* OpenURLFromTab(
       content::WebContents* source,
       const content::OpenURLParams& params) final;
diff --git a/third_party/WebKit/Source/core/editing/SurroundingTextTest.cpp b/third_party/WebKit/Source/core/editing/SurroundingTextTest.cpp
index a42052aa..918310b 100644
--- a/third_party/WebKit/Source/core/editing/SurroundingTextTest.cpp
+++ b/third_party/WebKit/Source/core/editing/SurroundingTextTest.cpp
@@ -11,7 +11,6 @@
 #include "core/editing/EphemeralRange.h"
 #include "core/editing/Position.h"
 #include "core/editing/SelectionTemplate.h"
-#include "core/editing/VisibleSelection.h"
 #include "core/html/HTMLElement.h"
 #include "core/html/forms/TextControlElement.h"
 #include "core/testing/DummyPageHolder.h"
@@ -23,8 +22,8 @@
  protected:
   Document& GetDocument() const { return dummy_page_holder_->GetDocument(); }
   void SetHTML(const String&);
-  VisibleSelection Select(int offset) { return Select(offset, offset); }
-  VisibleSelection Select(int start, int end);
+  EphemeralRange Select(int offset) { return Select(offset, offset); }
+  EphemeralRange Select(int start, int end);
 
  private:
   void SetUp() override;
@@ -41,21 +40,18 @@
   GetDocument().UpdateStyleAndLayout();
 }
 
-VisibleSelection SurroundingTextTest::Select(int start, int end) {
+EphemeralRange SurroundingTextTest::Select(int start, int end) {
   Element* element = GetDocument().getElementById("selection");
-  return CreateVisibleSelection(
-      SelectionInDOMTree::Builder()
-          .Collapse(Position(ToText(element->firstChild()), start))
-          .Extend(Position(ToText(element->firstChild()), end))
-          .Build());
+  return EphemeralRange(Position(element->firstChild(), start),
+                        Position(element->firstChild(), end));
 }
 
 TEST_F(SurroundingTextTest, BasicCaretSelection) {
   SetHTML(String("<p id='selection'>foo bar</p>"));
 
   {
-    VisibleSelection selection = Select(0);
-    SurroundingText surrounding_text(EphemeralRange(selection.Start()), 1);
+    EphemeralRange selection = Select(0);
+    SurroundingText surrounding_text(selection, 1);
 
     EXPECT_EQ("f", surrounding_text.Content());
     EXPECT_EQ(0u, surrounding_text.StartOffsetInContent());
@@ -63,8 +59,8 @@
   }
 
   {
-    VisibleSelection selection = Select(0);
-    SurroundingText surrounding_text(EphemeralRange(selection.Start()), 5);
+    EphemeralRange selection = Select(0);
+    SurroundingText surrounding_text(selection, 5);
 
     // maxlength/2 is used on the left and right.
     EXPECT_EQ("foo", surrounding_text.Content().SimplifyWhiteSpace());
@@ -73,8 +69,8 @@
   }
 
   {
-    VisibleSelection selection = Select(0);
-    SurroundingText surrounding_text(EphemeralRange(selection.Start()), 42);
+    EphemeralRange selection = Select(0);
+    SurroundingText surrounding_text(selection, 42);
 
     EXPECT_EQ("foo bar", surrounding_text.Content().SimplifyWhiteSpace());
     EXPECT_EQ(1u, surrounding_text.StartOffsetInContent());
@@ -82,8 +78,8 @@
   }
 
   {
-    VisibleSelection selection = Select(7);
-    SurroundingText surrounding_text(EphemeralRange(selection.Start()), 42);
+    EphemeralRange selection = Select(7);
+    SurroundingText surrounding_text(selection, 42);
 
     EXPECT_EQ("foo bar", surrounding_text.Content().SimplifyWhiteSpace());
     EXPECT_EQ(8u, surrounding_text.StartOffsetInContent());
@@ -91,8 +87,8 @@
   }
 
   {
-    VisibleSelection selection = Select(6);
-    SurroundingText surrounding_text(EphemeralRange(selection.Start()), 2);
+    EphemeralRange selection = Select(6);
+    SurroundingText surrounding_text(selection, 2);
 
     EXPECT_EQ("ar", surrounding_text.Content());
     EXPECT_EQ(1u, surrounding_text.StartOffsetInContent());
@@ -100,8 +96,8 @@
   }
 
   {
-    VisibleSelection selection = Select(6);
-    SurroundingText surrounding_text(EphemeralRange(selection.Start()), 42);
+    EphemeralRange selection = Select(6);
+    SurroundingText surrounding_text(selection, 42);
 
     EXPECT_EQ("foo bar", surrounding_text.Content().SimplifyWhiteSpace());
     EXPECT_EQ(7u, surrounding_text.StartOffsetInContent());
@@ -113,8 +109,8 @@
   SetHTML(String("<p id='selection'>Lorem ipsum dolor sit amet</p>"));
 
   {
-    VisibleSelection selection = Select(0, 5);
-    SurroundingText surrounding_text(FirstEphemeralRangeOf(selection), 1);
+    EphemeralRange selection = Select(0, 5);
+    SurroundingText surrounding_text(selection, 1);
 
     EXPECT_EQ("Lorem ", surrounding_text.Content());
     EXPECT_EQ(0u, surrounding_text.StartOffsetInContent());
@@ -122,8 +118,8 @@
   }
 
   {
-    VisibleSelection selection = Select(0, 5);
-    SurroundingText surrounding_text(FirstEphemeralRangeOf(selection), 5);
+    EphemeralRange selection = Select(0, 5);
+    SurroundingText surrounding_text(selection, 5);
 
     EXPECT_EQ("Lorem ip", surrounding_text.Content().SimplifyWhiteSpace());
     EXPECT_EQ(1u, surrounding_text.StartOffsetInContent());
@@ -131,8 +127,8 @@
   }
 
   {
-    VisibleSelection selection = Select(0, 5);
-    SurroundingText surrounding_text(FirstEphemeralRangeOf(selection), 42);
+    EphemeralRange selection = Select(0, 5);
+    SurroundingText surrounding_text(selection, 42);
 
     EXPECT_EQ("Lorem ipsum dolor sit amet",
               surrounding_text.Content().SimplifyWhiteSpace());
@@ -141,8 +137,8 @@
   }
 
   {
-    VisibleSelection selection = Select(6, 11);
-    SurroundingText surrounding_text(FirstEphemeralRangeOf(selection), 2);
+    EphemeralRange selection = Select(6, 11);
+    SurroundingText surrounding_text(selection, 2);
 
     EXPECT_EQ(" ipsum ", surrounding_text.Content());
     EXPECT_EQ(1u, surrounding_text.StartOffsetInContent());
@@ -150,8 +146,8 @@
   }
 
   {
-    VisibleSelection selection = Select(6, 11);
-    SurroundingText surrounding_text(FirstEphemeralRangeOf(selection), 42);
+    EphemeralRange selection = Select(6, 11);
+    SurroundingText surrounding_text(selection, 42);
 
     EXPECT_EQ("Lorem ipsum dolor sit amet",
               surrounding_text.Content().SimplifyWhiteSpace());
@@ -161,8 +157,8 @@
 
   {
     // Last word.
-    VisibleSelection selection = Select(22, 26);
-    SurroundingText surrounding_text(FirstEphemeralRangeOf(selection), 8);
+    EphemeralRange selection = Select(22, 26);
+    SurroundingText surrounding_text(selection, 8);
 
     EXPECT_EQ("sit amet", surrounding_text.Content());
     EXPECT_EQ(4u, surrounding_text.StartOffsetInContent());
@@ -176,8 +172,8 @@
              "selected node</div>"));
 
   {
-    VisibleSelection selection = Select(0);
-    SurroundingText surrounding_text(EphemeralRange(selection.Start()), 1);
+    EphemeralRange selection = Select(0);
+    SurroundingText surrounding_text(selection, 1);
 
     EXPECT_EQ("f", surrounding_text.Content());
     EXPECT_EQ(0u, surrounding_text.StartOffsetInContent());
@@ -185,8 +181,8 @@
   }
 
   {
-    VisibleSelection selection = Select(0);
-    SurroundingText surrounding_text(EphemeralRange(selection.Start()), 5);
+    EphemeralRange selection = Select(0);
+    SurroundingText surrounding_text(selection, 5);
 
     EXPECT_EQ("foo", surrounding_text.Content().SimplifyWhiteSpace());
     EXPECT_EQ(1u, surrounding_text.StartOffsetInContent());
@@ -194,8 +190,8 @@
   }
 
   {
-    VisibleSelection selection = Select(0);
-    SurroundingText surrounding_text(EphemeralRange(selection.Start()), 1337);
+    EphemeralRange selection = Select(0);
+    SurroundingText surrounding_text(selection, 1337);
 
     EXPECT_EQ("This is outside of foo bar the selected node",
               surrounding_text.Content().SimplifyWhiteSpace());
@@ -204,8 +200,8 @@
   }
 
   {
-    VisibleSelection selection = Select(6);
-    SurroundingText surrounding_text(EphemeralRange(selection.Start()), 2);
+    EphemeralRange selection = Select(6);
+    SurroundingText surrounding_text(selection, 2);
 
     EXPECT_EQ("ar", surrounding_text.Content());
     EXPECT_EQ(1u, surrounding_text.StartOffsetInContent());
@@ -213,8 +209,8 @@
   }
 
   {
-    VisibleSelection selection = Select(6);
-    SurroundingText surrounding_text(EphemeralRange(selection.Start()), 1337);
+    EphemeralRange selection = Select(6);
+    SurroundingText surrounding_text(selection, 1337);
 
     EXPECT_EQ("This is outside of foo bar the selected node",
               surrounding_text.Content().SimplifyWhiteSpace());
@@ -229,8 +225,8 @@
              "selected node</div>"));
 
   {
-    VisibleSelection selection = Select(0, 1);
-    SurroundingText surrounding_text(FirstEphemeralRangeOf(selection), 1);
+    EphemeralRange selection = Select(0, 1);
+    SurroundingText surrounding_text(selection, 1);
 
     EXPECT_EQ("fo", surrounding_text.Content().SimplifyWhiteSpace());
     EXPECT_EQ(0u, surrounding_text.StartOffsetInContent());
@@ -238,8 +234,8 @@
   }
 
   {
-    VisibleSelection selection = Select(0, 3);
-    SurroundingText surrounding_text(FirstEphemeralRangeOf(selection), 12);
+    EphemeralRange selection = Select(0, 3);
+    SurroundingText surrounding_text(selection, 12);
 
     EXPECT_EQ("e of foo bar", surrounding_text.Content().SimplifyWhiteSpace());
     EXPECT_EQ(5u, surrounding_text.StartOffsetInContent());
@@ -247,8 +243,8 @@
   }
 
   {
-    VisibleSelection selection = Select(0, 3);
-    SurroundingText surrounding_text(FirstEphemeralRangeOf(selection), 1337);
+    EphemeralRange selection = Select(0, 3);
+    SurroundingText surrounding_text(selection, 1337);
 
     EXPECT_EQ("This is outside of foo bar the selected node",
               surrounding_text.Content().SimplifyWhiteSpace());
@@ -257,8 +253,8 @@
   }
 
   {
-    VisibleSelection selection = Select(4, 7);
-    SurroundingText surrounding_text(FirstEphemeralRangeOf(selection), 12);
+    EphemeralRange selection = Select(4, 7);
+    SurroundingText surrounding_text(selection, 12);
 
     EXPECT_EQ("foo bar the se",
               surrounding_text.Content().SimplifyWhiteSpace());
@@ -267,8 +263,8 @@
   }
 
   {
-    VisibleSelection selection = Select(0, 7);
-    SurroundingText surrounding_text(FirstEphemeralRangeOf(selection), 1337);
+    EphemeralRange selection = Select(0, 7);
+    SurroundingText surrounding_text(selection, 1337);
 
     EXPECT_EQ("This is outside of foo bar the selected node",
               surrounding_text.Content().SimplifyWhiteSpace());
@@ -287,9 +283,9 @@
       (TextControlElement*)GetDocument().getElementById("selection");
 
   text_ctrl->SetSelectionRange(4, 7);
-  VisibleSelection selection = CreateVisibleSelection(text_ctrl->Selection());
+  EphemeralRange selection = text_ctrl->Selection().ComputeRange();
 
-  SurroundingText surrounding_text(FirstEphemeralRangeOf(selection), 20);
+  SurroundingText surrounding_text(selection, 20);
 
   EXPECT_EQ("abc def ghi", surrounding_text.Content().SimplifyWhiteSpace());
   EXPECT_EQ(4u, surrounding_text.StartOffsetInContent());
diff --git a/tools/gn/config.cc b/tools/gn/config.cc
index 953e677..e021fe4 100644
--- a/tools/gn/config.cc
+++ b/tools/gn/config.cc
@@ -8,8 +8,10 @@
 #include "tools/gn/input_file_manager.h"
 #include "tools/gn/scheduler.h"
 
-Config::Config(const Settings* settings, const Label& label)
-    : Item(settings, label), resolved_(false) {}
+Config::Config(const Settings* settings,
+               const Label& label,
+               const std::set<SourceFile>& build_dependency_files)
+    : Item(settings, label, build_dependency_files), resolved_(false) {}
 
 Config::~Config() = default;
 
diff --git a/tools/gn/config.h b/tools/gn/config.h
index 20cfe7e4..ad049737 100644
--- a/tools/gn/config.h
+++ b/tools/gn/config.h
@@ -5,6 +5,8 @@
 #ifndef TOOLS_GN_CONFIG_H_
 #define TOOLS_GN_CONFIG_H_
 
+#include <set>
+
 #include "base/logging.h"
 #include "base/macros.h"
 #include "tools/gn/config_values.h"
@@ -21,7 +23,11 @@
 // flags.
 class Config : public Item {
  public:
-  Config(const Settings* settings, const Label& label);
+  // We track the set of build files that may affect this config, please refer
+  // to Scope for how this is determined.
+  Config(const Settings* settings,
+         const Label& label,
+         const std::set<SourceFile>& build_dependency_files = {});
   ~Config() override;
 
   // Item implementation.
diff --git a/tools/gn/function_toolchain.cc b/tools/gn/function_toolchain.cc
index 9fcf1f6..230f77f 100644
--- a/tools/gn/function_toolchain.cc
+++ b/tools/gn/function_toolchain.cc
@@ -454,8 +454,8 @@
 
   // This object will actually be copied into the one owned by the toolchain
   // manager, but that has to be done in the lock.
-  std::unique_ptr<Toolchain> toolchain =
-      std::make_unique<Toolchain>(scope->settings(), label);
+  std::unique_ptr<Toolchain> toolchain = std::make_unique<Toolchain>(
+      scope->settings(), label, scope->build_dependency_files());
   toolchain->set_defined_from(function);
   toolchain->visibility().SetPublic();
 
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc
index 60a6eb7..38b3020 100644
--- a/tools/gn/functions.cc
+++ b/tools/gn/functions.cc
@@ -338,8 +338,8 @@
     g_scheduler->Log("Defining config", label.GetUserVisibleName(true));
 
   // Create the new config.
-  std::unique_ptr<Config> config =
-      std::make_unique<Config>(scope->settings(), label);
+  std::unique_ptr<Config> config = std::make_unique<Config>(
+      scope->settings(), label, scope->build_dependency_files());
   config->set_defined_from(function);
   if (!Visibility::FillItemVisibility(config.get(), scope, err))
     return Value();
@@ -633,6 +633,7 @@
   SourceFile import_file =
       input_dir.ResolveRelativeFile(args[0], err,
           scope->settings()->build_settings()->root_path_utf8());
+  scope->AddBuildDependencyFile(import_file);
   if (!err->has_error()) {
     scope->settings()->import_manager().DoImport(import_file, function,
                                                  scope, err);
@@ -910,7 +911,8 @@
   }
 
   // Create the new pool.
-  std::unique_ptr<Pool> pool = std::make_unique<Pool>(scope->settings(), label);
+  std::unique_ptr<Pool> pool = std::make_unique<Pool>(
+      scope->settings(), label, scope->build_dependency_files());
   pool->set_depth(depth->int_value());
 
   // Save the generated item.
diff --git a/tools/gn/item.cc b/tools/gn/item.cc
index 31abcdb..f36ff02 100644
--- a/tools/gn/item.cc
+++ b/tools/gn/item.cc
@@ -7,8 +7,13 @@
 #include "base/logging.h"
 #include "tools/gn/settings.h"
 
-Item::Item(const Settings* settings, const Label& label)
-    : settings_(settings), label_(label), defined_from_(nullptr) {}
+Item::Item(const Settings* settings,
+           const Label& label,
+           const std::set<SourceFile>& build_dependency_files)
+    : settings_(settings),
+      label_(label),
+      build_dependency_files_(build_dependency_files),
+      defined_from_(nullptr) {}
 
 Item::~Item() = default;
 
diff --git a/tools/gn/item.h b/tools/gn/item.h
index 3ec482a..9195b5e 100644
--- a/tools/gn/item.h
+++ b/tools/gn/item.h
@@ -5,15 +5,18 @@
 #ifndef TOOLS_GN_ITEM_H_
 #define TOOLS_GN_ITEM_H_
 
+#include <set>
 #include <string>
 
 #include "tools/gn/label.h"
+#include "tools/gn/source_file.h"
 #include "tools/gn/visibility.h"
 
 class Config;
 class ParseNode;
 class Pool;
 class Settings;
+class SourceFile;
 class Target;
 class Toolchain;
 
@@ -21,7 +24,9 @@
 // graph.
 class Item {
  public:
-  Item(const Settings* settings, const Label& label);
+  Item(const Settings* settings,
+       const Label& label,
+       const std::set<SourceFile>& build_dependency_files = {});
   virtual ~Item();
 
   const Settings* settings() const { return settings_; }
@@ -50,6 +55,12 @@
   // be used in logging and error messages.
   std::string GetItemTypeName() const;
 
+  // Returns the set of build files that may affect this item, please refer to
+  // Scope for how this is determined.
+  const std::set<SourceFile>& build_dependency_files() const {
+    return build_dependency_files_;
+  }
+
   // Called when this item is resolved, meaning it and all of its dependents
   // have no unresolved deps. Returns true on success. Sets the error and
   // returns false on failure.
@@ -58,6 +69,7 @@
  private:
   const Settings* settings_;
   Label label_;
+  const std::set<SourceFile> build_dependency_files_;
   const ParseNode* defined_from_;
 
   Visibility visibility_;
diff --git a/tools/gn/loader.cc b/tools/gn/loader.cc
index 616a224..2e10c9a 100644
--- a/tools/gn/loader.cc
+++ b/tools/gn/loader.cc
@@ -24,9 +24,7 @@
 
 struct SourceFileAndOrigin {
   SourceFileAndOrigin(const SourceFile& f, const LocationRange& o)
-      : file(f),
-        origin(o) {
-  }
+      : file(f), origin(o) {}
 
   SourceFile file;
   LocationRange origin;
@@ -39,9 +37,7 @@
 struct LoaderImpl::LoadID {
   LoadID() = default;
   LoadID(const SourceFile& f, const Label& tc_name)
-      : file(f),
-        toolchain_name(tc_name) {
-  }
+      : file(f), toolchain_name(tc_name) {}
 
   bool operator<(const LoadID& other) const {
     if (file.value() == other.file.value())
@@ -61,9 +57,10 @@
   ToolchainRecord(const BuildSettings* build_settings,
                   const Label& toolchain_label,
                   const Label& default_toolchain_label)
-      : settings(build_settings,
-                 GetOutputSubdirName(toolchain_label,
-                     toolchain_label == default_toolchain_label)),
+      : settings(
+            build_settings,
+            GetOutputSubdirName(toolchain_label,
+                                toolchain_label == default_toolchain_label)),
         is_toolchain_loaded(false),
         is_config_loaded(false) {
     settings.set_default_toolchain_label(default_toolchain_label);
@@ -111,7 +108,8 @@
                       const LocationRange& origin,
                       const Label& in_toolchain_name) {
   const Label& toolchain_name = in_toolchain_name.is_null()
-      ? default_toolchain_label_ : in_toolchain_name;
+                                    ? default_toolchain_label_
+                                    : in_toolchain_name;
   LoadID load_id(file, toolchain_name);
   if (!invocations_.insert(load_id).second)
     return;  // Already in set, so this file was already loaded or schedulerd.
@@ -253,6 +251,7 @@
   Scope our_scope(settings->base_config());
   ScopePerFileProvider per_file_provider(&our_scope, true);
   our_scope.set_source_dir(file_name.GetDir());
+  our_scope.AddBuildDependencyFile(file_name);
 
   // Targets, etc. generated as part of running this file will end up here.
   Scope::ItemVector collected_items;
@@ -294,9 +293,11 @@
 
   Scope* base_config = settings->base_config();
   base_config->set_source_dir(SourceDir("//"));
+  base_config->AddBuildDependencyFile(
+      settings->build_settings()->build_config_file());
 
-  settings->build_settings()->build_args().SetupRootScope(
-      base_config, toolchain_overrides);
+  settings->build_settings()->build_args().SetupRootScope(base_config,
+                                                          toolchain_overrides);
 
   base_config->SetProcessingBuildConfig();
 
@@ -306,7 +307,7 @@
     base_config->SetProperty(kDefaultToolchainKey, &default_toolchain_label);
 
   ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE,
-      settings->build_settings()->build_config_file().value());
+                    settings->build_settings()->build_config_file().value());
   trace.SetToolchain(settings->toolchain_label());
 
   Err err;
@@ -327,7 +328,8 @@
     // The default toolchain must have been set in the default build config
     // file.
     if (default_toolchain_label.is_null()) {
-      g_scheduler->FailWithError(Err(Location(),
+      g_scheduler->FailWithError(Err(
+          Location(),
           "The default build config file did not call set_default_toolchain()",
           "If you don't call this, I can't figure out what toolchain to use\n"
           "for all of this code."));
@@ -423,6 +425,5 @@
     return g_scheduler->input_file_manager()->AsyncLoadFile(
         origin, build_settings, file_name, callback, err);
   }
-  return async_load_file_.Run(
-      origin, build_settings, file_name, callback, err);
+  return async_load_file_.Run(origin, build_settings, file_name, callback, err);
 }
diff --git a/tools/gn/loader_unittest.cc b/tools/gn/loader_unittest.cc
index 8f51a42..4b240c32 100644
--- a/tools/gn/loader_unittest.cc
+++ b/tools/gn/loader_unittest.cc
@@ -20,6 +20,35 @@
 
 namespace {
 
+bool ItemContainsBuildDependencyFile(const Item* item,
+                                     const SourceFile& source_file) {
+  const auto& build_dependency_files = item->build_dependency_files();
+  return build_dependency_files.end() !=
+         build_dependency_files.find(source_file);
+}
+
+class MockBuilder {
+ public:
+  void OnItemDefined(std::unique_ptr<Item> item);
+  std::vector<const Item*> GetAllItems() const;
+
+ private:
+  std::vector<std::unique_ptr<Item>> items_;
+};
+
+void MockBuilder::OnItemDefined(std::unique_ptr<Item> item) {
+  items_.push_back(std::move(item));
+}
+
+std::vector<const Item*> MockBuilder::GetAllItems() const {
+  std::vector<const Item*> result;
+  for (const auto& item : items_) {
+    result.push_back(item.get());
+  }
+
+  return result;
+}
+
 class MockInputFileManager {
  public:
   typedef base::Callback<void(const ParseNode*)> Callback;
@@ -119,6 +148,7 @@
  protected:
   Scheduler scheduler_;
   BuildSettings build_settings_;
+  MockBuilder mock_builder_;
   MockInputFileManager mock_ifm_;
 };
 
@@ -184,3 +214,51 @@
 
   EXPECT_FALSE(scheduler_.is_failed());
 }
+
+TEST_F(LoaderTest, BuildDependencyFilesAreCollected) {
+  SourceFile build_config("//build/config/BUILDCONFIG.gn");
+  SourceFile root_build("//BUILD.gn");
+  build_settings_.set_build_config_file(build_config);
+  build_settings_.set_item_defined_callback(base::Bind(
+      &MockBuilder::OnItemDefined, base::Unretained(&mock_builder_)));
+
+  scoped_refptr<LoaderImpl> loader(new LoaderImpl(&build_settings_));
+  mock_ifm_.AddCannedResponse(build_config,
+                              "set_default_toolchain(\"//tc:tc\")");
+  mock_ifm_.AddCannedResponse(SourceFile("//test.gni"), "concurrent_jobs = 1");
+  std::string root_build_content =
+      "executable(\"a\") { sources = [ \"a.cc\" ] }\n"
+      "config(\"b\") { configs = [\"//t:t\"] }\n"
+      "toolchain(\"c\") {}\n"
+      "pool(\"d\") { depth = 1 }";
+  mock_ifm_.AddCannedResponse(root_build, root_build_content);
+
+  loader->set_async_load_file(mock_ifm_.GetCallback());
+
+  // Request the root build file be loaded. This should kick off the default
+  // build config loading.
+  loader->Load(root_build, LocationRange(), Label());
+  EXPECT_TRUE(mock_ifm_.HasOnePending(build_config));
+
+  // Completing the build config load should kick off the root build file load.
+  mock_ifm_.IssueAllPending();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(mock_ifm_.HasOnePending(root_build));
+
+  // Completing the root build file should define a target which must have
+  // set of source files hashes.
+  mock_ifm_.IssueAllPending();
+  base::RunLoop().RunUntilIdle();
+
+  std::vector<const Item*> items = mock_builder_.GetAllItems();
+  EXPECT_TRUE(items[0]->AsTarget());
+  EXPECT_TRUE(ItemContainsBuildDependencyFile(items[0], root_build));
+  EXPECT_TRUE(items[1]->AsConfig());
+  EXPECT_TRUE(ItemContainsBuildDependencyFile(items[1], root_build));
+  EXPECT_TRUE(items[2]->AsToolchain());
+  EXPECT_TRUE(ItemContainsBuildDependencyFile(items[2], root_build));
+  EXPECT_TRUE(items[3]->AsPool());
+  EXPECT_TRUE(ItemContainsBuildDependencyFile(items[3], root_build));
+
+  EXPECT_FALSE(scheduler_.is_failed());
+}
diff --git a/tools/gn/scope.cc b/tools/gn/scope.cc
index 444ce53..145d6ad7 100644
--- a/tools/gn/scope.cc
+++ b/tools/gn/scope.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "tools/gn/parse_tree.h"
+#include "tools/gn/source_file.h"
 #include "tools/gn/template.h"
 
 namespace {
@@ -30,8 +31,7 @@
 Scope::MergeOptions::MergeOptions()
     : clobber_existing(false),
       skip_private_vars(false),
-      mark_dest_used(false) {
-}
+      mark_dest_used(false) {}
 
 Scope::MergeOptions::~MergeOptions() = default;
 
@@ -51,14 +51,16 @@
       mutable_containing_(parent),
       settings_(parent->settings()),
       mode_flags_(0),
-      item_collector_(nullptr) {}
+      item_collector_(nullptr),
+      build_dependency_files_(parent->build_dependency_files_) {}
 
 Scope::Scope(const Scope* parent)
     : const_containing_(parent),
       mutable_containing_(nullptr),
       settings_(parent->settings()),
       mode_flags_(0),
-      item_collector_(nullptr) {}
+      item_collector_(nullptr),
+      build_dependency_files_(parent->build_dependency_files_) {}
 
 Scope::~Scope() = default;
 
@@ -121,8 +123,8 @@
 
   // Search in the parent mutable scope if requested, but not const one.
   if (search_mode == SEARCH_NESTED && mutable_containing_) {
-    return mutable_containing_->GetMutableValue(
-        ident, Scope::SEARCH_NESTED, counts_as_used);
+    return mutable_containing_->GetMutableValue(ident, Scope::SEARCH_NESTED,
+                                                counts_as_used);
   }
   return nullptr;
 }
@@ -247,7 +249,8 @@
 bool Scope::CheckForUnusedVars(Err* err) const {
   for (const auto& pair : values_) {
     if (!pair.second.used) {
-      std::string help = "You set the variable \"" + pair.first.as_string() +
+      std::string help =
+          "You set the variable \"" + pair.first.as_string() +
           "\" here and it was unused before it went\nout of scope.";
 
       const BinaryOpNode* binary = pair.second.value.origin()->AsBinaryOp();
@@ -294,13 +297,16 @@
         // Value present in both the source and the dest.
         std::string desc_string(desc_for_err);
         *err = Err(node_for_err, "Value collision.",
-            "This " + desc_string + " contains \"" + current_name.as_string() +
-            "\"");
-        err->AppendSubErr(Err(pair.second.value, "defined here.",
-            "Which would clobber the one in your current scope"));
-        err->AppendSubErr(Err(*existing_value, "defined here.",
-            "Executing " + desc_string + " should not conflict with anything "
-            "in the current\nscope unless the values are identical."));
+                   "This " + desc_string + " contains \"" +
+                       current_name.as_string() + "\"");
+        err->AppendSubErr(
+            Err(pair.second.value, "defined here.",
+                "Which would clobber the one in your current scope"));
+        err->AppendSubErr(
+            Err(*existing_value, "defined here.",
+                "Executing " + desc_string +
+                    " should not conflict with anything "
+                    "in the current\nscope unless the values are identical."));
         return false;
       }
     }
@@ -333,12 +339,18 @@
           // target defaults.
           std::string desc_string(desc_for_err);
           *err = Err(node_for_err, "Target defaults collision.",
-              "This " + desc_string + " contains target defaults for\n"
-              "\"" + current_name + "\" which would clobber one for the\n"
-              "same target type in your current scope. It's unfortunate that "
-              "I'm too stupid\nto tell you the location of where the target "
-              "defaults were set. Usually\nthis happens in the BUILDCONFIG.gn "
-              "file or in a related .gni file.\n");
+                     "This " + desc_string +
+                         " contains target defaults for\n"
+                         "\"" +
+                         current_name +
+                         "\" which would clobber one for the\n"
+                         "same target type in your current scope. It's "
+                         "unfortunate that "
+                         "I'm too stupid\nto tell you the location of where "
+                         "the target "
+                         "defaults were set. Usually\nthis happens in the "
+                         "BUILDCONFIG.gn "
+                         "file or in a related .gni file.\n");
           return false;
         }
       }
@@ -357,8 +369,9 @@
         // Sources assignment filter present in both the source and the dest.
         std::string desc_string(desc_for_err);
         *err = Err(node_for_err, "Assignment filter collision.",
-            "The " + desc_string + " contains a sources_assignment_filter "
-            "which\nwould clobber the one in your current scope.");
+                   "The " + desc_string +
+                       " contains a sources_assignment_filter "
+                       "which\nwould clobber the one in your current scope.");
         return false;
       }
     }
@@ -386,15 +399,16 @@
         // same one.
         std::string desc_string(desc_for_err);
         *err = Err(node_for_err, "Template collision.",
-            "This " + desc_string + " contains a template \"" +
-            current_name + "\"");
-        err->AppendSubErr(Err(pair.second->GetDefinitionRange(),
-            "defined here.",
-            "Which would clobber the one in your current scope"));
+                   "This " + desc_string + " contains a template \"" +
+                       current_name + "\"");
+        err->AppendSubErr(
+            Err(pair.second->GetDefinitionRange(), "defined here.",
+                "Which would clobber the one in your current scope"));
         err->AppendSubErr(Err(existing_template->GetDefinitionRange(),
-            "defined here.",
-            "Executing " + desc_string + " should not conflict with anything "
-            "in the current\nscope."));
+                              "defined here.",
+                              "Executing " + desc_string +
+                                  " should not conflict with anything "
+                                  "in the current\nscope."));
         return false;
       }
     }
@@ -403,6 +417,10 @@
     dest->templates_[current_name] = pair.second;
   }
 
+  // Propogate build dependency files,
+  dest->build_dependency_files_.insert(build_dependency_files_.begin(),
+                                       build_dependency_files_.end());
+
   return true;
 }
 
@@ -501,6 +519,10 @@
   return source_dir_;
 }
 
+void Scope::AddBuildDependencyFile(const SourceFile& build_dependency_file) {
+  build_dependency_files_.insert(build_dependency_file);
+}
+
 Scope::ItemVector* Scope::GetItemCollector() {
   if (item_collector_)
     return item_collector_;
diff --git a/tools/gn/scope.h b/tools/gn/scope.h
index 8ad14ed..9e683d2 100644
--- a/tools/gn/scope.h
+++ b/tools/gn/scope.h
@@ -22,6 +22,7 @@
 class Item;
 class ParseNode;
 class Settings;
+class SourceFile;
 class Template;
 
 // Scope for the script execution.
@@ -284,6 +285,15 @@
   const SourceDir& GetSourceDir() const;
   void set_source_dir(const SourceDir& d) { source_dir_ = d; }
 
+  // Set of files that may affect the execution of this scope. Note that this
+  // set is constructed conservatively, meanining that every file that can
+  // potentially affect this scope is included, but not necessarily every change
+  // to these files will affect this scope.
+  const std::set<SourceFile>& build_dependency_files() const {
+    return build_dependency_files_;
+  }
+  void AddBuildDependencyFile(const SourceFile& build_dependency_file);
+
   // The item collector is where Items (Targets, Configs, etc.) go that have
   // been defined. If a scope can generate items, this non-owning pointer will
   // point to the storage for such items. The creator of this scope will be
@@ -379,6 +389,8 @@
 
   SourceDir source_dir_;
 
+  std::set<SourceFile> build_dependency_files_;
+
   DISALLOW_COPY_AND_ASSIGN(Scope);
 };
 
diff --git a/tools/gn/scope_unittest.cc b/tools/gn/scope_unittest.cc
index a90d725..ce3fe0b1 100644
--- a/tools/gn/scope_unittest.cc
+++ b/tools/gn/scope_unittest.cc
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "tools/gn/scope.h"
+
 #include "testing/gtest/include/gtest/gtest.h"
 #include "tools/gn/input_file.h"
 #include "tools/gn/parse_tree.h"
-#include "tools/gn/scope.h"
+#include "tools/gn/source_file.h"
 #include "tools/gn/template.h"
 #include "tools/gn/test_with_scope.h"
 
@@ -22,8 +24,25 @@
   return value->string_value() == expected_value;
 }
 
+bool ContainsBuildDependencyFile(const Scope* scope,
+                                 const SourceFile& source_file) {
+  const auto& build_dependency_files = scope->build_dependency_files();
+  return build_dependency_files.end() !=
+         build_dependency_files.find(source_file);
+}
+
 }  // namespace
 
+TEST(Scope, InheritBuildDependencyFilesFromParent) {
+  TestWithScope setup;
+  SourceFile source_file = SourceFile("//a/BUILD.gn");
+  setup.scope()->AddBuildDependencyFile(source_file);
+
+  Scope new_scope(setup.scope());
+  EXPECT_EQ(1U, new_scope.build_dependency_files().size());
+  EXPECT_TRUE(ContainsBuildDependencyFile(&new_scope, source_file));
+}
+
 TEST(Scope, NonRecursiveMergeTo) {
   TestWithScope setup;
 
@@ -192,6 +211,24 @@
     EXPECT_TRUE(new_scope.CheckForUnusedVars(&err));
     EXPECT_FALSE(err.has_error());
   }
+
+  // Build dependency files are merged.
+  {
+    Scope from_scope(setup.settings());
+    SourceFile source_file = SourceFile("//a/BUILD.gn");
+    from_scope.AddBuildDependencyFile(source_file);
+
+    Scope to_scope(setup.settings());
+    EXPECT_FALSE(ContainsBuildDependencyFile(&to_scope, source_file));
+
+    Scope::MergeOptions options;
+    Err err;
+    EXPECT_TRUE(from_scope.NonRecursiveMergeTo(&to_scope, options, &assignment,
+                                               "error", &err));
+    EXPECT_FALSE(err.has_error());
+    EXPECT_EQ(1U, to_scope.build_dependency_files().size());
+    EXPECT_TRUE(ContainsBuildDependencyFile(&to_scope, source_file));
+  }
 }
 
 TEST(Scope, MakeClosure) {
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index dea3eae..9bb0b71 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -690,6 +690,7 @@
     return false;
   }
 
+  dotfile_scope_.AddBuildDependencyFile(SourceFile("//.gn"));
   dotfile_root_->Execute(&dotfile_scope_, &err);
   if (err.has_error()) {
     err.PrintToStdout();
diff --git a/tools/gn/target.cc b/tools/gn/target.cc
index d65e2658..5c5ff5c9 100644
--- a/tools/gn/target.cc
+++ b/tools/gn/target.cc
@@ -273,8 +273,10 @@
   future, do not rely on this behavior.
 )";
 
-Target::Target(const Settings* settings, const Label& label)
-    : Item(settings, label),
+Target::Target(const Settings* settings,
+               const Label& label,
+               const std::set<SourceFile>& build_dependency_files)
+    : Item(settings, label, build_dependency_files),
       output_type_(UNKNOWN),
       output_prefix_override_(false),
       output_extension_set_(false),
diff --git a/tools/gn/target.h b/tools/gn/target.h
index 1890a535..2c9dc35 100644
--- a/tools/gn/target.h
+++ b/tools/gn/target.h
@@ -55,7 +55,11 @@
   typedef std::vector<SourceFile> FileList;
   typedef std::vector<std::string> StringVector;
 
-  Target(const Settings* settings, const Label& label);
+  // We track the set of build files that may affect this target, please refer
+  // to Scope for how this is determined.
+  Target(const Settings* settings,
+         const Label& label,
+         const std::set<SourceFile>& build_dependency_files = {});
   ~Target() override;
 
   // Returns a string naming the output type.
diff --git a/tools/gn/target_generator.cc b/tools/gn/target_generator.cc
index 114bca7..c441f04f 100644
--- a/tools/gn/target_generator.cc
+++ b/tools/gn/target_generator.cc
@@ -90,8 +90,8 @@
   if (g_scheduler->verbose_logging())
     g_scheduler->Log("Defining target", label.GetUserVisibleName(true));
 
-  std::unique_ptr<Target> target =
-      std::make_unique<Target>(scope->settings(), label);
+  std::unique_ptr<Target> target = std::make_unique<Target>(
+      scope->settings(), label, scope->build_dependency_files());
   target->set_defined_from(function_call);
 
   // Create and call out to the proper generator.
diff --git a/tools/gn/toolchain.cc b/tools/gn/toolchain.cc
index ec02b3e..879acd94 100644
--- a/tools/gn/toolchain.cc
+++ b/tools/gn/toolchain.cc
@@ -28,8 +28,10 @@
 const char* Toolchain::kToolCompileXCAssets = "compile_xcassets";
 const char* Toolchain::kToolAction = "action";
 
-Toolchain::Toolchain(const Settings* settings, const Label& label)
-    : Item(settings, label), setup_complete_(false) {}
+Toolchain::Toolchain(const Settings* settings,
+                     const Label& label,
+                     const std::set<SourceFile>& build_dependency_files)
+    : Item(settings, label, build_dependency_files), setup_complete_(false) {}
 
 Toolchain::~Toolchain() = default;
 
diff --git a/tools/gn/toolchain.h b/tools/gn/toolchain.h
index 368c2db..1e9bc2e 100644
--- a/tools/gn/toolchain.h
+++ b/tools/gn/toolchain.h
@@ -77,7 +77,12 @@
   // Loader::GetToolchainSettings(). Many toolchain objects may be created in a
   // given build, but only a few might be used, and the Loader is in charge of
   // this process.
-  Toolchain(const Settings* settings, const Label& label);
+  //
+  // We also track the set of build files that may affect this target, please
+  // refer to Scope for how this is determined.
+  Toolchain(const Settings* settings,
+            const Label& label,
+            const std::set<SourceFile>& build_dependency_files = {});
   ~Toolchain() override;
 
   // Item overrides.
diff --git a/ui/display/display_layout.cc b/ui/display/display_layout.cc
index 89b9719..814e252 100644
--- a/ui/display/display_layout.cc
+++ b/ui/display/display_layout.cc
@@ -474,7 +474,7 @@
 // DisplayLayout
 
 DisplayLayout::DisplayLayout()
-    : mirrored(false), default_unified(true), primary_id(kInvalidDisplayId) {}
+    : default_unified(true), primary_id(kInvalidDisplayId) {}
 
 DisplayLayout::~DisplayLayout() {}
 
@@ -578,7 +578,6 @@
   std::unique_ptr<DisplayLayout> copy(new DisplayLayout);
   for (const auto& placement : placement_list)
     copy->placement_list.push_back(placement);
-  copy->mirrored = mirrored;
   copy->default_unified = default_unified;
   copy->primary_id = primary_id;
   return copy;
@@ -612,8 +611,6 @@
 std::string DisplayLayout::ToString() const {
   std::stringstream s;
   s << "primary=" << primary_id;
-  if (mirrored)
-    s << ", mirrored";
   if (default_unified)
     s << ", default_unified";
   bool added = false;
diff --git a/ui/display/display_layout.h b/ui/display/display_layout.h
index 9a59d32f..e269d589 100644
--- a/ui/display/display_layout.h
+++ b/ui/display/display_layout.h
@@ -100,10 +100,6 @@
 
   std::vector<DisplayPlacement> placement_list;
 
-  // TODO(crbug.com/791881) Remove this variable and related code.
-  // True if displays are mirrored.
-  bool mirrored;
-
   // True if multi displays should default to unified mode.
   bool default_unified;
 
diff --git a/ui/display/display_layout_builder.cc b/ui/display/display_layout_builder.cc
index add0d386..fc77eb40 100644
--- a/ui/display/display_layout_builder.cc
+++ b/ui/display/display_layout_builder.cc
@@ -26,11 +26,6 @@
   return *this;
 }
 
-DisplayLayoutBuilder& DisplayLayoutBuilder::SetMirrored(bool mirrored) {
-  layout_->mirrored = mirrored;
-  return *this;
-}
-
 DisplayLayoutBuilder& DisplayLayoutBuilder::ClearPlacements() {
   layout_->placement_list.clear();
   return *this;
diff --git a/ui/display/manager/display_layout_store.cc b/ui/display/manager/display_layout_store.cc
index 5a69e56..d9913a1 100644
--- a/ui/display/manager/display_layout_store.cc
+++ b/ui/display/manager/display_layout_store.cc
@@ -86,12 +86,6 @@
   layouts_[list] = std::move(layout);
 }
 
-bool DisplayLayoutStore::GetMirrorMode(const DisplayIdList& list) {
-  if (forced_mirror_mode_)
-    return true;
-  return GetRegisteredDisplayLayout(list).mirrored;
-}
-
 const DisplayLayout& DisplayLayoutStore::GetRegisteredDisplayLayout(
     const DisplayIdList& list) {
   DCHECK_GT(list.size(), 1u);
@@ -104,19 +98,12 @@
   return *layout;
 }
 
-void DisplayLayoutStore::UpdateMultiDisplayState(const DisplayIdList& list,
-                                                 bool mirrored,
-                                                 bool default_unified) {
+void DisplayLayoutStore::UpdateDefaultUnified(const DisplayIdList& list,
+                                              bool default_unified) {
   DCHECK(layouts_.find(list) != layouts_.end());
   if (layouts_.find(list) == layouts_.end())
     CreateDefaultDisplayLayout(list);
 
-  if (!forced_mirror_mode_) {
-    // Don't remember the mirrored status if it's forced by the
-    // force_mirror_mode_ flag because it'll always be mirrored
-    // regardless of the user setting.
-    layouts_[list]->mirrored = mirrored;
-  }
   layouts_[list]->default_unified = default_unified;
 }
 
diff --git a/ui/display/manager/display_layout_store.h b/ui/display/manager/display_layout_store.h
index d8243b3..878e4cd 100644
--- a/ui/display/manager/display_layout_store.h
+++ b/ui/display/manager/display_layout_store.h
@@ -33,19 +33,15 @@
   void RegisterLayoutForDisplayIdList(const DisplayIdList& list,
                                       std::unique_ptr<DisplayLayout> layout);
 
-  // Returns true if it should enter mirror mode for given display |list|.
-  bool GetMirrorMode(const DisplayIdList& list);
-
   // If no layout is registered, it creatas new layout using
   // |default_display_layout_|.
   const DisplayLayout& GetRegisteredDisplayLayout(const DisplayIdList& list);
 
-  // Update the multi display state in the display layout for
+  // Update the default unified desktop mode in the display layout for
   // |display_list|.  This creates new display layout if no layout is
   // registered for |display_list|.
-  void UpdateMultiDisplayState(const DisplayIdList& display_list,
-                               bool mirrored,
-                               bool default_unified);
+  void UpdateDefaultUnified(const DisplayIdList& display_list,
+                            bool default_unified);
 
  private:
   // Creates new layout for display list from |default_display_layout_|.
diff --git a/ui/display/manager/display_manager.cc b/ui/display/manager/display_manager.cc
index db76846..412c49d 100644
--- a/ui/display/manager/display_manager.cc
+++ b/ui/display/manager/display_manager.cc
@@ -1413,8 +1413,7 @@
     MultiDisplayMode mode) {
   DCHECK_NE(MIRRORING, mode);
   DisplayIdList list = GetCurrentDisplayIdList();
-  layout_store_->UpdateMultiDisplayState(list, IsInMirrorMode(),
-                                         mode == UNIFIED);
+  layout_store_->UpdateDefaultUnified(list, mode == UNIFIED);
   ReconfigureDisplays();
 }
 
diff --git a/ui/display/manager/json_converter.cc b/ui/display/manager/json_converter.cc
index 2520d1d..1d4c0a4 100644
--- a/ui/display/manager/json_converter.cc
+++ b/ui/display/manager/json_converter.cc
@@ -18,7 +18,6 @@
 namespace {
 
 // Persistent key names
-const char kMirroredKey[] = "mirrored";
 const char kDefaultUnifiedKey[] = "default_unified";
 const char kPrimaryIdKey[] = "primary-id";
 const char kDisplayPlacementKey[] = "display_placement";
@@ -151,8 +150,7 @@
   if (!value.GetAsDictionary(&dict_value))
     return false;
 
-  if (!UpdateFromDict(dict_value, kMirroredKey, &layout->mirrored) ||
-      !UpdateFromDict(dict_value, kDefaultUnifiedKey,
+  if (!UpdateFromDict(dict_value, kDefaultUnifiedKey,
                       &layout->default_unified) ||
       !UpdateFromDict(dict_value, kPrimaryIdKey, &layout->primary_id)) {
     return false;
@@ -172,7 +170,6 @@
   if (!value->GetAsDictionary(&dict_value))
     return false;
 
-  dict_value->SetBoolean(kMirroredKey, layout.mirrored);
   dict_value->SetBoolean(kDefaultUnifiedKey, layout.default_unified);
   dict_value->SetString(kPrimaryIdKey, base::Int64ToString(layout.primary_id));
 
diff --git a/ui/display/manager/json_converter_unittest.cc b/ui/display/manager/json_converter_unittest.cc
index ec30d51..071f3cc 100644
--- a/ui/display/manager/json_converter_unittest.cc
+++ b/ui/display/manager/json_converter_unittest.cc
@@ -16,7 +16,6 @@
 TEST(JsonConverterTest, JsonFromToDisplayLayout) {
   DisplayLayout layout;
   layout.primary_id = 1;
-  layout.mirrored = true;
   layout.default_unified = false;
   layout.placement_list.push_back(DisplayPlacement());
   layout.placement_list.push_back(DisplayPlacement());
@@ -35,7 +34,6 @@
   const char data[] =
       "{\n"
       "  \"primary-id\": \"1\",\n"
-      "  \"mirrored\": true,\n"
       "  \"default_unified\": false,\n"
       "  \"display_placement\": [{\n"
       "    \"display_id\": \"2\",\n"
@@ -59,7 +57,6 @@
 
   DisplayLayout read_layout;
   EXPECT_TRUE(JsonToDisplayLayout(*read_value, &read_layout));
-  EXPECT_EQ(read_layout.mirrored, layout.mirrored);
   EXPECT_EQ(read_layout.primary_id, layout.primary_id);
   EXPECT_EQ(read_layout.default_unified, layout.default_unified);
   EXPECT_TRUE(read_layout.HasSamePlacementList(layout));
@@ -69,7 +66,6 @@
   const char data[] =
       "{\n"
       "  \"primary-id\": \"1\",\n"
-      "  \"mirrored\": true,\n"
       "  \"default_unified\": false,\n"
       "  \"position\": \"bottom\",\n"
       "  \"offset\": 20\n"
@@ -83,7 +79,6 @@
 
   DisplayLayout read_layout;
   EXPECT_TRUE(JsonToDisplayLayout(*read_value, &read_layout));
-  EXPECT_EQ(true, read_layout.mirrored);
   EXPECT_EQ(1, read_layout.primary_id);
   EXPECT_FALSE(read_layout.default_unified);
   ASSERT_EQ(1u, read_layout.placement_list.size());
diff --git a/ui/display/mojo/display_layout.mojom b/ui/display/mojo/display_layout.mojom
index e2a1e92c..77d3c50 100644
--- a/ui/display/mojo/display_layout.mojom
+++ b/ui/display/mojo/display_layout.mojom
@@ -29,7 +29,6 @@
 
 // Corresponds to display::DisplayLayout.
 struct DisplayLayout {
-  bool mirrored;
   bool default_unified;
   int64 primary_display_id;
   array<DisplayPlacement> placement_list;
diff --git a/ui/display/mojo/display_layout_struct_traits.cc b/ui/display/mojo/display_layout_struct_traits.cc
index bd9086c..24a9d87 100644
--- a/ui/display/mojo/display_layout_struct_traits.cc
+++ b/ui/display/mojo/display_layout_struct_traits.cc
@@ -98,7 +98,6 @@
   if (!data.ReadPlacementList(&display_layout->placement_list))
     return false;
 
-  display_layout->mirrored = data.mirrored();
   display_layout->default_unified = data.default_unified();
   display_layout->primary_id = data.primary_display_id();
 
diff --git a/ui/display/mojo/display_layout_struct_traits.h b/ui/display/mojo/display_layout_struct_traits.h
index 1b9c453..45b109ad 100644
--- a/ui/display/mojo/display_layout_struct_traits.h
+++ b/ui/display/mojo/display_layout_struct_traits.h
@@ -63,10 +63,6 @@
 template <>
 struct StructTraits<display::mojom::DisplayLayoutDataView,
                     std::unique_ptr<display::DisplayLayout>> {
-  static bool mirrored(const std::unique_ptr<display::DisplayLayout>& layout) {
-    return layout->mirrored;
-  }
-
   static bool default_unified(
       const std::unique_ptr<display::DisplayLayout>& layout) {
     return layout->default_unified;
diff --git a/ui/display/mojo/display_struct_traits_unittest.cc b/ui/display/mojo/display_struct_traits_unittest.cc
index 7dce3b3..3dd7d2e38 100644
--- a/ui/display/mojo/display_struct_traits_unittest.cc
+++ b/ui/display/mojo/display_struct_traits_unittest.cc
@@ -50,7 +50,6 @@
                               const DisplayLayout& output) {
   EXPECT_NE(&input, &output);  // Make sure they aren't the same object.
   EXPECT_EQ(input.placement_list, output.placement_list);
-  EXPECT_EQ(input.mirrored, output.mirrored);
   EXPECT_EQ(input.default_unified, output.default_unified);
   EXPECT_EQ(input.primary_id, output.primary_id);
 }
@@ -193,7 +192,6 @@
   auto input = std::make_unique<DisplayLayout>();
   input->placement_list.push_back(placement);
   input->primary_id = kDisplayId2;
-  input->mirrored = false;
   input->default_unified = true;
 
   std::unique_ptr<DisplayLayout> output;
@@ -221,7 +219,6 @@
   input->placement_list.push_back(placement1);
   input->placement_list.push_back(placement2);
   input->primary_id = kDisplayId1;
-  input->mirrored = false;
   input->default_unified = false;
 
   std::unique_ptr<DisplayLayout> output;
@@ -230,26 +227,6 @@
   CheckDisplayLayoutsEqual(*input, *output);
 }
 
-TEST(DisplayStructTraitsTest, DisplayLayoutTwoMirrored) {
-  DisplayPlacement placement;
-  placement.display_id = kDisplayId1;
-  placement.parent_display_id = kDisplayId2;
-  placement.position = DisplayPlacement::RIGHT;
-  placement.offset = 0;
-  placement.offset_reference = DisplayPlacement::TOP_LEFT;
-
-  auto input = std::make_unique<DisplayLayout>();
-  input->placement_list.push_back(placement);
-  input->primary_id = kDisplayId2;
-  input->mirrored = true;
-  input->default_unified = true;
-
-  std::unique_ptr<DisplayLayout> output;
-  SerializeAndDeserialize<mojom::DisplayLayout>(input->Copy(), &output);
-
-  CheckDisplayLayoutsEqual(*input, *output);
-}
-
 TEST(DisplayStructTraitsTest, BasicGammaRampRGBEntry) {
   const GammaRampRGBEntry input{259, 81, 16};
 
diff --git a/ui/events/ozone/device/device_manager_manual.cc b/ui/events/ozone/device/device_manager_manual.cc
index c4a7099..8010870a 100644
--- a/ui/events/ozone/device/device_manager_manual.cc
+++ b/ui/events/ozone/device/device_manager_manual.cc
@@ -46,6 +46,11 @@
 
 void DeviceManagerManual::AddObserver(DeviceEventObserver* observer) {
   observers_.AddObserver(observer);
+  // Notify the new observer about existing devices.
+  for (const auto& path : devices_) {
+    DeviceEvent event(DeviceEvent::INPUT, DeviceEvent::ADD, path);
+    observer->OnDeviceEvent(event);
+  }
 }
 
 void DeviceManagerManual::RemoveObserver(DeviceEventObserver* observer) {
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index fc4b4fd44..98f3162 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -43,7 +43,7 @@
   all_dependent_configs = [ ":flags" ]
 
   public = [
-    "accessibility/native_view_accessibility.h",
+    "accessibility/view_accessibility.h",
     "accessible_pane_view.h",
     "animation/bounds_animator.h",
     "animation/bounds_animator_observer.h",
@@ -249,6 +249,7 @@
   ]
 
   sources = [
+    "accessibility/view_accessibility.cc",
     "accessible_pane_view.cc",
     "animation/bounds_animator.cc",
     "animation/flood_fill_ink_drop_ripple.cc",
@@ -703,8 +704,6 @@
       "accessibility/native_view_accessibility_win.cc",
       "accessibility/native_view_accessibility_win.h",
     ]
-  } else {
-    sources += [ "accessibility/native_view_accessibility_stub.cc" ]
   }
 
   if (is_fuchsia) {
diff --git a/ui/views/accessibility/ax_view_obj_wrapper.cc b/ui/views/accessibility/ax_view_obj_wrapper.cc
index f4ff851..f27df73 100644
--- a/ui/views/accessibility/ax_view_obj_wrapper.cc
+++ b/ui/views/accessibility/ax_view_obj_wrapper.cc
@@ -9,6 +9,7 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/events/event_utils.h"
 #include "ui/views/accessibility/ax_aura_obj_cache.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
@@ -46,26 +47,8 @@
 }
 
 void AXViewObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
-  view_->GetAccessibleNodeData(out_node_data);
-
+  view_->GetViewAccessibility().GetAccessibleNodeData(out_node_data);
   out_node_data->id = GetID();
-
-  if (view_->IsAccessibilityFocusable())
-    out_node_data->AddState(ui::AX_STATE_FOCUSABLE);
-  if (!view_->visible())
-    out_node_data->AddState(ui::AX_STATE_INVISIBLE);
-
-  if (!out_node_data->HasStringAttribute(ui::AX_ATTR_DESCRIPTION)) {
-    base::string16 description;
-    view_->GetTooltipText(gfx::Point(), &description);
-    out_node_data->AddStringAttribute(ui::AX_ATTR_DESCRIPTION,
-                                      base::UTF16ToUTF8(description));
-  }
-
-  out_node_data->AddStringAttribute(ui::AX_ATTR_CLASS_NAME,
-                                    view_->GetClassName());
-
-  out_node_data->location = gfx::RectF(view_->GetBoundsInScreen());
 }
 
 int32_t AXViewObjWrapper::GetID() {
diff --git a/ui/views/accessibility/native_view_accessibility_auralinux.cc b/ui/views/accessibility/native_view_accessibility_auralinux.cc
index 8654dd57..ac7452f 100644
--- a/ui/views/accessibility/native_view_accessibility_auralinux.cc
+++ b/ui/views/accessibility/native_view_accessibility_auralinux.cc
@@ -157,8 +157,7 @@
 }  // namespace
 
 // static
-std::unique_ptr<NativeViewAccessibility> NativeViewAccessibility::Create(
-    View* view) {
+std::unique_ptr<ViewAccessibility> ViewAccessibility::Create(View* view) {
   AuraLinuxApplication::GetInstance()->RegisterWidget(view->GetWidget());
   return std::make_unique<NativeViewAccessibilityAuraLinux>(view);
 }
diff --git a/ui/views/accessibility/native_view_accessibility_base.cc b/ui/views/accessibility/native_view_accessibility_base.cc
index 7571efc3..0f19b6b2 100644
--- a/ui/views/accessibility/native_view_accessibility_base.cc
+++ b/ui/views/accessibility/native_view_accessibility_base.cc
@@ -5,7 +5,6 @@
 #include "ui/views/accessibility/native_view_accessibility_base.h"
 
 #include "base/memory/ptr_util.h"
-#include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/events/event_utils.h"
 #include "ui/gfx/native_widget_types.h"
@@ -57,7 +56,7 @@
 }  // namespace
 
 NativeViewAccessibilityBase::NativeViewAccessibilityBase(View* view)
-    : view_(view) {
+    : ViewAccessibility(view) {
   ax_node_ = ui::AXPlatformNode::Create(this);
   DCHECK(ax_node_);
 
@@ -85,41 +84,30 @@
 // ui::AXPlatformNodeDelegate
 
 const ui::AXNodeData& NativeViewAccessibilityBase::GetData() const {
+  // Clear it, then populate it.
   data_ = ui::AXNodeData();
+  GetAccessibleNodeData(&data_);
 
-  // Views may misbehave if their widget is closed; return an unknown role
-  // rather than possibly crashing.
-  if (!view_->GetWidget() || view_->GetWidget()->IsClosed()) {
-    data_.role = ui::AX_ROLE_UNKNOWN;
-    data_.AddIntAttribute(ui::AX_ATTR_RESTRICTION, ui::AX_RESTRICTION_DISABLED);
-    return data_;
-  }
-
-  view_->GetAccessibleNodeData(&data_);
-  data_.location = GetBoundsInScreen();
-  base::string16 description;
-  view_->GetTooltipText(gfx::Point(), &description);
-  data_.AddStringAttribute(ui::AX_ATTR_DESCRIPTION,
-                           base::UTF16ToUTF8(description));
-
-  if (view_->IsAccessibilityFocusable())
-    data_.AddState(ui::AX_STATE_FOCUSABLE);
-
-  if (!view_->enabled()) {
-    data_.AddIntAttribute(ui::AX_ATTR_RESTRICTION, ui::AX_RESTRICTION_DISABLED);
-  }
-
-  if (!view_->IsDrawn())
+  // View::IsDrawn is true if a View is visible and all of its ancestors are
+  // visible too, since invisibility inherits.
+  //
+  // TODO(dmazzoni): Maybe consider moving this to ViewAccessibility?
+  // This will require ensuring that Chrome OS invalidates the whole
+  // subtree when a View changes its visibility state.
+  if (!view()->IsDrawn())
     data_.AddState(ui::AX_STATE_INVISIBLE);
 
-  if (view_->context_menu_controller())
-    data_.AddAction(ui::AX_ACTION_SHOW_CONTEXT_MENU);
-
   // Make sure this element is excluded from the a11y tree if there's a
   // focusable parent. All keyboard focusable elements should be leaf nodes.
   // Exceptions to this rule will themselves be accessibility focusable.
-  if (IsViewUnfocusableChildOfFocusableAncestor(view_))
+  //
+  // TODO(dmazzoni): this code was added to support MacViews acccessibility,
+  // because we needed a way to mark a View as a leaf node in the
+  // accessibility tree. We need to replace this with a cross-platform
+  // solution that works for ChromeVox, too, and move it to ViewAccessibility.
+  if (IsViewUnfocusableChildOfFocusableAncestor(view()))
     data_.role = ui::AX_ROLE_IGNORED;
+
   return data_;
 }
 
@@ -129,7 +117,7 @@
 }
 
 int NativeViewAccessibilityBase::GetChildCount() {
-  int child_count = view_->child_count();
+  int child_count = view()->child_count();
 
   std::vector<Widget*> child_widgets;
   PopulateChildWidgetVector(&child_widgets);
@@ -144,10 +132,10 @@
   PopulateChildWidgetVector(&child_widgets);
   int child_widget_count = static_cast<int>(child_widgets.size());
 
-  if (index < view_->child_count()) {
-    return view_->child_at(index)->GetNativeViewAccessible();
-  } else if (index < view_->child_count() + child_widget_count) {
-    Widget* child_widget = child_widgets[index - view_->child_count()];
+  if (index < view()->child_count()) {
+    return view()->child_at(index)->GetNativeViewAccessible();
+  } else if (index < view()->child_count() + child_widget_count) {
+    Widget* child_widget = child_widgets[index - view()->child_count()];
     return child_widget->GetRootView()->GetNativeViewAccessible();
   }
 
@@ -155,16 +143,16 @@
 }
 
 gfx::NativeWindow NativeViewAccessibilityBase::GetTopLevelWidget() {
-  if (view_->GetWidget())
-    return view_->GetWidget()->GetTopLevelWidget()->GetNativeWindow();
+  if (view()->GetWidget())
+    return view()->GetWidget()->GetTopLevelWidget()->GetNativeWindow();
   return nullptr;
 }
 
 gfx::NativeViewAccessible NativeViewAccessibilityBase::GetParent() {
-  if (view_->parent())
-    return view_->parent()->GetNativeViewAccessible();
+  if (view()->parent())
+    return view()->parent()->GetNativeViewAccessible();
 
-  if (Widget* widget = view_->GetWidget()) {
+  if (Widget* widget = view()->GetWidget()) {
     Widget* top_widget = widget->GetTopLevelWidget();
     if (top_widget && widget != top_widget && top_widget->GetRootView())
       return top_widget->GetRootView()->GetNativeViewAccessible();
@@ -174,12 +162,12 @@
 }
 
 gfx::Rect NativeViewAccessibilityBase::GetScreenBoundsRect() const {
-  return view_->GetBoundsInScreen();
+  return view()->GetBoundsInScreen();
 }
 
 gfx::NativeViewAccessible NativeViewAccessibilityBase::HitTestSync(int x,
                                                                    int y) {
-  if (!view_ || !view_->GetWidget())
+  if (!view() || !view()->GetWidget())
     return nullptr;
 
   // Search child widgets first, since they're on top in the z-order.
@@ -194,20 +182,20 @@
   }
 
   gfx::Point point(x, y);
-  View::ConvertPointFromScreen(view_, &point);
-  if (!view_->HitTestPoint(point))
+  View::ConvertPointFromScreen(view(), &point);
+  if (!view()->HitTestPoint(point))
     return nullptr;
 
   // Check if the point is within any of the immediate children of this
   // view. We don't have to search further because AXPlatformNode will
   // do a recursive hit test if we return anything other than |this| or NULL.
-  for (int i = view_->child_count() - 1; i >= 0; --i) {
-    View* child_view = view_->child_at(i);
+  for (int i = view()->child_count() - 1; i >= 0; --i) {
+    View* child_view = view()->child_at(i);
     if (!child_view->visible())
       continue;
 
     gfx::Point point_in_child_coords(point);
-    view_->ConvertPointToTarget(view_, child_view, &point_in_child_coords);
+    view()->ConvertPointToTarget(view(), child_view, &point_in_child_coords);
     if (child_view->HitTestPoint(point_in_child_coords))
       return child_view->GetNativeViewAccessible();
   }
@@ -217,7 +205,7 @@
 }
 
 gfx::NativeViewAccessible NativeViewAccessibilityBase::GetFocus() {
-  FocusManager* focus_manager = view_->GetFocusManager();
+  FocusManager* focus_manager = view()->GetFocusManager();
   View* focused_view =
       focus_manager ? focus_manager->GetFocusedView() : nullptr;
   return focused_view ? focused_view->GetNativeViewAccessible() : nullptr;
@@ -238,7 +226,7 @@
 
 bool NativeViewAccessibilityBase::AccessibilityPerformAction(
     const ui::AXActionData& data) {
-  return view_->HandleAccessibleAction(data);
+  return view()->HandleAccessibleAction(data);
 }
 
 bool NativeViewAccessibilityBase::ShouldIgnoreHoveredStateForTesting() {
@@ -251,16 +239,16 @@
 }
 
 gfx::RectF NativeViewAccessibilityBase::GetBoundsInScreen() const {
-  return gfx::RectF(view_->GetBoundsInScreen());
+  return gfx::RectF(view()->GetBoundsInScreen());
 }
 
 void NativeViewAccessibilityBase::PopulateChildWidgetVector(
     std::vector<Widget*>* result_child_widgets) {
   // Only attach child widgets to the root view.
-  Widget* widget = view_->GetWidget();
+  Widget* widget = view()->GetWidget();
   // Note that during window close, a Widget may exist in a state where it has
   // no NativeView, but hasn't yet torn down its view hierarchy.
-  if (!widget || !widget->GetNativeView() || widget->GetRootView() != view_)
+  if (!widget || !widget->GetNativeView() || widget->GetRootView() != view())
     return;
 
   std::set<Widget*> child_widgets;
diff --git a/ui/views/accessibility/native_view_accessibility_base.h b/ui/views/accessibility/native_view_accessibility_base.h
index e3debc0..a471a78cc 100644
--- a/ui/views/accessibility/native_view_accessibility_base.h
+++ b/ui/views/accessibility/native_view_accessibility_base.h
@@ -15,7 +15,7 @@
 #include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
 #include "ui/gfx/native_widget_types.h"
-#include "ui/views/accessibility/native_view_accessibility.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/views_export.h"
 #include "ui/views/widget/widget_observer.h"
 
@@ -26,8 +26,9 @@
 
 // Shared base class for platforms that require an implementation of
 // NativeViewAccessibility to interface with the native accessibility toolkit.
+// This class owns the AXPlatformNode, which implements those native APIs.
 class VIEWS_EXPORT NativeViewAccessibilityBase
-    : public NativeViewAccessibility,
+    : public ViewAccessibility,
       public ui::AXPlatformNodeDelegate {
  public:
   ~NativeViewAccessibilityBase() override;
@@ -56,9 +57,6 @@
  protected:
   explicit NativeViewAccessibilityBase(View* view);
 
-  // Weak. Owns this.
-  View* view_;
-
  protected:
   virtual gfx::RectF GetBoundsInScreen() const;
 
diff --git a/ui/views/accessibility/native_view_accessibility_mac.mm b/ui/views/accessibility/native_view_accessibility_mac.mm
index 14235921..c6374ce 100644
--- a/ui/views/accessibility/native_view_accessibility_mac.mm
+++ b/ui/views/accessibility/native_view_accessibility_mac.mm
@@ -13,8 +13,7 @@
 namespace views {
 
 // static
-std::unique_ptr<NativeViewAccessibility> NativeViewAccessibility::Create(
-    View* view) {
+std::unique_ptr<ViewAccessibility> ViewAccessibility::Create(View* view) {
   return std::make_unique<NativeViewAccessibilityMac>(view);
 }
 
@@ -22,11 +21,11 @@
     : NativeViewAccessibilityBase(view) {}
 
 gfx::NativeViewAccessible NativeViewAccessibilityMac::GetParent() {
-  if (view_->parent())
-    return view_->parent()->GetNativeViewAccessible();
+  if (view()->parent())
+    return view()->parent()->GetNativeViewAccessible();
 
-  if (view_->GetWidget())
-    return view_->GetWidget()->GetNativeView();
+  if (view()->GetWidget())
+    return view()->GetWidget()->GetNativeView();
 
   return nullptr;
 }
diff --git a/ui/views/accessibility/native_view_accessibility_stub.cc b/ui/views/accessibility/native_view_accessibility_stub.cc
deleted file mode 100644
index 3c4cda2..0000000
--- a/ui/views/accessibility/native_view_accessibility_stub.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/accessibility/native_view_accessibility.h"
-
-namespace views {
-
-// static
-std::unique_ptr<NativeViewAccessibility> NativeViewAccessibility::Create(
-    View* view) {
-  return nullptr;
-}
-
-}  // namespace views
diff --git a/ui/views/accessibility/native_view_accessibility_unittest.cc b/ui/views/accessibility/native_view_accessibility_unittest.cc
index b088174..5bf1eaaf 100644
--- a/ui/views/accessibility/native_view_accessibility_unittest.cc
+++ b/ui/views/accessibility/native_view_accessibility_unittest.cc
@@ -44,11 +44,9 @@
 
     button_ = new TestButton();
     button_->SetSize(gfx::Size(20, 20));
-    button_accessibility_ = NativeViewAccessibility::Create(button_);
 
     label_ = new Label();
     button_->AddChildView(label_);
-    label_accessibility_ = NativeViewAccessibility::Create(label_);
 
     widget_->GetContentsView()->AddChildView(button_);
     widget_->Show();
@@ -62,12 +60,12 @@
 
   NativeViewAccessibilityBase* button_accessibility() {
     return static_cast<NativeViewAccessibilityBase*>(
-        button_accessibility_.get());
+        &button_->GetViewAccessibility());
   }
 
   NativeViewAccessibilityBase* label_accessibility() {
     return static_cast<NativeViewAccessibilityBase*>(
-        label_accessibility_.get());
+        &label_->GetViewAccessibility());
   }
 
   bool SetFocused(NativeViewAccessibilityBase* view_accessibility,
@@ -80,9 +78,7 @@
  protected:
   Widget* widget_;
   TestButton* button_;
-  std::unique_ptr<NativeViewAccessibility> button_accessibility_;
   Label* label_;
-  std::unique_ptr<NativeViewAccessibility> label_accessibility_;
 
   DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityTest);
 };
diff --git a/ui/views/accessibility/native_view_accessibility_win.cc b/ui/views/accessibility/native_view_accessibility_win.cc
index 34e7f12..9fe2082 100644
--- a/ui/views/accessibility/native_view_accessibility_win.cc
+++ b/ui/views/accessibility/native_view_accessibility_win.cc
@@ -48,8 +48,7 @@
 }  // namespace
 
 // static
-std::unique_ptr<NativeViewAccessibility> NativeViewAccessibility::Create(
-    View* view) {
+std::unique_ptr<ViewAccessibility> ViewAccessibility::Create(View* view) {
   return std::make_unique<NativeViewAccessibilityWin>(view);
 }
 
@@ -60,12 +59,12 @@
 
 gfx::NativeViewAccessible NativeViewAccessibilityWin::GetParent() {
   // If the View has a parent View, return that View's IAccessible.
-  if (view_->parent())
-    return view_->parent()->GetNativeViewAccessible();
+  if (view()->parent())
+    return view()->parent()->GetNativeViewAccessible();
 
   // Otherwise we must be the RootView, get the corresponding Widget
   // and Window.
-  Widget* widget = view_->GetWidget();
+  Widget* widget = view()->GetWidget();
   if (!widget)
     return nullptr;
 
@@ -84,7 +83,7 @@
   }
 
   // If that fails, return the NativeViewAccessible for our owning HWND.
-  HWND hwnd = HWNDForView(view_);
+  HWND hwnd = HWNDForView(view());
   if (!hwnd)
     return nullptr;
 
@@ -99,12 +98,12 @@
 
 gfx::AcceleratedWidget
 NativeViewAccessibilityWin::GetTargetForNativeAccessibilityEvent() {
-  return HWNDForView(view_);
+  return HWNDForView(view());
 }
 
 gfx::RectF NativeViewAccessibilityWin::GetBoundsInScreen() const {
-  gfx::RectF bounds = gfx::RectF(view_->GetBoundsInScreen());
-  gfx::NativeView native_view = view_->GetWidget()->GetNativeView();
+  gfx::RectF bounds = gfx::RectF(view()->GetBoundsInScreen());
+  gfx::NativeView native_view = view()->GetWidget()->GetNativeView();
   float device_scale = ui::GetScaleFactorForNativeView(native_view);
   bounds.Scale(device_scale);
   return bounds;
diff --git a/ui/views/accessibility/view_accessibility.cc b/ui/views/accessibility/view_accessibility.cc
new file mode 100644
index 0000000..b8bd1c975
--- /dev/null
+++ b/ui/views/accessibility/view_accessibility.cc
@@ -0,0 +1,98 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/accessibility/view_accessibility.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/ui_features.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+namespace {
+
+bool IsValidRoleForViews(ui::AXRole role) {
+  switch (role) {
+    // These roles all have special meaning and shouldn't ever be
+    // set on a View.
+    case ui::AX_ROLE_DESKTOP:
+    case ui::AX_ROLE_NONE:
+    case ui::AX_ROLE_ROOT_WEB_AREA:
+    case ui::AX_ROLE_SVG_ROOT:
+    case ui::AX_ROLE_UNKNOWN:
+    case ui::AX_ROLE_WEB_AREA:
+      return false;
+
+    default:
+      return true;
+  }
+}
+
+}  // namespace
+
+#if !BUILDFLAG_INTERNAL_HAS_NATIVE_ACCESSIBILITY()
+// static
+std::unique_ptr<ViewAccessibility> ViewAccessibility::Create(View* view) {
+  return base::WrapUnique(new ViewAccessibility(view));
+}
+#endif
+
+ViewAccessibility::ViewAccessibility(View* view) : owner_view_(view) {}
+
+ViewAccessibility::~ViewAccessibility() {}
+
+void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const {
+  // Views may misbehave if their widget is closed; return an unknown role
+  // rather than possibly crashing.
+  if (!owner_view_->GetWidget() || owner_view_->GetWidget()->IsClosed()) {
+    data->role = ui::AX_ROLE_UNKNOWN;
+    data->AddIntAttribute(ui::AX_ATTR_RESTRICTION, ui::AX_RESTRICTION_DISABLED);
+    return;
+  }
+
+  owner_view_->GetAccessibleNodeData(data);
+  if (custom_data_.role != ui::AX_ROLE_UNKNOWN)
+    data->role = custom_data_.role;
+  if (custom_data_.HasStringAttribute(ui::AX_ATTR_NAME))
+    data->SetName(custom_data_.GetStringAttribute(ui::AX_ATTR_NAME));
+
+  data->location = gfx::RectF(owner_view_->GetBoundsInScreen());
+  if (!data->HasStringAttribute(ui::AX_ATTR_DESCRIPTION)) {
+    base::string16 description;
+    owner_view_->GetTooltipText(gfx::Point(), &description);
+    data->AddStringAttribute(ui::AX_ATTR_DESCRIPTION,
+                             base::UTF16ToUTF8(description));
+  }
+
+  data->AddStringAttribute(ui::AX_ATTR_CLASS_NAME, owner_view_->GetClassName());
+
+  if (owner_view_->IsAccessibilityFocusable())
+    data->AddState(ui::AX_STATE_FOCUSABLE);
+
+  if (!owner_view_->enabled())
+    data->AddIntAttribute(ui::AX_ATTR_RESTRICTION, ui::AX_RESTRICTION_DISABLED);
+
+  if (!owner_view_->visible())
+    data->AddState(ui::AX_STATE_INVISIBLE);
+
+  if (owner_view_->context_menu_controller())
+    data->AddAction(ui::AX_ACTION_SHOW_CONTEXT_MENU);
+}
+
+void ViewAccessibility::OverrideRole(ui::AXRole role) {
+  DCHECK(IsValidRoleForViews(role));
+
+  custom_data_.role = role;
+}
+
+void ViewAccessibility::OverrideName(const std::string& name) {
+  custom_data_.SetName(name);
+}
+
+gfx::NativeViewAccessible ViewAccessibility::GetNativeObject() {
+  return nullptr;
+}
+
+}  // namespace views
diff --git a/ui/views/accessibility/view_accessibility.h b/ui/views/accessibility/view_accessibility.h
new file mode 100644
index 0000000..e26b34f
--- /dev/null
+++ b/ui/views/accessibility/view_accessibility.h
@@ -0,0 +1,70 @@
+// Copyright 2017 The Chromium Authors. 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_ACCESSIBILITY_VIEW_ACCESSIBILITY_H_
+#define UI_VIEWS_ACCESSIBILITY_VIEW_ACCESSIBILITY_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "ui/accessibility/ax_enums.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+class View;
+
+// An object that manages the accessibility interface for a View.
+//
+// The default accessibility properties of a View is determined by
+// calling View::GetAccessibleNodeData(), which is overridden by many
+// View subclasses. ViewAccessibility lets you override these for a
+// particular view.
+//
+// On some platforms, subclasses of ViewAccessibility own the
+// AXPlatformNode that implements the native accessibility APIs on that
+// platform.
+class VIEWS_EXPORT ViewAccessibility {
+ public:
+  static std::unique_ptr<ViewAccessibility> Create(View* view);
+
+  virtual ~ViewAccessibility();
+
+  // Modifies |node_data| to reflect the current accessible state of the
+  // associated View, taking any custom overrides into account
+  // (see OverrideRole, etc. below).
+  virtual void GetAccessibleNodeData(ui::AXNodeData* node_data) const;
+
+  //
+  // These override anything returned from View::GetAccessibleNodeData().
+  // Note that string attributes are only used if non-empty, so you can't
+  // override a string with the empty string.
+  //
+  void OverrideRole(ui::AXRole role);
+  void OverrideName(const std::string& name);
+
+  virtual gfx::NativeViewAccessible GetNativeObject();
+  virtual void NotifyAccessibilityEvent(ui::AXEvent event_type) {}
+
+ protected:
+  explicit ViewAccessibility(View* view);
+
+  View* view() const { return owner_view_; }
+
+ private:
+  // Weak. Owns this.
+  View* const owner_view_;
+
+  // Contains data set explicitly via SetRole, SetName, etc. that overrides
+  // anything provided by GetAccessibleNodeData().
+  ui::AXNodeData custom_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViewAccessibility);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_ACCESSIBILITY_VIEW_ACCESSIBILITY_H_
diff --git a/ui/views/controls/native/native_view_host.cc b/ui/views/controls/native/native_view_host.cc
index fd7de908..2c5016d 100644
--- a/ui/views/controls/native/native_view_host.cc
+++ b/ui/views/controls/native/native_view_host.cc
@@ -7,7 +7,6 @@
 #include "base/logging.h"
 #include "ui/base/cursor/cursor.h"
 #include "ui/gfx/canvas.h"
-#include "ui/views/accessibility/native_view_accessibility.h"
 #include "ui/views/controls/native/native_view_host_wrapper.h"
 #include "ui/views/widget/widget.h"
 
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 56734ae8..61c4d68 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -46,7 +46,7 @@
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/transform.h"
 #include "ui/native_theme/native_theme.h"
-#include "ui/views/accessibility/native_view_accessibility.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
 #include "ui/views/context_menu_controller.h"
@@ -1408,6 +1408,12 @@
 
 // Accessibility----------------------------------------------------------------
 
+ViewAccessibility& View::GetViewAccessibility() {
+  if (!view_accessibility_)
+    view_accessibility_ = ViewAccessibility::Create(this);
+  return *view_accessibility_;
+}
+
 bool View::HandleAccessibleAction(const ui::AXActionData& action_data) {
   switch (action_data.action) {
     case ui::AX_ACTION_BLUR:
@@ -1448,11 +1454,7 @@
 }
 
 gfx::NativeViewAccessible View::GetNativeViewAccessible() {
-  if (!native_view_accessibility_)
-    native_view_accessibility_ = NativeViewAccessibility::Create(this);
-  if (native_view_accessibility_)
-    return native_view_accessibility_->GetNativeObject();
-  return nullptr;
+  return GetViewAccessibility().GetNativeObject();
 }
 
 void View::NotifyAccessibilityEvent(
@@ -1461,12 +1463,8 @@
   if (ViewsDelegate::GetInstance())
     ViewsDelegate::GetInstance()->NotifyAccessibilityEvent(this, event_type);
 
-  if (send_native_event && GetWidget()) {
-    if (!native_view_accessibility_)
-      native_view_accessibility_ = NativeViewAccessibility::Create(this);
-    if (native_view_accessibility_)
-      native_view_accessibility_->NotifyAccessibilityEvent(event_type);
-  }
+  if (send_native_event && GetWidget())
+    GetViewAccessibility().NotifyAccessibilityEvent(event_type);
 
   OnAccessibilityEvent(event_type);
 }
diff --git a/ui/views/view.h b/ui/views/view.h
index a582753..4a4f120 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -75,7 +75,7 @@
 class FocusManager;
 class FocusTraversable;
 class LayoutManager;
-class NativeViewAccessibility;
+class ViewAccessibility;
 class ScrollView;
 class ViewObserver;
 class Widget;
@@ -1095,6 +1095,9 @@
 
   // Accessibility -------------------------------------------------------------
 
+  // Get the object managing the accessibility interface for this View.
+  ViewAccessibility& GetViewAccessibility();
+
   // Modifies |node_data| to reflect the current accessible state of this view.
   virtual void GetAccessibleNodeData(ui::AXNodeData* node_data) {}
 
@@ -1830,8 +1833,8 @@
 
   // Accessibility -------------------------------------------------------------
 
-  // The accessibility element used to represent this View.
-  std::unique_ptr<NativeViewAccessibility> native_view_accessibility_;
+  // Manages the accessibility interface for this View.
+  std::unique_ptr<ViewAccessibility> view_accessibility_;
 
   // Observers -------------------------------------------------------------