diff --git a/.gitignore b/.gitignore
index a7d022e9..6334517 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,10 @@
 .pydevproject
 .checkstyle
 cscope.*
+GPATH
+GRTAGS
+GSYMS
+GTAGS
 Session.vim
 tags
 Thumbs.db
@@ -148,6 +152,7 @@
 /components/leveldb_proto_test_support.xml
 /components/rappor.xml
 /components/resources/default_100_percent/google_chrome
+/components/resources/default_200_percent/google_chrome
 /components/search_engines/prepopulated_engines.xml
 /components/suggestions.xml
 /components/variations.xml
diff --git a/BUILD.gn b/BUILD.gn
index b169525..2b19ec1 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -177,7 +177,10 @@
       "//ui/touch_selection:ui_touch_selection_unittests",
     ]
   } else {
-    deps += [ "//ios/net:ios_net_unittests" ]
+    deps += [
+      "//ios/net:ios_net_unittests",
+      "//ios/third_party/gcdwebserver",
+    ]
   }
 
   deps += root_extra_deps
diff --git a/DEPS b/DEPS
index b14694d8..8d7cd348 100644
--- a/DEPS
+++ b/DEPS
@@ -59,7 +59,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '35902e725aa6cc83a317c3b6fdd1926b81b8e44b',
+  'pdfium_revision': '1f439a7a3b7c44235ecdac9a411add8fb62b0d83',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn
index 9d9b467..c4b6609 100644
--- a/base/trace_event/BUILD.gn
+++ b/base/trace_event/BUILD.gn
@@ -27,7 +27,6 @@
     "process_memory_dump.h",
     "process_memory_maps.cc",
     "process_memory_maps.h",
-    "process_memory_maps_dump_provider.cc",
     "process_memory_maps_dump_provider.h",
     "process_memory_totals.cc",
     "process_memory_totals.h",
@@ -76,6 +75,7 @@
     sources += [
       "malloc_dump_provider.cc",
       "malloc_dump_provider.h",
+      "process_memory_maps_dump_provider.cc",
     ]
   }
 
@@ -111,7 +111,6 @@
     "memory_profiler_allocation_context_unittest.cc",
     "memory_profiler_allocation_register_unittest.cc",
     "process_memory_dump_unittest.cc",
-    "process_memory_maps_dump_provider_unittest.cc",
     "process_memory_totals_dump_provider_unittest.cc",
     "trace_config_memory_test_util.h",
     "trace_config_unittest.cc",
@@ -124,6 +123,10 @@
     "winheap_dump_provider_win_unittest.cc",
   ]
 
+  if (is_linux || is_android) {
+    sources += [ "process_memory_maps_dump_provider_unittest.cc" ]
+  }
+
   deps = [
     "//base/test:test_support",
     "//testing/gmock",
diff --git a/base/trace_event/process_memory_maps_dump_provider.cc b/base/trace_event/process_memory_maps_dump_provider.cc
index 335dd829a..19f8d89 100644
--- a/base/trace_event/process_memory_maps_dump_provider.cc
+++ b/base/trace_event/process_memory_maps_dump_provider.cc
@@ -4,6 +4,7 @@
 
 #include "base/trace_event/process_memory_maps_dump_provider.h"
 
+#include "base/files/scoped_file.h"
 #include "base/format_macros.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
@@ -13,7 +14,6 @@
 namespace base {
 namespace trace_event {
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
 // static
 FILE* ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = nullptr;
 
@@ -134,7 +134,6 @@
 }
 
 }  // namespace
-#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
 
 // static
 ProcessMemoryMapsDumpProvider* ProcessMemoryMapsDumpProvider::GetInstance() {
@@ -157,23 +156,17 @@
     return true;
 
   uint32 res = 0;
-
-#if defined(OS_LINUX) || defined(OS_ANDROID)
   if (UNLIKELY(proc_smaps_for_testing)) {
     res = ReadLinuxProcSmapsFile(proc_smaps_for_testing, pmd->process_mmaps());
   } else {
     ScopedFILE smaps_file(fopen("/proc/self/smaps", "r"));
     res = ReadLinuxProcSmapsFile(smaps_file.get(), pmd->process_mmaps());
   }
-#else
-  LOG(ERROR) << "ProcessMemoryMaps dump provider is supported only on Linux";
-#endif
 
   if (res > 0) {
     pmd->set_has_process_mmaps();
     return true;
   }
-
   return false;
 }
 
diff --git a/base/trace_event/process_memory_maps_dump_provider.h b/base/trace_event/process_memory_maps_dump_provider.h
index 74529bd..f302a48d 100644
--- a/base/trace_event/process_memory_maps_dump_provider.h
+++ b/base/trace_event/process_memory_maps_dump_provider.h
@@ -9,10 +9,6 @@
 #include "base/memory/singleton.h"
 #include "base/trace_event/memory_dump_provider.h"
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
-#include "base/files/scoped_file.h"
-#endif
-
 namespace base {
 namespace trace_event {
 
@@ -29,7 +25,7 @@
   friend struct DefaultSingletonTraits<ProcessMemoryMapsDumpProvider>;
   FRIEND_TEST_ALL_PREFIXES(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps);
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_NACL)
   static FILE* proc_smaps_for_testing;
 #endif
 
diff --git a/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
index 8fcc9cc..cce33eba 100644
--- a/base/trace_event/process_memory_maps_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -13,7 +13,6 @@
 namespace base {
 namespace trace_event {
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
 namespace {
 const char kTestSmaps1[] =
     "00400000-004be000 r-xp 00000000 fc:01 1234              /file/1\n"
@@ -184,7 +183,6 @@
   EXPECT_EQ(4 * 1024UL, regions_2[0].byte_stats_private_dirty_resident);
   EXPECT_EQ(0 * 1024UL, regions_2[0].byte_stats_swapped);
 }
-#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
 
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi
index 27184189..8fcf5d2 100644
--- a/base/trace_event/trace_event.gypi
+++ b/base/trace_event/trace_event.gypi
@@ -27,7 +27,6 @@
       'trace_event/process_memory_dump.h',
       'trace_event/process_memory_maps.cc',
       'trace_event/process_memory_maps.h',
-      'trace_event/process_memory_maps_dump_provider.cc',
       'trace_event/process_memory_maps_dump_provider.h',
       'trace_event/process_memory_totals.cc',
       'trace_event/process_memory_totals.h',
@@ -64,14 +63,6 @@
       'trace_event/winheap_dump_provider_win.cc',
       'trace_event/winheap_dump_provider_win.h',
     ],
-    'conditions': [
-      ['OS == "linux" or OS == "android"', {
-          'trace_event_sources': [
-            'trace_event/malloc_dump_provider.cc',
-            'trace_event/malloc_dump_provider.h',
-          ],
-      }],
-    ],
     'trace_event_test_sources' : [
       'trace_event/java_heap_dump_provider_android_unittest.cc',
       'trace_event/memory_allocator_dump_unittest.cc',
@@ -79,7 +70,6 @@
       'trace_event/memory_profiler_allocation_context_unittest.cc',
       'trace_event/memory_profiler_allocation_register_unittest.cc',
       'trace_event/process_memory_dump_unittest.cc',
-      'trace_event/process_memory_maps_dump_provider_unittest.cc',
       'trace_event/process_memory_totals_dump_provider_unittest.cc',
       'trace_event/trace_config_memory_test_util.h',
       'trace_event/trace_config_unittest.cc',
@@ -91,5 +81,17 @@
       'trace_event/trace_event_win_unittest.cc',
       'trace_event/winheap_dump_provider_win_unittest.cc',
     ],
+    'conditions': [
+      ['OS == "linux" or OS == "android"', {
+          'trace_event_sources': [
+            'trace_event/malloc_dump_provider.cc',
+            'trace_event/malloc_dump_provider.h',
+            'trace_event/process_memory_maps_dump_provider.cc',
+          ],
+          'trace_event_test_sources' : [
+            'trace_event/process_memory_maps_dump_provider_unittest.cc',
+          ],
+      }],
+    ],
   },
 }
diff --git a/chrome/browser/android/favicon_helper.cc b/chrome/browser/android/favicon_helper.cc
index 67f0c3ef..182348f 100644
--- a/chrome/browser/android/favicon_helper.cc
+++ b/chrome/browser/android/favicon_helper.cc
@@ -31,8 +31,8 @@
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/color_analysis.h"
 #include "ui/gfx/color_utils.h"
-#include "ui/gfx/favicon_size.h"
 #include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
 
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
@@ -68,6 +68,16 @@
                                                j_icon_url.obj());
 }
 
+size_t GetLargestSizeIndex(const std::vector<gfx::Size>& sizes) {
+  DCHECK(!sizes.empty());
+  size_t ret = 0;
+  for (size_t i = 1; i < sizes.size(); ++i) {
+    if (sizes[ret].GetArea() < sizes[i].GetArea())
+      ret = i;
+  }
+  return ret;
+}
+
 void OnFaviconDownloaded(
     const ScopedJavaGlobalRef<jobject>& j_availability_callback,
     Profile* profile,
@@ -79,10 +89,9 @@
     const std::vector<gfx::Size>& original_sizes) {
   bool success = !bitmaps.empty();
   if (success) {
-    gfx::Image image = gfx::Image(CreateFaviconImageSkia(bitmaps,
-                                                         original_sizes,
-                                                         gfx::kFaviconSize,
-                                                         nullptr));
+    // Only keep the largest favicon available.
+    gfx::Image image = gfx::Image(gfx::ImageSkia(
+        gfx::ImageSkiaRep(bitmaps[GetLargestSizeIndex(original_sizes)], 0)));
     favicon_base::SetFaviconColorSpace(&image);
     favicon::FaviconService* service = FaviconServiceFactory::GetForProfile(
         profile, ServiceAccessType::IMPLICIT_ACCESS);
diff --git a/chrome/browser/browser_shutdown.cc b/chrome/browser/browser_shutdown.cc
index aa7486c..3e28ea2 100644
--- a/chrome/browser/browser_shutdown.cc
+++ b/chrome/browser/browser_shutdown.cc
@@ -19,6 +19,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
 #include "chrome/browser/about_flags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
@@ -30,6 +31,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/common/switch_utils.h"
 #include "components/metrics/metrics_service.h"
+#include "components/tracing/tracing_switches.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
 
@@ -112,7 +114,7 @@
 #if !defined(OS_CHROMEOS)
   // Start the shutdown tracing. Note that On ChromeOS this has already been
   // called in AttemptUserExit().
-  chrome::StartShutdownTracing();
+  StartShutdownTracing();
 #endif
 
   g_shutdown_type = type;
@@ -218,7 +220,7 @@
 
 #if defined(OS_WIN)
   if (!browser_util::IsBrowserAlreadyRunning() &&
-      g_shutdown_type != browser_shutdown::END_SESSION) {
+      g_shutdown_type != END_SESSION) {
     upgrade_util::SwapNewChromeExeIfPresent();
   }
 #endif
@@ -346,4 +348,17 @@
   return g_trying_to_quit;
 }
 
+void StartShutdownTracing() {
+  const base::CommandLine& command_line =
+      *base::CommandLine::ForCurrentProcess();
+  if (command_line.HasSwitch(switches::kTraceShutdown)) {
+    base::trace_event::TraceConfig trace_config(
+        command_line.GetSwitchValueASCII(switches::kTraceShutdown), "");
+    base::trace_event::TraceLog::GetInstance()->SetEnabled(
+        trace_config,
+        base::trace_event::TraceLog::RECORDING_MODE);
+  }
+  TRACE_EVENT0("shutdown", "StartShutdownTracing");
+}
+
 }  // namespace browser_shutdown
diff --git a/chrome/browser/browser_shutdown.h b/chrome/browser/browser_shutdown.h
index 1d10200..080a4b1 100644
--- a/chrome/browser/browser_shutdown.h
+++ b/chrome/browser/browser_shutdown.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_BROWSER_SHUTDOWN_H__
-#define CHROME_BROWSER_BROWSER_SHUTDOWN_H__
+#ifndef CHROME_BROWSER_BROWSER_SHUTDOWN_H_
+#define CHROME_BROWSER_BROWSER_SHUTDOWN_H_
 
 class PrefRegistrySimple;
 
@@ -68,6 +68,11 @@
 // General accessor.
 bool IsTryingToQuit();
 
+// Starts to collect shutdown traces. On ChromeOS this will start immediately
+// on AttemptUserExit() and all other systems will start once all tabs are
+// closed.
+void StartShutdownTracing();
+
 }  // namespace browser_shutdown
 
-#endif  // CHROME_BROWSER_BROWSER_SHUTDOWN_H__
+#endif  // CHROME_BROWSER_BROWSER_SHUTDOWN_H_
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index 1b6481f..1cd1713d 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -75,7 +75,6 @@
     ::switches::kDisableAcceleratedVideoDecode,
     ::switches::kDisableBlinkFeatures,
     ::switches::kDisableCastStreamingHWEncoding,
-    ::switches::kDisableCompositorAnimationTimelines,
     ::switches::kDisableDistanceFieldText,
     ::switches::kDisableGpu,
     ::switches::kDisableGpuMemoryBufferVideoFrames,
@@ -97,6 +96,7 @@
     ::switches::kDisableTouchDragDrop,
     ::switches::kDisableZeroCopy,
     ::switches::kEnableBlinkFeatures,
+    ::switches::kEnableCompositorAnimationTimelines,
     ::switches::kDisableDisplayList2dCanvas,
     ::switches::kEnableDisplayList2dCanvas,
     ::switches::kForceDisplayList2dCanvas,
diff --git a/chrome/browser/lifetime/application_lifetime.cc b/chrome/browser/lifetime/application_lifetime.cc
index 06a900869..448b492 100644
--- a/chrome/browser/lifetime/application_lifetime.cc
+++ b/chrome/browser/lifetime/application_lifetime.cc
@@ -5,14 +5,12 @@
 #include "chrome/browser/lifetime/application_lifetime.h"
 
 #include "base/bind.h"
-#include "base/command_line.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "base/process/process.h"
 #include "base/process/process_handle.h"
-#include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
@@ -31,9 +29,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/user_manager.h"
 #include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
-#include "components/tracing/tracing_switches.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/notification_service.h"
@@ -50,10 +46,6 @@
 #include "base/win/win_util.h"
 #endif
 
-#if defined(USE_ASH)
-#include "ash/shell.h"
-#endif
-
 namespace chrome {
 namespace {
 
@@ -148,7 +140,7 @@
 
 void AttemptUserExit() {
 #if defined(OS_CHROMEOS)
-  StartShutdownTracing();
+  browser_shutdown::StartShutdownTracing();
   chromeos::BootTimesRecorder::Get()->AddLogoutTimeMarker("LogoutStarted",
                                                           false);
 
@@ -180,19 +172,6 @@
 #endif
 }
 
-void StartShutdownTracing() {
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kTraceShutdown)) {
-    base::trace_event::TraceConfig trace_config(
-        command_line.GetSwitchValueASCII(switches::kTraceShutdown), "");
-    base::trace_event::TraceLog::GetInstance()->SetEnabled(
-        trace_config,
-        base::trace_event::TraceLog::RECORDING_MODE);
-  }
-  TRACE_EVENT0("shutdown", "StartShutdownTracing");
-}
-
 // The Android implementation is in application_lifetime_android.cc
 #if !defined(OS_ANDROID)
 void AttemptRestart() {
@@ -388,25 +367,6 @@
   HandleAppExitingForPlatform();
 }
 
-bool ShouldStartShutdown(Browser* browser) {
-  if (BrowserList::GetInstance(browser->host_desktop_type())->size() > 1)
-    return false;
-#if defined(OS_WIN)
-  // On Windows 8 the desktop and ASH environments could be active
-  // at the same time.
-  // We should not start the shutdown process in the following cases:-
-  // 1. If the desktop type of the browser going away is ASH and there
-  //    are browser windows open in the desktop.
-  // 2. If the desktop type of the browser going away is desktop and the ASH
-  //    environment is still active.
-  if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_NATIVE)
-    return !ash::Shell::HasInstance();
-  else if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
-    return BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE)->empty();
-#endif
-  return true;
-}
-
 void DisableShutdownForTesting(bool disable_shutdown_for_testing) {
   g_disable_shutdown_for_testing = disable_shutdown_for_testing;
   if (!g_disable_shutdown_for_testing && !WillKeepAlive())
diff --git a/chrome/browser/lifetime/application_lifetime.h b/chrome/browser/lifetime/application_lifetime.h
index 3cf1854..a0acd684 100644
--- a/chrome/browser/lifetime/application_lifetime.h
+++ b/chrome/browser/lifetime/application_lifetime.h
@@ -18,11 +18,6 @@
 // SIGTERM to start actual exit process.
 void AttemptUserExit();
 
-// Starts to collect shutdown traces. On ChromeOS this will start immediately
-// on AttemptUserExit() and all other systems will start once all tabs are
-// closed.
-void StartShutdownTracing();
-
 // Starts a user initiated restart process. On platforms other than
 // chromeos, this sets a restart bit in the preference so that
 // chrome will be restarted at the end of shutdown process. On
@@ -112,10 +107,6 @@
 // processing required.
 void HandleAppExitingForPlatform();
 
-// Returns true if we can start the shutdown sequence for the browser, i.e. the
-// last browser window is being closed.
-bool ShouldStartShutdown(Browser* browser);
-
 // Disable browser shutdown for unit tests.
 void DisableShutdownForTesting(bool disable_shutdown_for_testing);
 
diff --git a/chrome/browser/sync/glue/bookmark_change_processor.cc b/chrome/browser/sync/glue/bookmark_change_processor.cc
index c93cb70..d612240 100644
--- a/chrome/browser/sync/glue/bookmark_change_processor.cc
+++ b/chrome/browser/sync/glue/bookmark_change_processor.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/profile_sync_service.h"
 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "components/bookmarks/browser/bookmark_client.h"
diff --git a/chrome/browser/sync/glue/bookmark_change_processor.h b/chrome/browser/sync/glue/bookmark_change_processor.h
index 6ec5b5c..9c69cc5 100644
--- a/chrome/browser/sync/glue/bookmark_change_processor.h
+++ b/chrome/browser/sync/glue/bookmark_change_processor.h
@@ -9,7 +9,6 @@
 
 #include "base/compiler_specific.h"
 #include "chrome/browser/sync/glue/bookmark_model_associator.h"
-#include "chrome/browser/sync/glue/sync_backend_host.h"
 #include "components/bookmarks/browser/bookmark_model_observer.h"
 #include "components/bookmarks/browser/bookmark_node.h"
 #include "components/sync_driver/change_processor.h"
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller.cc b/chrome/browser/sync/glue/bookmark_data_type_controller.cc
index f2d687c..99a8073 100644
--- a/chrome/browser/sync/glue/bookmark_data_type_controller.cc
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller.cc
@@ -5,30 +5,22 @@
 #include "chrome/browser/sync/glue/bookmark_data_type_controller.h"
 
 #include "base/metrics/histogram.h"
-#include "chrome/browser/bookmarks/bookmark_model_factory.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/history/history_service_factory.h"
-#include "chrome/browser/sync/glue/chrome_report_unrecoverable_error.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/sync_driver/sync_api_component_factory.h"
 #include "components/sync_driver/sync_client.h"
-#include "content/public/browser/browser_thread.h"
 
 using bookmarks::BookmarkModel;
-using content::BrowserThread;
 
 namespace browser_sync {
 
 BookmarkDataTypeController::BookmarkDataTypeController(
+    const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
+    const base::Closure& error_callback,
     sync_driver::SyncClient* sync_client)
-    : FrontendDataTypeController(
-          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
-          base::Bind(&ChromeReportUnrecoverableError),
-          sync_client),
+    : FrontendDataTypeController(ui_thread, error_callback, sync_client),
       history_service_observer_(this),
-      bookmark_model_observer_(this) {
-}
+      bookmark_model_observer_(this) {}
 
 syncer::ModelType BookmarkDataTypeController::type() const {
   return syncer::BOOKMARKS;
@@ -99,7 +91,6 @@
 
 void BookmarkDataTypeController::OnHistoryServiceLoaded(
     history::HistoryService* service) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK_EQ(state_, MODEL_STARTING);
   history_service_observer_.RemoveAll();
 
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller.h b/chrome/browser/sync/glue/bookmark_data_type_controller.h
index 07c3843b..30d8cde0 100644
--- a/chrome/browser/sync/glue/bookmark_data_type_controller.h
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller.h
@@ -13,8 +13,6 @@
 #include "components/history/core/browser/history_service_observer.h"
 #include "components/sync_driver/frontend_data_type_controller.h"
 
-class ProfileSyncService;
-
 namespace browser_sync {
 
 // A class that manages the startup and shutdown of bookmark sync.
@@ -22,7 +20,10 @@
                                    public bookmarks::BaseBookmarkModelObserver,
                                    public history::HistoryServiceObserver {
  public:
-  explicit BookmarkDataTypeController(sync_driver::SyncClient* sync_client);
+  BookmarkDataTypeController(
+      const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
+      const base::Closure& error_callback,
+      sync_driver::SyncClient* sync_client);
 
   // FrontendDataTypeController:
   syncer::ModelType type() const override;
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
index 86f584c..7cd3b0a 100644
--- a/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
@@ -113,7 +113,9 @@
     profile_sync_factory_.reset(
         new ProfileSyncComponentsFactoryMock(model_associator_,
                                              change_processor_));
-    bookmark_dtc_ = new BookmarkDataTypeController(this);
+    bookmark_dtc_ =
+        new BookmarkDataTypeController(base::ThreadTaskRunnerHandle::Get(),
+                                       base::Bind(&base::DoNothing), this);
   }
 
  protected:
diff --git a/chrome/browser/sync/glue/bookmark_model_associator.cc b/chrome/browser/sync/glue/bookmark_model_associator.cc
index 9955676..5bb4f9a 100644
--- a/chrome/browser/sync/glue/bookmark_model_associator.cc
+++ b/chrome/browser/sync/glue/bookmark_model_associator.cc
@@ -17,7 +17,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/thread_task_runner_handle.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/glue/bookmark_change_processor.h"
 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "components/bookmarks/browser/bookmark_client.h"
diff --git a/chrome/browser/sync/profile_sync_components_factory_impl.cc b/chrome/browser/sync/profile_sync_components_factory_impl.cc
index 207a0a7..098bb8a 100644
--- a/chrome/browser/sync/profile_sync_components_factory_impl.cc
+++ b/chrome/browser/sync/profile_sync_components_factory_impl.cc
@@ -208,8 +208,9 @@
   // Bookmark sync is enabled by default.  Register unless explicitly
   // disabled.
   if (!disabled_types.Has(syncer::BOOKMARKS)) {
-    sync_service->RegisterDataTypeController(
-        new BookmarkDataTypeController(sync_client));
+    sync_service->RegisterDataTypeController(new BookmarkDataTypeController(
+        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+        base::Bind(&ChromeReportUnrecoverableError), sync_client));
   }
 
   const bool history_disabled =
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 24e66d5..584a1d6 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -219,6 +219,7 @@
 
 #if defined(USE_ASH)
 #include "ash/ash_switches.h"
+#include "ash/shell.h"
 #endif
 
 using base::TimeDelta;
@@ -713,7 +714,7 @@
   bool should_quit_if_last_browser =
       browser_shutdown::IsTryingToQuit() || !chrome::WillKeepAlive();
 
-  if (should_quit_if_last_browser && chrome::ShouldStartShutdown(this))
+  if (should_quit_if_last_browser && ShouldStartShutdown())
     browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);
 
   // Don't use GetForProfileIfExisting here, we want to force creation of the
@@ -2601,6 +2602,25 @@
   return window_ && window_->ShouldHideUIForFullscreen();
 }
 
+bool Browser::ShouldStartShutdown() const {
+  if (BrowserList::GetInstance(host_desktop_type())->size() > 1)
+    return false;
+#if defined(OS_WIN)
+  // On Windows 8 the desktop and ASH environments could be active
+  // at the same time.
+  // We should not start the shutdown process in the following cases:-
+  // 1. If the desktop type of the browser going away is ASH and there
+  //    are browser windows open in the desktop.
+  // 2. If the desktop type of the browser going away is desktop and the ASH
+  //    environment is still active.
+  if (host_desktop_type() == chrome::HOST_DESKTOP_TYPE_NATIVE)
+    return !ash::Shell::HasInstance();
+  if (host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
+    return BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE)->empty();
+#endif
+  return true;
+}
+
 bool Browser::MaybeCreateBackgroundContents(
     int route_id,
     int main_frame_route_id,
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index e296569..b421e4b 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -826,6 +826,10 @@
 
   bool ShouldHideUIForFullscreen() const;
 
+  // Returns true if we can start the shutdown sequence for the browser, i.e.
+  // the last browser window is being closed.
+  bool ShouldStartShutdown() const;
+
   // Creates a BackgroundContents if appropriate; return true if one was
   // created.
   bool MaybeCreateBackgroundContents(
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 0f7b2378..dc03b79d 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1226,7 +1226,6 @@
     switches::kDisableAcceleratedVideoDecode,
     switches::kDisableBlinkFeatures,
     switches::kDisableBreakpad,
-    switches::kDisableCompositorAnimationTimelines,
     switches::kDisablePreferCompositingToLCDText,
     switches::kDisableDatabases,
     switches::kDisableDelayAgnosticAec,
@@ -1265,6 +1264,7 @@
     switches::kDomAutomationController,
     switches::kEnableBlinkFeatures,
     switches::kEnableBrowserSideNavigation,
+    switches::kEnableCompositorAnimationTimelines,
     switches::kEnableCredentialManagerAPI,
     switches::kEnableDisplayList2dCanvas,
     switches::kEnableDistanceFieldText,
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 374f228..aa0cc6d9 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -83,10 +83,6 @@
 // features.
 const char kDisableBlinkFeatures[]          = "disable-blink-features";
 
-// Disables new cc/animation system (Project Heaviside). crbug.com/394772
-const char kDisableCompositorAnimationTimelines[] =
-    "disable-compositor-animation-timelines";
-
 // Disable the creation of compositing layers when it would prevent LCD text.
 const char kDisablePreferCompositingToLCDText[] =
     "disable-prefer-compositing-to-lcd-text";
@@ -293,6 +289,10 @@
 const char kDisableAcceleratedJpegDecoding[] =
     "disable-accelerated-jpeg-decoding";
 
+// Enables new cc/animation system (Project Heaviside). crbug.com/394772
+const char kEnableCompositorAnimationTimelines[] =
+    "enable-compositor-animation-timelines";
+
 // Enables LCD text.
 const char kEnableLCDText[]                 = "enable-lcd-text";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index fb2b2d6..fe4a2fcd 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -28,13 +28,12 @@
 CONTENT_EXPORT extern const char kDefaultTileHeight[];
 CONTENT_EXPORT extern const char kDisable2dCanvasAntialiasing[];
 CONTENT_EXPORT extern const char kDisable3DAPIs[];
+CONTENT_EXPORT extern const char kDisableBlinkFeatures[];
 CONTENT_EXPORT extern const char kDisableAccelerated2dCanvas[];
 CONTENT_EXPORT extern const char kDisableAcceleratedJpegDecoding[];
 CONTENT_EXPORT extern const char kDisableAcceleratedMjpegDecode[];
 CONTENT_EXPORT extern const char kDisableAcceleratedVideoDecode[];
 extern const char kDisableBackingStoreLimit[];
-CONTENT_EXPORT extern const char kDisableBlinkFeatures[];
-CONTENT_EXPORT extern const char kDisableCompositorAnimationTimelines[];
 CONTENT_EXPORT extern const char kDisablePreferCompositingToLCDText[];
 CONTENT_EXPORT extern const char kDisableDatabases[];
 CONTENT_EXPORT extern const char kDisableDelayAgnosticAec[];
@@ -96,6 +95,7 @@
 CONTENT_EXPORT extern const char kDomAutomationController[];
 extern const char kEnable2dCanvasClipAntialiasing[];
 CONTENT_EXPORT extern const char kEnableAggressiveDOMStorageFlushing[];
+CONTENT_EXPORT extern const char kEnableCompositorAnimationTimelines[];
 CONTENT_EXPORT extern const char kEnableCredentialManagerAPI[];
 CONTENT_EXPORT extern const char kEnablePreferCompositingToLCDText[];
 CONTENT_EXPORT extern const char kEnableBlinkFeatures[];
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index 04df33c0..2e97735 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -246,10 +246,10 @@
   settings.accelerated_animation_enabled =
       compositor_deps_->IsThreadedAnimationEnabled();
 
-  settings.use_compositor_animation_timelines =
-      !cmd->HasSwitch(switches::kDisableCompositorAnimationTimelines);
-  blink::WebRuntimeFeatures::enableCompositorAnimationTimelines(
-      settings.use_compositor_animation_timelines);
+  if (cmd->HasSwitch(switches::kEnableCompositorAnimationTimelines)) {
+    settings.use_compositor_animation_timelines = true;
+    blink::WebRuntimeFeatures::enableCompositorAnimationTimelines(true);
+  }
 
   settings.default_tile_size = CalculateDefaultTileSize(widget_);
   if (cmd->HasSwitch(switches::kDefaultTileWidth)) {
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index a72214d..c8ca4bdb 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -653,8 +653,8 @@
       *base::CommandLine::ForCurrentProcess();
 
   cc::LayerSettings layer_settings;
-  layer_settings.use_compositor_animation_timelines =
-      !command_line.HasSwitch(switches::kDisableCompositorAnimationTimelines);
+  if (command_line.HasSwitch(switches::kEnableCompositorAnimationTimelines))
+    layer_settings.use_compositor_animation_timelines = true;
   cc_blink::WebLayerImpl::SetLayerSettings(layer_settings);
   cc::SetClientNameForMetrics("Renderer");
 
diff --git a/ios/third_party/gcdwebserver/BUILD.gn b/ios/third_party/gcdwebserver/BUILD.gn
new file mode 100644
index 0000000..da07148
--- /dev/null
+++ b/ios/third_party/gcdwebserver/BUILD.gn
@@ -0,0 +1,59 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+config("public_config") {
+  ldflags = [ "-lz" ]
+  libs = [
+    "CFNetwork.framework",
+    "MobileCoreServices.framework",
+  ]
+  include_dirs = [
+    "src/GCDWebServer/Core",
+    "src/GCDWebServer/Requests",
+    "src/GCDWebServer/Responses",
+  ]
+}
+
+config("internal_config") {
+  visibility = [ ":gcdwebserver" ]
+  cflags_objc = [ "-fobjc-arc" ]
+}
+
+source_set("gcdwebserver") {
+  testonly = true
+
+  sources = [
+    "src/GCDWebServer/Core/GCDWebServer.h",
+    "src/GCDWebServer/Core/GCDWebServer.m",
+    "src/GCDWebServer/Core/GCDWebServerConnection.h",
+    "src/GCDWebServer/Core/GCDWebServerConnection.m",
+    "src/GCDWebServer/Core/GCDWebServerFunctions.h",
+    "src/GCDWebServer/Core/GCDWebServerFunctions.m",
+    "src/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h",
+    "src/GCDWebServer/Core/GCDWebServerPrivate.h",
+    "src/GCDWebServer/Core/GCDWebServerRequest.h",
+    "src/GCDWebServer/Core/GCDWebServerRequest.m",
+    "src/GCDWebServer/Core/GCDWebServerResponse.h",
+    "src/GCDWebServer/Core/GCDWebServerResponse.m",
+    "src/GCDWebServer/Requests/GCDWebServerDataRequest.h",
+    "src/GCDWebServer/Requests/GCDWebServerDataRequest.m",
+    "src/GCDWebServer/Requests/GCDWebServerFileRequest.h",
+    "src/GCDWebServer/Requests/GCDWebServerFileRequest.m",
+    "src/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h",
+    "src/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m",
+    "src/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h",
+    "src/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m",
+    "src/GCDWebServer/Responses/GCDWebServerDataResponse.h",
+    "src/GCDWebServer/Responses/GCDWebServerDataResponse.m",
+    "src/GCDWebServer/Responses/GCDWebServerErrorResponse.h",
+    "src/GCDWebServer/Responses/GCDWebServerErrorResponse.m",
+    "src/GCDWebServer/Responses/GCDWebServerFileResponse.h",
+    "src/GCDWebServer/Responses/GCDWebServerFileResponse.m",
+    "src/GCDWebServer/Responses/GCDWebServerStreamedResponse.h",
+    "src/GCDWebServer/Responses/GCDWebServerStreamedResponse.m",
+  ]
+
+  public_configs = [ ":public_config" ]
+  configs += [ ":internal_config" ]
+}
diff --git a/ios/third_party/gcdwebserver/gcdwebserver.gyp b/ios/third_party/gcdwebserver/gcdwebserver.gyp
index 117c6a2d..28f7738 100644
--- a/ios/third_party/gcdwebserver/gcdwebserver.gyp
+++ b/ios/third_party/gcdwebserver/gcdwebserver.gyp
@@ -4,6 +4,7 @@
 {
   'targets' : [
     {
+      # GN version: //ios/third_party/gcdwebserver
       'target_name' : 'gcdwebserver',
       'type': 'static_library',
       'include_dirs': [
diff --git a/media/midi/midi_message_queue.cc b/media/midi/midi_message_queue.cc
index d35acc2..20fcc87 100644
--- a/media/midi/midi_message_queue.cc
+++ b/media/midi/midi_message_queue.cc
@@ -20,10 +20,6 @@
   return (data & 0x80) == 0;
 }
 
-bool IsFirstStatusByte(uint8 data) {
-  return !IsDataByte(data) && data != kEndOfSysEx;
-}
-
 bool IsSystemRealTimeMessage(uint8 data) {
   return 0xf8 <= data;
 }
@@ -51,74 +47,79 @@
   message->clear();
 
   while (true) {
+    // Check if |next_message_| is already a complete MIDI message or not.
+    if (!next_message_.empty()) {
+      const uint8 status_byte = next_message_.front();
+      const size_t target_len = GetMidiMessageLength(status_byte);
+      if (target_len == 0) {
+        DCHECK_EQ(kSysEx, status_byte);
+        if (next_message_.back() == kEndOfSysEx) {
+           // OK, this is a complete SysEx message.
+           std::swap(*message, next_message_);
+           DCHECK(next_message_.empty());
+          return;
+        }
+      } else if (next_message_.size() == target_len) {
+        // OK, this is a complete non-SysEx message.
+        std::swap(*message, next_message_);
+        DCHECK(next_message_.empty());
+        if (allow_running_status_ && !IsSystemMessage(status_byte)) {
+          // Speculatively keep the status byte in case of running status.
+          // If this assumption is not true, |next_message_| will be cleared
+          // anyway.  Note that system common messages should reset the
+          // running status.
+          next_message_.push_back(status_byte);
+        }
+        return;
+      } else if (next_message_.size() > target_len) {
+        NOTREACHED();
+      }
+    }
+
     if (queue_.empty())
       return;
 
-    const uint8 next = queue_.front();
-    queue_.pop_front();
-
-    // "System Real Time Messages" is a special kind of MIDI messages, which can
-    // appear at arbitrary byte position of MIDI stream. Here we reorder
+    // "System Real Time Messages" is a special MIDI message, which can appear
+    // at an arbitrary byte position of MIDI stream. Here we reorder
     // "System Real Time Messages" prior to |next_message_| so that each message
     // can be clearly separated as a complete MIDI message.
+    const uint8 next = queue_.front();
     if (IsSystemRealTimeMessage(next)) {
       message->push_back(next);
+      queue_.pop_front();
       return;
     }
 
-    // Here |next_message_[0]| may contain the previous status byte when
-    // |allow_running_status_| is true. Following condition fixes up
-    // |next_message_| if running status condition is not fulfilled.
-    if (!next_message_.empty() &&
-        ((next_message_[0] == kSysEx && IsFirstStatusByte(next)) ||
-         (next_message_[0] != kSysEx && !IsDataByte(next)))) {
-      // An invalid data sequence is found or running status condition is not
-      // fulfilled.
-      next_message_.clear();
-    }
-
     if (next_message_.empty()) {
-      if (IsFirstStatusByte(next)) {
+      const size_t target_len = GetMidiMessageLength(next);
+      // If |target_len| is zero, it means either |next| is not a valid status
+      // byte or |next| is a valid status byte but the message length is
+      // unpredictable.  For the latter case, only SysEx can be accepted.
+      if (target_len > 0 || next == kSysEx) {
         next_message_.push_back(next);
-      } else {
-        // MIDI protocol doesn't provide any error correction mechanism in
-        // physical layers, and incoming messages can be corrupted, and should
-        // be corrected here.
       }
+      // Consume |next| always, since if |next| isn't status byte, which means
+      // that |next| is just corrupted data, or a data byte followed by
+      // reserved message, which we are unable to understand and deal with
+      // anyway.
+      queue_.pop_front();
       continue;
     }
 
-    // Here we can assume |next_message_| starts with a valid status byte.
-    const uint8 status_byte = next_message_[0];
-    next_message_.push_back(next);
+    const uint8 status_byte = next_message_.front();
 
-    if (status_byte == kSysEx) {
-      if (next == kEndOfSysEx) {
-        std::swap(*message, next_message_);
-        next_message_.clear();
-        return;
-      }
-      continue;
-    }
-
-    DCHECK(IsDataByte(next));
-    DCHECK_NE(kSysEx, status_byte);
-    const size_t target_len = GetMidiMessageLength(status_byte);
-    if (next_message_.size() < target_len)
-      continue;
-    if (next_message_.size() == target_len) {
-      std::swap(*message, next_message_);
+    // If we receive a new non-data byte before completing the pending message,
+    // drop the pending message and respin the loop to re-evaluate |next|.
+    // This also clears the running status byte speculatively added above, as
+    // well as any broken incomplete messages.
+    if (!IsDataByte(next) && !(status_byte == kSysEx && next == kEndOfSysEx)) {
       next_message_.clear();
-      if (allow_running_status_ && !IsSystemMessage(status_byte)) {
-        // Speculatively keep the status byte in case of running status. If this
-        // assumption is not true, |next_message_| will be cleared anyway.
-        // Note that system common messages should reset the running status.
-        next_message_.push_back(status_byte);
-      }
-      return;
+      continue;
     }
 
-    NOTREACHED();
+    // OK to consume this byte.
+    next_message_.push_back(next);
+    queue_.pop_front();
   }
 }
 
diff --git a/media/midi/midi_message_queue_unittest.cc b/media/midi/midi_message_queue_unittest.cc
index d25a692..4abdc5b 100644
--- a/media/midi/midi_message_queue_unittest.cc
+++ b/media/midi/midi_message_queue_unittest.cc
@@ -11,10 +11,17 @@
 namespace {
 
 const uint8 kGMOn[] = { 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 };
+const uint8 kPartialGMOn1st[] = { 0xf0 };
+const uint8 kPartialGMOn2nd[] = { 0x7e, 0x7f, 0x09, 0x01 };
+const uint8 kPartialGMOn3rd[] = { 0xf7 };
 const uint8 kGSOn[] = {
   0xf0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7f, 0x00, 0x41, 0xf7,
 };
 const uint8 kNoteOn[] = { 0x90, 0x3c, 0x7f };
+const uint8 kPartialNoteOn1st[] = { 0x90 };
+const uint8 kPartialNoteOn2nd[] = { 0x3c };
+const uint8 kPartialNoteOn3rd[] = { 0x7f };
+
 const uint8 kNoteOnWithRunningStatus[] = {
   0x90, 0x3c, 0x7f, 0x3c, 0x7f, 0x3c, 0x7f,
 };
@@ -23,12 +30,19 @@
   0xd0, 0x01, 0x01, 0x01,
 };
 const uint8 kTimingClock[] = { 0xf8 };
+const uint8 kSystemCommonMessageTuneRequest[] = { 0xf6 };
 const uint8 kMTCFrame[] = { 0xf1, 0x00 };
-const uint8 kBrokenData1[] = { 0x90 };
+const uint8 kBrokenData1[] = { 0x92 };
 const uint8 kBrokenData2[] = { 0xf7 };
 const uint8 kBrokenData3[] = { 0xf2, 0x00 };
 const uint8 kDataByte0[] = { 0x00 };
 
+const uint8 kReservedMessage1[] = { 0xf4 };
+const uint8 kReservedMessage2[] = { 0xf5 };
+const uint8 kReservedMessage1WithDataBytes[] = {
+  0xf4, 0x01, 0x01, 0x01, 0x01, 0x01
+};
+
 template <typename T, size_t N>
 void Add(MidiMessageQueue* queue, const T(&array)[N]) {
   queue->Add(array, N);
@@ -190,6 +204,369 @@
   EXPECT_TRUE(message.empty());
 }
 
+TEST(MidiMessageQueueTest, Issue540016) {
+  const uint8 kData[] = { 0xf4, 0x3a };
+  MidiMessageQueue queue(false);
+  Add(&queue, kData);
+  std::vector<uint8> message;
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+}
+
+TEST(MidiMessageQueueTest, ReconstructNonSysExMessage) {
+  MidiMessageQueue queue(true);
+  std::vector<uint8> message;
+
+  Add(&queue, kPartialNoteOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialNoteOn2nd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialNoteOn3rd);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+}
+
+TEST(MidiMessageQueueTest, ReconstructBrokenNonSysExMessage) {
+  MidiMessageQueue queue(true);
+  std::vector<uint8> message;
+
+  Add(&queue, kPartialNoteOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialNoteOn2nd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialGMOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialNoteOn3rd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+}
+
+TEST(MidiMessageQueueTest, ReconstructSysExMessage) {
+  MidiMessageQueue queue(true);
+  std::vector<uint8> message;
+
+  Add(&queue, kPartialGMOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialGMOn2nd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialGMOn3rd);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kGMOn, message);
+
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+}
+
+TEST(MidiMessageQueueTest, ReconstructBrokenSysExMessage) {
+  MidiMessageQueue queue(true);
+  std::vector<uint8> message;
+
+  Add(&queue, kPartialGMOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialGMOn2nd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialNoteOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialGMOn3rd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+}
+
+TEST(MidiMessageQueueTest, OneByteMessage) {
+  MidiMessageQueue queue(true);
+  std::vector<uint8> message;
+
+  Add(&queue, kSystemCommonMessageTuneRequest);
+  Add(&queue, kSystemCommonMessageTuneRequest);
+  Add(&queue, kSystemCommonMessageTuneRequest);
+  Add(&queue, kSystemCommonMessageTuneRequest);
+  Add(&queue, kNoteOn);
+  Add(&queue, kSystemCommonMessageTuneRequest);
+  Add(&queue, kNoteOn);
+  Add(&queue, kNoteOn);
+  Add(&queue, kSystemCommonMessageTuneRequest);
+
+  queue.Get(&message);
+  EXPECT_MESSAGE(kSystemCommonMessageTuneRequest, message);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kSystemCommonMessageTuneRequest, message);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kSystemCommonMessageTuneRequest, message);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kSystemCommonMessageTuneRequest, message);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kSystemCommonMessageTuneRequest, message);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kSystemCommonMessageTuneRequest, message);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+}
+
+TEST(MidiMessageQueueTest, OneByteMessageInjectedInNonSysExMessage) {
+  MidiMessageQueue queue(true);
+  std::vector<uint8> message;
+
+  Add(&queue, kPartialNoteOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialNoteOn2nd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kSystemCommonMessageTuneRequest);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kSystemCommonMessageTuneRequest, message);
+
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialNoteOn3rd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+}
+
+TEST(MidiMessageQueueTest, OneByteMessageInjectedInSysExMessage) {
+  MidiMessageQueue queue(true);
+  std::vector<uint8> message;
+
+  Add(&queue, kPartialGMOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialGMOn2nd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kSystemCommonMessageTuneRequest);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kSystemCommonMessageTuneRequest, message);
+
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kPartialGMOn3rd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+}
+
+TEST(MidiMessageQueueTest, ReservedMessage) {
+  MidiMessageQueue queue(true);
+  std::vector<uint8> message;
+
+  Add(&queue, kReservedMessage1);
+  Add(&queue, kNoteOn);
+  Add(&queue, kReservedMessage2);
+  Add(&queue, kNoteOn);
+  Add(&queue, kReservedMessage1WithDataBytes);
+  Add(&queue, kNoteOn);
+  Add(&queue, kReservedMessage2);
+  Add(&queue, kReservedMessage1WithDataBytes);
+  Add(&queue, kNoteOn);
+  Add(&queue, kReservedMessage1WithDataBytes);
+  Add(&queue, kReservedMessage2);
+  Add(&queue, kNoteOn);
+
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+
+  Add(&queue, kReservedMessage1);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kNoteOn);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kReservedMessage2);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kNoteOn);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kReservedMessage1WithDataBytes);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kNoteOn);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kReservedMessage2);
+  Add(&queue, kReservedMessage1WithDataBytes);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kNoteOn);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kReservedMessage1WithDataBytes);
+  Add(&queue, kReservedMessage2);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  Add(&queue, kNoteOn);
+  queue.Get(&message);
+  EXPECT_MESSAGE(kNoteOn, message);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+}
+
+TEST(MidiMessageQueueTest, ReservedMessageInjectedInNonSysExMessage) {
+  MidiMessageQueue queue(true);
+  std::vector<uint8> message;
+
+  // Inject |kReservedMessage1|
+  Add(&queue, kPartialNoteOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kPartialNoteOn2nd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kReservedMessage1);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kPartialNoteOn3rd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  // Inject |kReservedMessage2|
+  Add(&queue, kPartialNoteOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kPartialNoteOn2nd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kReservedMessage2);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kPartialNoteOn3rd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  // Inject |kReservedMessage1WithDataBytes|
+  Add(&queue, kPartialNoteOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kPartialNoteOn2nd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kReservedMessage1WithDataBytes);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kPartialNoteOn3rd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+}
+
+TEST(MidiMessageQueueTest, ReservedMessageInjectedInSysExMessage) {
+  MidiMessageQueue queue(true);
+  std::vector<uint8> message;
+
+  // Inject |kReservedMessage1|
+  Add(&queue, kPartialGMOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kPartialGMOn2nd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kReservedMessage1);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kPartialGMOn3rd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  // Inject |kReservedMessage2|
+  Add(&queue, kPartialGMOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kPartialGMOn2nd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kReservedMessage2);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kPartialGMOn3rd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+
+  // Inject |kReservedMessage1WithDataBytes|
+  Add(&queue, kPartialGMOn1st);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kPartialGMOn2nd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kReservedMessage1WithDataBytes);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+  Add(&queue, kPartialGMOn3rd);
+  queue.Get(&message);
+  EXPECT_TRUE(message.empty());
+}
+
 }  // namespace
 }  // namespace midi
 }  // namespace media
diff --git a/media/midi/midi_message_util.cc b/media/midi/midi_message_util.cc
index e8e953d..e329ac3c 100644
--- a/media/midi/midi_message_util.cc
+++ b/media/midi/midi_message_util.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/logging.h"
 #include "media/midi/midi_message_util.h"
 
 namespace media {
@@ -16,20 +17,36 @@
     return 2;
   if (0xe0 <= status_byte && status_byte <= 0xef)
     return 3;
-  if (status_byte == 0xf0)
-    return 0;
-  if (status_byte == 0xf1)
-    return 2;
-  if (status_byte == 0xf2)
-    return 3;
-  if (status_byte == 0xf3)
-    return 2;
-  if (0xf4 <= status_byte && status_byte <= 0xf6)
-    return 1;
-  if (status_byte == 0xf7)
-    return 0;
-  // 0xf8 <= status_byte && status_byte <= 0xff
-  return 1;
+
+  switch (status_byte) {
+    case 0xf0:
+      return 0;
+    case 0xf1:
+      return 2;
+    case 0xf2:
+      return 3;
+    case 0xf3:
+      return 2;
+    case 0xf4:  // Reserved
+    case 0xf5:  // Reserved
+      return 0;
+    case 0xf6:
+      return 1;
+    case 0xf7:
+      return 0;
+    case 0xf8:
+    case 0xf9:
+    case 0xfa:
+    case 0xfb:
+    case 0xfc:
+    case 0xfd:
+    case 0xfe:
+    case 0xff:
+      return 1;
+    default:
+      NOTREACHED();
+      return 0;
+  }
 }
 
 }  // namespace midi
diff --git a/media/midi/midi_message_util.h b/media/midi/midi_message_util.h
index 6533ab3..851b65c9 100644
--- a/media/midi/midi_message_util.h
+++ b/media/midi/midi_message_util.h
@@ -17,8 +17,9 @@
 // Returns the length of a MIDI message in bytes. Never returns 4 or greater.
 // Returns 0 if |status_byte| is:
 // - not a valid status byte, namely data byte.
-// - the MIDI System Exclusive message.
-// - the End of System Exclusive message.
+// - MIDI System Exclusive message.
+// - End of System Exclusive message.
+// - Reserved System Common Message (0xf4, 0xf5)
 MIDI_EXPORT size_t GetMidiMessageLength(uint8 status_byte);
 
 const uint8 kSysExByte = 0xf0;
diff --git a/media/midi/midi_message_util_unittest.cc b/media/midi/midi_message_util_unittest.cc
index 25dbf5e..cb284af9 100644
--- a/media/midi/midi_message_util_unittest.cc
+++ b/media/midi/midi_message_util_unittest.cc
@@ -12,19 +12,28 @@
 
 const uint8 kGMOn[] = { 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 };
 const uint8 kNoteOn[] = { 0x90, 0x3c, 0x7f };
+const uint8 kSystemCommonMessageReserved1[] = { 0xf4 };
+const uint8 kSystemCommonMessageReserved2[] = { 0xf5 };
+const uint8 kSystemCommonMessageTuneRequest[] = { 0xf6 };
 const uint8 kChannelPressure[] = { 0xd0, 0x01 };
 const uint8 kTimingClock[] = { 0xf8 };
 
-TEST(GetMidiMessageLengthTest, BasicTest) {
+TEST(MidiMessageUtilTest, GetMidiMessageLength) {
   // Check basic functionarity
   EXPECT_EQ(arraysize(kNoteOn), GetMidiMessageLength(kNoteOn[0]));
   EXPECT_EQ(arraysize(kChannelPressure),
             GetMidiMessageLength(kChannelPressure[0]));
   EXPECT_EQ(arraysize(kTimingClock), GetMidiMessageLength(kTimingClock[0]));
+  EXPECT_EQ(arraysize(kSystemCommonMessageTuneRequest),
+            GetMidiMessageLength(kSystemCommonMessageTuneRequest[0]));
 
   // SysEx message should be mapped to 0-length
   EXPECT_EQ(0u, GetMidiMessageLength(kGMOn[0]));
 
+  // Any reserved message should be mapped to 0-length
+  EXPECT_EQ(0u, GetMidiMessageLength(kSystemCommonMessageReserved1[0]));
+  EXPECT_EQ(0u, GetMidiMessageLength(kSystemCommonMessageReserved2[0]));
+
   // Any data byte should be mapped to 0-length
   EXPECT_EQ(0u, GetMidiMessageLength(kGMOn[1]));
   EXPECT_EQ(0u, GetMidiMessageLength(kNoteOn[1]));
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 7841a9b..5cf89ba 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -247,7 +247,8 @@
 crbug.com/418091 [ SnowLeopard Debug ] inspector/elements/bidi-dom-tree.html [ Pass Crash ]
 crbug.com/449242 [ SnowLeopard Debug ] fast/css/word-spacing-characters-complex-text.html [ Pass Crash ]
 crbug.com/419696 [ Mac Debug ] fast/text/font-linux-normalize.html [ Crash Pass ]
-
+crbug.com/423739 fast/js/string-replace-2.html [ NeedsManualRebaseline ]
+crbug.com/423739 fast/dom/Window/Location/location-override-valueOf.html [ NeedsManualRebaseline ]
 crbug.com/524859 fast/text/complex-text-opacity.html [ NeedsManualRebaseline ]
 # crbug.com/498021 [ Linux ] fast/text/complex-text-opacity.html [ ImageOnlyFailure ]
 # crbug.com/509025 [ Yosemite ] fast/text/complex-text-opacity.html [ Failure ]
@@ -460,6 +461,11 @@
 crbug.com/380217 [ Linux Win ] fast/shapes/shape-outside-floats/shape-outside-floats-inset-rounded-large-radius.html [ Skip ]
 crbug.com/380217 [ Win ] fast/shapes/shape-outside-floats/shape-outside-floats-inset-rounded-bottom-left.html [ Skip ]
 
+crbug.com/533448 svg/W3C-SVG-1.1/text-align-06-b.svg [ NeedsRebaseline ]
+crbug.com/533448 [ Linux Mac Win7 ] svg/batik/text/verticalText.svg [ NeedsRebaseline ]
+crbug.com/533448 svg/batik/text/verticalTextOnPath.svg [ NeedsRebaseline ]
+crbug.com/533448 svg/text/text-selection-align-06-b.svg [ NeedsRebaseline ]
+
 crbug.com/405389 imported/csswg-test/css-shapes-1/shape-outside/supported-shapes/polygon/shape-outside-polygon-017.html [ ImageOnlyFailure ]
 crbug.com/424365 imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-010.html [ ImageOnlyFailure ]
 crbug.com/424365 imported/csswg-test/css-shapes-1/shape-outside/shape-image/shape-image-024.html [ ImageOnlyFailure ]
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt
index f4d76ed2..975207b 100644
--- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt
@@ -298,7 +298,7 @@
 word-break: normal
 word-spacing: 0px
 word-wrap: normal
-writing-mode: lr-tb
+writing-mode: horizontal-tb
 x: 0px
 y: 0px
 z-index: auto
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
index e2d96f7..dd20990 100644
--- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
@@ -298,7 +298,7 @@
 word-break: normal
 word-spacing: 0px
 word-wrap: normal
-writing-mode: lr-tb
+writing-mode: horizontal-tb
 x: 0px
 y: 0px
 z-index: auto
diff --git a/third_party/WebKit/LayoutTests/fast/selectors/style-sharing-attribute-selector-expected.txt b/third_party/WebKit/LayoutTests/fast/selectors/style-sharing-attribute-selector-expected.txt
new file mode 100644
index 0000000..b7da77e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/selectors/style-sharing-attribute-selector-expected.txt
@@ -0,0 +1,14 @@
+Style sharing based on attribute selectors
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Attribute selector in nested functional syntax
+PASS getComputedStyle(firstDiv).color is black
+PASS getComputedStyle(secondDiv).color is green
+PASS internals.isSharingStyle(firstDiv, secondDiv) is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+This text should be black
+This text should be green
diff --git a/third_party/WebKit/LayoutTests/fast/selectors/style-sharing-attribute-selector.html b/third_party/WebKit/LayoutTests/fast/selectors/style-sharing-attribute-selector.html
new file mode 100644
index 0000000..8a5354ba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/selectors/style-sharing-attribute-selector.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script src="../../resources/js-test.js"></script>
+<style>
+    #t1 > :-webkit-any(:not([myattr])) { color: green }
+</style>
+<div id="t1">
+    <div myattr>This text should be black</div>
+    <div>This text should be green</div>
+</div>
+<script>
+description("Style sharing based on attribute selectors");
+
+var black = "rgb(0, 0, 0)";
+var green = "rgb(0, 128, 0)";
+
+
+debug("Attribute selector in nested functional syntax");
+
+var firstDiv = t1.querySelector("div");
+var secondDiv = t1.querySelector("div+div");
+
+shouldBe("getComputedStyle(firstDiv).color", "black");
+shouldBe("getComputedStyle(secondDiv).color", "green");
+if (window.internals)
+    shouldBeFalse("internals.isSharingStyle(firstDiv, secondDiv)");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/writing-mode/prefixed-parsing.html b/third_party/WebKit/LayoutTests/fast/writing-mode/prefixed-parsing.html
index 2be29cd..630bbd0 100644
--- a/third_party/WebKit/LayoutTests/fast/writing-mode/prefixed-parsing.html
+++ b/third_party/WebKit/LayoutTests/fast/writing-mode/prefixed-parsing.html
@@ -35,6 +35,22 @@
   <div style="unicode-bidi: -webkit-plaintext" data-expected="plaintext"></div>
 </div>
 
+<div data-property="writingMode">
+  <div title="Initial value of writingMode" data-expected="horizontal-tb"></div>
+  <div style="-webkit-writing-mode: vertical-lr" data-expected="vertical-lr">
+    <div style="-webkit-writing-mode: horizontal-tb" data-expected="horizontal-tb"></div>
+  </div>
+  <div style="-webkit-writing-mode: vertical-rl" data-expected="vertical-rl"></div>
+</div>
+
+<div data-property="webkitWritingMode">
+  <div title="Initial value of webkitWritingMode" data-expected="horizontal-tb"></div>
+  <div style="writing-mode: vertical-lr" data-expected="vertical-lr">
+    <div style="writing-mode: horizontal-tb" data-expected="horizontal-tb"></div>
+  </div>
+  <div style="writing-mode: vertical-rl" data-expected="vertical-rl"></div>
+</div>
+
 <script>
 Array.prototype.forEach.call(document.querySelectorAll("[data-property]"), function (element) {
   var property = element.dataset.property;
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-001-expected.txt b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-001-expected.txt
deleted file mode 100644
index d094d13c..0000000
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-001-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-This is a testharness.js-based test.
-FAIL writing-mode initial value assert_equals: expected "horizontal-tb" but got "lr-tb"
-FAIL -webkit-writing-mode: vertical-rl assert_equals: expected "vertical-rl" but got "lr-tb"
-FAIL -webkit-writing-mode: vertical-lr assert_equals: expected "vertical-lr" but got "lr-tb"
-FAIL writing-mode should inherit assert_equals: expected "vertical-rl" but got "lr-tb"
-FAIL -webkit-writing-mode: horizontal-tb assert_equals: expected "horizontal-tb" but got "lr-tb"
-FAIL -webkit-writing-mode: initial assert_equals: expected "horizontal-tb" but got "lr-tb"
-FAIL -webkit-writing-mode: inherit assert_equals: expected "vertical-rl" but got "lr-tb"
-FAIL -webkit-writing-mode: foo assert_equals: expected "vertical-rl" but got "lr-tb"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-sideways-lr-001-expected.txt b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-sideways-lr-001-expected.txt
index 7274ec7..c44a99aa 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-sideways-lr-001-expected.txt
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-sideways-lr-001-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL -webkit-writing-mode: sideways-lr assert_equals: expected "sideways-lr" but got "lr-tb"
+FAIL -webkit-writing-mode: sideways-lr assert_equals: expected "sideways-lr" but got "horizontal-tb"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-sideways-rl-001-expected.txt b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-sideways-rl-001-expected.txt
index 4a139fe9..9f630972 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-sideways-rl-001-expected.txt
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-sideways-rl-001-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL -webkit-writing-mode: sideways-rl assert_equals: expected "sideways-rl" but got "lr-tb"
+FAIL -webkit-writing-mode: sideways-rl assert_equals: expected "sideways-rl" but got "horizontal-tb"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-svg1-001-expected.txt b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-svg1-001-expected.txt
index 8001b3e..d18fccf 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-svg1-001-expected.txt
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-svg1-001-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
-FAIL -webkit-writing-mode: lr assert_equals: expected "lr" but got "lr-tb"
-FAIL -webkit-writing-mode: rl assert_equals: expected "rl" but got "lr-tb"
-FAIL -webkit-writing-mode: tb assert_equals: expected "tb" but got "lr-tb"
+FAIL -webkit-writing-mode: lr assert_equals: expected "lr" but got "horizontal-tb"
+FAIL -webkit-writing-mode: rl assert_equals: expected "rl" but got "horizontal-tb"
+FAIL -webkit-writing-mode: tb assert_equals: expected "tb" but got "horizontal-tb"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-svg1-002-expected.txt b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-svg1-002-expected.txt
index 3a55955..ba354b2 100644
--- a/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-svg1-002-expected.txt
+++ b/third_party/WebKit/LayoutTests/imported/csswg-test/css-writing-modes-3/writing-mode-parsing-svg1-002-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
-PASS -webkit-writing-mode: lr-tb 
-FAIL -webkit-writing-mode: rl-tb assert_equals: expected "rl-tb" but got "lr-tb"
-FAIL -webkit-writing-mode: tb-rl assert_equals: expected "tb-rl" but got "lr-tb"
+FAIL -webkit-writing-mode: lr-tb assert_equals: expected "lr-tb" but got "horizontal-tb"
+FAIL -webkit-writing-mode: rl-tb assert_equals: expected "rl-tb" but got "horizontal-tb"
+FAIL -webkit-writing-mode: tb-rl assert_equals: expected "tb-rl" but got "horizontal-tb"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt b/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt
index 9b31585..a6f751d3 100644
--- a/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt
@@ -298,7 +298,7 @@
 word-break: normal
 word-spacing: 0px
 word-wrap: normal
-writing-mode: lr-tb
+writing-mode: horizontal-tb
 x: 0px
 y: 0px
 z-index: auto
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
index ede7402..cfaa62d 100644
--- a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
+++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
@@ -2679,8 +2679,14 @@
     ASSERT(isValueID());
     switch (m_value.valueID) {
     case CSSValueHorizontalTb:
+    case CSSValueLr:
+    case CSSValueLrTb:
+    case CSSValueRl:
+    case CSSValueRlTb:
         return TopToBottomWritingMode;
     case CSSValueVerticalRl:
+    case CSSValueTb:
+    case CSSValueTbRl:
         return RightToLeftWritingMode;
     case CSSValueVerticalLr:
         return LeftToRightWritingMode;
@@ -4128,56 +4134,6 @@
     return TA_START;
 }
 
-template<> inline CSSPrimitiveValue::CSSPrimitiveValue(SVGWritingMode e)
-    : CSSValue(PrimitiveClass)
-{
-    init(UnitType::ValueID);
-    switch (e) {
-    case WM_LRTB:
-        m_value.valueID = CSSValueLrTb;
-        break;
-    case WM_LR:
-        m_value.valueID = CSSValueLr;
-        break;
-    case WM_RLTB:
-        m_value.valueID = CSSValueRlTb;
-        break;
-    case WM_RL:
-        m_value.valueID = CSSValueRl;
-        break;
-    case WM_TBRL:
-        m_value.valueID = CSSValueTbRl;
-        break;
-    case WM_TB:
-        m_value.valueID = CSSValueTb;
-        break;
-    }
-}
-
-template<> inline CSSPrimitiveValue::operator SVGWritingMode() const
-{
-    ASSERT(isValueID());
-    switch (m_value.valueID) {
-    case CSSValueLrTb:
-        return WM_LRTB;
-    case CSSValueLr:
-        return WM_LR;
-    case CSSValueRlTb:
-        return WM_RLTB;
-    case CSSValueRl:
-        return WM_RL;
-    case CSSValueTbRl:
-        return WM_TBRL;
-    case CSSValueTb:
-        return WM_TB;
-    default:
-        break;
-    }
-
-    ASSERT_NOT_REACHED();
-    return WM_LRTB;
-}
-
 template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EVectorEffect e)
     : CSSValue(PrimitiveClass)
 {
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.in b/third_party/WebKit/Source/core/css/CSSProperties.in
index 2a13af6f..f94f37f 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.in
+++ b/third_party/WebKit/Source/core/css/CSSProperties.in
@@ -97,6 +97,7 @@
 -webkit-locale inherited, custom_value
 text-orientation inherited, custom_value
 -webkit-text-orientation inherited, custom_value
+writing-mode inherited, custom_value
 -webkit-writing-mode inherited, custom_value
 text-rendering inherited, font, type_name=TextRenderingMode
 zoom custom_all
@@ -396,7 +397,6 @@
 word-spacing interpolable, inherited, initial=initialLetterWordSpacing, converter=convertSpacing
 // UAs must treat 'word-wrap' as an alternate name for the 'overflow-wrap' property. So using the same handlers.
 word-wrap inherited, name_for_methods=OverflowWrap
-writing-mode inherited, svg, type_name=SVGWritingMode
 z-index interpolable, type_name=int, custom_all
 
 // Non-standard direction aware properties
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
index 152de0b..ee540e2a 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
+++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -2340,6 +2340,7 @@
     }
     case CSSPropertyPointerEvents:
         return cssValuePool().createValue(style.pointerEvents());
+    case CSSPropertyWritingMode:
     case CSSPropertyWebkitWritingMode:
         return cssValuePool().createValue(style.writingMode());
     case CSSPropertyWebkitTextCombine:
@@ -2563,8 +2564,6 @@
         return CSSPrimitiveValue::create(svgStyle.dominantBaseline());
     case CSSPropertyTextAnchor:
         return CSSPrimitiveValue::create(svgStyle.textAnchor());
-    case CSSPropertyWritingMode:
-        return CSSPrimitiveValue::create(svgStyle.writingMode());
     case CSSPropertyClipPath:
         if (!svgStyle.clipperResource().isEmpty())
             return CSSURIValue::create(serializeAsFragmentIdentifier(svgStyle.clipperResource()));
diff --git a/third_party/WebKit/Source/core/css/RuleSet.cpp b/third_party/WebKit/Source/core/css/RuleSet.cpp
index b0572ea0..54db1e85 100644
--- a/third_party/WebKit/Source/core/css/RuleSet.cpp
+++ b/third_party/WebKit/Source/core/css/RuleSet.cpp
@@ -50,16 +50,16 @@
 
 // -----------------------------------------------------------------
 
+static bool containsUncommonAttributeSelector(const CSSSelector&);
+
 static inline bool selectorListContainsUncommonAttributeSelector(const CSSSelector* selector)
 {
     const CSSSelectorList* selectorList = selector->selectorList();
     if (!selectorList)
         return false;
     for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector)) {
-        for (const CSSSelector* component = selector; component; component = component->tagHistory()) {
-            if (component->isAttributeSelector())
-                return true;
-        }
+        if (containsUncommonAttributeSelector(*selector))
+            return true;
     }
     return false;
 }
@@ -70,7 +70,7 @@
     return attribute == typeAttr || attribute == readonlyAttr;
 }
 
-static inline bool containsUncommonAttributeSelector(const CSSSelector& selector)
+static bool containsUncommonAttributeSelector(const CSSSelector& selector)
 {
     const CSSSelector* current = &selector;
     for (; current; current = current->tagHistory()) {
diff --git a/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp b/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp
index 2ffe6bc..b40d7b9 100644
--- a/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp
+++ b/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp
@@ -609,7 +609,7 @@
     const unsigned size = shorthand.length();
 
     // Begin by collecting the properties into a vector.
-    WillBeHeapVector<const CSSValue*> values(size);
+    WillBeHeapVector<RawPtrWillBeMember<const CSSValue>> values(size);
     // If the below loop succeeds, there should always be at minimum 1 layer.
     size_t numLayers = 1U;
 
@@ -662,7 +662,7 @@
                 ASSERT(shorthand.properties()[propertyIndex + 1] == CSSPropertyBackgroundRepeatY
                     || shorthand.properties()[propertyIndex + 1] == CSSPropertyWebkitMaskRepeatY);
                 const CSSValue* yValue = values[propertyIndex + 1]->isValueList() ?
-                    toCSSValueList(values[propertyIndex + 1])->item(layer) : values[propertyIndex + 1];
+                    toCSSValueList(values[propertyIndex + 1])->item(layer) : values[propertyIndex + 1].get();
 
 
                 // FIXME: At some point we need to fix this code to avoid returning an invalid shorthand,
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
index 7596cee..104d718 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
@@ -690,7 +690,9 @@
     case CSSPropertyWebkitWritingMode:
         return valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt;
     case CSSPropertyWritingMode:
-        return valueID == CSSValueLrTb || valueID == CSSValueRlTb || valueID == CSSValueTbRl
+        return valueID == CSSValueHorizontalTb
+            || valueID == CSSValueVerticalRl || valueID == CSSValueVerticalLr
+            || valueID == CSSValueLrTb || valueID == CSSValueRlTb || valueID == CSSValueTbRl
             || valueID == CSSValueLr || valueID == CSSValueRl || valueID == CSSValueTb;
     case CSSPropertyWhiteSpace: // normal | pre | nowrap
         return valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap;
diff --git a/third_party/WebKit/Source/core/css/resolver/CSSPropertyPriority.h b/third_party/WebKit/Source/core/css/resolver/CSSPropertyPriority.h
index f9894b24..58a6fbb7 100644
--- a/third_party/WebKit/Source/core/css/resolver/CSSPropertyPriority.h
+++ b/third_party/WebKit/Source/core/css/resolver/CSSPropertyPriority.h
@@ -41,7 +41,7 @@
 template<>
 inline CSSPropertyID CSSPropertyPriorityData<HighPropertyPriority>::last()
 {
-    static_assert(CSSPropertyZoom == CSSPropertyColor + 18, "CSSPropertyZoom should be the end of the high priority property range");
+    static_assert(CSSPropertyZoom == CSSPropertyColor + 19, "CSSPropertyZoom should be the end of the high priority property range");
     static_assert(CSSPropertyTextRendering == CSSPropertyZoom - 1, "CSSPropertyTextRendering should be immediately before CSSPropertyZoom");
     return CSSPropertyZoom;
 }
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
index 979f32cc..5791ab7 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
@@ -803,6 +803,11 @@
     state.document().setHasAnnotatedRegions(true);
 }
 
+void StyleBuilderFunctions::applyValueCSSPropertyWritingMode(StyleResolverState& state, CSSValue* value)
+{
+    state.setWritingMode(*toCSSPrimitiveValue(value));
+}
+
 void StyleBuilderFunctions::applyValueCSSPropertyWebkitWritingMode(StyleResolverState& state, CSSValue* value)
 {
     state.setWritingMode(*toCSSPrimitiveValue(value));
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index 02b6ce1..d2cf3d5b 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -2489,7 +2489,7 @@
 {
     ASSERT(m_frame == m_frame->localFrameRoot());
 
-    WillBeHeapVector<LocalFrame*> newHoverFrameChain;
+    WillBeHeapVector<RawPtrWillBeMember<LocalFrame>> newHoverFrameChain;
     LocalFrame* newHoverFrameInDocument = innerElement ? innerElement->document().frame() : nullptr;
     // Insert the ancestors of the frame having the new hovered node to the frame chain
     // The frame chain doesn't include the main frame to avoid the redundant work that cleans the hover state.
@@ -2549,7 +2549,7 @@
     // - Dispatch mouseover/mouseenter events of the entered frames into the inside.
 
     // Insert the ancestors of the frame having the new target node to the entered frame chain
-    WillBeHeapVector<LocalFrame*> enteredFrameChain;
+    WillBeHeapVector<RawPtrWillBeMember<LocalFrame>> enteredFrameChain;
     LocalFrame* enteredFrameInDocument = targetedEvent.hitTestResult().innerNodeFrame();
     while (enteredFrameInDocument) {
         enteredFrameChain.append(enteredFrameInDocument);
@@ -2559,7 +2559,7 @@
 
     size_t indexEnteredFrameChain = enteredFrameChain.size();
     LocalFrame* exitedFrameInDocument = m_frame;
-    WillBeHeapVector<LocalFrame*> exitedFrameChain;
+    WillBeHeapVector<RawPtrWillBeMember<LocalFrame>> exitedFrameChain;
     // Insert the frame from the disagreement between last frames and entered frames
     while (exitedFrameInDocument) {
         Node* lastNodeUnderTap = exitedFrameInDocument->eventHandler().m_nodeUnderMouse.get();
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index 48d0480..7dd1549 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -153,19 +153,6 @@
     void setLastChildIsSelfCollapsingBlockWithClearance(bool value) { m_lastChildIsSelfCollapsingBlockWithClearance = value; }
     bool lastChildIsSelfCollapsingBlockWithClearance() const { return m_lastChildIsSelfCollapsingBlockWithClearance; }
 };
-static bool inNormalFlow(LayoutBox* child)
-{
-    LayoutBlock* curr = child->containingBlock();
-    LayoutView* layoutView = child->view();
-    while (curr && curr != layoutView) {
-        if (curr->isLayoutFlowThread())
-            return true;
-        if (curr->isFloatingOrOutOfFlowPositioned())
-            return false;
-        curr = curr->containingBlock();
-    }
-    return true;
-}
 
 LayoutBlockFlow::LayoutBlockFlow(ContainerNode* node)
     : LayoutBlock(node)
@@ -1716,14 +1703,8 @@
 
 LayoutUnit LayoutBlockFlow::applyBeforeBreak(LayoutBox& child, LayoutUnit logicalOffset)
 {
-    // FIXME: Add page break checking here when we support printing.
-    LayoutFlowThread* flowThread = flowThreadContainingBlock();
-    bool checkColumnBreaks = flowThread;
-    bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->pageLogicalHeight(); // FIXME: Once columns can print we have to check this.
-    bool checkBeforeAlways = (checkColumnBreaks && child.style()->columnBreakBefore() == PBALWAYS)
-        || (checkPageBreaks && child.style()->pageBreakBefore() == PBALWAYS);
-    if (checkBeforeAlways && inNormalFlow(&child)) {
-        if (checkColumnBreaks) {
+    if (child.hasForcedBreakBefore()) {
+        if (LayoutFlowThread* flowThread = flowThreadContainingBlock()) {
             LayoutUnit offsetBreakAdjustment = 0;
             if (flowThread->addForcedColumnBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
                 return logicalOffset + offsetBreakAdjustment;
@@ -1735,17 +1716,11 @@
 
 LayoutUnit LayoutBlockFlow::applyAfterBreak(LayoutBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
 {
-    // FIXME: Add page break checking here when we support printing.
-    LayoutFlowThread* flowThread = flowThreadContainingBlock();
-    bool checkColumnBreaks = flowThread;
-    bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->pageLogicalHeight(); // FIXME: Once columns can print we have to check this.
-    bool checkAfterAlways = (checkColumnBreaks && child.style()->columnBreakAfter() == PBALWAYS)
-        || (checkPageBreaks && child.style()->pageBreakAfter() == PBALWAYS);
-    if (checkAfterAlways && inNormalFlow(&child)) {
+    if (child.hasForcedBreakAfter()) {
         // So our margin doesn't participate in the next collapsing steps.
         marginInfo.clearMargin();
 
-        if (checkColumnBreaks) {
+        if (LayoutFlowThread* flowThread = flowThreadContainingBlock()) {
             LayoutUnit offsetBreakAdjustment = 0;
             if (flowThread->addForcedColumnBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, false, &offsetBreakAdjustment))
                 return logicalOffset + offsetBreakAdjustment;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index cc1ea91..ad71db13 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -956,6 +956,7 @@
         SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<LayoutBox&>(*this));
 #endif
         const_cast<LayoutBox*>(this)->computePreferredLogicalWidths();
+        ASSERT(!preferredLogicalWidthsDirty());
     }
 
     return m_minPreferredLogicalWidth;
@@ -968,6 +969,7 @@
         SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<LayoutBox&>(*this));
 #endif
         const_cast<LayoutBox*>(this)->computePreferredLogicalWidths();
+        ASSERT(!preferredLogicalWidthsDirty());
     }
 
     return m_maxPreferredLogicalWidth;
@@ -1779,6 +1781,46 @@
     ensureRareData().m_paginationStrut = strut;
 }
 
+static bool isForcedBreakAllowed(const LayoutBox* child)
+{
+    // We currently only support forced breaks on in-flow block level elements, which is the minimum
+    // requirement according to the spec.
+    if (child->isInline() || child->isFloatingOrOutOfFlowPositioned())
+        return false;
+    const LayoutBlock* curr = child->containingBlock();
+    if (!curr || !curr->isLayoutBlockFlow())
+        return false;
+    const LayoutView* layoutView = child->view();
+    while (curr && curr != layoutView) {
+        if (curr->isLayoutFlowThread())
+            return true;
+        if (curr->isFloatingOrOutOfFlowPositioned())
+            return false;
+        curr = curr->containingBlock();
+    }
+    return true;
+}
+
+bool LayoutBox::hasForcedBreakBefore() const
+{
+    LayoutFlowThread* flowThread = flowThreadContainingBlock();
+    bool checkColumnBreaks = flowThread;
+    bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->pageLogicalHeight(); // TODO(mstensho): Once columns can print, we have to check this.
+    bool checkBeforeAlways = (checkColumnBreaks && style()->columnBreakBefore() == PBALWAYS)
+        || (checkPageBreaks && style()->pageBreakBefore() == PBALWAYS);
+    return checkBeforeAlways && isForcedBreakAllowed(this);
+}
+
+bool LayoutBox::hasForcedBreakAfter() const
+{
+    LayoutFlowThread* flowThread = flowThreadContainingBlock();
+    bool checkColumnBreaks = flowThread;
+    bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->pageLogicalHeight(); // TODO(mstensho): Once columns can print, we have to check this.
+    bool checkAfterAlways = (checkColumnBreaks && style()->columnBreakAfter() == PBALWAYS)
+        || (checkPageBreaks && style()->pageBreakAfter() == PBALWAYS);
+    return checkAfterAlways && isForcedBreakAllowed(this);
+}
+
 LayoutRect LayoutBox::clippedOverflowRectForPaintInvalidation(const LayoutBoxModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
 {
     if (style()->visibility() != VISIBLE) {
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h
index 7ec9481..bff4e10 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -590,6 +590,9 @@
             m_rareData->m_paginationStrut = LayoutUnit();
     }
 
+    bool hasForcedBreakBefore() const;
+    bool hasForcedBreakAfter() const;
+
     LayoutRect clippedOverflowRectForPaintInvalidation(const LayoutBoxModelObject* paintInvalidationContainer, const PaintInvalidationState* = nullptr) const override;
     void mapRectToPaintInvalidationBacking(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect&, const PaintInvalidationState*) const override;
     virtual void invalidatePaintForOverhangingFloats(bool paintAllDescendants);
@@ -911,9 +914,14 @@
 
     virtual void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const;
 
-    // This function calculates the minimum and maximum preferred widths for an object.
-    // These values are used in shrink-to-fit layout systems.
-    // These include tables, positioned objects, floats and flexible boxes.
+    // This function calculates the preferred widths for an object.
+    //
+    // This function is only expected to be called if
+    // the boolean preferredLogicalWidthsDirty is true. It also MUST clear the
+    // boolean before returning.
+    //
+    // See INTRINSIC SIZES / PREFERRED LOGICAL WIDTHS in LayoutObject.h for more
+    // details about those widths.
     virtual void computePreferredLogicalWidths() { clearPreferredLogicalWidthsDirty(); }
 
     LayoutBoxRareData& ensureRareData()
@@ -957,15 +965,15 @@
     LayoutRectOutsets m_marginBoxOutsets;
 
 protected:
-    // The preferred logical width of the element if it were to break its lines at every
-    // possible opportunity. CSS 2.1 calls this width the "preferred minimum width" and
-    // "minimum content width".
-    // See https://drafts.csswg.org/css-sizing-3/#intrinsic for more information.
+    // The logical width of the element if it were to break its lines at every
+    // possible opportunity.
+    //
+    // See LayoutObject::minPreferredLogicalWidth() for more details.
     LayoutUnit m_minPreferredLogicalWidth;
 
-    // The preferred logical width of the element if it never breaks any lines at all.
-    // CSS 2.1 calls this width the "preferred width" and "maximum cell width".
-    // See https://drafts.csswg.org/css-sizing-3/#intrinsic for more information.
+    // The logical width of the element if it never breaks any lines at all.
+    //
+    // See LayoutObject::maxPreferredLogicalWidth() for more details.
     LayoutUnit m_maxPreferredLogicalWidth;
 
     // Our overflow information.
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h
index 77815983..aab292f0 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -155,6 +155,30 @@
 //   (See https://drafts.csswg.org/css-backgrounds-3/#the-background-image)
 // - image (LayoutImage, LayoutSVGImage) or video (LayoutVideo) objects that are placeholders for
 //   displaying them.
+//
+// ***** INTRINSIC SIZES / PREFERRED LOGICAL WIDTHS *****
+// The preferred logical widths are the intrinsic sizes of this element
+// (https://drafts.csswg.org/css-sizing-3/#intrinsic). Intrinsic sizes depend
+// mostly on the content and a limited set of style properties (e.g. any
+// font-related property for text, 'min-width'/'max-width',
+// 'min-height'/'max-height').
+//
+// Those widths are used to determine the final layout logical width, which
+// depends on the layout algorithm used and the available logical width.
+//
+// LayoutObject only has getters for the widths (minPreferredLogicalWidth and
+// maxPreferredLogicalWidth). However the storage for them is in LayoutBox
+// (see m_minPreferredLogicalWidth and m_maxPreferredLogicalWidth). This is
+// because only boxes implementing the full box model have a need for them.
+// Because LayoutBlockFlow's intrinsic widths rely on the underlying text
+// content, LayoutBlockFlow may call LayoutText::computePreferredLogicalWidths.
+//
+// The 2 widths are computed lazily during layout when the getters are called.
+// The computation is done by calling computePreferredLogicalWidths() behind the
+// scene. The boolean used to control the lazy recomputation is
+// preferredLogicalWidthsDirty.
+//
+// See the individual getters below for more details about what each width is.
 class CORE_EXPORT LayoutObject : public ImageResourceClient {
     friend class LayoutObjectChildList;
     WTF_MAKE_NONCOPYABLE(LayoutObject);
@@ -908,7 +932,27 @@
     // the rect that will be painted if this object is passed as the paintingRoot
     IntRect paintingRootRect(IntRect& topLevelRect);
 
+    // This function returns the minimal logical width this object can have
+    // without overflowing. This means that all the opportunities for wrapping
+    // have been taken.
+    //
+    // See INTRINSIC SIZES / PREFERRED LOGICAL WIDTHS above.
+    //
+    // CSS 2.1 calls this width the "preferred minimum width" (thus this name)
+    // and "minimum content width" (for table).
+    // However CSS 3 calls it the "min-content inline size".
+    // https://drafts.csswg.org/css-sizing-3/#min-content-inline-size
+    // TODO(jchaffraix): We will probably want to rename it to match CSS 3.
     virtual LayoutUnit minPreferredLogicalWidth() const { return 0; }
+
+    // This function returns the maximum logical width this object can have.
+    //
+    // See INTRINSIC SIZES / PREFERRED LOGICAL WIDTHS above.
+    //
+    // CSS 2.1 calls this width the "preferred width". However CSS 3 calls it
+    // the "max-content inline size".
+    // https://drafts.csswg.org/css-sizing-3/#max-content-inline-size
+    // TODO(jchaffraix): We will probably want to rename it to match CSS 3.
     virtual LayoutUnit maxPreferredLogicalWidth() const { return 0; }
 
     const ComputedStyle* style() const { return m_style.get(); }
@@ -1594,19 +1638,10 @@
         // bleed into its containing block's so we have to recompute it in some cases.
         ADD_BOOLEAN_BITFIELD(childNeedsOverflowRecalcAfterStyleChange, ChildNeedsOverflowRecalcAfterStyleChange);
 
-        // The preferred logical widths are the intrinsic sizes of this element.
-        // Intrinsic sizes depend mostly on the content and a limited set of style
-        // properties (e.g. any font-related property for text, 'min-width'/'max-width',
-        // 'min-height'/'max-height').
+        // This boolean marks preferred logical widths for lazy recomputation.
         //
-        // Those widths are used to determine the final layout logical width, which
-        // depends on the layout algorithm used and the available logical width.
-        //
-        // Blink stores them in LayoutBox (m_minPreferredLogicalWidth and
-        // m_maxPreferredLogicalWidth).
-        //
-        // Setting this boolean marks both widths for lazy recomputation when
-        // LayoutBox::minPreferredLogicalWidth() or maxPreferredLogicalWidth() is called.
+        // See INTRINSIC SIZES / PREFERRED LOGICAL WIDTHS above about those
+        // widths.
         ADD_BOOLEAN_BITFIELD(preferredLogicalWidthsDirty, PreferredLogicalWidthsDirty);
 
         ADD_BOOLEAN_BITFIELD(shouldInvalidateOverflowForPaint, ShouldInvalidateOverflowForPaint); // TODO(wangxianzhu): Remove for slimming paint v2.
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp
index 2b23d4f..e027a86 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp
@@ -217,14 +217,29 @@
 
 void LayoutSVGInlineText::updateScaledFont()
 {
-    computeNewScaledFontForStyle(this, style(), m_scalingFactor, m_scaledFont);
+    computeNewScaledFontForStyle(this, m_scalingFactor, m_scaledFont);
 }
 
-void LayoutSVGInlineText::computeNewScaledFontForStyle(LayoutObject* layoutObject, const ComputedStyle* style, float& scalingFactor, Font& scaledFont)
+void LayoutSVGInlineText::computeNewScaledFontForStyle(LayoutObject* layoutObject, float& scalingFactor, Font& scaledFont)
 {
+    const ComputedStyle* style = layoutObject->style();
     ASSERT(style);
     ASSERT(layoutObject);
 
+    // layoutTextOnLineOrPath() expects fonts to do nothing for vertical flow so
+    // that it can position each glyph precisely. Make sure the selected font is
+    // the one for horizontal flow to not to break the assumption.
+    // TODO(kojii): This might be done better by obsoleting the
+    // 'glyph-orientation-vertical' property as recommended in:
+    // https://drafts.csswg.org/css-writing-modes/#glyph-orientation
+    if (style->font().fontDescription().orientation() != FontOrientation::Horizontal) {
+        FontDescription description = style->font().fontDescription();
+        FontSelector* fontSelector = style->font().fontSelector();
+        description.setOrientation(FontOrientation::Horizontal);
+        layoutObject->mutableStyleRef().setFontDescription(description);
+        style->font().update(fontSelector);
+    }
+
     // Alter font-size to the right on-screen value to avoid scaling the glyphs themselves, except when GeometricPrecision is specified.
     scalingFactor = SVGLayoutSupport::calculateScreenFontSizeScalingFactor(layoutObject);
     if (style->effectiveZoom() == 1 && (scalingFactor == 1 || !scalingFactor)) {
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.h
index 33f3f351..84610b8 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.h
@@ -38,7 +38,7 @@
     float scalingFactor() const { return m_scalingFactor; }
     const Font& scaledFont() const { return m_scaledFont; }
     void updateScaledFont();
-    static void computeNewScaledFontForStyle(LayoutObject*, const ComputedStyle*, float& scalingFactor, Font& scaledFont);
+    static void computeNewScaledFontForStyle(LayoutObject*, float& scalingFactor, Font& scaledFont);
 
     // Preserves floating point precision for the use in DRT. It knows how to round and does a better job than enclosingIntRect.
     FloatRect floatLinesBoundingBox() const;
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGLayoutTreeAsText.cpp b/third_party/WebKit/Source/core/layout/svg/SVGLayoutTreeAsText.cpp
index 87c93ac4..81c1c29 100644
--- a/third_party/WebKit/Source/core/layout/svg/SVGLayoutTreeAsText.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/SVGLayoutTreeAsText.cpp
@@ -416,7 +416,7 @@
         // FIXME: Remove this hack, once the new text layout engine is completly landed. We want to preserve the old layout test results for now.
         ts << "chunk 1 ";
         ETextAnchor anchor = svgStyle.textAnchor();
-        bool isVerticalText = svgStyle.isVerticalWritingMode();
+        bool isVerticalText = !textLineLayout.style()->isHorizontalWritingMode();
         if (anchor == TA_MIDDLE) {
             ts << "(middle anchor";
             if (isVerticalText)
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGTextChunkBuilder.cpp b/third_party/WebKit/Source/core/layout/svg/SVGTextChunkBuilder.cpp
index c1e3c195..0a5bc59 100644
--- a/third_party/WebKit/Source/core/layout/svg/SVGTextChunkBuilder.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/SVGTextChunkBuilder.cpp
@@ -162,7 +162,7 @@
 {
     const ComputedStyle& style = (*boxStart)->layoutObject().styleRef();
 
-    ChunkLengthAccumulator lengthAccumulator(style.svgStyle().isVerticalWritingMode());
+    ChunkLengthAccumulator lengthAccumulator(!style.isHorizontalWritingMode());
     lengthAccumulator.processRange(boxStart, boxEnd);
 
     // Handle text-anchor as additional start offset for text paths.
@@ -209,7 +209,7 @@
     if (!processTextAnchor && !processTextLength)
         return;
 
-    bool isVerticalText = style.svgStyle().isVerticalWritingMode();
+    bool isVerticalText = !style.isHorizontalWritingMode();
 
     // Calculate absolute length of whole text chunk (starting from text box 'start', spanning 'length' text boxes).
     ChunkLengthAccumulator lengthAccumulator(isVerticalText);
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGTextLayoutEngine.cpp b/third_party/WebKit/Source/core/layout/svg/SVGTextLayoutEngine.cpp
index fae2e5e9..bfcbb00d 100644
--- a/third_party/WebKit/Source/core/layout/svg/SVGTextLayoutEngine.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/SVGTextLayoutEngine.cpp
@@ -215,7 +215,7 @@
     const ComputedStyle& style = text.styleRef();
 
     textBox->clearTextFragments();
-    m_isVerticalText = style.svgStyle().isVerticalWritingMode();
+    m_isVerticalText = !style.isHorizontalWritingMode();
     layoutTextOnLineOrPath(textBox, text, style);
 
     if (m_inPathLayout)
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGTextQuery.cpp b/third_party/WebKit/Source/core/layout/svg/SVGTextQuery.cpp
index 2a0ef77..cbccd506 100644
--- a/third_party/WebKit/Source/core/layout/svg/SVGTextQuery.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/SVGTextQuery.cpp
@@ -106,7 +106,7 @@
     queryData->textBox = textBox;
     queryData->textLayoutObject = &toLayoutSVGInlineText(textBox->layoutObject());
 
-    queryData->isVerticalText = textBox->layoutObject().style()->svgStyle().isVerticalWritingMode();
+    queryData->isVerticalText = !textBox->layoutObject().style()->isHorizontalWritingMode();
 
     // Loop over all text fragments in this text box, firing a callback for each.
     for (const SVGTextFragment& fragment : textBox->textFragments()) {
diff --git a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
index c2bbeae..8cf6f64 100644
--- a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
@@ -247,7 +247,7 @@
 
     float scalingFactor = 1;
     Font scaledFont;
-    LayoutSVGInlineText::computeNewScaledFontForStyle(decorationLayoutObject, &decorationStyle, scalingFactor, scaledFont);
+    LayoutSVGInlineText::computeNewScaledFontForStyle(decorationLayoutObject, scalingFactor, scaledFont);
     ASSERT(scalingFactor);
 
     float thickness = thicknessForDecoration(decoration, scaledFont);
diff --git a/third_party/WebKit/Source/core/style/SVGComputedStyle.cpp b/third_party/WebKit/Source/core/style/SVGComputedStyle.cpp
index e3d82d9..c2818945 100644
--- a/third_party/WebKit/Source/core/style/SVGComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/SVGComputedStyle.cpp
@@ -154,7 +154,6 @@
 
     // All text related properties influence layout.
     if (svg_inherited_flags._textAnchor != other->svg_inherited_flags._textAnchor
-        || svg_inherited_flags._writingMode != other->svg_inherited_flags._writingMode
         || svg_inherited_flags._glyphOrientationHorizontal != other->svg_inherited_flags._glyphOrientationHorizontal
         || svg_inherited_flags._glyphOrientationVertical != other->svg_inherited_flags._glyphOrientationVertical
         || svg_inherited_flags.dominantBaseline != other->svg_inherited_flags.dominantBaseline
diff --git a/third_party/WebKit/Source/core/style/SVGComputedStyle.h b/third_party/WebKit/Source/core/style/SVGComputedStyle.h
index ac9f432..9145dc9 100644
--- a/third_party/WebKit/Source/core/style/SVGComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/SVGComputedStyle.h
@@ -65,7 +65,6 @@
     static LineJoin initialJoinStyle() { return MiterJoin; }
     static EShapeRendering initialShapeRendering() { return SR_AUTO; }
     static ETextAnchor initialTextAnchor() { return TA_START; }
-    static SVGWritingMode initialWritingMode() { return WM_LRTB; }
     static EGlyphOrientation initialGlyphOrientationHorizontal() { return GO_0DEG; }
     static EGlyphOrientation initialGlyphOrientationVertical() { return GO_AUTO; }
     static float initialFillOpacity() { return 1; }
@@ -116,7 +115,6 @@
     void setJoinStyle(LineJoin val) { svg_inherited_flags._joinStyle = val; }
     void setShapeRendering(EShapeRendering val) { svg_inherited_flags._shapeRendering = val; }
     void setTextAnchor(ETextAnchor val) { svg_inherited_flags._textAnchor = val; }
-    void setWritingMode(SVGWritingMode val) { svg_inherited_flags._writingMode = val; }
     void setGlyphOrientationHorizontal(EGlyphOrientation val) { svg_inherited_flags._glyphOrientationHorizontal = val; }
     void setGlyphOrientationVertical(EGlyphOrientation val) { svg_inherited_flags._glyphOrientationVertical = val; }
     void setMaskType(EMaskType val) { svg_noninherited_flags.f.maskType = val; }
@@ -321,7 +319,6 @@
     LineJoin joinStyle() const { return (LineJoin) svg_inherited_flags._joinStyle; }
     EShapeRendering shapeRendering() const { return (EShapeRendering) svg_inherited_flags._shapeRendering; }
     ETextAnchor textAnchor() const { return (ETextAnchor) svg_inherited_flags._textAnchor; }
-    SVGWritingMode writingMode() const { return (SVGWritingMode) svg_inherited_flags._writingMode; }
     EGlyphOrientation glyphOrientationHorizontal() const { return (EGlyphOrientation) svg_inherited_flags._glyphOrientationHorizontal; }
     EGlyphOrientation glyphOrientationVertical() const { return (EGlyphOrientation) svg_inherited_flags._glyphOrientationVertical; }
     float fillOpacity() const { return fill->opacity; }
@@ -376,7 +373,6 @@
     bool hasSquareCapStyle() const { return capStyle() == SquareCap; }
     bool hasMiterJoinStyle() const { return joinStyle() == MiterJoin; }
     bool hasFill() const { return fillPaintType() != SVG_PAINTTYPE_NONE; }
-    bool isVerticalWritingMode() const { return writingMode() == WM_TBRL || writingMode() == WM_TB; }
 
 protected:
     // inherit
@@ -392,7 +388,6 @@
                 && (_textAnchor == other._textAnchor)
                 && (_colorInterpolation == other._colorInterpolation)
                 && (_colorInterpolationFilters == other._colorInterpolationFilters)
-                && (_writingMode == other._writingMode)
                 && (_glyphOrientationHorizontal == other._glyphOrientationHorizontal)
                 && (_glyphOrientationVertical == other._glyphOrientationVertical)
                 && (paintOrder == other.paintOrder)
@@ -413,7 +408,6 @@
         unsigned _textAnchor : 2; // ETextAnchor
         unsigned _colorInterpolation : 2; // EColorInterpolation
         unsigned _colorInterpolationFilters : 2; // EColorInterpolation
-        unsigned _writingMode : 3; // SVGWritingMode
         unsigned _glyphOrientationHorizontal : 3; // EGlyphOrientation
         unsigned _glyphOrientationVertical : 3; // EGlyphOrientation
         unsigned paintOrder : 3; // EPaintOrder
@@ -471,7 +465,6 @@
         svg_inherited_flags._joinStyle = initialJoinStyle();
         svg_inherited_flags._colorInterpolation = initialColorInterpolation();
         svg_inherited_flags._colorInterpolationFilters = initialColorInterpolationFilters();
-        svg_inherited_flags._writingMode = initialWritingMode();
         svg_inherited_flags._glyphOrientationHorizontal = initialGlyphOrientationHorizontal();
         svg_inherited_flags._glyphOrientationVertical = initialGlyphOrientationVertical();
         svg_inherited_flags.paintOrder = initialPaintOrder();
diff --git a/third_party/WebKit/Source/core/style/SVGComputedStyleDefs.h b/third_party/WebKit/Source/core/style/SVGComputedStyleDefs.h
index eb5d21fd..eff0768e 100644
--- a/third_party/WebKit/Source/core/style/SVGComputedStyleDefs.h
+++ b/third_party/WebKit/Source/core/style/SVGComputedStyleDefs.h
@@ -72,10 +72,6 @@
     SR_AUTO, SR_OPTIMIZESPEED, SR_CRISPEDGES, SR_GEOMETRICPRECISION
 };
 
-enum SVGWritingMode {
-    WM_LRTB, WM_LR, WM_RLTB, WM_RL, WM_TBRL, WM_TB
-};
-
 enum EGlyphOrientation {
     GO_0DEG, GO_90DEG, GO_180DEG, GO_270DEG, GO_AUTO
 };
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py
index 8764f0d..53845c2 100755
--- a/tools/gn/bootstrap/bootstrap.py
+++ b/tools/gn/bootstrap/bootstrap.py
@@ -250,7 +250,6 @@
       'base/trace_event/memory_profiler_allocation_context.cc',
       'base/trace_event/process_memory_dump.cc',
       'base/trace_event/process_memory_maps.cc',
-      'base/trace_event/process_memory_maps_dump_provider.cc',
       'base/trace_event/process_memory_totals.cc',
       'base/trace_event/process_memory_totals_dump_provider.cc',
       'base/trace_event/trace_buffer.cc',
@@ -338,6 +337,7 @@
         'base/sys_info_linux.cc',
         'base/threading/platform_thread_linux.cc',
         'base/trace_event/malloc_dump_provider.cc',
+        'base/trace_event/process_memory_maps_dump_provider.cc',
     ])
     static_libraries['libevent']['include_dirs'].extend([
         os.path.join(SRC_ROOT, 'third_party', 'libevent', 'linux')
diff --git a/tools/telemetry/telemetry/internal/backends/browser_backend.py b/tools/telemetry/telemetry/internal/backends/browser_backend.py
index d5b71e8..3f765101 100644
--- a/tools/telemetry/telemetry/internal/backends/browser_backend.py
+++ b/tools/telemetry/telemetry/internal/backends/browser_backend.py
@@ -141,6 +141,10 @@
       self, suppressed, timeout=web_contents.DEFAULT_WEB_CONTENTS_TIMEOUT):
     raise NotImplementedError()
 
+  def SimulateMemoryPressureNotification(
+      self, pressure_level, timeout=web_contents.DEFAULT_WEB_CONTENTS_TIMEOUT):
+    raise NotImplementedError()
+
   @property
   def supports_cpu_metrics(self):
     raise NotImplementedError()
diff --git a/tools/telemetry/telemetry/internal/backends/chrome/chrome_browser_backend.py b/tools/telemetry/telemetry/internal/backends/chrome/chrome_browser_backend.py
index 75d010a..41b18a1 100644
--- a/tools/telemetry/telemetry/internal/backends/chrome/chrome_browser_backend.py
+++ b/tools/telemetry/telemetry/internal/backends/chrome/chrome_browser_backend.py
@@ -329,7 +329,13 @@
 
   def SetMemoryPressureNotificationsSuppressed(
       self, suppressed, timeout=web_contents.DEFAULT_WEB_CONTENTS_TIMEOUT):
-    self.devtools_client.SetMemoryPressureNotificationsSuppressed(suppressed)
+    self.devtools_client.SetMemoryPressureNotificationsSuppressed(
+        suppressed, timeout)
+
+  def SimulateMemoryPressureNotification(
+      self, pressure_level, timeout=web_contents.DEFAULT_WEB_CONTENTS_TIMEOUT):
+    self.devtools_client.SimulateMemoryPressureNotification(
+        pressure_level, timeout)
 
   @property
   def supports_cpu_metrics(self):
diff --git a/tools/telemetry/telemetry/internal/backends/chrome_inspector/devtools_client_backend.py b/tools/telemetry/telemetry/internal/backends/chrome_inspector/devtools_client_backend.py
index a7930810..2efb830 100644
--- a/tools/telemetry/telemetry/internal/backends/chrome_inspector/devtools_client_backend.py
+++ b/tools/telemetry/telemetry/internal/backends/chrome_inspector/devtools_client_backend.py
@@ -13,6 +13,7 @@
 from telemetry.internal.backends.chrome_inspector import devtools_http
 from telemetry.internal.backends.chrome_inspector import inspector_backend
 from telemetry.internal.backends.chrome_inspector import inspector_websocket
+from telemetry.internal.backends.chrome_inspector import memory_backend
 from telemetry.internal.backends.chrome_inspector import tracing_backend
 from telemetry.internal.backends.chrome_inspector import websocket
 from telemetry.internal.platform.tracing_agent import chrome_tracing_agent
@@ -97,6 +98,7 @@
     self._devtools_http = devtools_http.DevToolsHttp(devtools_port)
     self._browser_inspector_websocket = None
     self._tracing_backend = None
+    self._memory_backend = None
     self._app_backend = app_backend
     self._devtools_context_map_backend = _DevToolsContextMapBackend(
         self._app_backend, self)
@@ -168,6 +170,9 @@
     if self._tracing_backend:
       self._tracing_backend.Close()
       self._tracing_backend = None
+    if self._memory_backend:
+      self._memory_backend.Close()
+      self._memory_backend = None
     # Close the browser inspector socket last (in case the backend needs to
     # interact with it before closing).
     if self._browser_inspector_websocket:
@@ -269,6 +274,13 @@
       self._tracing_backend = tracing_backend.TracingBackend(
           self._browser_inspector_websocket, is_tracing_running)
 
+  def _CreateMemoryBackendIfNeeded(self):
+    assert self.supports_overriding_memory_pressure_notifications
+    if not self._memory_backend:
+      self._CreateAndConnectBrowserInspectorWebsocketIfNeeded()
+      self._memory_backend = memory_backend.MemoryBackend(
+          self._browser_inspector_websocket)
+
   def _CreateAndConnectBrowserInspectorWebsocketIfNeeded(self):
     if not self._browser_inspector_websocket:
       self._browser_inspector_websocket = (
@@ -342,17 +354,35 @@
       timeout: The timeout in seconds.
 
     Raises:
-      TracingTimeoutException: If more than |timeout| seconds has passed
+      MemoryTimeoutException: If more than |timeout| seconds has passed
       since the last time any data is received.
-      TracingUnrecoverableException: If there is a websocket error.
-      TracingUnexpectedResponseException: If the response contains an error
+      MemoryUnrecoverableException: If there is a websocket error.
+      MemoryUnexpectedResponseException: If the response contains an error
       or does not contain the expected result.
     """
-    assert self.supports_overriding_memory_pressure_notifications
-    self._CreateTracingBackendIfNeeded()
-    return self._tracing_backend.SetMemoryPressureNotificationsSuppressed(
+    self._CreateMemoryBackendIfNeeded()
+    return self._memory_backend.SetMemoryPressureNotificationsSuppressed(
         suppressed, timeout)
 
+  def SimulateMemoryPressureNotification(self, pressure_level, timeout=30):
+    """Simulate a memory pressure notification.
+
+    Args:
+      pressure level: The memory pressure level of the notification ('moderate'
+      or 'critical').
+      timeout: The timeout in seconds.
+
+    Raises:
+      MemoryTimeoutException: If more than |timeout| seconds has passed
+      since the last time any data is received.
+      MemoryUnrecoverableException: If there is a websocket error.
+      MemoryUnexpectedResponseException: If the response contains an error
+      or does not contain the expected result.
+    """
+    self._CreateMemoryBackendIfNeeded()
+    return self._memory_backend.SimulateMemoryPressureNotification(
+        pressure_level, timeout)
+
 
 class _DevToolsContextMapBackend(object):
   def __init__(self, app_backend, devtools_client):
diff --git a/tools/telemetry/telemetry/internal/backends/chrome_inspector/memory_backend.py b/tools/telemetry/telemetry/internal/backends/chrome_inspector/memory_backend.py
new file mode 100644
index 0000000..bb6ce09
--- /dev/null
+++ b/tools/telemetry/telemetry/internal/backends/chrome_inspector/memory_backend.py
@@ -0,0 +1,90 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import logging
+import socket
+
+from telemetry.internal.backends.chrome_inspector import inspector_websocket
+from telemetry.internal.backends.chrome_inspector import websocket
+
+
+class MemoryTimeoutException(Exception):
+  pass
+
+
+class MemoryUnrecoverableException(Exception):
+  pass
+
+
+class MemoryUnexpectedResponseException(Exception):
+  pass
+
+
+class MemoryBackend(object):
+
+  def __init__(self, inspector_socket):
+    self._inspector_websocket = inspector_socket
+
+  def SetMemoryPressureNotificationsSuppressed(self, suppressed, timeout=30):
+    """Enable/disable suppressing memory pressure notifications.
+
+    Args:
+      suppressed: If true, memory pressure notifications will be suppressed.
+      timeout: The timeout in seconds.
+
+    Raises:
+      MemoryTimeoutException: If more than |timeout| seconds has passed
+      since the last time any data is received.
+      MemoryUnrecoverableException: If there is a websocket error.
+      MemoryUnexpectedResponseException: If the response contains an error
+      or does not contain the expected result.
+    """
+    self._SendMemoryRequest('setPressureNotificationsSuppressed',
+                            {'suppressed': suppressed}, timeout)
+
+  def SimulateMemoryPressureNotification(self, pressure_level, timeout=30):
+    """Simulate a memory pressure notification.
+
+    Args:
+      pressure level: The memory pressure level of the notification ('moderate'
+          or 'critical').
+      timeout: The timeout in seconds.
+
+    Raises:
+      MemoryTimeoutException: If more than |timeout| seconds has passed
+      since the last time any data is received.
+      MemoryUnrecoverableException: If there is a websocket error.
+      MemoryUnexpectedResponseException: If the response contains an error
+      or does not contain the expected result.
+    """
+    self._SendMemoryRequest('simulatePressureNotification',
+                            {'level': pressure_level}, timeout)
+
+  def _SendMemoryRequest(self, command, params, timeout):
+    method = 'Memory.%s' % command
+    request = {
+      'method': method,
+      'params': params
+    }
+    try:
+      response = self._inspector_websocket.SyncRequest(request, timeout)
+    except websocket.WebSocketTimeoutException:
+      raise MemoryTimeoutException
+    except (socket.error, websocket.WebSocketException,
+            inspector_websocket.WebSocketDisconnected):
+      raise MemoryUnrecoverableException
+
+    if 'error' in response:
+      code = response['error']['code']
+      if code == inspector_websocket.InspectorWebsocket.METHOD_NOT_FOUND_CODE:
+        logging.warning(
+            '%s DevTools method not supported by the browser' % method)
+      else:
+        raise MemoryUnexpectedResponseException(
+            'Inspector returned unexpected response for %s:\n%s' %
+                (method, json.dumps(response, indent=2)))
+
+  def Close(self):
+    self._inspector_websocket = None
diff --git a/tools/telemetry/telemetry/internal/backends/chrome_inspector/memory_backend_unittest.py b/tools/telemetry/telemetry/internal/backends/chrome_inspector/memory_backend_unittest.py
new file mode 100644
index 0000000..5829d1d00
--- /dev/null
+++ b/tools/telemetry/telemetry/internal/backends/chrome_inspector/memory_backend_unittest.py
@@ -0,0 +1,152 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import mock
+import unittest
+
+
+from telemetry.internal.backends.chrome_inspector import inspector_websocket
+from telemetry.internal.backends.chrome_inspector import memory_backend
+from telemetry.testing import fakes
+from telemetry.testing import simple_mock
+from telemetry.testing import tab_test_case
+
+
+class MemoryBackendTest(tab_test_case.TabTestCase):
+
+  def setUp(self):
+    super(MemoryBackendTest, self).setUp()
+    if not self._browser.supports_overriding_memory_pressure_notifications:
+      self.skipTest('Browser does not support overriding memory pressure '
+                    'notification signals, skipping test.')
+
+  def testSetMemoryPressureNotificationsSuppressed(self):
+    def PerformCheck(suppressed):
+      # Check that the method sends the correct DevTools request.
+      with mock.patch.object(inspector_websocket.InspectorWebsocket,
+                             'SyncRequest') as mock_method:
+        self._browser.SetMemoryPressureNotificationsSuppressed(suppressed)
+        self.assertEqual(1, mock_method.call_count)
+        request = mock_method.call_args[0][0]
+        self.assertEqual('Memory.setPressureNotificationsSuppressed',
+                         request['method'])
+        self.assertEqual(suppressed, request['params']['suppressed'])
+
+      # Check that the request and the response from the browser are handled
+      # properly.
+      self._browser.SetMemoryPressureNotificationsSuppressed(suppressed)
+
+    PerformCheck(True)
+    PerformCheck(False)
+
+  def testSimulateMemoryPressureNotification(self):
+    def PerformCheck(pressure_level):
+      # Check that the method sends the correct DevTools request.
+      with mock.patch.object(inspector_websocket.InspectorWebsocket,
+                             'SyncRequest') as mock_method:
+        self._browser.SimulateMemoryPressureNotification(pressure_level)
+        self.assertEqual(1, mock_method.call_count)
+        request = mock_method.call_args[0][0]
+        self.assertEqual('Memory.simulatePressureNotification',
+                         request['method'])
+        self.assertEqual(pressure_level, request['params']['level'])
+
+      # Check that the request and the response from the browser are handled
+      # properly.
+      self._browser.SimulateMemoryPressureNotification(pressure_level)
+
+    PerformCheck('moderate')
+    PerformCheck('critical')
+
+
+class MemoryBackendUnitTest(unittest.TestCase):
+
+  def setUp(self):
+    self._mock_timer = simple_mock.MockTimer()
+    self._inspector_socket = fakes.FakeInspectorWebsocket(self._mock_timer)
+
+  def tearDown(self):
+    self._mock_timer.Restore()
+
+  def testSetMemoryPressureNotificationsSuppressedSuccess(self):
+    response_handler = mock.Mock(return_value={'result': {}})
+    self._inspector_socket.AddResponseHandler(
+        'Memory.setPressureNotificationsSuppressed', response_handler)
+    backend = memory_backend.MemoryBackend(self._inspector_socket)
+
+    backend.SetMemoryPressureNotificationsSuppressed(True)
+    self.assertEqual(1, response_handler.call_count)
+    self.assertTrue(response_handler.call_args[0][0]['params']['suppressed'])
+
+    backend.SetMemoryPressureNotificationsSuppressed(False)
+    self.assertEqual(2, response_handler.call_count)
+    self.assertFalse(response_handler.call_args[0][0]['params']['suppressed'])
+
+  def testSetMemoryPressureNotificationsSuppressedFailure(self):
+    response_handler = mock.Mock()
+    backend = memory_backend.MemoryBackend(self._inspector_socket)
+    self._inspector_socket.AddResponseHandler(
+        'Memory.setPressureNotificationsSuppressed', response_handler)
+
+    # If the DevTools method is missing, the backend should fail silently.
+    response_handler.return_value = {
+      'result': {},
+      'error': {
+        'code': -32601  # Method does not exist.
+      }
+    }
+    backend.SetMemoryPressureNotificationsSuppressed(True)
+    self.assertEqual(1, response_handler.call_count)
+
+    # All other errors should raise an exception.
+    response_handler.return_value = {
+      'result': {},
+      'error': {
+        'code': -32602  # Invalid method params.
+      }
+    }
+    self.assertRaises(memory_backend.MemoryUnexpectedResponseException,
+                      backend.SetMemoryPressureNotificationsSuppressed, True)
+
+  def testSimulateMemoryPressureNotificationSuccess(self):
+    response_handler = mock.Mock(return_value={'result': {}})
+    self._inspector_socket.AddResponseHandler(
+        'Memory.simulatePressureNotification', response_handler)
+    backend = memory_backend.MemoryBackend(self._inspector_socket)
+
+    backend.SimulateMemoryPressureNotification('critical')
+    self.assertEqual(1, response_handler.call_count)
+    self.assertEqual('critical',
+                     response_handler.call_args[0][0]['params']['level'])
+
+    backend.SimulateMemoryPressureNotification('moderate')
+    self.assertEqual(2, response_handler.call_count)
+    self.assertEqual('moderate',
+                     response_handler.call_args[0][0]['params']['level'])
+
+  def testSimulateMemoryPressureNotificationFailure(self):
+    response_handler = mock.Mock()
+    backend = memory_backend.MemoryBackend(self._inspector_socket)
+    self._inspector_socket.AddResponseHandler(
+        'Memory.simulatePressureNotification', response_handler)
+
+    # If the DevTools method is missing, the backend should fail silently.
+    response_handler.return_value = {
+      'result': {},
+      'error': {
+        'code': -32601  # Method does not exist.
+      }
+    }
+    backend.SimulateMemoryPressureNotification('critical')
+    self.assertEqual(1, response_handler.call_count)
+
+    # All other errors should raise an exception.
+    response_handler.return_value = {
+      'result': {},
+      'error': {
+        'code': -32602  # Invalid method params.
+      }
+    }
+    self.assertRaises(memory_backend.MemoryUnexpectedResponseException,
+                      backend.SimulateMemoryPressureNotification, 'critical')
diff --git a/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend.py b/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend.py
index 8b96e6a..24696b96 100644
--- a/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend.py
+++ b/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend.py
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 import json
-import logging
 import socket
 import time
 
@@ -168,45 +167,6 @@
     result = response['result']
     return result['dumpGuid'] if result['success'] else None
 
-  def SetMemoryPressureNotificationsSuppressed(self, suppressed, timeout=30):
-    """Enable/disable suppressing memory pressure notifications.
-
-    Args:
-      suppressed: If true, memory pressure notifications will be suppressed.
-      timeout: The timeout in seconds.
-
-    Raises:
-      TracingTimeoutException: If more than |timeout| seconds has passed
-      since the last time any data is received.
-      TracingUnrecoverableException: If there is a websocket error.
-      TracingUnexpectedResponseException: If the response contains an error
-      or does not contain the expected result.
-    """
-    request = {
-      'method': 'Memory.setPressureNotificationsSuppressed',
-      'params': {
-        'suppressed': suppressed
-      }
-    }
-    try:
-      response = self._inspector_websocket.SyncRequest(request, timeout)
-    except websocket.WebSocketTimeoutException:
-      raise TracingTimeoutException
-    except (socket.error, websocket.WebSocketException,
-            inspector_websocket.WebSocketDisconnected):
-      raise TracingUnrecoverableException
-
-    if 'error' in response:
-      code = response['error']['code']
-      if code == inspector_websocket.InspectorWebsocket.METHOD_NOT_FOUND_CODE:
-        logging.warning('Memory.setPressureNotificationsSuppressed DevTools '
-                        'method not supported by the browser')
-      else:
-        raise TracingUnexpectedResponseException(
-            'Inspector returned unexpected response for '
-            'Memory.setPressureNotificationsSuppressed:\n' +
-            json.dumps(response, indent=2))
-
   def _CollectTracingData(self, timeout):
     """Collects tracing data. Assumes that Tracing.end has already been sent.
 
diff --git a/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py b/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py
index ccafea56..88cb8e553 100644
--- a/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py
+++ b/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py
@@ -4,101 +4,17 @@
 
 import unittest
 
-from telemetry.internal.backends.chrome_inspector import inspector_websocket
 from telemetry.internal.backends.chrome_inspector import tracing_backend
-from telemetry.internal.backends.chrome_inspector import websocket
+from telemetry.testing import fakes
 from telemetry.testing import simple_mock
 from telemetry.testing import tab_test_case
 from telemetry.timeline import model as model_module
 from telemetry.timeline import tracing_category_filter
 from telemetry.timeline import tracing_options
-import mock
-
-
-class FakeInspectorWebsocket(object):
-  _NOTIFICATION_EVENT = 1
-  _NOTIFICATION_CALLBACK = 2
-
-  """A fake InspectorWebsocket.
-
-  A fake that allows tests to send pregenerated data. Normal
-  InspectorWebsockets allow for any number of domain handlers. This fake only
-  allows up to 1 domain handler, and assumes that the domain of the response
-  always matches that of the handler.
-  """
-  def __init__(self, mock_timer):
-    self._mock_timer = mock_timer
-    self._notifications = []
-    self._response_handlers = {}
-    self._pending_callbacks = {}
-    self._handler = None
-
-  def RegisterDomain(self, _, handler):
-    self._handler = handler
-
-  def AddEvent(self, method, params, time):
-    if self._notifications:
-      assert self._notifications[-1][1] < time, (
-          'Current response is scheduled earlier than previous response.')
-    response = {'method': method, 'params': params}
-    self._notifications.append((response, time, self._NOTIFICATION_EVENT))
-
-  def AddAsyncResponse(self, method, result, time):
-    if self._notifications:
-      assert self._notifications[-1][1] < time, (
-          'Current response is scheduled earlier than previous response.')
-    response = {'method': method, 'result': result}
-    self._notifications.append((response, time, self._NOTIFICATION_CALLBACK))
-
-  def AddResponseHandler(self, method, handler):
-    self._response_handlers[method] = handler
-
-  def SyncRequest(self, request, *_args, **_kwargs):
-    handler = self._response_handlers[request['method']]
-    return handler(request) if handler else None
-
-  def AsyncRequest(self, request, callback):
-    self._pending_callbacks.setdefault(request['method'], []).append(callback)
-
-  def SendAndIgnoreResponse(self, request):
-    pass
-
-  def Connect(self, _):
-    pass
-
-  def DispatchNotifications(self, timeout):
-    current_time = self._mock_timer.time()
-    if not self._notifications:
-      self._mock_timer.SetTime(current_time + timeout + 1)
-      raise websocket.WebSocketTimeoutException()
-
-    response, time, kind = self._notifications[0]
-    if time - current_time > timeout:
-      self._mock_timer.SetTime(current_time + timeout + 1)
-      raise websocket.WebSocketTimeoutException()
-
-    self._notifications.pop(0)
-    self._mock_timer.SetTime(time + 1)
-    if kind == self._NOTIFICATION_EVENT:
-      self._handler(response)
-    elif kind == self._NOTIFICATION_CALLBACK:
-      callback = self._pending_callbacks.get(response['method']).pop(0)
-      callback(response)
-    else:
-      raise Exception('Unexpected response type')
 
 
 class TracingBackendTest(tab_test_case.TabTestCase):
 
-  def setUp(self):
-    super(TracingBackendTest, self).setUp()
-    self._tracing_controller = self._browser.platform.tracing_controller
-    if not self._tracing_controller.IsChromeTracingSupported():
-      self.skipTest('Browser does not support tracing, skipping test.')
-
-
-class TracingBackendMemoryDumpTest(TracingBackendTest):
-
   # Number of consecutively requested memory dumps.
   _REQUESTED_DUMP_COUNT = 3
 
@@ -114,7 +30,10 @@
     ])
 
   def setUp(self):
-    super(TracingBackendMemoryDumpTest, self).setUp()
+    super(TracingBackendTest, self).setUp()
+    self._tracing_controller = self._browser.platform.tracing_controller
+    if not self._tracing_controller.IsChromeTracingSupported():
+      self.skipTest('Browser does not support tracing, skipping test.')
     if not self._browser.supports_memory_dumping:
       self.skipTest('Browser does not support memory dumping, skipping test.')
 
@@ -178,47 +97,22 @@
     self.assertEqual(len(list(model.IterGlobalMemoryDumps())), 0)
 
 
-class TracingBackendMemoryPressureNotificationsTest(TracingBackendTest):
-
-  def setUp(self):
-    super(TracingBackendMemoryPressureNotificationsTest, self).setUp()
-    if not self._browser.supports_overriding_memory_pressure_notifications:
-      self.skipTest('Browser does not support overriding memory pressure '
-                    'notification signals, skipping test.')
-
-  def testSetMemoryPressureNotificationsSuppressed(self):
-    def perform_check(suppressed):
-      # Check that the method sends the correct DevTools request.
-      with mock.patch.object(inspector_websocket.InspectorWebsocket,
-                             'SyncRequest') as mock_method:
-        self._browser.SetMemoryPressureNotificationsSuppressed(suppressed)
-        self.assertEqual(1, mock_method.call_count)
-        request = mock_method.call_args[0][0]
-        self.assertEqual('Memory.setPressureNotificationsSuppressed',
-                         request['method'])
-        self.assertEqual(suppressed, request['params']['suppressed'])
-
-      # Check that the request and the response from the browser are handled
-      # properly.
-      self._browser.SetMemoryPressureNotificationsSuppressed(suppressed)
-
-    perform_check(True)
-    perform_check(False)
-
-
 class TracingBackendUnitTest(unittest.TestCase):
+
   def setUp(self):
     self._mock_timer = simple_mock.MockTimer(tracing_backend)
+    self._inspector_socket = fakes.FakeInspectorWebsocket(self._mock_timer)
 
   def tearDown(self):
     self._mock_timer.Restore()
 
   def testCollectTracingDataTimeout(self):
-    inspector = FakeInspectorWebsocket(self._mock_timer)
-    inspector.AddEvent('Tracing.dataCollected', {'value': [{'ph': 'B'}]}, 9)
-    inspector.AddEvent('Tracing.dataCollected', {'value': [{'ph': 'E'}]}, 19)
-    inspector.AddEvent('Tracing.tracingComplete', {}, 35)
-    backend = tracing_backend.TracingBackend(inspector)
+    self._inspector_socket.AddEvent(
+        'Tracing.dataCollected', {'value': [{'ph': 'B'}]}, 9)
+    self._inspector_socket.AddEvent(
+        'Tracing.dataCollected', {'value': [{'ph': 'E'}]}, 19)
+    self._inspector_socket.AddEvent('Tracing.tracingComplete', {}, 35)
+    backend = tracing_backend.TracingBackend(self._inspector_socket)
 
     # The third response is 16 seconds after the second response, so we expect
     # a TracingTimeoutException.
@@ -228,83 +122,42 @@
     self.assertFalse(backend._has_received_all_tracing_data)
 
   def testCollectTracingDataNoTimeout(self):
-    inspector = FakeInspectorWebsocket(self._mock_timer)
-    inspector.AddEvent('Tracing.dataCollected', {'value': [{'ph': 'B'}]}, 9)
-    inspector.AddEvent('Tracing.dataCollected', {'value': [{'ph': 'E'}]}, 14)
-    inspector.AddEvent('Tracing.tracingComplete', {}, 19)
-    backend = tracing_backend.TracingBackend(inspector)
+    self._inspector_socket.AddEvent(
+        'Tracing.dataCollected', {'value': [{'ph': 'B'}]}, 9)
+    self._inspector_socket.AddEvent(
+        'Tracing.dataCollected', {'value': [{'ph': 'E'}]}, 14)
+    self._inspector_socket.AddEvent('Tracing.tracingComplete', {}, 19)
+    backend = tracing_backend.TracingBackend(self._inspector_socket)
 
     backend._CollectTracingData(10)
     self.assertEqual(2, len(backend._trace_events))
     self.assertTrue(backend._has_received_all_tracing_data)
 
   def testCollectTracingDataFromStream(self):
-    inspector = FakeInspectorWebsocket(self._mock_timer)
-    inspector.AddEvent('Tracing.tracingComplete', {'stream': '42'}, 1)
-    inspector.AddAsyncResponse('IO.read', {'data': '[{},{},{'}, 2)
-    inspector.AddAsyncResponse('IO.read', {'data': '},{},{}]', 'eof': True}, 3)
-    backend = tracing_backend.TracingBackend(inspector)
+    self._inspector_socket.AddEvent(
+        'Tracing.tracingComplete', {'stream': '42'}, 1)
+    self._inspector_socket.AddAsyncResponse(
+        'IO.read', {'data': '[{},{},{'}, 2)
+    self._inspector_socket.AddAsyncResponse(
+        'IO.read', {'data': '},{},{}]', 'eof': True}, 3)
+    backend = tracing_backend.TracingBackend(self._inspector_socket)
 
     backend._CollectTracingData(10)
     self.assertEqual(5, len(backend._trace_events))
     self.assertTrue(backend._has_received_all_tracing_data)
 
   def testDumpMemorySuccess(self):
-    inspector = FakeInspectorWebsocket(self._mock_timer)
-    inspector.AddResponseHandler(
+    self._inspector_socket.AddResponseHandler(
         'Tracing.requestMemoryDump',
         lambda req: {'result': {'success': True, 'dumpGuid': '42abc'}})
-    backend = tracing_backend.TracingBackend(inspector)
+    backend = tracing_backend.TracingBackend(self._inspector_socket)
 
     self.assertEqual(backend.DumpMemory(), '42abc')
 
   def testDumpMemoryFailure(self):
-    inspector = FakeInspectorWebsocket(self._mock_timer)
-    inspector.AddResponseHandler(
+    self._inspector_socket.AddResponseHandler(
         'Tracing.requestMemoryDump',
         lambda req: {'result': {'success': False, 'dumpGuid': '42abc'}})
-    backend = tracing_backend.TracingBackend(inspector)
+    backend = tracing_backend.TracingBackend(self._inspector_socket)
 
     self.assertIsNone(backend.DumpMemory())
-
-  def testSetMemoryPressureNotificationsSuppressedSuccess(self):
-    response_handler = mock.Mock(return_value={'result': {}})
-    inspector = FakeInspectorWebsocket(self._mock_timer)
-    inspector.AddResponseHandler(
-        'Memory.setPressureNotificationsSuppressed', response_handler)
-    backend = tracing_backend.TracingBackend(inspector)
-
-    backend.SetMemoryPressureNotificationsSuppressed(True)
-    self.assertEqual(1, response_handler.call_count)
-    self.assertTrue(response_handler.call_args[0][0]['params']['suppressed'])
-
-    backend.SetMemoryPressureNotificationsSuppressed(False)
-    self.assertEqual(2, response_handler.call_count)
-    self.assertFalse(response_handler.call_args[0][0]['params']['suppressed'])
-
-  def testSetMemoryPressureNotificationsSuppressedFailure(self):
-    response_handler = mock.Mock()
-    inspector = FakeInspectorWebsocket(self._mock_timer)
-    backend = tracing_backend.TracingBackend(inspector)
-    inspector.AddResponseHandler(
-        'Memory.setPressureNotificationsSuppressed', response_handler)
-
-    # If the DevTools method is missing, the backend should fail silently.
-    response_handler.return_value = {
-      'result': {},
-      'error': {
-        'code': -32601  # Method does not exist.
-      }
-    }
-    backend.SetMemoryPressureNotificationsSuppressed(True)
-    self.assertEqual(1, response_handler.call_count)
-
-    # All other errors should raise an exception.
-    response_handler.return_value = {
-      'result': {},
-      'error': {
-        'code': -32602  # Invalid method params.
-      }
-    }
-    self.assertRaises(tracing_backend.TracingUnexpectedResponseException,
-                      backend.SetMemoryPressureNotificationsSuppressed, True)
diff --git a/tools/telemetry/telemetry/internal/browser/browser.py b/tools/telemetry/telemetry/internal/browser/browser.py
index 5f26aade..248a932 100644
--- a/tools/telemetry/telemetry/internal/browser/browser.py
+++ b/tools/telemetry/telemetry/internal/browser/browser.py
@@ -268,6 +268,11 @@
     self._browser_backend.SetMemoryPressureNotificationsSuppressed(
         suppressed, timeout)
 
+  def SimulateMemoryPressureNotification(
+      self, pressure_level, timeout=web_contents.DEFAULT_WEB_CONTENTS_TIMEOUT):
+    self._browser_backend.SimulateMemoryPressureNotification(
+        pressure_level, timeout)
+
   @property
   def supports_cpu_metrics(self):
     return self._browser_backend.supports_cpu_metrics
diff --git a/tools/telemetry/telemetry/testing/fakes/__init__.py b/tools/telemetry/telemetry/testing/fakes/__init__.py
index 7eecc43..2502799 100644
--- a/tools/telemetry/telemetry/testing/fakes/__init__.py
+++ b/tools/telemetry/telemetry/testing/fakes/__init__.py
@@ -11,6 +11,7 @@
 may need to be called in tests.
 """
 
+from telemetry.internal.backends.chrome_inspector import websocket
 from telemetry.internal.browser import browser_options
 from telemetry.internal.platform import system_info
 from telemetry.page import shared_page_state
@@ -291,3 +292,76 @@
       if tab.id == identifier:
         return tab
     return None
+
+
+class FakeInspectorWebsocket(object):
+  _NOTIFICATION_EVENT = 1
+  _NOTIFICATION_CALLBACK = 2
+
+  """A fake InspectorWebsocket.
+
+  A fake that allows tests to send pregenerated data. Normal
+  InspectorWebsockets allow for any number of domain handlers. This fake only
+  allows up to 1 domain handler, and assumes that the domain of the response
+  always matches that of the handler.
+  """
+  def __init__(self, mock_timer):
+    self._mock_timer = mock_timer
+    self._notifications = []
+    self._response_handlers = {}
+    self._pending_callbacks = {}
+    self._handler = None
+
+  def RegisterDomain(self, _, handler):
+    self._handler = handler
+
+  def AddEvent(self, method, params, time):
+    if self._notifications:
+      assert self._notifications[-1][1] < time, (
+          'Current response is scheduled earlier than previous response.')
+    response = {'method': method, 'params': params}
+    self._notifications.append((response, time, self._NOTIFICATION_EVENT))
+
+  def AddAsyncResponse(self, method, result, time):
+    if self._notifications:
+      assert self._notifications[-1][1] < time, (
+          'Current response is scheduled earlier than previous response.')
+    response = {'method': method, 'result': result}
+    self._notifications.append((response, time, self._NOTIFICATION_CALLBACK))
+
+  def AddResponseHandler(self, method, handler):
+    self._response_handlers[method] = handler
+
+  def SyncRequest(self, request, *_args, **_kwargs):
+    handler = self._response_handlers[request['method']]
+    return handler(request) if handler else None
+
+  def AsyncRequest(self, request, callback):
+    self._pending_callbacks.setdefault(request['method'], []).append(callback)
+
+  def SendAndIgnoreResponse(self, request):
+    pass
+
+  def Connect(self, _):
+    pass
+
+  def DispatchNotifications(self, timeout):
+    current_time = self._mock_timer.time()
+    if not self._notifications:
+      self._mock_timer.SetTime(current_time + timeout + 1)
+      raise websocket.WebSocketTimeoutException()
+
+    response, time, kind = self._notifications[0]
+    if time - current_time > timeout:
+      self._mock_timer.SetTime(current_time + timeout + 1)
+      raise websocket.WebSocketTimeoutException()
+
+    self._notifications.pop(0)
+    self._mock_timer.SetTime(time + 1)
+    if kind == self._NOTIFICATION_EVENT:
+      self._handler(response)
+    elif kind == self._NOTIFICATION_CALLBACK:
+      callback = self._pending_callbacks.get(response['method']).pop(0)
+      callback(response)
+    else:
+      raise Exception('Unexpected response type')