diff --git a/DEPS b/DEPS
index 49bc7f5d..0182c5b 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,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': 'bae888e652dfe5c2ce840eff7760c8ab7317b7d6',
+  'skia_revision': 'a5fdc974a996dca79be8388e61db68043001760b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -96,7 +96,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': '36a50828018d37783cb7259e57b2510b38e085ce',
+  'catapult_revision': '84a7af661032933b0bd10cdc1f656cdf6b6781c3',
   # 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/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index 2a87f4a..19f822f9 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -982,6 +982,17 @@
   NavigationRequest* ongoing_navigation_request =
       frame_tree_node->navigation_request();
 
+  // Client redirects during the initial history navigation of a child frame
+  // should take precedence over the history navigation (despite being renderer-
+  // initiated).  See https://crbug.com/348447 and https://crbug.com/691168.
+  if (ongoing_navigation_request &&
+      ongoing_navigation_request->request_params()
+          .is_history_navigation_in_new_child) {
+    // Preemptively clear this local pointer before deleting the request.
+    ongoing_navigation_request = nullptr;
+    frame_tree_node->ResetNavigationRequest(false);
+  }
+
   // The renderer-initiated navigation request is ignored iff a) there is an
   // ongoing request b) which is browser or user-initiated and c) the renderer
   // request is not user-initiated.
@@ -1150,8 +1161,12 @@
 
   // This value must be set here because creating a NavigationRequest might
   // change the renderer live/non-live status and change this result.
+  // We don't want to dispatch a beforeunload handler if
+  // is_history_navigation_in_new_child is true. This indicates a newly created
+  // child frame which does not have a beforunload handler.
   bool should_dispatch_beforeunload =
       !is_same_document_history_load &&
+      !is_history_navigation_in_new_child &&
       frame_tree_node->current_frame_host()->ShouldDispatchBeforeUnload();
   FrameMsg_Navigate_Type::Value navigation_type = GetNavigationType(
       frame_tree_node->current_url(),  // old_url
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
index e181286c..20de8a1 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
@@ -50,10 +50,6 @@
 Bug(none) http/tests/security/location-href-clears-username-password.html [ Failure ]
 Bug(none) virtual/mojo-loading/http/tests/security/location-href-clears-username-password.html [ Failure ]
 
-# New untriaged.
-Bug(none) http/tests/navigation/back-to-dynamic-iframe.html [ Failure ]
-Bug(none) virtual/mojo-loading/http/tests/navigation/back-to-dynamic-iframe.html [ Failure ]
-
 # This test seems to be partially failing without PlzNavigate as well.
 
 # These tests are flaky.
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/box-sizing-padding-keeping-size-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/box-sizing-padding-keeping-size-expected.txt
index 79d6fea..f700373f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/box-sizing-padding-keeping-size-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/box-sizing-padding-keeping-size-expected.txt
@@ -4,20 +4,7 @@
       "name": "LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow (positioned) DIV id='target2' class='border-box'",
-          "rect": [0, 200, 100, 100],
-          "reason": "content box change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow (positioned) DIV id='target2' class='border-box'",
-      "reason": "content box change"
+      "drawsContent": true
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
index 024270b..c8310639 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -27,6 +27,11 @@
           "reason": "layoutObject insertion"
         },
         {
+          "object": "LayoutView #document",
+          "rect": [10, 94, 728, 90],
+          "reason": "layout overflow box change"
+        },
+        {
           "object": "LayoutImage IMG",
           "rect": [58, 236, 489, 537],
           "reason": "bounds change"
@@ -74,7 +79,7 @@
     },
     {
       "object": "LayoutView #document",
-      "reason": "location change"
+      "reason": "layout overflow box change"
     },
     {
       "object": "LayoutBlockFlow HTML",
diff --git a/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
index a88792e..1a66f206 100644
--- a/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/disable-spinvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -27,6 +27,11 @@
           "reason": "layoutObject insertion"
         },
         {
+          "object": "LayoutView #document",
+          "rect": [10, 88, 728, 90],
+          "reason": "layout overflow box change"
+        },
+        {
           "object": "LayoutImage IMG",
           "rect": [58, 230, 489, 537],
           "reason": "bounds change"
@@ -74,7 +79,7 @@
     },
     {
       "object": "LayoutView #document",
-      "reason": "location change"
+      "reason": "layout overflow box change"
     },
     {
       "object": "LayoutBlockFlow HTML",
diff --git a/third_party/WebKit/Source/core/inspector/PRESUBMIT.py b/third_party/WebKit/Source/core/inspector/PRESUBMIT.py
new file mode 100644
index 0000000..5465d00
--- /dev/null
+++ b/third_party/WebKit/Source/core/inspector/PRESUBMIT.py
@@ -0,0 +1,35 @@
+# 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.
+
+
+def _CompileDevtoolsFrontend(input_api, output_api):
+    # Need to get all affected files from change (not just within this subtree)
+    local_paths = [f.AbsoluteLocalPath() for f in input_api.change.AffectedFiles()]
+    devtools = input_api.os_path.realpath(
+        input_api.os_path.join(input_api.PresubmitLocalPath(), '..', '..', 'devtools'))
+
+    # If a devtools file is changed, the PRESUBMIT hook in Source/devtools
+    # will run closure compiler
+    if (any("browser_protocol.json" in path for path in local_paths) and
+            all(devtools not in path for path in local_paths)):
+        compile_path = input_api.os_path.join(
+            input_api.PresubmitLocalPath(), "..", "..", "devtools", "scripts", "compile_frontend.py")
+        out, _ = input_api.subprocess.Popen(
+            [input_api.python_executable, compile_path], stdout=input_api.subprocess.PIPE,
+            stderr=input_api.subprocess.STDOUT).communicate()
+        if "ERROR" in out or "WARNING" in out:
+            return [output_api.PresubmitError(out)]
+        if "NOTE" in out:
+            return [output_api.PresubmitPromptWarning(out)]
+    return []
+
+
+def CheckChangeOnUpload(input_api, output_api):
+    results = []
+    results.extend(_CompileDevtoolsFrontend(input_api, output_api))
+    return results
+
+
+def CheckChangeOnCommit(input_api, output_api):
+    return []
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index 49c8fd5..0f73e71 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -85,6 +85,7 @@
 
 struct SameSizeAsLayoutBox : public LayoutBoxModelObject {
   LayoutRect frameRect;
+  LayoutSize previousSize;
   LayoutUnit intrinsicContentLogicalHeight;
   LayoutRectOutsets marginBoxOutsets;
   LayoutUnit preferredLogicalWidth[2];
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h
index 1aa640e..ca26cdb 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -318,6 +318,7 @@
     return LayoutSize(m_frameRect.x(), m_frameRect.y());
   }
   LayoutSize size() const { return m_frameRect.size(); }
+  LayoutSize previousSize() const { return m_previousSize; }
   IntSize pixelSnappedSize() const { return m_frameRect.pixelSnappedSize(); }
 
   void setLocation(const LayoutPoint& location) {
@@ -1308,6 +1309,21 @@
 
   virtual bool hasControlClip() const { return false; }
 
+  class MutableForPainting : public LayoutObject::MutableForPainting {
+   public:
+    void setPreviousSize(const LayoutSize& size) {
+      static_cast<LayoutBox&>(m_layoutObject).m_previousSize = size;
+    }
+
+   protected:
+    friend class LayoutBox;
+    MutableForPainting(const LayoutBox& box)
+        : LayoutObject::MutableForPainting(box) {}
+  };
+  MutableForPainting getMutableForPainting() const {
+    return MutableForPainting(*this);
+  }
+
  protected:
   virtual LayoutRect controlClipRect(const LayoutPoint&) const {
     return LayoutRect();
@@ -1507,21 +1523,6 @@
 
   void updateBackgroundAttachmentFixedStatusAfterStyleChange();
 
-  // The CSS border box rect for this box.
-  //
-  // The rectangle is in this box's physical coordinates but with a
-  // flipped block-flow direction (see the COORDINATE SYSTEMS section
-  // in LayoutBoxModelObject). The location is the distance from this
-  // object's border edge to the container's border edge (which is not
-  // always the parent). Thus it includes any logical top/left along
-  // with this box's margins.
-  LayoutRect m_frameRect;
-
-  // Our intrinsic height, used for min-height: min-content etc. Maintained by
-  // updateLogicalHeight. This is logicalHeight() before it is clamped to
-  // min/max.
-  mutable LayoutUnit m_intrinsicContentLogicalHeight;
-
   void inflateVisualRectForFilter(LayoutRect&) const;
   void inflateVisualRectForFilterUnderContainer(
       LayoutRect&,
@@ -1535,6 +1536,24 @@
 
   LayoutRect debugRect() const override;
 
+  // The CSS border box rect for this box.
+  //
+  // The rectangle is in this box's physical coordinates but with a
+  // flipped block-flow direction (see the COORDINATE SYSTEMS section
+  // in LayoutBoxModelObject). The location is the distance from this
+  // object's border edge to the container's border edge (which is not
+  // always the parent). Thus it includes any logical top/left along
+  // with this box's margins.
+  LayoutRect m_frameRect;
+
+  // Previous size of m_frameRect, updated after paint invalidation.
+  LayoutSize m_previousSize;
+
+  // Our intrinsic height, used for min-height: min-content etc. Maintained by
+  // updateLogicalHeight. This is logicalHeight() before it is clamped to
+  // min/max.
+  mutable LayoutUnit m_intrinsicContentLogicalHeight;
+
  protected:
   // The logical width of the element if it were to break its lines at every
   // possible opportunity.
diff --git a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
index 3181583..23d2efb 100644
--- a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
@@ -16,7 +16,6 @@
 namespace blink {
 
 struct PreviousBoxGeometries {
-  LayoutSize borderBoxSize;
   LayoutRect contentBoxRect;
   LayoutRect layoutOverflowRect;
 };
@@ -123,8 +122,7 @@
       previousContentBoxRect() != m_box.contentBoxRect())
     return PaintInvalidationContentBoxChange;
 
-  LayoutSize oldBorderBoxSize =
-      previousBorderBoxSize(m_box, m_context.oldVisualRect.size());
+  LayoutSize oldBorderBoxSize = m_box.previousSize();
   LayoutSize newBorderBoxSize = m_box.size();
   bool borderBoxChanged = oldBorderBoxSize != newBorderBoxSize;
   if (!borderBoxChanged && m_context.oldVisualRect == m_context.newVisualRect)
@@ -232,21 +230,20 @@
     }
     shouldFullyInvalidateOnScrollingContentsLayer = true;
   } else {
-    // Check change of layout overflow for incremental invalidation.
-    if (!m_box.hasPreviousBoxGeometries() ||
-        newLayoutOverflow == oldLayoutOverflow)
+    // Check change of layout overflow for full or incremental invalidation.
+    if (newLayoutOverflow == oldLayoutOverflow)
       return;
+    bool shouldFullyInvalidate =
+        shouldFullyInvalidateBackgroundOnLayoutOverflowChange(
+            oldLayoutOverflow, newLayoutOverflow);
     if (!paintsOntoScrollingContentsLayer) {
-      if (shouldFullyInvalidateBackgroundOnLayoutOverflowChange(
-              oldLayoutOverflow, newLayoutOverflow)) {
+      if (shouldFullyInvalidate) {
         m_box.getMutableForPainting().setShouldDoFullPaintInvalidation(
             PaintInvalidationLayoutOverflowBoxChange);
       }
       return;
     }
-    shouldFullyInvalidateOnScrollingContentsLayer =
-        shouldFullyInvalidateBackgroundOnLayoutOverflowChange(
-            oldLayoutOverflow, newLayoutOverflow);
+    shouldFullyInvalidateOnScrollingContentsLayer = shouldFullyInvalidate;
   }
 
   if (shouldFullyInvalidateOnScrollingContentsLayer) {
@@ -280,9 +277,7 @@
           reason, m_context.oldVisualRect, m_context.newVisualRect);
     } else {
       invalidated = incrementallyInvalidatePaint(
-          reason, LayoutRect(m_context.oldLocation,
-                             previousBorderBoxSize(
-                                 m_box, m_context.oldVisualRect.size())),
+          reason, LayoutRect(m_context.oldLocation, m_box.previousSize()),
           LayoutRect(m_context.newLocation, m_box.size()));
     }
     if (invalidated) {
@@ -314,20 +309,13 @@
 }
 
 bool BoxPaintInvalidator::needsToSavePreviousBoxGeometries() {
-  LayoutSize paintInvalidationSize = m_context.newVisualRect.size();
+  // Don't save old box geometries if the paint rect is empty because we'll
+  // fully invalidate once the paint rect becomes non-empty.
+  if (m_context.newVisualRect.isEmpty())
+    return false;
 
-  // The shortcuts doesn't apply to HTML element. ViewPaintInvalidator needs to
-  // know its previous border box size even if it has visibility:hidden (causing
-  // empty paintInvalidationSize) or has no painted output.
-  if (!m_box.node() || !m_box.node()->isHTMLElement()) {
-    // Don't save old box geometries if the paint rect is empty because we'll
-    // fully invalidate once the paint rect becomes non-empty.
-    if (paintInvalidationSize.isEmpty())
-      return false;
-
-    if (m_box.paintedOutputOfObjectHasNoEffectRegardlessOfSize())
-      return false;
-  }
+  if (m_box.paintedOutputOfObjectHasNoEffectRegardlessOfSize())
+    return false;
 
   const ComputedStyle& style = m_box.styleRef();
 
@@ -336,11 +324,6 @@
   if (style.boxSizing() == EBoxSizing::kBorderBox)
     return true;
 
-  // No need to save old border box size if we can use size of the old paint
-  // rect as the old border box size in the next invalidation.
-  if (paintInvalidationSize != m_box.size())
-    return true;
-
   // Background and mask layers can depend on other boxes than border box. See
   // crbug.com/490533
   if (style.backgroundLayers().thisOrNextLayersUseContentBox() ||
@@ -353,6 +336,8 @@
 }
 
 void BoxPaintInvalidator::savePreviousBoxGeometriesIfNeeded() {
+  m_box.getMutableForPainting().setPreviousSize(m_box.size());
+
   DCHECK(m_box.hasPreviousBoxGeometries() ==
          previousBoxGeometriesMap().contains(&m_box));
   if (!needsToSavePreviousBoxGeometries()) {
@@ -363,28 +348,18 @@
     return;
   }
 
-  PreviousBoxGeometries geometries = {m_box.size(), m_box.contentBoxRect(),
+  PreviousBoxGeometries geometries = {m_box.contentBoxRect(),
                                       m_box.layoutOverflowRect()};
   previousBoxGeometriesMap().set(&m_box, geometries);
   m_box.getMutableForPainting().setHasPreviousBoxGeometries(true);
 }
 
-LayoutSize BoxPaintInvalidator::previousBorderBoxSize(
-    const LayoutBox& box,
-    const LayoutSize& defaultSize) {
-  DCHECK(box.hasPreviousBoxGeometries() ==
-         previousBoxGeometriesMap().contains(&box));
-  if (box.hasPreviousBoxGeometries())
-    return previousBoxGeometriesMap().get(&box).borderBoxSize;
-  return defaultSize;
-}
-
 LayoutRect BoxPaintInvalidator::previousContentBoxRect() {
   DCHECK(m_box.hasPreviousBoxGeometries() ==
          previousBoxGeometriesMap().contains(&m_box));
   return m_box.hasPreviousBoxGeometries()
              ? previousBoxGeometriesMap().get(&m_box).contentBoxRect
-             : LayoutRect();
+             : LayoutRect(LayoutPoint(), m_box.previousSize());
 }
 
 LayoutRect BoxPaintInvalidator::previousLayoutOverflowRect() {
@@ -392,7 +367,7 @@
          previousBoxGeometriesMap().contains(&m_box));
   return m_box.hasPreviousBoxGeometries()
              ? previousBoxGeometriesMap().get(&m_box).layoutOverflowRect
-             : LayoutRect();
+             : LayoutRect(LayoutPoint(), m_box.previousSize());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.h b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.h
index 7d7c81168..b2b23a35 100644
--- a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.h
+++ b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.h
@@ -12,7 +12,6 @@
 
 class LayoutBox;
 class LayoutRect;
-class LayoutSize;
 struct PaintInvalidatorContext;
 
 class BoxPaintInvalidator {
@@ -27,9 +26,6 @@
 
   PaintInvalidationReason invalidatePaintIfNeeded();
 
-  static LayoutSize previousBorderBoxSize(const LayoutBox&,
-                                          const LayoutSize& defaultSize);
-
  private:
   bool backgroundGeometryDependsOnLayoutOverflowRect();
   bool backgroundPaintsOntoScrollingContentsLayer();
diff --git a/third_party/WebKit/Source/core/paint/ViewPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/ViewPaintInvalidator.cpp
index 1527c8d0..eceb1da 100644
--- a/third_party/WebKit/Source/core/paint/ViewPaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/ViewPaintInvalidator.cpp
@@ -33,8 +33,7 @@
     return;
 
   const LayoutBox& backgroundBox = toLayoutBox(*backgroundObject);
-  LayoutSize oldSize = BoxPaintInvalidator::previousBorderBoxSize(
-      backgroundBox, backgroundBox.visualRect().size());
+  LayoutSize oldSize = backgroundBox.previousSize();
   LayoutSize newSize = backgroundBox.size();
   const auto& backgroundLayers = m_view.styleRef().backgroundLayers();
   if ((oldSize.width() != newSize.width() &&
diff --git a/third_party/WebKit/Source/devtools/PRESUBMIT.py b/third_party/WebKit/Source/devtools/PRESUBMIT.py
index 353e2cdb3..8078939 100644
--- a/third_party/WebKit/Source/devtools/PRESUBMIT.py
+++ b/third_party/WebKit/Source/devtools/PRESUBMIT.py
@@ -34,8 +34,6 @@
 from collections import namedtuple
 import sys
 
-compile_note = "Be sure to run your patch by the compile_frontend.py script prior to committing!"
-
 CheckOutput = namedtuple('CheckOutput', ['results', 'has_errors'])
 
 
@@ -112,26 +110,14 @@
 
 
 def _CompileDevtoolsFrontend(input_api, output_api):
-    local_paths = [f.LocalPath() for f in input_api.AffectedFiles()]
-
-    # FIXME: The compilation does not actually run if injected script-related files
-    # have changed, as they reside in core/inspector, which is not affected
-    # by this presubmit.
-    # Once this is fixed, injected_script_externs.js
-    # should be added to the list of triggers.
-    devtools_front_end = input_api.os_path.join("devtools", "front_end")
-    if (any(devtools_front_end in path for path in local_paths) or any("_protocol.json" in path for path in local_paths) or
-            any("compile_frontend.py" in path for path in local_paths) or any("InjectedScriptSource.js" in path
-                                                                              for path in local_paths) or
-            any("DebuggerScript.js" in path for path in local_paths)):
-        lint_path = input_api.os_path.join(input_api.PresubmitLocalPath(), "scripts", "compile_frontend.py")
-        out, _ = input_api.subprocess.Popen(
-            [input_api.python_executable, lint_path], stdout=input_api.subprocess.PIPE,
-            stderr=input_api.subprocess.STDOUT).communicate()
-        if "ERROR" in out or "WARNING" in out:
-            return [output_api.PresubmitError(out)]
-        if "NOTE" in out:
-            return [output_api.PresubmitPromptWarning(out + compile_note)]
+    compile_path = input_api.os_path.join(input_api.PresubmitLocalPath(), "scripts", "compile_frontend.py")
+    out, _ = input_api.subprocess.Popen(
+        [input_api.python_executable, compile_path], stdout=input_api.subprocess.PIPE,
+        stderr=input_api.subprocess.STDOUT).communicate()
+    if "ERROR" in out or "WARNING" in out:
+        return [output_api.PresubmitError(out)]
+    if "NOTE" in out:
+        return [output_api.PresubmitPromptWarning(out)]
     return []
 
 
diff --git a/tools/perf/benchmarks/benchmark_smoke_unittest.py b/tools/perf/benchmarks/benchmark_smoke_unittest.py
index 8808a991c..b386869 100644
--- a/tools/perf/benchmarks/benchmark_smoke_unittest.py
+++ b/tools/perf/benchmarks/benchmark_smoke_unittest.py
@@ -52,7 +52,6 @@
   def BenchmarkSmokeTest(self):
     # Only measure a single page so that this test cycles reasonably quickly.
     benchmark.options['pageset_repeat'] = 1
-    benchmark.options['page_repeat'] = 1
 
     class SinglePageBenchmark(benchmark):  # pylint: disable=no-init
 
diff --git a/tools/perf/benchmarks/system_health_smoke_test.py b/tools/perf/benchmarks/system_health_smoke_test.py
index 1b0e7843..3ad67e4 100644
--- a/tools/perf/benchmarks/system_health_smoke_test.py
+++ b/tools/perf/benchmarks/system_health_smoke_test.py
@@ -119,7 +119,7 @@
   benchmark_module.ProcessCommandLineArgs(None, options)
   # Only measure a single story so that this test cycles reasonably quickly.
   options.pageset_repeat = 1
-  options.page_repeat = 1
+
   # Enable browser logging in the smoke test only. Hopefully, this will detect
   # all crashes and hence remove the need to enable logging in actual perf
   # benchmarks.
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index 6063a224..7e9fdb64 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -4,6 +4,7 @@
 
 #include "ui/views/widget/widget.h"
 
+#include "base/auto_reset.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
@@ -174,7 +175,8 @@
       auto_release_capture_(true),
       views_with_layers_dirty_(false),
       movement_disabled_(false),
-      observer_manager_(this) {}
+      observer_manager_(this),
+      processing_theme_changed_(false) {}
 
 Widget::~Widget() {
   DestroyRootView();
@@ -898,6 +900,8 @@
 }
 
 void Widget::FrameTypeChanged() {
+  if (processing_theme_changed_)
+    return;
   native_widget_->FrameTypeChanged();
 }
 
@@ -1401,6 +1405,10 @@
     observer_manager_.Add(current_native_theme);
   }
 
+  DCHECK_EQ(processing_theme_changed_, false);
+
+  base::AutoReset<bool> auto_theme_changed_recursion_break(
+      &processing_theme_changed_, true);
   root_view_->PropagateNativeThemeChanged(current_native_theme);
 }
 
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h
index 33c06564..505beb1 100644
--- a/ui/views/widget/widget.h
+++ b/ui/views/widget/widget.h
@@ -992,6 +992,9 @@
 
   ScopedObserver<ui::NativeTheme, ui::NativeThemeObserver> observer_manager_;
 
+  // Guard to avoid reentrancy while processing a theme changed message.
+  bool processing_theme_changed_;
+
   DISALLOW_COPY_AND_ASSIGN(Widget);
 };