diff --git a/DEPS b/DEPS
index 3363f0e..9dd07c7 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '63afe64a5f33a61235706dbec0f0cc695c88469b',
+  'skia_revision': '99d4721171f9b8f23cd907ef3da938c4c5579ae9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -64,7 +64,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': '00d4064e5414fc0845e354b50c7f1a8323449268',
+  'pdfium_revision': 'c8017b2581b7ade6b05ba086eb7221465414173f',
   # 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.
@@ -88,7 +88,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': 'afa90269512fe22519d7a8445e0d54a177d63f42',
+  'nacl_revision': '70540f6583440d4174e6d75743bb544cfbaaf204',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype-android
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '2c3f1f3d69c01170e93ab32a441b51b1712016c1',
+  'catapult_revision': '4ee31ea3b497ffe08391e88a5434e0a340e48342',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/android_webview/java/src/org/chromium/android_webview/AwActionModeCallback.java b/android_webview/java/src/org/chromium/android_webview/AwActionModeCallback.java
index 82b4595a..2c54cdd 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwActionModeCallback.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwActionModeCallback.java
@@ -93,7 +93,7 @@
         RecordUserAction.record("MobileActionMode.ProcessTextIntent");
         assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
 
-        String query = mHelper.sanitizeQuery(mHelper.getSelectedText(),
+        String query = ActionModeCallbackHelper.sanitizeQuery(mHelper.getSelectedText(),
                 ActionModeCallbackHelper.MAX_SEARCH_QUERY_LENGTH);
         if (TextUtils.isEmpty(query)) return;
 
diff --git a/ash/common/system/tray/tray_details_view.cc b/ash/common/system/tray/tray_details_view.cc
index 9fbe9c6..4a5fecd 100644
--- a/ash/common/system/tray/tray_details_view.cc
+++ b/ash/common/system/tray/tray_details_view.cc
@@ -23,7 +23,7 @@
 #include "ui/compositor/paint_context.h"
 #include "ui/compositor/paint_recorder.h"
 #include "ui/gfx/canvas.h"
-#include "ui/gfx/skia_util.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/label.h"
diff --git a/ash/magnifier/partial_magnification_controller.cc b/ash/magnifier/partial_magnification_controller.cc
index a9184eb8..61feab3 100644
--- a/ash/magnifier/partial_magnification_controller.cc
+++ b/ash/magnifier/partial_magnification_controller.cc
@@ -14,6 +14,7 @@
 #include "ui/events/event.h"
 #include "ui/events/event_constants.h"
 #include "ui/gfx/shadow_value.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/coordinate_conversion.h"
 
diff --git a/base/android/application_status_listener_unittest.cc b/base/android/application_status_listener_unittest.cc
index a6f098b..803dedb 100644
--- a/base/android/application_status_listener_unittest.cc
+++ b/base/android/application_status_listener_unittest.cc
@@ -69,9 +69,6 @@
         APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES);
     event_.Wait();
     EXPECT_EQ(APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES, state_);
-
-    // Delete |listener_| on the thread on which it was created.
-    thread_.task_runner()->DeleteSoon(FROM_HERE, listener_.release());
   }
 
  private:
diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h
index f8481de..afb1010 100644
--- a/base/observer_list_threadsafe.h
+++ b/base/observer_list_threadsafe.h
@@ -5,48 +5,52 @@
 #ifndef BASE_OBSERVER_LIST_THREADSAFE_H_
 #define BASE_OBSERVER_LIST_THREADSAFE_H_
 
-#include <unordered_map>
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <tuple>
 
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
-#include "base/sequenced_task_runner.h"
-#include "base/stl_util.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "base/threading/thread_local.h"
-#include "build/build_config.h"
-
-// TODO(fdoray): Removing these includes causes IWYU failures in other headers,
-// remove them in a follow- up CL.
-#include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_task_runner_handle.h"
 
 ///////////////////////////////////////////////////////////////////////////////
 //
 // OVERVIEW:
 //
-//   A thread-safe container for a list of observers. This is similar to the
-//   observer_list (see observer_list.h), but it is more robust for multi-
-//   threaded situations.
+//   A thread-safe container for a list of observers.
+//   This is similar to the observer_list (see observer_list.h), but it
+//   is more robust for multi-threaded situations.
 //
 //   The following use cases are supported:
-//    * Observers can register for notifications from any sequence. They are
-//      always notified on the sequence from which they were registered.
-//    * Any sequence may trigger a notification via Notify().
-//    * Observers can remove themselves from the observer list inside of a
-//      callback.
-//    * If one sequence is notifying observers concurrently with an observer
-//      removing itself from the observer list, the notifications will be
-//      silently dropped.
+//    * Observers can register for notifications from any thread.
+//      Callbacks to the observer will occur on the same thread where
+//      the observer initially called AddObserver() from.
+//    * Any thread may trigger a notification via Notify().
+//    * Observers can remove themselves from the observer list inside
+//      of a callback.
+//    * If one thread is notifying observers concurrently with an observer
+//      removing itself from the observer list, the notifications will
+//      be silently dropped.
 //
-//   The drawback of the threadsafe observer list is that notifications are not
-//   as real-time as the non-threadsafe version of this class. Notifications
-//   will always be done via PostTask() to another sequence, whereas with the
-//   non-thread-safe observer_list, notifications happen synchronously.
+//   The drawback of the threadsafe observer list is that notifications
+//   are not as real-time as the non-threadsafe version of this class.
+//   Notifications will always be done via PostTask() to another thread,
+//   whereas with the non-thread-safe observer_list, notifications happen
+//   synchronously and immediately.
+//
+//   IMPLEMENTATION NOTES
+//   The ObserverListThreadSafe maintains an ObserverList for each thread
+//   which uses the ThreadSafeObserver.  When Notifying the observers,
+//   we simply call PostTask to each registered thread, and then each thread
+//   will notify its regular ObserverList.
 //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -73,72 +77,68 @@
   using NotificationType =
       typename ObserverList<ObserverType>::NotificationType;
 
-  ObserverListThreadSafe() = default;
+  ObserverListThreadSafe()
+      : type_(ObserverListBase<ObserverType>::NOTIFY_ALL) {}
   explicit ObserverListThreadSafe(NotificationType type) : type_(type) {}
 
-  // Adds |observer| to the list. |observer| must not already be in the list.
-  void AddObserver(ObserverType* observer) {
-    // TODO(fdoray): Change this to a DCHECK once all call sites have a
-    // SequencedTaskRunnerHandle.
-    if (!SequencedTaskRunnerHandle::IsSet())
+  // Add an observer to the list.  An observer should not be added to
+  // the same list more than once.
+  void AddObserver(ObserverType* obs) {
+    // If there is no ThreadTaskRunnerHandle, it is impossible to notify on it,
+    // so do not add the observer.
+    if (!ThreadTaskRunnerHandle::IsSet())
       return;
 
-    AutoLock auto_lock(lock_);
-
-    // Add |observer| to the list of observers.
-    DCHECK(!ContainsKey(observers_, observer));
-    const scoped_refptr<SequencedTaskRunner> task_runner =
-        SequencedTaskRunnerHandle::Get();
-    observers_[observer] = task_runner;
-
-    // If this is called while a notification is being dispatched on this thread
-    // and |type_| is NOTIFY_ALL, |observer| must be notified (if a notification
-    // is being dispatched on another thread in parallel, the notification may
-    // or may not make it to |observer| depending on the outcome of the race to
-    // |lock_|).
-    if (type_ == NotificationType::NOTIFY_ALL) {
-      const NotificationData* current_notification =
-          tls_current_notification_.Get();
-      if (current_notification) {
-        task_runner->PostTask(
-            current_notification->from_here,
-            Bind(&ObserverListThreadSafe<ObserverType>::NotifyWrapper, this,
-                 observer, *current_notification));
+    ObserverList<ObserverType>* list = nullptr;
+    PlatformThreadId thread_id = PlatformThread::CurrentId();
+    {
+      AutoLock lock(list_lock_);
+      if (observer_lists_.find(thread_id) == observer_lists_.end()) {
+        observer_lists_[thread_id] =
+            base::MakeUnique<ObserverListContext>(type_);
       }
+      list = &(observer_lists_[thread_id]->list);
     }
+    list->AddObserver(obs);
   }
 
   // Remove an observer from the list if it is in the list.
   // If there are pending notifications in-transit to the observer, they will
   // be aborted.
   // If the observer to be removed is in the list, RemoveObserver MUST
-  // be called from the same sequence which called AddObserver.
-  void RemoveObserver(ObserverType* observer) {
-    AutoLock auto_lock(lock_);
-    auto it = observers_.find(observer);
-    if (it == observers_.end())
-      return;
+  // be called from the same thread which called AddObserver.
+  void RemoveObserver(ObserverType* obs) {
+    PlatformThreadId thread_id = PlatformThread::CurrentId();
+    {
+      AutoLock lock(list_lock_);
+      auto it = observer_lists_.find(thread_id);
+      if (it == observer_lists_.end()) {
+        // This will happen if we try to remove an observer on a thread
+        // we never added an observer for.
+        return;
+      }
+      ObserverList<ObserverType>& list = it->second->list;
 
-    // TODO(fdoray): Enable this on Android once all tests pass.
-#if !defined(OS_ANDROID)
-    DCHECK(it->second->RunsTasksOnCurrentThread());
-#endif
+      list.RemoveObserver(obs);
 
-    observers_.erase(it);
+      // If that was the last observer in the list, remove the ObserverList
+      // entirely.
+      if (list.size() == 0)
+        observer_lists_.erase(it);
+    }
   }
 
   // Verifies that the list is currently empty (i.e. there are no observers).
   void AssertEmpty() const {
-#if DCHECK_IS_ON()
-    AutoLock auto_lock(lock_);
-    DCHECK(observers_.empty());
-#endif
+    AutoLock lock(list_lock_);
+    DCHECK(observer_lists_.empty());
   }
 
-  // Asynchronously invokes a callback on all observers, on their registration
-  // sequence. You cannot assume that at the completion of the Notify call that
-  // all Observers have been Notified. The notification may still be pending
-  // delivery.
+  // Notify methods.
+  // Make a thread-safe callback to each Observer in the list.
+  // Note, these calls are effectively asynchronous.  You cannot assume
+  // that at the completion of the Notify call that all Observers have
+  // been Notified.  The notification may still be pending delivery.
   template <typename Method, typename... Params>
   void Notify(const tracked_objects::Location& from_here,
               Method m, Params&&... params) {
@@ -146,71 +146,79 @@
         Bind(&internal::Dispatcher<ObserverType, Method>::Run,
              m, std::forward<Params>(params)...);
 
-    AutoLock lock(lock_);
-    for (const auto& observer : observers_) {
-      observer.second->PostTask(
+    AutoLock lock(list_lock_);
+    for (const auto& entry : observer_lists_) {
+      ObserverListContext* context = entry.second.get();
+      context->task_runner->PostTask(
           from_here,
-          Bind(&ObserverListThreadSafe<ObserverType>::NotifyWrapper, this,
-               observer.first, NotificationData(from_here, method)));
+          Bind(&ObserverListThreadSafe<ObserverType>::NotifyWrapper,
+               this, context, method));
     }
   }
 
  private:
   friend class RefCountedThreadSafe<ObserverListThreadSafe<ObserverType>>;
 
-  struct NotificationData {
-    NotificationData(const tracked_objects::Location& from_here_in,
-                     const Callback<void(ObserverType*)>& method_in)
-        : from_here(from_here_in), method(method_in) {}
+  struct ObserverListContext {
+    explicit ObserverListContext(NotificationType type)
+        : task_runner(ThreadTaskRunnerHandle::Get()), list(type) {}
 
-    tracked_objects::Location from_here;
-    Callback<void(ObserverType*)> method;
+    scoped_refptr<SingleThreadTaskRunner> task_runner;
+    ObserverList<ObserverType> list;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(ObserverListContext);
   };
 
-  ~ObserverListThreadSafe() = default;
-
-  void NotifyWrapper(ObserverType* observer,
-                     const NotificationData& notification) {
-    {
-      AutoLock auto_lock(lock_);
-
-      // Check whether the observer still needs a notification.
-      auto it = observers_.find(observer);
-      if (it == observers_.end())
-        return;
-      DCHECK(it->second->RunsTasksOnCurrentThread());
-    }
-
-    // Keep track of the notification being dispatched on the current thread.
-    // This will be used if the callback below calls AddObserver().
-    //
-    // Note: |tls_current_notification_| may not be nullptr if this runs in a
-    // nested loop started by a notification callback. In that case, it is
-    // important to save the previous value to restore it later.
-    const NotificationData* const previous_notification =
-        tls_current_notification_.Get();
-    tls_current_notification_.Set(&notification);
-
-    // Invoke the callback.
-    notification.method.Run(observer);
-
-    // Reset the notification being dispatched on the current thread to its
-    // previous value.
-    tls_current_notification_.Set(previous_notification);
+  ~ObserverListThreadSafe() {
   }
 
-  const NotificationType type_ = NotificationType::NOTIFY_ALL;
+  // Wrapper which is called to fire the notifications for each thread's
+  // ObserverList.  This function MUST be called on the thread which owns
+  // the unsafe ObserverList.
+  void NotifyWrapper(ObserverListContext* context,
+                     const Callback<void(ObserverType*)>& method) {
+    // Check that this list still needs notifications.
+    {
+      AutoLock lock(list_lock_);
+      auto it = observer_lists_.find(PlatformThread::CurrentId());
 
-  // Synchronizes access to |observers_|.
-  mutable Lock lock_;
+      // The ObserverList could have been removed already.  In fact, it could
+      // have been removed and then re-added!  If the master list's loop
+      // does not match this one, then we do not need to finish this
+      // notification.
+      if (it == observer_lists_.end() || it->second.get() != context)
+        return;
+    }
 
-  // Keys are observers. Values are the SequencedTaskRunners on which they must
-  // be notified.
-  std::unordered_map<ObserverType*, scoped_refptr<SequencedTaskRunner>>
-      observers_;
+    for (auto& observer : context->list) {
+      method.Run(&observer);
+    }
 
-  // Notification being dispatched on the current thread.
-  ThreadLocalPointer<const NotificationData> tls_current_notification_;
+    // If there are no more observers on the list, we can now delete it.
+    if (context->list.size() == 0) {
+      {
+        AutoLock lock(list_lock_);
+        // Remove |list| if it's not already removed.
+        // This can happen if multiple observers got removed in a notification.
+        // See http://crbug.com/55725.
+        auto it = observer_lists_.find(PlatformThread::CurrentId());
+        if (it != observer_lists_.end() && it->second.get() == context)
+          observer_lists_.erase(it);
+      }
+    }
+  }
+
+  mutable Lock list_lock_;  // Protects the observer_lists_.
+
+  // Key by PlatformThreadId because in tests, clients can attempt to remove
+  // observers without a SingleThreadTaskRunner. If this were keyed by
+  // SingleThreadTaskRunner, that operation would be silently ignored, leaving
+  // garbage in the ObserverList.
+  std::map<PlatformThreadId, std::unique_ptr<ObserverListContext>>
+      observer_lists_;
+
+  const NotificationType type_;
 
   DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafe);
 };
diff --git a/base/observer_list_unittest.cc b/base/observer_list_unittest.cc
index 653d881..c5e556b 100644
--- a/base/observer_list_unittest.cc
+++ b/base/observer_list_unittest.cc
@@ -5,18 +5,13 @@
 #include "base/observer_list.h"
 #include "base/observer_list_threadsafe.h"
 
-#include <utility>
 #include <vector>
 
-#include "base/bind.h"
 #include "base/compiler_specific.h"
 #include "base/location.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
-#include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/test/scoped_task_scheduler.h"
 #include "base/threading/platform_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -70,6 +65,20 @@
   bool remove_self_;
 };
 
+class ThreadSafeDisrupter : public Foo {
+ public:
+  ThreadSafeDisrupter(ObserverListThreadSafe<Foo>* list, Foo* doomed)
+      : list_(list),
+        doomed_(doomed) {
+  }
+  ~ThreadSafeDisrupter() override {}
+  void Observe(int x) override { list_->RemoveObserver(doomed_); }
+
+ private:
+  ObserverListThreadSafe<Foo>* list_;
+  Foo* doomed_;
+};
+
 template <typename ObserverListType>
 class AddInObserve : public Foo {
  public:
@@ -267,6 +276,7 @@
   Adder b(-1);
   Adder c(1);
   Adder d(-1);
+  ThreadSafeDisrupter evil(observer_list.get(), &c);
 
   observer_list->AddObserver(&a);
   observer_list->AddObserver(&b);
@@ -274,11 +284,11 @@
   observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
   RunLoop().RunUntilIdle();
 
+  observer_list->AddObserver(&evil);
   observer_list->AddObserver(&c);
   observer_list->AddObserver(&d);
 
   observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
-  observer_list->RemoveObserver(&c);
   RunLoop().RunUntilIdle();
 
   EXPECT_EQ(20, a.total);
@@ -319,18 +329,18 @@
   EXPECT_EQ(0, b.total);
 }
 
-TEST(ObserverListThreadSafeTest, WithoutSequence) {
+TEST(ObserverListThreadSafeTest, WithoutMessageLoop) {
   scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
       new ObserverListThreadSafe<Foo>);
 
   Adder a(1), b(1), c(1);
 
-  // No sequence, so these should not be added.
+  // No MessageLoop, so these should not be added.
   observer_list->AddObserver(&a);
   observer_list->AddObserver(&b);
 
   {
-    // Add c when there's a sequence.
+    // Add c when there's a loop.
     MessageLoop loop;
     observer_list->AddObserver(&c);
 
@@ -341,10 +351,10 @@
     EXPECT_EQ(0, b.total);
     EXPECT_EQ(10, c.total);
 
-    // Now add a when there's a sequence.
+    // Now add a when there's a loop.
     observer_list->AddObserver(&a);
 
-    // Remove c when there's a sequence.
+    // Remove c when there's a loop.
     observer_list->RemoveObserver(&c);
 
     // Notify again.
@@ -356,7 +366,7 @@
     EXPECT_EQ(10, c.total);
   }
 
-  // Removing should always succeed with or without a sequence.
+  // Removing should always succeed with or without a loop.
   observer_list->RemoveObserver(&a);
 
   // Notifying should not fail but should also be a no-op.
@@ -481,79 +491,6 @@
   observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
 }
 
-namespace {
-
-class SequenceVerificationObserver : public Foo {
- public:
-  explicit SequenceVerificationObserver(
-      scoped_refptr<SequencedTaskRunner> task_runner)
-      : task_runner_(std::move(task_runner)) {}
-  ~SequenceVerificationObserver() override = default;
-
-  void Observe(int x) override {
-    called_on_valid_sequence_ = task_runner_->RunsTasksOnCurrentThread();
-  }
-
-  bool called_on_valid_sequence() const { return called_on_valid_sequence_; }
-
- private:
-  const scoped_refptr<SequencedTaskRunner> task_runner_;
-  bool called_on_valid_sequence_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(SequenceVerificationObserver);
-};
-
-}  // namespace
-
-// Verify that observers are notified on the correct sequence.
-TEST(ObserverListThreadSafeTest, NotificationOnValidSequence) {
-  test::ScopedTaskScheduler scoped_task_scheduler;
-
-  auto task_runner_1 = CreateSequencedTaskRunnerWithTraits(TaskTraits());
-  auto task_runner_2 = CreateSequencedTaskRunnerWithTraits(TaskTraits());
-
-  auto observer_list = make_scoped_refptr(new ObserverListThreadSafe<Foo>());
-
-  SequenceVerificationObserver observer_1(task_runner_1);
-  SequenceVerificationObserver observer_2(task_runner_2);
-
-  task_runner_1->PostTask(
-      FROM_HERE, Bind(&ObserverListThreadSafe<Foo>::AddObserver, observer_list,
-                      Unretained(&observer_1)));
-  task_runner_2->PostTask(
-      FROM_HERE, Bind(&ObserverListThreadSafe<Foo>::AddObserver, observer_list,
-                      Unretained(&observer_2)));
-
-  RunLoop().RunUntilIdle();
-
-  observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
-
-  RunLoop().RunUntilIdle();
-
-  EXPECT_TRUE(observer_1.called_on_valid_sequence());
-  EXPECT_TRUE(observer_2.called_on_valid_sequence());
-}
-
-// Verify that when an observer is added to a NOTIFY_ALL ObserverListThreadSafe
-// from a notification, it is itself notified.
-TEST(ObserverListThreadSafeTest, AddObserverFromNotificationNotifyAll) {
-  MessageLoop message_loop;
-  auto observer_list = make_scoped_refptr(new ObserverListThreadSafe<Foo>());
-
-  Adder observer_added_from_notification(1);
-
-  AddInObserve<ObserverListThreadSafe<Foo>> initial_observer(
-      observer_list.get());
-  initial_observer.SetToAdd(&observer_added_from_notification);
-  observer_list->AddObserver(&initial_observer);
-
-  observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
-
-  RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(1, observer_added_from_notification.GetValue());
-}
-
 TEST(ObserverListTest, Existing) {
   ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY);
   Adder a(1);
diff --git a/cc/raster/bitmap_raster_buffer_provider.cc b/cc/raster/bitmap_raster_buffer_provider.cc
index 5ff8e4f..3d6d0a4 100644
--- a/cc/raster/bitmap_raster_buffer_provider.cc
+++ b/cc/raster/bitmap_raster_buffer_provider.cc
@@ -116,6 +116,20 @@
   return true;
 }
 
+bool BitmapRasterBufferProvider::IsResourceReadyToDraw(
+    ResourceId resource_id) const {
+  // Bitmap resources are immediately ready to draw.
+  return true;
+}
+
+uint64_t BitmapRasterBufferProvider::SetReadyToDrawCallback(
+    const ResourceProvider::ResourceIdArray& resource_ids,
+    const base::Closure& callback,
+    uint64_t pending_callback_id) const {
+  // Bitmap resources are immediately ready to draw.
+  return 0;
+}
+
 void BitmapRasterBufferProvider::Shutdown() {}
 
 }  // namespace cc
diff --git a/cc/raster/bitmap_raster_buffer_provider.h b/cc/raster/bitmap_raster_buffer_provider.h
index ded16f5..d4e44e7 100644
--- a/cc/raster/bitmap_raster_buffer_provider.h
+++ b/cc/raster/bitmap_raster_buffer_provider.h
@@ -37,6 +37,11 @@
   ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
   bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
   bool CanPartialRasterIntoProvidedResource() const override;
+  bool IsResourceReadyToDraw(ResourceId id) const override;
+  uint64_t SetReadyToDrawCallback(
+      const ResourceProvider::ResourceIdArray& resource_ids,
+      const base::Closure& callback,
+      uint64_t pending_callback_id) const override;
   void Shutdown() override;
 
  protected:
diff --git a/cc/raster/gpu_raster_buffer_provider.cc b/cc/raster/gpu_raster_buffer_provider.cc
index 97fb581..d874928 100644
--- a/cc/raster/gpu_raster_buffer_provider.cc
+++ b/cc/raster/gpu_raster_buffer_provider.cc
@@ -17,6 +17,7 @@
 #include "cc/playback/raster_source.h"
 #include "cc/raster/scoped_gpu_raster.h"
 #include "cc/resources/resource.h"
+#include "gpu/command_buffer/client/context_support.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "third_party/skia/include/core/SkMultiPictureDraw.h"
 #include "third_party/skia/include/core/SkPictureRecorder.h"
@@ -186,6 +187,47 @@
   return msaa_sample_count_ == 0;
 }
 
+bool GpuRasterBufferProvider::IsResourceReadyToDraw(
+    ResourceId resource_id) const {
+  if (!async_worker_context_enabled_)
+    return true;
+
+  ResourceProvider::ResourceIdArray resources;
+  resources.push_back(resource_id);
+  gpu::SyncToken sync_token =
+      resource_provider_->GetSyncTokenForResources(resources);
+  if (!sync_token.HasData())
+    return true;
+
+  // IsSyncTokenSignalled is threadsafe, no need for worker context lock.
+  return worker_context_provider_->ContextSupport()->IsSyncTokenSignalled(
+      sync_token);
+}
+
+uint64_t GpuRasterBufferProvider::SetReadyToDrawCallback(
+    const ResourceProvider::ResourceIdArray& resource_ids,
+    const base::Closure& callback,
+    uint64_t pending_callback_id) const {
+  if (!async_worker_context_enabled_)
+    return 0;
+
+  gpu::SyncToken sync_token =
+      resource_provider_->GetSyncTokenForResources(resource_ids);
+  uint64_t callback_id = sync_token.release_count();
+  DCHECK_NE(callback_id, 0u);
+
+  // If the callback is different from the one the caller is already waiting on,
+  // pass the callback through to SignalSinkToken. Otherwise the request is
+  // redundant.
+  if (callback_id != pending_callback_id) {
+    // SignalSyncToken is threadsafe, no need for worker context lock.
+    worker_context_provider_->ContextSupport()->SignalSyncToken(sync_token,
+                                                                callback);
+  }
+
+  return callback_id;
+}
+
 void GpuRasterBufferProvider::Shutdown() {
   pending_raster_buffers_.clear();
 }
diff --git a/cc/raster/gpu_raster_buffer_provider.h b/cc/raster/gpu_raster_buffer_provider.h
index 0df055b2..195eef84 100644
--- a/cc/raster/gpu_raster_buffer_provider.h
+++ b/cc/raster/gpu_raster_buffer_provider.h
@@ -35,6 +35,11 @@
   ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
   bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
   bool CanPartialRasterIntoProvidedResource() const override;
+  bool IsResourceReadyToDraw(ResourceId id) const override;
+  uint64_t SetReadyToDrawCallback(
+      const ResourceProvider::ResourceIdArray& resource_ids,
+      const base::Closure& callback,
+      uint64_t pending_callback_id) const override;
   void Shutdown() override;
 
   void PlaybackOnWorkerThread(
diff --git a/cc/raster/one_copy_raster_buffer_provider.cc b/cc/raster/one_copy_raster_buffer_provider.cc
index 9f11314..0f34334 100644
--- a/cc/raster/one_copy_raster_buffer_provider.cc
+++ b/cc/raster/one_copy_raster_buffer_provider.cc
@@ -21,6 +21,7 @@
 #include "cc/resources/resource_util.h"
 #include "cc/resources/scoped_resource.h"
 #include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/context_support.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
 #include "ui/gfx/buffer_format_util.h"
@@ -162,6 +163,47 @@
   return false;
 }
 
+bool OneCopyRasterBufferProvider::IsResourceReadyToDraw(
+    ResourceId resource_id) const {
+  if (!async_worker_context_enabled_)
+    return true;
+
+  ResourceProvider::ResourceIdArray resources;
+  resources.push_back(resource_id);
+  gpu::SyncToken sync_token =
+      resource_provider_->GetSyncTokenForResources(resources);
+  if (!sync_token.HasData())
+    return true;
+
+  // IsSyncTokenSignalled is threadsafe, no need for worker context lock.
+  return worker_context_provider_->ContextSupport()->IsSyncTokenSignalled(
+      sync_token);
+}
+
+uint64_t OneCopyRasterBufferProvider::SetReadyToDrawCallback(
+    const ResourceProvider::ResourceIdArray& resource_ids,
+    const base::Closure& callback,
+    uint64_t pending_callback_id) const {
+  if (!async_worker_context_enabled_)
+    return 0;
+
+  gpu::SyncToken sync_token =
+      resource_provider_->GetSyncTokenForResources(resource_ids);
+  uint64_t callback_id = sync_token.release_count();
+  DCHECK_NE(callback_id, 0u);
+
+  // If the callback is different from the one the caller is already waiting on,
+  // pass the callback through to SignalSinkToken. Otherwise the request is
+  // redundant.
+  if (callback_id != pending_callback_id) {
+    // SignalSyncToken is threadsafe, no need for worker context lock.
+    worker_context_provider_->ContextSupport()->SignalSyncToken(sync_token,
+                                                                callback);
+  }
+
+  return callback_id;
+}
+
 void OneCopyRasterBufferProvider::Shutdown() {
   staging_pool_.Shutdown();
   pending_raster_buffers_.clear();
diff --git a/cc/raster/one_copy_raster_buffer_provider.h b/cc/raster/one_copy_raster_buffer_provider.h
index e1fa666..22e0dd5 100644
--- a/cc/raster/one_copy_raster_buffer_provider.h
+++ b/cc/raster/one_copy_raster_buffer_provider.h
@@ -41,6 +41,11 @@
   ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
   bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
   bool CanPartialRasterIntoProvidedResource() const override;
+  bool IsResourceReadyToDraw(ResourceId id) const override;
+  uint64_t SetReadyToDrawCallback(
+      const ResourceProvider::ResourceIdArray& resource_ids,
+      const base::Closure& callback,
+      uint64_t pending_callback_id) const override;
   void Shutdown() override;
 
   // Playback raster source and copy result into |resource|.
diff --git a/cc/raster/raster_buffer_provider.h b/cc/raster/raster_buffer_provider.h
index 30dcc29..4804584 100644
--- a/cc/raster/raster_buffer_provider.h
+++ b/cc/raster/raster_buffer_provider.h
@@ -12,6 +12,7 @@
 #include "cc/raster/task_graph_runner.h"
 #include "cc/raster/tile_task.h"
 #include "cc/resources/resource_format.h"
+#include "cc/resources/resource_provider.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -63,6 +64,20 @@
   // the Resource provided in AcquireBufferForRaster.
   virtual bool CanPartialRasterIntoProvidedResource() const = 0;
 
+  // Returns true if the indicated resource is ready to draw.
+  virtual bool IsResourceReadyToDraw(ResourceId id) const = 0;
+
+  // Calls the provided |callback| when the provided |resources| are ready to
+  // draw. Returns a callback ID which can be used to track this callback.
+  // Will return 0 if no callback is needed (resources are already ready to
+  // draw). The caller may optionally pass the ID of a pending callback to
+  // avoid creating a new callback unnecessarily. If the caller does not
+  // have a pending callback, 0 should be passed for |pending_callback_id|.
+  virtual uint64_t SetReadyToDrawCallback(
+      const ResourceProvider::ResourceIdArray& resource_ids,
+      const base::Callback<void()>& callback,
+      uint64_t pending_callback_id) const = 0;
+
   // Shutdown for doing cleanup.
   virtual void Shutdown() = 0;
 
diff --git a/cc/raster/raster_buffer_provider_unittest.cc b/cc/raster/raster_buffer_provider_unittest.cc
index 3b8668d..2f51ef7f 100644
--- a/cc/raster/raster_buffer_provider_unittest.cc
+++ b/cc/raster/raster_buffer_provider_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "cc/base/unique_notifier.h"
@@ -47,7 +48,9 @@
 enum RasterBufferProviderType {
   RASTER_BUFFER_PROVIDER_TYPE_ZERO_COPY,
   RASTER_BUFFER_PROVIDER_TYPE_ONE_COPY,
+  RASTER_BUFFER_PROVIDER_TYPE_ASYNC_ONE_COPY,
   RASTER_BUFFER_PROVIDER_TYPE_GPU,
+  RASTER_BUFFER_PROVIDER_TYPE_ASYNC_GPU,
   RASTER_BUFFER_PROVIDER_TYPE_BITMAP
 };
 
@@ -62,13 +65,11 @@
 class TestRasterTaskImpl : public TileTask {
  public:
   TestRasterTaskImpl(TestRasterTaskCompletionHandler* completion_handler,
-                     std::unique_ptr<ScopedResource> resource,
                      unsigned id,
                      std::unique_ptr<RasterBuffer> raster_buffer,
                      TileTask::Vector* dependencies)
       : TileTask(true, dependencies),
         completion_handler_(completion_handler),
-        resource_(std::move(resource)),
         id_(id),
         raster_buffer_(std::move(raster_buffer)),
         raster_source_(FakeRasterSource::CreateFilled(gfx::Size(1, 1))) {}
@@ -96,7 +97,6 @@
 
  private:
   TestRasterTaskCompletionHandler* completion_handler_;
-  std::unique_ptr<ScopedResource> resource_;
   unsigned id_;
   std::unique_ptr<RasterBuffer> raster_buffer_;
   scoped_refptr<RasterSource> raster_source_;
@@ -108,13 +108,11 @@
  public:
   BlockingTestRasterTaskImpl(
       TestRasterTaskCompletionHandler* completion_handler,
-      std::unique_ptr<ScopedResource> resource,
       unsigned id,
       std::unique_ptr<RasterBuffer> raster_buffer,
       base::Lock* lock,
       TileTask::Vector* dependencies)
       : TestRasterTaskImpl(completion_handler,
-                           std::move(resource),
                            id,
                            std::move(raster_buffer),
                            dependencies),
@@ -172,12 +170,26 @@
             kMaxBytesPerCopyOperation, false, kMaxStagingBuffers,
             PlatformColor::BestTextureFormat(), false);
         break;
+      case RASTER_BUFFER_PROVIDER_TYPE_ASYNC_ONE_COPY:
+        Create3dResourceProvider();
+        raster_buffer_provider_ = base::MakeUnique<OneCopyRasterBufferProvider>(
+            base::ThreadTaskRunnerHandle::Get().get(), context_provider_.get(),
+            worker_context_provider_.get(), resource_provider_.get(),
+            kMaxBytesPerCopyOperation, false, kMaxStagingBuffers,
+            PlatformColor::BestTextureFormat(), true);
+        break;
       case RASTER_BUFFER_PROVIDER_TYPE_GPU:
         Create3dResourceProvider();
         raster_buffer_provider_ = base::MakeUnique<GpuRasterBufferProvider>(
             context_provider_.get(), worker_context_provider_.get(),
             resource_provider_.get(), false, 0, false);
         break;
+      case RASTER_BUFFER_PROVIDER_TYPE_ASYNC_GPU:
+        Create3dResourceProvider();
+        raster_buffer_provider_ = base::MakeUnique<GpuRasterBufferProvider>(
+            context_provider_.get(), worker_context_provider_.get(),
+            resource_provider_.get(), false, 0, true);
+        break;
       case RASTER_BUFFER_PROVIDER_TYPE_BITMAP:
         CreateSoftwareResourceProvider();
         raster_buffer_provider_ =
@@ -191,6 +203,7 @@
   }
 
   void TearDown() override {
+    resources_.clear();
     tile_task_manager_->Shutdown();
     tile_task_manager_->CheckForCompletedTasks();
 
@@ -233,8 +246,9 @@
     std::unique_ptr<RasterBuffer> raster_buffer =
         raster_buffer_provider_->AcquireBufferForRaster(resource.get(), 0, 0);
     TileTask::Vector empty;
-    tasks_.push_back(new TestRasterTaskImpl(this, std::move(resource), id,
-                                            std::move(raster_buffer), &empty));
+    tasks_.push_back(
+        new TestRasterTaskImpl(this, id, std::move(raster_buffer), &empty));
+    resources_.push_back(std::move(resource));
   }
 
   void AppendTask(unsigned id) { AppendTask(id, gfx::Size(1, 1)); }
@@ -251,7 +265,8 @@
         raster_buffer_provider_->AcquireBufferForRaster(resource.get(), 0, 0);
     TileTask::Vector empty;
     tasks_.push_back(new BlockingTestRasterTaskImpl(
-        this, std::move(resource), id, std::move(raster_buffer), lock, &empty));
+        this, id, std::move(raster_buffer), lock, &empty));
+    resources_.push_back(std::move(resource));
   }
 
   const std::vector<RasterTaskResult>& completed_tasks() const {
@@ -313,6 +328,7 @@
   bool timed_out_;
   RasterTaskVector tasks_;
   std::vector<RasterTaskResult> completed_tasks_;
+  std::vector<std::unique_ptr<ScopedResource>> resources_;
   TaskGraph graph_;
 };
 
@@ -382,12 +398,65 @@
   EXPECT_FALSE(completed_tasks()[1].canceled);
 }
 
-INSTANTIATE_TEST_CASE_P(RasterBufferProviderTests,
-                        RasterBufferProviderTest,
-                        ::testing::Values(RASTER_BUFFER_PROVIDER_TYPE_ZERO_COPY,
-                                          RASTER_BUFFER_PROVIDER_TYPE_ONE_COPY,
-                                          RASTER_BUFFER_PROVIDER_TYPE_GPU,
-                                          RASTER_BUFFER_PROVIDER_TYPE_BITMAP));
+TEST_P(RasterBufferProviderTest, ReadyToDrawCallback) {
+  AppendTask(0u);
+  ScheduleTasks();
+  RunMessageLoopUntilAllTasksHaveCompleted();
+
+  ResourceProvider::ResourceIdArray array;
+  for (const auto& resource : resources_) {
+    array.push_back(resource->id());
+  }
+  base::RunLoop run_loop;
+  uint64_t callback_id = raster_buffer_provider_->SetReadyToDrawCallback(
+      array,
+      base::Bind([](base::RunLoop* run_loop) { run_loop->Quit(); }, &run_loop),
+      0);
+
+  if (GetParam() == RASTER_BUFFER_PROVIDER_TYPE_ASYNC_GPU ||
+      GetParam() == RASTER_BUFFER_PROVIDER_TYPE_ASYNC_ONE_COPY)
+    EXPECT_TRUE(callback_id);
+
+  if (!callback_id)
+    return;
+
+  run_loop.Run();
+}
+
+TEST_P(RasterBufferProviderTest, ReadyToDrawCallbackNoDuplicate) {
+  AppendTask(0u);
+  ScheduleTasks();
+  RunMessageLoopUntilAllTasksHaveCompleted();
+
+  ResourceProvider::ResourceIdArray array;
+  for (const auto& resource : resources_) {
+    array.push_back(resource->id());
+  }
+
+  uint64_t callback_id = raster_buffer_provider_->SetReadyToDrawCallback(
+      array, base::Bind([]() {}), 0);
+
+  // Calling SetReadyToDrawCallback a second time for the same resources
+  // should return the same callback ID.
+  uint64_t callback_id_2 = raster_buffer_provider_->SetReadyToDrawCallback(
+      array, base::Bind([]() {}), 0);
+
+  EXPECT_EQ(callback_id, callback_id_2);
+
+  if (GetParam() == RASTER_BUFFER_PROVIDER_TYPE_ASYNC_GPU ||
+      GetParam() == RASTER_BUFFER_PROVIDER_TYPE_ASYNC_ONE_COPY)
+    EXPECT_TRUE(callback_id);
+}
+
+INSTANTIATE_TEST_CASE_P(
+    RasterBufferProviderTests,
+    RasterBufferProviderTest,
+    ::testing::Values(RASTER_BUFFER_PROVIDER_TYPE_ZERO_COPY,
+                      RASTER_BUFFER_PROVIDER_TYPE_ONE_COPY,
+                      RASTER_BUFFER_PROVIDER_TYPE_ASYNC_ONE_COPY,
+                      RASTER_BUFFER_PROVIDER_TYPE_GPU,
+                      RASTER_BUFFER_PROVIDER_TYPE_ASYNC_GPU,
+                      RASTER_BUFFER_PROVIDER_TYPE_BITMAP));
 
 }  // namespace
 }  // namespace cc
diff --git a/cc/raster/zero_copy_raster_buffer_provider.cc b/cc/raster/zero_copy_raster_buffer_provider.cc
index 17ef437..a4d02c65 100644
--- a/cc/raster/zero_copy_raster_buffer_provider.cc
+++ b/cc/raster/zero_copy_raster_buffer_provider.cc
@@ -125,6 +125,20 @@
   return false;
 }
 
+bool ZeroCopyRasterBufferProvider::IsResourceReadyToDraw(
+    ResourceId resource_id) const {
+  // Zero-copy resources are immediately ready to draw.
+  return true;
+}
+
+uint64_t ZeroCopyRasterBufferProvider::SetReadyToDrawCallback(
+    const ResourceProvider::ResourceIdArray& resource_ids,
+    const base::Closure& callback,
+    uint64_t pending_callback_id) const {
+  // Zero-copy resources are immediately ready to draw.
+  return 0;
+}
+
 void ZeroCopyRasterBufferProvider::Shutdown() {}
 
 }  // namespace cc
diff --git a/cc/raster/zero_copy_raster_buffer_provider.h b/cc/raster/zero_copy_raster_buffer_provider.h
index 6abf129..686ba7a 100644
--- a/cc/raster/zero_copy_raster_buffer_provider.h
+++ b/cc/raster/zero_copy_raster_buffer_provider.h
@@ -39,6 +39,11 @@
   ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
   bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
   bool CanPartialRasterIntoProvidedResource() const override;
+  bool IsResourceReadyToDraw(ResourceId id) const override;
+  uint64_t SetReadyToDrawCallback(
+      const ResourceProvider::ResourceIdArray& resource_ids,
+      const base::Closure& callback,
+      uint64_t pending_callback_id) const override;
   void Shutdown() override;
 
  protected:
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 68311f8c..d0733c9f 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -974,6 +974,17 @@
   }
 }
 
+gpu::SyncToken ResourceProvider::GetSyncTokenForResources(
+    const ResourceIdArray& resource_ids) {
+  gpu::SyncToken latest_sync_token;
+  for (ResourceId id : resource_ids) {
+    const gpu::SyncToken& sync_token = GetResource(id)->mailbox().sync_token();
+    if (sync_token.release_count() > latest_sync_token.release_count())
+      latest_sync_token = sync_token;
+  }
+  return latest_sync_token;
+}
+
 ResourceProvider::Resource* ResourceProvider::InsertResource(
     ResourceId id,
     Resource resource) {
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index 7f265b7..f03da6f 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -165,6 +165,9 @@
   void GenerateSyncTokenForResource(ResourceId resource_id);
   void GenerateSyncTokenForResources(const ResourceIdArray& resource_ids);
 
+  // Gets the most recent sync token from the indicated resources.
+  gpu::SyncToken GetSyncTokenForResources(const ResourceIdArray& resource_ids);
+
   // Creates accounting for a child. Returns a child ID.
   int CreateChild(const ReturnCallback& return_callback);
 
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index 3351282..c4777b70d 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -3784,5 +3784,35 @@
   }
 }
 
+TEST_P(ResourceProviderTest, GetSyncTokenForResources) {
+  if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
+    return;
+
+  gfx::Size size(1, 1);
+  ResourceFormat format = RGBA_8888;
+
+  // ~Random set of |release_count|s to set on sync tokens.
+  uint64_t release_counts[5] = {7, 3, 10, 2, 5};
+
+  ResourceProvider::ResourceIdArray array;
+  for (uint32_t i = 0; i < arraysize(release_counts); ++i) {
+    ResourceId id = resource_provider_->CreateResource(
+        size, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format,
+        gfx::ColorSpace());
+    array.push_back(id);
+
+    ResourceProvider::ScopedWriteLockGL lock(resource_provider_.get(), id,
+                                             false);
+    gpu::SyncToken token;
+    token.Set(gpu::CommandBufferNamespace::INVALID, 0, gpu::CommandBufferId(),
+              release_counts[i]);
+    lock.set_sync_token(token);
+  }
+
+  gpu::SyncToken last_token =
+      resource_provider_->GetSyncTokenForResources(array);
+  EXPECT_EQ(last_token.release_count(), 10u);
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/test/fake_raster_buffer_provider.cc b/cc/test/fake_raster_buffer_provider.cc
index 20c91fa..3a5db5f 100644
--- a/cc/test/fake_raster_buffer_provider.cc
+++ b/cc/test/fake_raster_buffer_provider.cc
@@ -38,6 +38,18 @@
   return true;
 }
 
+bool FakeRasterBufferProviderImpl::IsResourceReadyToDraw(
+    ResourceId resource_id) const {
+  return true;
+}
+
+uint64_t FakeRasterBufferProviderImpl::SetReadyToDrawCallback(
+    const ResourceProvider::ResourceIdArray& resource_ids,
+    const base::Callback<void()>& callback,
+    uint64_t pending_callback_id) const {
+  return 0;
+}
+
 void FakeRasterBufferProviderImpl::Shutdown() {}
 
 }  // namespace cc
diff --git a/cc/test/fake_raster_buffer_provider.h b/cc/test/fake_raster_buffer_provider.h
index cb0c634..e28713f 100644
--- a/cc/test/fake_raster_buffer_provider.h
+++ b/cc/test/fake_raster_buffer_provider.h
@@ -25,6 +25,11 @@
   ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
   bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
   bool CanPartialRasterIntoProvidedResource() const override;
+  bool IsResourceReadyToDraw(ResourceId id) const override;
+  uint64_t SetReadyToDrawCallback(
+      const ResourceProvider::ResourceIdArray& resource_ids,
+      const base::Callback<void()>& callback,
+      uint64_t pending_callback_id) const override;
   void Shutdown() override;
 };
 
diff --git a/cc/tiles/picture_layer_tiling.h b/cc/tiles/picture_layer_tiling.h
index 16d7983..0c9b57a 100644
--- a/cc/tiles/picture_layer_tiling.h
+++ b/cc/tiles/picture_layer_tiling.h
@@ -247,6 +247,8 @@
   void AsValueInto(base::trace_event::TracedValue* array) const;
   size_t GPUMemoryUsageInBytes() const;
 
+  void UpdateRequiredStatesOnTile(Tile* tile) const;
+
  protected:
   friend class CoverageIterator;
   friend class PrioritizedTile;
@@ -290,7 +292,6 @@
   Tile::CreateInfo CreateInfoForTile(int i, int j) const;
   bool ShouldCreateTileAt(const Tile::CreateInfo& info) const;
   bool IsTileOccluded(const Tile* tile) const;
-  void UpdateRequiredStatesOnTile(Tile* tile) const;
   PrioritizedTile MakePrioritizedTile(
       Tile* tile,
       PriorityRectType priority_rect_type) const;
diff --git a/cc/tiles/tile_draw_info.cc b/cc/tiles/tile_draw_info.cc
index 29f2cc83..560345ad 100644
--- a/cc/tiles/tile_draw_info.cc
+++ b/cc/tiles/tile_draw_info.cc
@@ -10,11 +10,7 @@
 namespace cc {
 
 TileDrawInfo::TileDrawInfo()
-    : mode_(RESOURCE_MODE),
-      solid_color_(SK_ColorWHITE),
-      resource_(nullptr),
-      contents_swizzled_(false),
-      was_ever_ready_to_draw_(false),
+    : was_ever_ready_to_draw_(false),
       was_ever_used_to_draw_(false),
       was_a_prepaint_tile_(false) {}
 
@@ -32,4 +28,10 @@
                     mode_ == SOLID_COLOR_MODE && !SkColorGetA(solid_color_));
 }
 
+Resource* TileDrawInfo::TakeResource() {
+  Resource* resource = resource_;
+  set_resource(nullptr);
+  return resource;
+}
+
 }  // namespace cc
diff --git a/cc/tiles/tile_draw_info.h b/cc/tiles/tile_draw_info.h
index a51d27b..0a4db758 100644
--- a/cc/tiles/tile_draw_info.h
+++ b/cc/tiles/tile_draw_info.h
@@ -27,7 +27,7 @@
   bool IsReadyToDraw() const {
     switch (mode_) {
       case RESOURCE_MODE:
-        return !!resource_;
+        return is_resource_ready_to_draw_;
       case SOLID_COLOR_MODE:
       case OOM_MODE:
         return true;
@@ -81,7 +81,6 @@
 
   void AsValueInto(base::trace_event::TracedValue* state) const;
 
-  void set_was_ever_ready_to_draw() { was_ever_ready_to_draw_ = true; }
   void set_was_ever_used_to_draw() { was_ever_used_to_draw_ = true; }
   void set_was_a_prepaint_tile() { was_a_prepaint_tile_ = true; }
 
@@ -89,19 +88,34 @@
   friend class Tile;
   friend class TileManager;
 
-  void set_use_resource() { mode_ = RESOURCE_MODE; }
+  const Resource* resource() const { return resource_; }
+
+  void set_resource(Resource* resource) {
+    mode_ = RESOURCE_MODE;
+    is_resource_ready_to_draw_ = false;
+    resource_ = resource;
+  }
+
+  void set_resource_ready_for_draw() {
+    is_resource_ready_to_draw_ = true;
+    was_ever_ready_to_draw_ = true;
+  }
+
+  Resource* TakeResource();
 
   void set_solid_color(const SkColor& color) {
     mode_ = SOLID_COLOR_MODE;
     solid_color_ = color;
+    was_ever_ready_to_draw_ = true;
   }
 
   void set_oom() { mode_ = OOM_MODE; }
 
-  Mode mode_;
-  SkColor solid_color_;
-  Resource* resource_;
-  bool contents_swizzled_;
+  Mode mode_ = RESOURCE_MODE;
+  SkColor solid_color_ = SK_ColorWHITE;
+  Resource* resource_ = nullptr;
+  bool contents_swizzled_ = false;
+  bool is_resource_ready_to_draw_ = false;
 
   // Used for gathering UMA stats.
   bool was_ever_ready_to_draw_ : 1;
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index a20df654..12f3dfd 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -372,7 +372,8 @@
       prepare_tiles_count_(0u),
       next_tile_id_(0u),
       check_tile_priority_inversion_(check_tile_priority_inversion),
-      task_set_finished_weak_ptr_factory_(this) {}
+      task_set_finished_weak_ptr_factory_(this),
+      ready_to_draw_callback_weak_ptr_factory_(this) {}
 
 TileManager::~TileManager() {
   FinishTasksAndCleanUp();
@@ -397,6 +398,7 @@
   more_tiles_need_prepare_check_notifier_.Cancel();
   signals_check_notifier_.Cancel();
   task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
+  ready_to_draw_callback_weak_ptr_factory_.InvalidateWeakPtrs();
   raster_buffer_provider_ = nullptr;
 
   image_controller_.SetImageDecodeCache(nullptr);
@@ -423,6 +425,7 @@
 void TileManager::Release(Tile* tile) {
   FreeResourcesForTile(tile);
   tiles_.erase(tile->id());
+  pending_gpu_work_tiles_.erase(tile);
 }
 
 void TileManager::DidFinishRunningTileTasksRequiredForActivation() {
@@ -518,12 +521,17 @@
 
   tile_task_manager_->CheckForCompletedTasks();
   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
+  CheckPendingGpuWorkTiles(true /* issue_signals */);
 
   TRACE_EVENT_INSTANT1("cc", "DidFlush", TRACE_EVENT_SCOPE_THREAD, "stats",
                        RasterTaskCompletionStatsAsValue(flush_stats_));
   flush_stats_ = RasterTaskCompletionStats();
 }
 
+void TileManager::DidModifyTilePriorities() {
+  pending_tile_requirements_dirty_ = true;
+}
+
 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
 TileManager::BasicStateAsValue() const {
   std::unique_ptr<base::trace_event::TracedValue> value(
@@ -661,7 +669,6 @@
               tile->content_rect(), tile->contents_scale(), &color);
       if (is_solid_color) {
         tile->draw_info().set_solid_color(color);
-        tile->draw_info().set_was_ever_ready_to_draw();
         if (!tile_is_needed_now)
           tile->draw_info().set_was_a_prepaint_tile();
         client_->NotifyTileStateChanged(tile);
@@ -794,10 +801,9 @@
 
 void TileManager::FreeResourcesForTile(Tile* tile) {
   TileDrawInfo& draw_info = tile->draw_info();
-  if (draw_info.resource_) {
-    resource_pool_->ReleaseResource(draw_info.resource_);
-    draw_info.resource_ = nullptr;
-  }
+  Resource* resource = draw_info.TakeResource();
+  if (resource)
+    resource_pool_->ReleaseResource(resource);
 }
 
 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
@@ -855,7 +861,7 @@
     Tile* tile = prioritized_tile.tile();
 
     DCHECK(tile->draw_info().requires_resource());
-    DCHECK(!tile->draw_info().resource_);
+    DCHECK(!tile->draw_info().resource());
 
     if (!tile->raster_task_)
       tile->raster_task_ = CreateRasterTask(
@@ -1063,12 +1069,18 @@
   }
 
   TileDrawInfo& draw_info = tile->draw_info();
-  draw_info.set_use_resource();
-  draw_info.resource_ = resource;
+  draw_info.set_resource(resource);
   draw_info.contents_swizzled_ = DetermineResourceRequiresSwizzle(tile);
 
-  DCHECK(draw_info.IsReadyToDraw());
-  draw_info.set_was_ever_ready_to_draw();
+  // In SMOOTHNESS_TAKES_PRIORITY mode, we wait for GPU work to complete for a
+  // tile before setting it as ready to draw.
+  if (global_state_.tree_priority == SMOOTHNESS_TAKES_PRIORITY &&
+      !raster_buffer_provider_->IsResourceReadyToDraw(resource->id())) {
+    pending_gpu_work_tiles_.insert(tile);
+    return;
+  }
+
+  draw_info.set_resource_ready_for_draw();
   client_->NotifyTileStateChanged(tile);
 }
 
@@ -1125,14 +1137,16 @@
 
 bool TileManager::IsReadyToActivate() const {
   TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
-  return AreRequiredTilesReadyToDraw(
-      RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
+  return pending_required_for_activation_callback_id_ == 0 &&
+         AreRequiredTilesReadyToDraw(
+             RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
 }
 
 bool TileManager::IsReadyToDraw() const {
   TRACE_EVENT0("cc", "TileManager::IsReadyToDraw");
-  return AreRequiredTilesReadyToDraw(
-      RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
+  return pending_required_for_draw_callback_id_ == 0 &&
+         AreRequiredTilesReadyToDraw(
+             RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
 }
 
 void TileManager::CheckAndIssueSignals() {
@@ -1140,6 +1154,8 @@
   tile_task_manager_->CheckForCompletedTasks();
   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
 
+  CheckPendingGpuWorkTiles(false /* issue_signals */);
+
   // Ready to activate.
   if (signals_.ready_to_activate && !signals_.did_notify_ready_to_activate) {
     signals_.ready_to_activate = false;
@@ -1289,6 +1305,71 @@
          raster_buffer_provider_->CanPartialRasterIntoProvidedResource();
 }
 
+void TileManager::CheckPendingGpuWorkTiles(bool issue_signals) {
+  ResourceProvider::ResourceIdArray required_for_activation_ids;
+  ResourceProvider::ResourceIdArray required_for_draw_ids;
+
+  for (auto it = pending_gpu_work_tiles_.begin();
+       it != pending_gpu_work_tiles_.end();) {
+    Tile* tile = *it;
+    const Resource* resource = tile->draw_info().resource();
+
+    if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY ||
+        raster_buffer_provider_->IsResourceReadyToDraw(resource->id())) {
+      tile->draw_info().set_resource_ready_for_draw();
+      client_->NotifyTileStateChanged(tile);
+      it = pending_gpu_work_tiles_.erase(it);
+      continue;
+    }
+
+    // TODO(ericrk): If a tile in our list no longer has valid tile priorities,
+    // it may still report that it is required, and unnecessarily delay
+    // activation. crbug.com/687265
+    if (pending_tile_requirements_dirty_)
+      tile->tiling()->UpdateRequiredStatesOnTile(tile);
+    if (tile->required_for_activation())
+      required_for_activation_ids.push_back(resource->id());
+    if (tile->required_for_draw())
+      required_for_draw_ids.push_back(resource->id());
+
+    ++it;
+  }
+
+  if (required_for_activation_ids.empty()) {
+    pending_required_for_activation_callback_id_ = 0;
+  } else {
+    pending_required_for_activation_callback_id_ =
+        raster_buffer_provider_->SetReadyToDrawCallback(
+            required_for_activation_ids,
+            base::Bind(&TileManager::CheckPendingGpuWorkTiles,
+                       ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr(),
+                       true /* issue_signals */),
+            pending_required_for_activation_callback_id_);
+  }
+
+  pending_required_for_draw_callback_id_ = 0;
+  if (!required_for_draw_ids.empty()) {
+    pending_required_for_draw_callback_id_ =
+        raster_buffer_provider_->SetReadyToDrawCallback(
+            required_for_draw_ids,
+            base::Bind(&TileManager::CheckPendingGpuWorkTiles,
+                       ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr(),
+                       true /* issue_signals */),
+            pending_required_for_draw_callback_id_);
+  }
+
+  // Update our signals now that we know whether we have pending resources.
+  signals_.ready_to_activate =
+      (pending_required_for_activation_callback_id_ == 0);
+  signals_.ready_to_draw = (pending_required_for_draw_callback_id_ == 0);
+
+  if (issue_signals && (signals_.ready_to_activate || signals_.ready_to_draw))
+    signals_check_notifier_.Schedule();
+
+  // We've just updated all pending tile requirements if necessary.
+  pending_tile_requirements_dirty_ = false;
+}
+
 // Utility function that can be used to create a "Task set finished" task that
 // posts |callback| to |task_runner| when run.
 scoped_refptr<TileTask> TileManager::CreateTaskSetFinishedTask(
@@ -1307,8 +1388,8 @@
       resource_count_(static_cast<int>(resource_count)) {
   // MemoryUsage is constructed using size_ts, since it deals with memory and
   // the inputs are typically size_t. However, during the course of usage (in
-  // particular operator-=) can cause internal values to become negative. Thus,
-  // member variables are signed.
+  // particular operator-=) can cause internal values to become negative.
+  // Thus, member variables are signed.
   DCHECK_LE(memory_bytes,
             static_cast<size_t>(std::numeric_limits<int64_t>::max()));
   DCHECK_LE(resource_count,
@@ -1320,7 +1401,8 @@
     const gfx::Size& size,
     ResourceFormat format) {
   // We can use UncheckedSizeInBytes here since this is used with a tile
-  // size which is determined by the compositor (it's at most max texture size).
+  // size which is determined by the compositor (it's at most max texture
+  // size).
   return MemoryUsage(ResourceUtil::UncheckedSizeInBytes<size_t>(size, format),
                      1);
 }
@@ -1328,9 +1410,9 @@
 // static
 TileManager::MemoryUsage TileManager::MemoryUsage::FromTile(const Tile* tile) {
   const TileDrawInfo& draw_info = tile->draw_info();
-  if (draw_info.resource_) {
-    return MemoryUsage::FromConfig(draw_info.resource_->size(),
-                                   draw_info.resource_->format());
+  if (draw_info.resource()) {
+    return MemoryUsage::FromConfig(draw_info.resource()->size(),
+                                   draw_info.resource()->format());
   }
   return MemoryUsage();
 }
diff --git a/cc/tiles/tile_manager.h b/cc/tiles/tile_manager.h
index f1a933e..90041452 100644
--- a/cc/tiles/tile_manager.h
+++ b/cc/tiles/tile_manager.h
@@ -132,6 +132,10 @@
   // date draw information.
   void Flush();
 
+  // Called when the required-for-activation/required-for-draw state of tiles
+  // may have changed.
+  void DidModifyTilePriorities();
+
   std::unique_ptr<Tile> CreateTile(const Tile::CreateInfo& info,
                                    int layer_id,
                                    int source_frame_number,
@@ -151,10 +155,11 @@
   void InitializeTilesWithResourcesForTesting(const std::vector<Tile*>& tiles) {
     for (size_t i = 0; i < tiles.size(); ++i) {
       TileDrawInfo& draw_info = tiles[i]->draw_info();
-      draw_info.resource_ = resource_pool_->AcquireResource(
+      draw_info.set_resource(resource_pool_->AcquireResource(
           tiles[i]->desired_texture_size(),
           raster_buffer_provider_->GetResourceFormat(false),
-          client_->GetTileColorSpace());
+          client_->GetTileColorSpace()));
+      draw_info.set_resource_ready_for_draw();
     }
   }
 
@@ -302,6 +307,8 @@
 
   bool UsePartialRaster() const;
 
+  void CheckPendingGpuWorkTiles(bool issue_signals);
+
   TileManagerClient* client_;
   base::SequencedTaskRunner* task_runner_;
   ResourcePool* resource_pool_;
@@ -337,11 +344,24 @@
   uint64_t prepare_tiles_count_;
   uint64_t next_tile_id_;
 
+  std::unordered_set<Tile*> pending_gpu_work_tiles_;
+  uint64_t pending_required_for_activation_callback_id_ = 0;
+  uint64_t pending_required_for_draw_callback_id_ = 0;
+  // If true, we should re-compute tile requirements in
+  // CheckPendingGpuWorkTiles.
+  bool pending_tile_requirements_dirty_ = false;
+
   std::unordered_map<Tile::Id, std::vector<DrawImage>> scheduled_draw_images_;
   std::vector<scoped_refptr<TileTask>> locked_image_tasks_;
   const bool check_tile_priority_inversion_;
 
+  // We need two WeakPtrFactory objects as the invalidation pattern of each is
+  // different. The |task_set_finished_weak_ptr_factory_| is invalidated any
+  // time new tasks are scheduled, preventing a race when the callback has
+  // been scheduled but not yet executed.
   base::WeakPtrFactory<TileManager> task_set_finished_weak_ptr_factory_;
+  // The |ready_to_draw_callback_weak_ptr_factory_| is never invalidated.
+  base::WeakPtrFactory<TileManager> ready_to_draw_callback_weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(TileManager);
 };
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index 73460f67..b657339 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -5,6 +5,8 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "base/bind.h"
+#include "base/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -39,6 +41,11 @@
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkSurface.h"
 
+using testing::_;
+using testing::Invoke;
+using testing::Return;
+using testing::StrictMock;
+
 namespace cc {
 namespace {
 
@@ -1489,7 +1496,7 @@
       const LayerTreeSettings& settings,
       TaskRunnerProvider* task_runner_provider,
       TaskGraphRunner* task_graph_runner) override {
-    return base::MakeUnique<MockLayerTreeHostImpl>(
+    return base::MakeUnique<testing::NiceMock<MockLayerTreeHostImpl>>(
         settings, task_runner_provider, task_graph_runner);
   }
 
@@ -1925,5 +1932,336 @@
   RunPartialRasterCheck(TakeHostImpl(), false /* partial_raster_enabled */);
 }
 
+// FakeRasterBufferProviderImpl that allows us to mock ready to draw
+// functionality.
+class MockReadyToDrawRasterBufferProviderImpl
+    : public FakeRasterBufferProviderImpl {
+ public:
+  MOCK_CONST_METHOD1(IsResourceReadyToDraw, bool(ResourceId resource_id));
+  MOCK_CONST_METHOD3(
+      SetReadyToDrawCallback,
+      uint64_t(const ResourceProvider::ResourceIdArray& resource_ids,
+               const base::Closure& callback,
+               uint64_t pending_callback_id));
+
+  std::unique_ptr<RasterBuffer> AcquireBufferForRaster(
+      const Resource* resource,
+      uint64_t resource_content_id,
+      uint64_t previous_content_id) override {
+    return base::MakeUnique<FakeRasterBuffer>();
+  }
+
+ private:
+  class FakeRasterBuffer : public RasterBuffer {
+   public:
+    void Playback(
+        const RasterSource* raster_source,
+        const gfx::Rect& raster_full_rect,
+        const gfx::Rect& raster_dirty_rect,
+        uint64_t new_content_id,
+        float scale,
+        const RasterSource::PlaybackSettings& playback_settings) override {}
+  };
+};
+
+class TileManagerReadyToDrawTest : public TileManagerTest {
+ public:
+  ~TileManagerReadyToDrawTest() override {
+    // Ensure that the host impl doesn't outlive |raster_buffer_provider_|.
+    TakeHostImpl();
+  }
+
+  void SetUp() override {
+    TileManagerTest::SetUp();
+    host_impl()->tile_manager()->SetRasterBufferProviderForTesting(
+        &mock_raster_buffer_provider_);
+
+    const gfx::Size layer_bounds(1000, 1000);
+
+    solid_color_recording_source_ =
+        FakeRecordingSource::CreateFilledRecordingSource(layer_bounds);
+
+    SkPaint solid_paint;
+    SkColor solid_color = SkColorSetARGB(255, 12, 23, 34);
+    solid_paint.setColor(solid_color);
+    solid_color_recording_source_->add_draw_rect_with_paint(
+        gfx::Rect(layer_bounds), solid_paint);
+
+    solid_color_recording_source_->Rerecord();
+
+    recording_source_ =
+        FakeRecordingSource::CreateFilledRecordingSource(layer_bounds);
+    SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67);
+    SkPaint non_solid_paint;
+    non_solid_paint.setColor(non_solid_color);
+
+    for (int i = 0; i < 100; ++i) {
+      for (int j = 0; j < 100; ++j) {
+        recording_source_->add_draw_rect_with_paint(
+            gfx::Rect(10 * i, 10 * j, 5, 5), non_solid_paint);
+      }
+    }
+    recording_source_->Rerecord();
+  }
+
+  LayerTreeSettings CreateSettings() override {
+    LayerTreeSettingsForTesting settings;
+    settings.renderer_settings.buffer_to_texture_target_map =
+        DefaultBufferToTextureTargetMapForTesting();
+    return settings;
+  }
+
+  void SetupTreesWithActiveTreeTiles() {
+    scoped_refptr<RasterSource> active_tree_raster_source =
+        RasterSource::CreateFromRecordingSource(recording_source_.get(), false);
+    scoped_refptr<RasterSource> pending_tree_raster_source =
+        RasterSource::CreateFromRecordingSource(
+            solid_color_recording_source_.get(), false);
+
+    SetupTrees(pending_tree_raster_source, active_tree_raster_source);
+  }
+
+  void SetupTreesWithPendingTreeTiles() {
+    scoped_refptr<RasterSource> active_tree_raster_source =
+        RasterSource::CreateFromRecordingSource(
+            solid_color_recording_source_.get(), false);
+    scoped_refptr<RasterSource> pending_tree_raster_source =
+        RasterSource::CreateFromRecordingSource(recording_source_.get(), false);
+
+    SetupTrees(pending_tree_raster_source, active_tree_raster_source);
+  }
+
+  TileManager* tile_manager() { return host_impl()->tile_manager(); }
+  MockReadyToDrawRasterBufferProviderImpl* mock_raster_buffer_provider() {
+    return &mock_raster_buffer_provider_;
+  }
+
+ private:
+  StrictMock<MockReadyToDrawRasterBufferProviderImpl>
+      mock_raster_buffer_provider_;
+  std::unique_ptr<FakeRecordingSource> recording_source_;
+  std::unique_ptr<FakeRecordingSource> solid_color_recording_source_;
+};
+
+TEST_F(TileManagerReadyToDrawTest, SmoothActivationWaitsOnCallback) {
+  host_impl()->SetTreePriority(SMOOTHNESS_TAKES_PRIORITY);
+  SetupTreesWithPendingTreeTiles();
+
+  base::Closure callback;
+  {
+    base::RunLoop run_loop;
+
+    // Until we activate our ready to draw callback, treat all resources as not
+    // ready to draw.
+    EXPECT_CALL(*mock_raster_buffer_provider(),
+                IsResourceReadyToDraw(testing::_))
+        .WillRepeatedly(Return(false));
+
+    EXPECT_CALL(*mock_raster_buffer_provider(), SetReadyToDrawCallback(_, _, 0))
+        .WillOnce(testing::Invoke([&run_loop, &callback](
+            const ResourceProvider::ResourceIdArray& resource_ids,
+            const base::Closure& callback_in, uint64_t pending_callback_id) {
+          callback = callback_in;
+          run_loop.Quit();
+          return 1;
+        }));
+    host_impl()->tile_manager()->DidModifyTilePriorities();
+    host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+    run_loop.Run();
+  }
+
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToDraw());
+  EXPECT_FALSE(host_impl()->tile_manager()->IsReadyToActivate());
+
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(MockHostImpl(), NotifyReadyToActivate())
+        .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
+    EXPECT_CALL(*mock_raster_buffer_provider(),
+                IsResourceReadyToDraw(testing::_))
+        .WillRepeatedly(Return(true));
+    callback.Run();
+    run_loop.Run();
+  }
+
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToDraw());
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToActivate());
+}
+
+TEST_F(TileManagerReadyToDrawTest, NonSmoothActivationDoesNotWaitOnCallback) {
+  SetupTreesWithPendingTreeTiles();
+
+  // We're using a StrictMock on the RasterBufferProvider, so any function call
+  // will cause a test failure.
+  base::RunLoop run_loop;
+
+  host_impl()->tile_manager()->DidModifyTilePriorities();
+  host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+  EXPECT_CALL(MockHostImpl(), NotifyReadyToActivate())
+      .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
+  run_loop.Run();
+
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToDraw());
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToActivate());
+}
+
+TEST_F(TileManagerReadyToDrawTest, SmoothDrawWaitsOnCallback) {
+  host_impl()->SetTreePriority(SMOOTHNESS_TAKES_PRIORITY);
+  SetupTreesWithActiveTreeTiles();
+
+  base::Closure callback;
+  {
+    base::RunLoop run_loop;
+
+    // Until we activate our ready to draw callback, treat all resources as not
+    // ready to draw.
+    EXPECT_CALL(*mock_raster_buffer_provider(),
+                IsResourceReadyToDraw(testing::_))
+        .WillRepeatedly(Return(false));
+
+    EXPECT_CALL(*mock_raster_buffer_provider(), SetReadyToDrawCallback(_, _, 0))
+        .WillOnce(Invoke([&run_loop, &callback](
+            const ResourceProvider::ResourceIdArray& resource_ids,
+            const base::Closure& callback_in, uint64_t pending_callback_id) {
+          callback = callback_in;
+          run_loop.Quit();
+          return 1;
+        }));
+    host_impl()->tile_manager()->DidModifyTilePriorities();
+    host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+    run_loop.Run();
+  }
+
+  EXPECT_FALSE(host_impl()->tile_manager()->IsReadyToDraw());
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToActivate());
+
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(MockHostImpl(), NotifyReadyToDraw())
+        .WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); }));
+    EXPECT_CALL(*mock_raster_buffer_provider(),
+                IsResourceReadyToDraw(testing::_))
+        .WillRepeatedly(Return(true));
+    callback.Run();
+    run_loop.Run();
+  }
+
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToDraw());
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToActivate());
+}
+
+TEST_F(TileManagerReadyToDrawTest, NonSmoothDrawDoesNotWaitOnCallback) {
+  SetupTreesWithActiveTreeTiles();
+
+  // We're using a StrictMock on the RasterBufferProvider, so any function call
+  // will cause a test failure.
+  base::RunLoop run_loop;
+
+  host_impl()->tile_manager()->DidModifyTilePriorities();
+  host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+  EXPECT_CALL(MockHostImpl(), NotifyReadyToDraw())
+      .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
+  run_loop.Run();
+
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToDraw());
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToActivate());
+}
+
+TEST_F(TileManagerReadyToDrawTest, NoCallbackWhenAlreadyReadyToDraw) {
+  host_impl()->SetTreePriority(SMOOTHNESS_TAKES_PRIORITY);
+  SetupTreesWithPendingTreeTiles();
+
+  base::RunLoop run_loop;
+  host_impl()->tile_manager()->DidModifyTilePriorities();
+  host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+  EXPECT_CALL(MockHostImpl(), NotifyReadyToActivate())
+      .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
+  EXPECT_CALL(*mock_raster_buffer_provider(), IsResourceReadyToDraw(_))
+      .WillRepeatedly(Return(true));
+  run_loop.Run();
+
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToDraw());
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToActivate());
+}
+
+void UpdateVisibleRect(FakePictureLayerImpl* layer,
+                       const gfx::Rect visible_rect) {
+  PictureLayerTilingSet* tiling_set = layer->tilings();
+  for (size_t j = 0; j < tiling_set->num_tilings(); ++j) {
+    PictureLayerTiling* tiling = tiling_set->tiling_at(j);
+    tiling->SetTilePriorityRectsForTesting(
+        visible_rect,                  // Visible rect.
+        visible_rect,                  // Skewport rect.
+        visible_rect,                  // Soon rect.
+        gfx::Rect(0, 0, 1000, 1000));  // Eventually rect.
+  }
+}
+
+TEST_F(TileManagerReadyToDrawTest, ReadyToDrawRespectsRequirementChange) {
+  host_impl()->SetTreePriority(SMOOTHNESS_TAKES_PRIORITY);
+  SetupTreesWithPendingTreeTiles();
+
+  // Initially create a tiling with a visible rect of (0, 0, 100, 100) and
+  // a soon rect of the rest of the layer.
+  UpdateVisibleRect(pending_layer(), gfx::Rect(0, 0, 100, 100));
+
+  // Mark all these tiles as ready to draw.
+  base::RunLoop run_loop;
+  host_impl()->tile_manager()->DidModifyTilePriorities();
+  host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+  EXPECT_CALL(MockHostImpl(), NotifyReadyToActivate())
+      .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
+  EXPECT_CALL(*mock_raster_buffer_provider(), IsResourceReadyToDraw(_))
+      .WillRepeatedly(Return(true));
+  run_loop.Run();
+
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToDraw());
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToActivate());
+
+  // Move the viewport to (900, 900, 100, 100), so that we need a different set
+  // of tilings.
+  UpdateVisibleRect(pending_layer(), gfx::Rect(900, 900, 100, 100));
+
+  EXPECT_CALL(*mock_raster_buffer_provider(), IsResourceReadyToDraw(testing::_))
+      .WillRepeatedly(Return(false));
+
+  base::Closure callback;
+  {
+    base::RunLoop run_loop;
+
+    EXPECT_CALL(*mock_raster_buffer_provider(), SetReadyToDrawCallback(_, _, 0))
+        .WillOnce(testing::Invoke([&run_loop, &callback](
+            const ResourceProvider::ResourceIdArray& resource_ids,
+            const base::Closure& callback_in, uint64_t pending_callback_id) {
+          callback = callback_in;
+          run_loop.Quit();
+          return 1;
+        }));
+    host_impl()->tile_manager()->DidModifyTilePriorities();
+    host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+    run_loop.Run();
+  }
+
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToDraw());
+  EXPECT_FALSE(host_impl()->tile_manager()->IsReadyToActivate());
+
+  // Now switch back to our original tiling. We should be immediately able to
+  // activate, as we still have the original tile, and no longer need the
+  // tiles from the previous callback.
+  UpdateVisibleRect(pending_layer(), gfx::Rect(0, 0, 100, 100));
+
+  {
+    base::RunLoop run_loop;
+    host_impl()->tile_manager()->DidModifyTilePriorities();
+    host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+    EXPECT_CALL(MockHostImpl(), NotifyReadyToActivate())
+        .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
+    run_loop.Run();
+  }
+
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToDraw());
+  EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToActivate());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 23444716..3e11243 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -634,13 +634,6 @@
             android:exported="false" >
         </activity>
 
-        <!-- Opt-in activity for Physical Web -->
-        <activity android:name="org.chromium.chrome.browser.physicalweb.PhysicalWebOptInActivity"
-            android:label="@string/physical_web_list_urls_activity_title"
-            android:theme="@style/PhysicalWebOptInStyle"
-            android:exported="false">
-        </activity>
-
         <!-- Service for handling Nearby Messages -->
         <service android:name="org.chromium.chrome.browser.physicalweb.NearbyMessageIntentService"
             android:exported="false" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeCallback.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeCallback.java
index a5255a61..291faa36 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeCallback.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeCallback.java
@@ -87,7 +87,7 @@
         RecordUserAction.record("MobileActionMode.WebSearch");
         if (mTab.getTabModelSelector() == null) return;
 
-        String query = mHelper.sanitizeQuery(mHelper.getSelectedText(),
+        String query = ActionModeCallbackHelper.sanitizeQuery(mHelper.getSelectedText(),
                 ActionModeCallbackHelper.MAX_SEARCH_QUERY_LENGTH);
         if (TextUtils.isEmpty(query)) return;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 1e88167..8df645a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -1825,7 +1825,7 @@
             mUmaSessionStats = new UmaSessionStats(this);
         }
 
-        mUmaSessionStats.updateMetricsServiceState();
+        UmaSessionStats.updateMetricsServiceState();
         mUmaSessionStats.startNewSession(getTabModelSelector());
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 4325a36..5428229e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -48,6 +48,23 @@
         return sTestEnabledFeatures.contains(featureName);
     }
 
+    /**
+     * Returns a field trial param as an int for the specified feature.
+     *
+     * Note: Features queried through this API must be added to the array
+     * |kFeaturesExposedToJava| in chrome/browser/android/chrome_feature_list.cc
+     *
+     * @param featureName The name of the feature to retrieve a param for.
+     * @param paramName The name of the param for which to get as an integer.
+     * @param defaultValue The integer value to use if the param is not available.
+     * @return The parameter value as an int. Default value if the feature does not exist or the
+     *         specified parameter does not exist.
+     */
+    public static long getFieldTrialParamByFeatureAsInt(
+            String featureName, String paramName, int defaultValue) {
+        return nativeGetFieldTrialParamByFeatureAsInt(featureName, paramName, defaultValue);
+    }
+
     // Alphabetical:
     public static final String ANDROID_PAY_INTEGRATION_V1 = "AndroidPayIntegrationV1";
     public static final String ANDROID_PAY_INTEGRATION_V2 = "AndroidPayIntegrationV2";
@@ -77,6 +94,9 @@
     public static final String WEB_PAYMENTS = "WebPayments";
     public static final String WEB_PAYMENTS_MODIFIERS = "WebPaymentsModifiers";
     public static final String WEB_PAYMENTS_SINGLE_APP_UI_SKIP = "WebPaymentsSingleAppUiSkip";
+    public static final String WEBVR_CARDBOARD_SUPPORT = "WebVRCardboardSupport";
 
     private static native boolean nativeIsEnabled(String featureName);
+    private static native int nativeGetFieldTrialParamByFeatureAsInt(
+            String featureName, String paramName, int defaultValue);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
index 628b54f3..30dfc81 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
@@ -402,7 +402,7 @@
             Log.w(TAG, "Could not find a crash dump with local ID " + localId);
             return;
         }
-        File renamedMinidumpFile = fileManager.trySetForcedUpload(minidumpFile);
+        File renamedMinidumpFile = CrashFileManager.trySetForcedUpload(minidumpFile);
         if (renamedMinidumpFile == null) {
             Log.w(TAG, "Could not rename the file " + minidumpFile.getName() + " for re-upload");
             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
index 2ff6b14..6c986de 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
@@ -212,7 +212,7 @@
                         ChromeSwitches.ENABLE_LIGHTWEIGHT_FIRST_RUN_EXPERIENCE)) {
                 // Launch the First Run Experience for VIEW Intents with URLs before launching
                 // ChromeTabbedActivity if necessary.
-                if (getIntent() != null && getIntent().getAction() == Intent.ACTION_VIEW
+                if (getIntent() != null && Intent.ACTION_VIEW.equals(getIntent().getAction())
                         && IntentHandler.getUrlFromIntent(getIntent()) != null) {
                     if (launchFirstRunExperience(true)) {
                         finish();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
index fc9ed5b..c33e7ac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -184,7 +184,7 @@
             DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).cancelTask();
             // Limit the number of auto resumption attempts in case Chrome falls into a vicious
             // cycle.
-            if (intent.getAction() == ACTION_DOWNLOAD_RESUME_ALL) {
+            if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())) {
                 if (mNumAutoResumptionAttemptLeft > 0) {
                     mNumAutoResumptionAttemptLeft--;
                     updateResumptionAttemptLeft();
@@ -613,7 +613,7 @@
      * @param intent Intent that contains the download action.
      */
     private DownloadSharedPreferenceEntry getDownloadEntryFromIntent(Intent intent) {
-        if (intent.getAction() == ACTION_DOWNLOAD_RESUME_ALL) return null;
+        if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())) return null;
         String guid = IntentUtils.safeGetStringExtra(intent, EXTRA_DOWNLOAD_GUID);
         return mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceEntry(guid);
     }
@@ -634,14 +634,14 @@
             return;
         }
 
-        if (intent.getAction() == ACTION_DOWNLOAD_PAUSE) {
+        if (ACTION_DOWNLOAD_PAUSE.equals(intent.getAction())) {
             // If browser process already goes away, the download should have already paused. Do
             // nothing in that case.
             if (!DownloadManagerService.hasDownloadManagerService()) {
                 notifyDownloadPaused(entry.downloadGuid, !entry.isOffTheRecord, false);
                 return;
             }
-        } else if (intent.getAction() == ACTION_DOWNLOAD_RESUME) {
+        } else if (ACTION_DOWNLOAD_RESUME.equals(intent.getAction())) {
             boolean metered = DownloadManagerService.isActiveNetworkMetered(mContext);
             if (!entry.canDownloadWhileMetered) {
                 // If user manually resumes a download, update the network type if it
@@ -651,11 +651,11 @@
             entry.isAutoResumable = true;
             // Update the SharedPreference entry.
             mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry(entry);
-        } else if (intent.getAction() == ACTION_DOWNLOAD_RESUME_ALL
+        } else if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())
                 && (mDownloadSharedPreferenceHelper.getEntries().isEmpty()
                         || DownloadManagerService.hasDownloadManagerService())) {
             return;
-        } else if (intent.getAction() == ACTION_DOWNLOAD_OPEN) {
+        } else if (ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) {
             // TODO(fgorski): Do we even need to do anything special here, before we launch Chrome?
         }
 
@@ -668,14 +668,13 @@
             @Override
             public void finishNativeInitialization() {
                 int itemType = entry != null ? entry.itemType
-                        : (intent.getAction() == ACTION_DOWNLOAD_OPEN
+                        : (ACTION_DOWNLOAD_OPEN.equals(intent.getAction())
                                 ? DownloadSharedPreferenceEntry.ITEM_TYPE_OFFLINE_PAGE
                                 : DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD);
                 DownloadServiceDelegate downloadServiceDelegate =
-                        intent.getAction() == ACTION_DOWNLOAD_OPEN ? null
+                        ACTION_DOWNLOAD_OPEN.equals(intent.getAction()) ? null
                                 : getServiceDelegate(itemType);
-                switch (intent.getAction()) {
-                    case ACTION_DOWNLOAD_CANCEL:
+                if (ACTION_DOWNLOAD_CANCEL.equals(intent.getAction())) {
                         // TODO(qinmin): Alternatively, we can delete the downloaded content on
                         // SD card, and remove the download ID from the SharedPreferences so we
                         // don't need to restart the browser process. http://crbug.com/579643.
@@ -683,30 +682,24 @@
                         downloadServiceDelegate.cancelDownload(entry.downloadGuid,
                                 entry.isOffTheRecord, IntentUtils.safeGetBooleanExtra(
                                         intent, EXTRA_NOTIFICATION_DISMISSED, false));
-                        break;
-                    case ACTION_DOWNLOAD_PAUSE:
+                } else if (ACTION_DOWNLOAD_PAUSE.equals(intent.getAction())) {
                         downloadServiceDelegate.pauseDownload(entry.downloadGuid,
                                 entry.isOffTheRecord);
-                        break;
-                    case ACTION_DOWNLOAD_RESUME:
+                } else if (ACTION_DOWNLOAD_RESUME.equals(intent.getAction())) {
                         notifyDownloadPending(entry.downloadGuid, entry.fileName,
                                 entry.isOffTheRecord, entry.canDownloadWhileMetered,
                                 entry.isOfflinePage());
                         downloadServiceDelegate.resumeDownload(entry.buildDownloadItem(), true);
-                        break;
-                    case ACTION_DOWNLOAD_RESUME_ALL:
+                } else if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())) {
                         assert entry == null;
                         resumeAllPendingDownloads();
-                        break;
-                    case ACTION_DOWNLOAD_OPEN:
+                } else if (ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) {
                         OfflinePageDownloadBridge.openDownloadedPage(
                                 IntentUtils.safeGetStringExtra(intent, EXTRA_DOWNLOAD_GUID));
-                        break;
-                    default:
+                } else {
                         Log.e(TAG, "Unrecognized intent action.", intent);
-                        break;
                 }
-                if (intent.getAction() != ACTION_DOWNLOAD_OPEN) {
+                if (!ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) {
                     downloadServiceDelegate.destroyServiceDelegate();
                 }
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
index 0273b15..fa9c7a6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
@@ -580,7 +580,7 @@
         Intent intent = tab.getTabRedirectHandler() != null
                 ? tab.getTabRedirectHandler().getInitialIntent() : null;
         // TODO(mariakhomenko): consider also handling NDEF_DISCOVER action redirects.
-        if (isIncomingRedirect && intent != null && intent.getAction() == Intent.ACTION_VIEW) {
+        if (isIncomingRedirect && intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
             // Set the URL the redirect was resolved to for checking the existence of the
             // instant app inside handleIncomingIntent().
             Intent resolvedIntent = new Intent(intent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/mojo/ChromeInterfaceRegistrar.java b/chrome/android/java/src/org/chromium/chrome/browser/mojo/ChromeInterfaceRegistrar.java
index bb0353c8..f30ab895 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/mojo/ChromeInterfaceRegistrar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/mojo/ChromeInterfaceRegistrar.java
@@ -19,6 +19,8 @@
 import org.chromium.shape_detection.mojom.TextDetection;
 import org.chromium.webshare.mojom.ShareService;
 
+@SuppressWarnings("MultipleTopLevelClassesInFile")
+
 /** Registers mojo interface implementations exposed to C++ code at the Chrome layer. */
 class ChromeInterfaceRegistrar {
     @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/pageinfo/CertificateViewer.java b/chrome/android/java/src/org/chromium/chrome/browser/pageinfo/CertificateViewer.java
index e0f722e..c5770f3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/pageinfo/CertificateViewer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/pageinfo/CertificateViewer.java
@@ -8,7 +8,6 @@
 import android.content.Context;
 import android.graphics.Typeface;
 import android.net.http.SslCertificate;
-import android.text.format.DateFormat;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -30,6 +29,7 @@
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
+import java.text.DateFormat;
 import java.util.ArrayList;
 
 /**
@@ -170,7 +170,7 @@
                 sslCert.getIssuedBy().getUName());
 
         addSectionTitle(certificateView, nativeGetCertValidityText());
-        java.text.DateFormat dateFormat = DateFormat.getDateFormat(mContext);
+        DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM);
         addItem(certificateView, nativeGetCertIssuedOnText(),
                 dateFormat.format(sslCert.getValidNotBeforeDate()));
         addItem(certificateView, nativeGetCertExpiresOnText(),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebOptInActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebOptInActivity.java
deleted file mode 100644
index e8fe2e3..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebOptInActivity.java
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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.
-
-package org.chromium.chrome.browser.physicalweb;
-
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.text.SpannableString;
-import android.text.TextPaint;
-import android.text.method.LinkMovementMethod;
-import android.text.style.ClickableSpan;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager;
-import org.chromium.ui.text.SpanApplier;
-import org.chromium.ui.text.SpanApplier.SpanInfo;
-
-/**
- * This activity invites the user to opt-in to the Physical Web feature.
- */
-public class PhysicalWebOptInActivity extends AppCompatActivity {
-    private static final String EXTRA_CUSTOM_TABS_SESSION =
-            "android.support.customtabs.extra.SESSION";
-    private static final String PHYSICAL_WEB_LEARN_MORE_URL =
-            "https://support.google.com/chrome/answer/6239299/";
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.physical_web_optin);
-
-        TextView description = (TextView) findViewById(R.id.physical_web_optin_description);
-        description.setMovementMethod(LinkMovementMethod.getInstance());
-        description.setText(getDescriptionText());
-
-        Button declineButton = (Button) findViewById(R.id.physical_web_decline);
-        declineButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                PhysicalWebUma.onOptInDeclineButtonPressed();
-                PrivacyPreferencesManager.getInstance().setPhysicalWebEnabled(false);
-                finish();
-            }
-        });
-
-        Button enableButton = (Button) findViewById(R.id.physical_web_enable);
-        enableButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                PhysicalWebUma.onOptInEnableButtonPressed();
-                PrivacyPreferencesManager.getInstance().setPhysicalWebEnabled(true);
-                startActivity(createListUrlsIntent(PhysicalWebOptInActivity.this));
-                finish();
-            }
-        });
-    }
-
-    private static Intent createListUrlsIntent(Context context) {
-        Intent intent = new Intent(context, ListUrlsActivity.class);
-        intent.putExtra(ListUrlsActivity.REFERER_KEY,
-                ListUrlsActivity.OPTIN_REFERER);
-        return intent;
-    }
-
-    private SpannableString getDescriptionText() {
-        return SpanApplier.applySpans(
-                getString(R.string.physical_web_optin_description),
-                new SpanInfo("<learnmore>", "</learnmore>", new ClickableSpan() {
-                    @Override
-                    public void onClick(View v) {
-                        Intent intent = new Intent(Intent.ACTION_VIEW,
-                                Uri.parse(PHYSICAL_WEB_LEARN_MORE_URL));
-                        // Add the SESSION extra to indicate we want a Chrome custom tab. This
-                        // allows the help page to open in the same task as the opt-in activity so
-                        // they can share a back stack.
-                        String session = null;
-                        intent.putExtra(EXTRA_CUSTOM_TABS_SESSION, session);
-                        PhysicalWebOptInActivity.this.startActivity(intent);
-                    }
-
-                    @Override
-                    public void updateDrawState(TextPaint ds) {
-                        // Color links but do not underline them.
-                        ds.setColor(ds.linkColor);
-                    }
-                }));
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 2f80c7f..b46bfe2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -60,6 +60,7 @@
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.util.MathUtils;
 import org.chromium.chrome.browser.widget.TintedImageButton;
+import org.chromium.chrome.browser.widget.animation.CancelAwareAnimatorListener;
 import org.chromium.chrome.browser.widget.newtab.NewTabButton;
 import org.chromium.ui.base.LocalizationUtils;
 import org.chromium.ui.interpolators.BakedBezierInterpolator;
@@ -1750,11 +1751,9 @@
         mUrlFocusLayoutAnimator.playTogether(animators);
 
         mUrlFocusChangeInProgress = true;
-        mUrlFocusLayoutAnimator.addListener(new AnimatorListenerAdapter() {
-            private boolean mCanceled;
-
+        mUrlFocusLayoutAnimator.addListener(new CancelAwareAnimatorListener() {
             @Override
-            public void onAnimationStart(Animator animation) {
+            public void onStart(Animator animation) {
                 if (!hasFocus) {
                     mDisableLocationBarRelayout = true;
                 } else {
@@ -1764,14 +1763,12 @@
             }
 
             @Override
-            public void onAnimationCancel(Animator animation) {
-                mCanceled = true;
+            public void onCancel(Animator animation) {
+                if (!hasFocus) mDisableLocationBarRelayout = false;
             }
 
             @Override
-            public void onAnimationEnd(Animator animation) {
-                if (mCanceled) return;
-
+            public void onEnd(Animator animation) {
                 if (!hasFocus) {
                     mDisableLocationBarRelayout = false;
                     mLayoutLocationBarInFocusedMode = false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index 8f0b7f14..acead93 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -10,6 +10,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.os.Build;
 import android.os.Handler;
 import android.os.StrictMode;
 import android.os.SystemClock;
@@ -73,6 +74,8 @@
     private static final String DAYDREAM_CATEGORY = "com.google.intent.category.DAYDREAM";
     private static final String CARDBOARD_CATEGORY = "com.google.intent.category.CARDBOARD";
 
+    private static final String MIN_SDK_VERSION_PARAM_NAME = "min_sdk_version";
+
     private static final String VR_ACTIVITY_ALIAS =
             "org.chromium.chrome.browser.VRChromeTabbedActivity";
 
@@ -126,6 +129,26 @@
             mVrDaydreamApi = mVrClassesWrapper.createVrDaydreamApi();
         }
 
+        // Check cardboard support for non-daydream devices.
+        if (!mVrDaydreamApi.isDaydreamReadyDevice()) {
+            // Native libraries may not be ready in which case skip for now and check later.
+            if (LibraryLoader.isInitialized()) {
+                // Supported Build version is determined by the webvr cardboard support feature.
+                // Default is KITKAT unless specified via server side finch config.
+                if (Build.VERSION.SDK_INT
+                        < ChromeFeatureList.getFieldTrialParamByFeatureAsInt(
+                                ChromeFeatureList.WEBVR_CARDBOARD_SUPPORT,
+                                MIN_SDK_VERSION_PARAM_NAME,
+                                Build.VERSION_CODES.KITKAT)) {
+                    mVrSupportLevel = VR_NOT_AVAILABLE;
+                    mEnterVRIntent = null;
+                    mTabObserver = null;
+                    mTabModelSelectorObserver = null;
+                    return;
+                }
+            }
+        }
+
         if (mEnterVRIntent == null) {
             mEnterVRIntent =
                     mVrDaydreamApi.createVrIntent(new ComponentName(mActivity, VR_ACTIVITY_ALIAS));
@@ -172,6 +195,8 @@
      * can be initialized.
      */
     public void onNativeLibraryReady() {
+        // Libraries may not have been loaded when we first set the support level, so check again.
+        updateVrSupportLevel();
         if (mVrSupportLevel == VR_NOT_AVAILABLE) return;
         mNativeVrShellDelegate = nativeInit();
         Choreographer choreographer = Choreographer.getInstance();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
index 4c73c02f..6757f218 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -54,8 +54,8 @@
     private static final float WEBVR_DPR = 1.0f;
     // Fairly arbitrary values that put a good amount of content on the screen without making the
     // text too small to read.
-    private static final float DEFAULT_CONTENT_WIDTH = 1024f;
-    private static final float DEFAULT_CONTENT_HEIGHT = 576f;
+    private static final float DEFAULT_CONTENT_WIDTH = 960f;
+    private static final float DEFAULT_CONTENT_HEIGHT = 640f;
     // Temporary values that will be changed when the UI loads and figures out how what size it
     // needs to be.
     private static final float DEFAULT_UI_WIDTH = 1920f;
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 97ac3fdff..6bb282b 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -743,7 +743,6 @@
   "java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBleClient.java",
   "java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java",
   "java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebEnvironment.java",
-  "java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebOptInActivity.java",
   "java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java",
   "java/src/org/chromium/chrome/browser/physicalweb/PwCollection.java",
   "java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/router/cast/CastMessageHandlerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/router/cast/CastMessageHandlerTest.java
index ac43c54..29028b7 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/media/router/cast/CastMessageHandlerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/router/cast/CastMessageHandlerTest.java
@@ -23,11 +23,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.media.router.cast.CastMessageHandler.RequestRecord;
-import org.chromium.chrome.browser.media.router.cast.JSONTestUtils.JSONObjectLike;
-import org.chromium.chrome.browser.media.router.cast.JSONTestUtils.JSONStringLike;
-import org.chromium.testing.local.LocalRobolectricTestRunner;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.junit.Before;
@@ -38,6 +33,12 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowLog;
 
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.media.router.cast.CastMessageHandler.RequestRecord;
+import org.chromium.chrome.browser.media.router.cast.JSONTestUtils.JSONObjectLike;
+import org.chromium.chrome.browser.media.router.cast.JSONTestUtils.JSONStringLike;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
 import java.util.ArrayDeque;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -273,7 +274,7 @@
                 any(JSONObject.class), anyString(), anyString(), anyInt());
         for (String messageType : CastMessageHandler.getMediaMessageTypesForTest()) {
             // TODO(zqzhang): SET_VOLUME and STOP should not reach here?
-            if (messageType == "MEDIA_SET_VOLUME" || messageType == "STOP_MEDIA")
+            if ("MEDIA_SET_VOLUME".equals(messageType) || "STOP_MEDIA".equals(messageType))
                 continue;
             JSONObject innerMessage = new JSONObject().put("type", messageType);
             JSONObject message = buildCastV2Message(CLIENT_ID1, innerMessage);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerTest.java
index 2e8ab62..0e22add 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerTest.java
@@ -14,8 +14,6 @@
 import com.google.android.gms.gcm.GcmNetworkManager;
 import com.google.android.gms.gcm.Task;
 
-import org.chromium.base.BaseChromiumApplication;
-import org.chromium.base.test.util.Feature;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -23,6 +21,9 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.internal.ShadowExtractor;
 
+import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.test.util.Feature;
+
 /**
  * Unit tests for BackgroundScheduler.
  */
@@ -47,9 +48,8 @@
     @Test
     @Feature({"OfflinePages"})
     public void testSchedule() {
-        BackgroundScheduler scheduler = new BackgroundScheduler();
         assertNull(mGcmNetworkManager.getScheduledTask());
-        scheduler.schedule(mContext, mConditions1);
+        BackgroundScheduler.schedule(mContext, mConditions1);
         // Check with gcmNetworkManagerShadow that schedule got called.
         assertNotNull(mGcmNetworkManager.getScheduledTask());
 
@@ -65,13 +65,12 @@
     @Test
     @Feature({"OfflinePages"})
     public void testUnschedule() {
-        BackgroundScheduler scheduler = new BackgroundScheduler();
         assertNull(mGcmNetworkManager.getScheduledTask());
-        scheduler.schedule(mContext, mConditions1);
+        BackgroundScheduler.schedule(mContext, mConditions1);
         assertNotNull(mGcmNetworkManager.getScheduledTask());
 
         assertNull(mGcmNetworkManager.getCanceledTask());
-        scheduler.unschedule(mContext);
+        BackgroundScheduler.unschedule(mContext);
         assertNotNull(mGcmNetworkManager.getCanceledTask());
     }
 }
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 8fb5016..87ac87bf 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1434,6 +1434,12 @@
   <message name="IDS_FLAGS_QUICK_UNLOCK_PIN_DESCRIPTION" desc="Description of the flag used to enable quick unlock pin.">
     Enabling PIN quick unlock allows you to use a PIN to unlock your Chromebook on the lock screen after you have signed into your device.
   </message>
+  <message name="IDS_FLAGS_QUICK_UNLOCK_FINGERPRINT" desc="Title of the flag used to enable quick unlock fingerprint.">
+    Quick Unlock (Fingerprint)
+  </message>
+  <message name="IDS_FLAGS_QUICK_UNLOCK_FINGERPRINT_DESCRIPTION" desc="Description of the flag used to enable quick unlock fingerprint.">
+    Enabling fingerprint quick unlock allows you to setup and use a fingerprint to unlock your Chromebook on the lock screen after you have signed into your device.
+  </message>
   <message name="IDS_OFFERS_CONSENT_INFOBAR_LABEL_LEARN_MORE" desc="Text of the Learn More link in the echo dialog.">
     Learn More
   </message>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index d4adc756..cf3abaf 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -2136,6 +2136,24 @@
     <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_SETUP_PIN_BUTTON" desc="Button that is used to setup a new PIN when the user does not have a PIN yet.">
       Set up PIN
     </message>
+    <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_REGISTERED_FINGERPRINTS_LABEL" desc="Text above fingerprint list that tells users their registered fingerprints.">
+      Registered fingerprints:
+    </message>
+    <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_ADD_FINGERPRINT_BUTTON" desc="Button that is used to add a new fingerprint.">
+      Add Fingerprint
+    </message>
+    <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_CANNOT_ADD_NEW_FINGERPRINT" desc="Text telling users they have reached the maximum allowed fingerprints.">
+      You can only add <ph name="MAX_FINGERPRINTS">$1<ex>5</ex></ph> fingerprints.
+    </message>
+    <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_FINGERPRINT_LESS_SECURE" desc="Text telling users that fingerprints might be less secure than strong PINs or passwords.">
+      Note: Your fingerprint may be less secure than a strong password or PIN.
+    </message>
+    <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NEW_FINGERPRINT_DEFAULT_NAME" desc="The default name (plus a number for a newly added fingerprint).">
+      Finger <ph name="NEW_FINGER_NUMBER">$1<ex>1</ex></ph>
+    </message>
+    <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_ENABLE_FINGERPRINT_CHECKBOX_LABEL" desc="The text on the label of the checkbox which allows users to enable or disable fingerprint usage.">
+      Enable fingerprint login and authentication
+    </message>
     <message name="IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_TITLE" desc="Title of the password prompt dialog popup.">
       Confirm your password
     </message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 38d3592..561d9e3 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2061,6 +2061,9 @@
     {"quick-unlock-pin", IDS_FLAGS_QUICK_UNLOCK_PIN,
      IDS_FLAGS_QUICK_UNLOCK_PIN_DESCRIPTION, kOsCrOS,
      FEATURE_VALUE_TYPE(features::kQuickUnlockPin)},
+    {"quick-unlock-fingerprint", IDS_FLAGS_QUICK_UNLOCK_FINGERPRINT,
+     IDS_FLAGS_QUICK_UNLOCK_FINGERPRINT_DESCRIPTION, kOsCrOS,
+     FEATURE_VALUE_TYPE(features::kQuickUnlockFingerprint)},
 #endif  // OS_CHROMEOS
     {"browser-task-scheduler", IDS_FLAGS_BROWSER_TASK_SCHEDULER_NAME,
      IDS_FLAGS_BROWSER_TASK_SCHEDULER_DESCRIPTION, kOsAll,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index d237ad8..c2886e3 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -11,6 +11,7 @@
 #include "base/android/jni_string.h"
 #include "base/feature_list.h"
 #include "base/macros.h"
+#include "base/metrics/field_trial_params.h"
 #include "chrome/common/chrome_features.h"
 #include "components/autofill/core/browser/autofill_experiments.h"
 #include "components/ntp_snippets/features.h"
@@ -60,6 +61,7 @@
     &kTabReparenting,
     &kWebPaymentsModifiers,
     &kWebPaymentsSingleAppUiSkip,
+    &kWebVRCardboardSupport,
     &ntp_snippets::kIncreasedVisibility,
     &ntp_snippets::kForeignSessionsSuggestionsFeature,
     &ntp_snippets::kOfflineBadgeFeature,
@@ -144,6 +146,9 @@
 const base::Feature kWebPaymentsSingleAppUiSkip{
     "WebPaymentsSingleAppUiSkip", base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kWebVRCardboardSupport{
+    "WebVRCardboardSupport", base::FEATURE_ENABLED_BY_DEFAULT};
+
 static jboolean IsEnabled(JNIEnv* env,
                           const JavaParamRef<jclass>& clazz,
                           const JavaParamRef<jstring>& jfeature_name) {
@@ -157,6 +162,26 @@
   return false;
 }
 
+static jint GetFieldTrialParamByFeatureAsInt(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz,
+    const JavaParamRef<jstring>& jfeature_name,
+    const JavaParamRef<jstring>& jparam_name,
+    const jint jdefault_value) {
+  const std::string feature_name = ConvertJavaStringToUTF8(env, jfeature_name);
+  const std::string param_name = ConvertJavaStringToUTF8(env, jparam_name);
+  int default_value = static_cast<int>(jdefault_value);
+
+  for (size_t i = 0; i < arraysize(kFeaturesExposedToJava); ++i) {
+    if (kFeaturesExposedToJava[i]->name == feature_name)
+      return base::GetFieldTrialParamByFeatureAsInt(
+          *kFeaturesExposedToJava[i], param_name, default_value);
+  }
+  // Features queried via this API must be present in |kFeaturesExposedToJava|.
+  NOTREACHED();
+  return jdefault_value;
+}
+
 bool RegisterChromeFeatureListJni(JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index e7e6ea2c..00fff86 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -36,6 +36,7 @@
 extern const base::Feature kUserMediaScreenCapturing;
 extern const base::Feature kWebPaymentsModifiers;
 extern const base::Feature kWebPaymentsSingleAppUiSkip;
+extern const base::Feature kWebVRCardboardSupport;
 
 bool RegisterChromeFeatureListJni(JNIEnv* env);
 
diff --git a/chrome/browser/android/vr_shell/ui_interface.h b/chrome/browser/android/vr_shell/ui_interface.h
index 85b2c862..d31995d8 100644
--- a/chrome/browser/android/vr_shell/ui_interface.h
+++ b/chrome/browser/android/vr_shell/ui_interface.h
@@ -26,7 +26,7 @@
 class UiInterface {
  public:
   enum Mode {
-    STANDARD,
+    STANDARD = 0,
     WEB_VR
   };
 
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index 6c43cf7..f6268fe2 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -562,6 +562,11 @@
 }
 
 bool AccessibilityManager::ShouldToggleSpokenFeedbackViaTouch() {
+#if 1
+  // Temporarily disabling this feature until UI feedback is fixed.
+  // http://crbug.com/662501
+  return false;
+#else
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
   if (!connector)
@@ -582,6 +587,7 @@
   KioskAppManager::App app;
   CHECK(manager->GetApp(manager->GetAutoLaunchApp(), &app));
   return app.was_auto_launched_with_zero_delay;
+#endif
 }
 
 bool AccessibilityManager::PlaySpokenFeedbackToggleCountdown(int tick_count) {
diff --git a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
index 653539f..79307a47 100644
--- a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
+++ b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
@@ -36,6 +36,8 @@
   // 0 indicates no maximum length for the pin.
   registry->RegisterIntegerPref(prefs::kPinUnlockMaximumLength, 0);
   registry->RegisterBooleanPref(prefs::kPinUnlockWeakPinsAllowed, true);
+
+  registry->RegisterBooleanPref(prefs::kEnableQuickUnlockFingerprint, false);
 }
 
 bool IsPinUnlockEnabled(PrefService* pref_service) {
@@ -64,6 +66,11 @@
   return base::FeatureList::IsEnabled(features::kQuickUnlockPin);
 }
 
+bool IsFingerprintUnlockEnabled() {
+  // Enable fingerprint unlock only if the switch is present.
+  return base::FeatureList::IsEnabled(features::kQuickUnlockFingerprint);
+}
+
 void EnableQuickUnlockForTesting() {
   enable_for_testing_ = true;
 }
diff --git a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h
index 845574e..979d4eec 100644
--- a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h
+++ b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h
@@ -28,6 +28,9 @@
 // flag is present.
 bool IsPinUnlockEnabled(PrefService* pref_service);
 
+// Returns true if the fingerprint unlock feature flag is present.
+bool IsFingerprintUnlockEnabled();
+
 // Forcibly enable quick-unlock for testing.
 void EnableQuickUnlockForTesting();
 
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 00d49ea5..7848899 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -208,6 +208,8 @@
       settings_private::PrefType::PREF_TYPE_LIST;
   (*s_whitelist)[::prefs::kEnableAutoScreenLock] =
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_whitelist)[::prefs::kEnableQuickUnlockFingerprint] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
 
   // Accessibility.
   (*s_whitelist)[::prefs::kAccessibilitySpokenFeedbackEnabled] =
diff --git a/chrome/browser/extensions/updater/local_extension_cache.cc b/chrome/browser/extensions/updater/local_extension_cache.cc
index 84295d7..ee92b47 100644
--- a/chrome/browser/extensions/updater/local_extension_cache.cc
+++ b/chrome/browser/extensions/updater/local_extension_cache.cc
@@ -560,7 +560,8 @@
 
   CacheMap::iterator it = InsertCacheEntry(cached_extensions_, id, info, false);
   if (it == cached_extensions_.end()) {
-    DCHECK(0) << "Cache contains newer or the same version";
+    LOG(WARNING) << "Cache contains newer or the same version for extension "
+                 << id << " version " << info.version;
     callback.Run(info.file_path, true);
     return;
   }
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win_unittest.cc b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win_unittest.cc
index 3b97bc2..7d0f923 100644
--- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win_unittest.cc
+++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win_unittest.cc
@@ -111,11 +111,6 @@
 }
 
 void MTPDeviceDelegateImplWinTest::TearDown() {
-  // The MediaFileSystemRegistry owned by the TestingBrowserProcess must be
-  // destroyed before the StorageMonitor because it calls
-  // StorageMonitor::RemoveObserver() in its destructor.
-  TestingBrowserProcess::DeleteInstance();
-
   // Windows storage monitor must be destroyed on the same thread
   // as construction.
   TestStorageMonitor::Destroy();
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index f352d9c..a13f2b9 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -742,6 +742,21 @@
   ASSERT_MULTILINE_STREQ(kExpectedPDFAXTree, ax_tree_dump);
 }
 
+#if defined(GOOGLE_CHROME_BUILD)
+// Test a particular PDF encountered in the wild that triggered a crash
+// when accessibility is enabled.  (http://crbug.com/668724)
+IN_PROC_BROWSER_TEST_F(PDFExtensionTest, PdfAccessibilityTextRunCrash) {
+  content::BrowserAccessibilityState::GetInstance()->EnableAccessibility();
+  GURL test_pdf_url(embedded_test_server()->GetURL(
+      "/pdf_private/accessibility_crash_2.pdf"));
+
+  content::WebContents* guest_contents = LoadPdfGetGuestContents(test_pdf_url);
+  ASSERT_TRUE(guest_contents);
+
+  WaitForAccessibilityTreeToContainNodeWithName(guest_contents, "Page 1");
+}
+#endif
+
 IN_PROC_BROWSER_TEST_F(PDFExtensionTest, LinkCtrlLeftClick) {
   host_resolver()->AddRule("www.example.com", "127.0.0.1");
   GURL test_pdf_url(embedded_test_server()->GetURL("/pdf/test-link.pdf"));
diff --git a/chrome/browser/resources/options/chromeos/quick_unlock_configure_overlay.js b/chrome/browser/resources/options/chromeos/quick_unlock_configure_overlay.js
index ade63273..b6d0678 100644
--- a/chrome/browser/resources/options/chromeos/quick_unlock_configure_overlay.js
+++ b/chrome/browser/resources/options/chromeos/quick_unlock_configure_overlay.js
@@ -66,7 +66,8 @@
       var lockScreen = document.querySelector('settings-lock-screen');
 
       var checkbox =
-          lockScreen.root.querySelector('div.settings-box');
+          lockScreen.root.querySelector(
+              'div.settings-box.single-column.screen-lock');
       checkbox.hidden = true;
 
       var passwordPrompt = lockScreen.root.
diff --git a/chrome/browser/resources/options_resources.grd b/chrome/browser/resources/options_resources.grd
index ae79ee13..afb6dcd 100644
--- a/chrome/browser/resources/options_resources.grd
+++ b/chrome/browser/resources/options_resources.grd
@@ -64,6 +64,12 @@
                    type="chrome_html"
                    flattenhtml="true"
                    allowexternalscript="true" />
+        <structure name="IDR_OPTIONS_FINGERPRINT_LIST_JS"
+                   file="settings/people_page/fingerprint_list.js"
+                   type="chrome_html" />
+        <structure name="IDR_OPTIONS_FINGERPRINT_LIST_HTML"
+                   file="settings/people_page/fingerprint_list.html"
+                   type="chrome_html" />
         <structure name="IDR_OPTIONS_LOCK_SCREEN_JS"
                    file="settings/people_page/lock_screen.js"
                    type="chrome_html" />
diff --git a/chrome/browser/resources/settings/people_page/fingerprint_list.html b/chrome/browser/resources/settings/people_page/fingerprint_list.html
new file mode 100644
index 0000000..5483336
--- /dev/null
+++ b/chrome/browser/resources/settings/people_page/fingerprint_list.html
@@ -0,0 +1,36 @@
+<link rel="import" href="chrome://resources/cr_elements/icons.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
+<link rel="import" href="/settings_shared_css.html">
+
+<dom-module id="settings-fingerprint-list">
+  <template>
+    <style include="settings-shared"></style>
+
+    <div>$i18n{lockScreenRegisteredFingerprints}</div>
+    <iron-list id="fingerprintsList" items="[[fingerprints_]]">
+      <template>
+        <div class="list-item">
+          <paper-input value="{{item}}"></paper-input>
+          <button is="paper-icon-button-light"
+              on-tap="onFingerprintDelete_">
+            <iron-icon icon="cr:delete"></iron-icon>
+          </button>
+          </paper-icon-button>
+        </div>
+      </template>
+    </iron-list>
+    <div class="settings-box first radio-indent">
+      <paper-button class="action-button" on-tap="onAddFingerprint_"
+          disabled="[[!canAddNewFingerprint_(fingerprints_.*)]]">
+        [[getFingerprintButtonText_(fingerprints_.*)]]
+      </paper-button>
+    </div>
+    <i>$i18n{lockScreenFingerprintWarning}</i>
+  </template>
+  <script src="fingerprint_list.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/people_page/fingerprint_list.js b/chrome/browser/resources/settings/people_page/fingerprint_list.js
new file mode 100644
index 0000000..46deca9
--- /dev/null
+++ b/chrome/browser/resources/settings/people_page/fingerprint_list.js
@@ -0,0 +1,82 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function() {
+'use strict';
+
+/**
+ * The max number of fingerprints this list can hold.
+ * @const {number}
+ */
+var MAX_NUMBER_FINGERPRINTS_ALLOWED = 5;
+
+Polymer({
+  is: 'settings-fingerprint-list',
+
+  behaviors: [
+    I18nBehavior,
+  ],
+
+  properties: {
+    /**
+     * The list of fingerprint objects.
+     * @private {!Array<string>}
+     */
+    fingerprints_: {
+      type: Array,
+      value: function() {
+        return [];
+      }
+    }
+  },
+
+  /**
+   * Adds a fingerprint with a default name.
+   * @private
+   */
+  onAddFingerprint_: function() {
+    // Determines what the newly added fingerprint's name should be.
+    // TODO(sammiequon): Add fingerprint using private API once it is ready.
+
+    for (var i = 1; i <= MAX_NUMBER_FINGERPRINTS_ALLOWED; ++i) {
+      var fingerprintName = this.i18n('lockScreenFingerprintNewName', i);
+      if (!this.fingerprints_.includes(fingerprintName)) {
+        this.push('fingerprints_', fingerprintName);
+        break;
+      }
+    }
+  },
+
+  /**
+   * Deletes a fingerprint from |fingerprints_|.
+   * @private
+   */
+  onFingerprintDelete_: function(e) {
+    // TODO(sammiequon): Remove fingerprint using private API once it is ready.
+    this.splice('fingerprints_', e.model.index, 1);
+  },
+
+  /**
+   * Returns the text to be displayed for the add fingerprint button.
+   * @return {string}
+   * @private
+   */
+  getFingerprintButtonText_: function() {
+    if (this.canAddNewFingerprint_())
+      return this.i18n('lockScreenAddFingerprint');
+
+    return this.i18n('lockScreenCannotAddFingerprint',
+                     MAX_NUMBER_FINGERPRINTS_ALLOWED);
+  },
+
+  /**
+   * Checks whether another fingerprint can be added.
+   * @return {boolean}
+   * @private
+   */
+  canAddNewFingerprint_: function() {
+    return this.fingerprints_.length < MAX_NUMBER_FINGERPRINTS_ALLOWED;
+  }
+});
+})();
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.html b/chrome/browser/resources/settings/people_page/lock_screen.html
index b55127bc97..63b6748a 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.html
+++ b/chrome/browser/resources/settings/people_page/lock_screen.html
@@ -4,6 +4,7 @@
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html">
 <link rel="import" href="/controls/settings_toggle_button.html">
+<link rel="import" href="/people_page/fingerprint_list.html">
 <link rel="import" href="/people_page/lock_screen_constants.html">
 <link rel="import" href="/people_page/lock_state_behavior.html">
 <link rel="import" href="/people_page/password_prompt_dialog.html">
@@ -38,6 +39,21 @@
         </div>
       </div>
 
+      <template is="dom-if" if="[[fingerprintUnlockEnabled_]]">
+        <div class="settings-box">
+          <settings-toggle-button class="start"
+              pref="{{prefs.settings.enable_quick_unlock_fingerprint}}"
+              label="$i18n{lockScreenFingerprintEnable}">
+          </settings-toggle-button>
+        </div>
+        <iron-collapse
+            opened="[[prefs.settings.enable_quick_unlock_fingerprint.value]]">
+          <div class="settings-box continuation">
+            <settings-fingerprint-list></settings-fingerprint-list>
+          </div>
+        </iron-collapse>
+      </template>
+
       <div class="settings-box">
         <settings-toggle-button class="start"
             pref="{{prefs.settings.enable_screen_lock}}"
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.js b/chrome/browser/resources/settings/people_page/lock_screen.js
index 73fcdb6..0ea3d20 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.js
+++ b/chrome/browser/resources/settings/people_page/lock_screen.js
@@ -48,7 +48,31 @@
     writeUma_: {
       type: Object,
       value: function() { return settings.recordLockScreenProgress; }
-    }
+    },
+
+    /**
+     * True if pin unlock settings should be displayed on this machine.
+     * @private
+     */
+    pinUnlockEnabled_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('pinUnlockEnabled');
+      },
+      readOnly: true,
+    },
+
+    /**
+     * True if fingerprint unlock settings should be displayed on this machine.
+     * @private
+     */
+    fingerprintUnlockEnabled_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('fingerprintUnlockEnabled');
+      },
+      readOnly: true,
+    },
   },
 
   /** selectedUnlockType is defined in LockStateBehavior. */
diff --git a/chrome/browser/resources/settings/people_page/people_page.js b/chrome/browser/resources/settings/people_page/people_page.js
index d019e75..76115fdd 100644
--- a/chrome/browser/resources/settings/people_page/people_page.js
+++ b/chrome/browser/resources/settings/people_page/people_page.js
@@ -89,7 +89,8 @@
     quickUnlockEnabled_: {
       type: Boolean,
       value: function() {
-        return loadTimeData.getBoolean('pinUnlockEnabled');
+        return loadTimeData.getBoolean('pinUnlockEnabled') ||
+            loadTimeData.getBoolean('fingerprintUnlockEnabled');
       },
       readOnly: true,
     },
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index ef20bb8..5b6389b 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -1187,6 +1187,12 @@
                    type="chrome_html"
                    preprocess="true"
                    allowexternalscript="true" />
+        <structure name="IDR_SETTINGS_PEOPLE_FINGERPRINT_LIST_JS"
+                   file="people_page/fingerprint_list.js"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_PEOPLE_FINGERPRINT_LIST_HTML"
+                   file="people_page/fingerprint_list.html"
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_KEYBOARD_PIN_JS"
                    file="people_page/pin_keyboard.js"
                    type="chrome_html"
diff --git a/chrome/browser/resources/vr_shell/vr_shell_ui.js b/chrome/browser/resources/vr_shell/vr_shell_ui.js
index df4c561..86cc664a 100644
--- a/chrome/browser/resources/vr_shell/vr_shell_ui.js
+++ b/chrome/browser/resources/vr_shell/vr_shell_ui.js
@@ -31,6 +31,9 @@
       /** @const */ this.SCREEN_RATIO = 16 / 9;
       /** @const */ this.BROWSING_SCREEN_DISTANCE = 2.0;
       /** @const */ this.FULLSCREEN_DISTANCE = 3.0;
+      /** @const */ this.CSS_WIDTH_PIXELS = 960.0;
+      /** @const */ this.CSS_HEIGHT_PIXELS = 640.0;
+      /** @const */ this.DPR = 1.2;
 
       let element = new api.UiElement(0, 0, 0, 0);
       element.setIsContentQuad();
@@ -45,6 +48,13 @@
       let update = new api.UiElementUpdate();
       update.setVisible(enabled);
       ui.updateElement(this.elementId, update);
+      if (enabled) {
+        api.setContentCssSize(
+          this.CSS_WIDTH_PIXELS, this.CSS_HEIGHT_PIXELS, this.DPR);
+      } else {
+        // TODO(mthiesse): Restore the webVR resolution (which matches native
+        // display resolution).
+      }
     }
 
     setOpacity(opacity) {
diff --git a/chrome/browser/resources/vr_shell/vr_shell_ui_api.js b/chrome/browser/resources/vr_shell/vr_shell_ui_api.js
index 5424ca723..2979532 100644
--- a/chrome/browser/resources/vr_shell/vr_shell_ui_api.js
+++ b/chrome/browser/resources/vr_shell/vr_shell_ui_api.js
@@ -99,6 +99,16 @@
 };
 
 /**
+ * Sets the CSS size for the content window.
+ * @param {number} width
+ * @param {number} height
+ * @param {number} dpr
+ */
+api.setContentCssSize = function(width, height, dpr) {
+  chrome.send('setContentCssSize', [width, height, dpr]);
+};
+
+/**
  * Sets the CSS size for this page.
  * @param {number} width
  * @param {number} height
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc
index beb0d06..570dd2c 100644
--- a/chrome/browser/safe_browsing/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -1065,10 +1065,12 @@
     ReferrerChainData* referrer_chain_data =
       static_cast<ReferrerChainData*>(
           item_->GetUserData(kDownloadReferrerChainDataKey));
-    if (referrer_chain_data &&
-        !referrer_chain_data->GetReferrerChain()->empty()) {
-      request.mutable_referrer_chain()->Swap(
-          referrer_chain_data->GetReferrerChain());
+    if (referrer_chain_data) {
+      request.set_download_attribution_finch_enabled(true);
+      if (!referrer_chain_data->GetReferrerChain()->empty()) {
+        request.mutable_referrer_chain()->Swap(
+            referrer_chain_data->GetReferrerChain());
+      }
     }
 
     if (archive_is_valid_ != ArchiveValid::UNSET)
@@ -1300,6 +1302,8 @@
       scoped_refptr<SafeBrowsingDatabaseManager> database_manager)
       : requestor_url_(requestor_url),
         initiating_frame_url_(initiating_frame_url),
+        initiating_main_frame_url_(
+            web_contents ? web_contents->GetLastCommittedURL() : GURL()),
         tab_id_(SessionTabHelper::IdForTab(web_contents)),
         default_file_path_(default_file_path),
         alternate_extensions_(alternate_extensions),
@@ -1433,10 +1437,8 @@
     }
 
     service_->AddReferrerChainToPPAPIClientDownloadRequest(
-        initiating_frame_url_,
-        tab_id_,
-        has_user_gesture_,
-        &request);
+        initiating_frame_url_, initiating_main_frame_url_, tab_id_,
+        has_user_gesture_, &request);
 
     if (!request.SerializeToString(&client_download_request_data_)) {
       // More of an internal error than anything else. Note that the UNKNOWN
@@ -1560,9 +1562,12 @@
   // URL of document that requested the PPAPI download.
   const GURL requestor_url_;
 
-  // URL of the frame that hosted the PPAPI plugin.
+  // URL of the frame that hosts the PPAPI plugin.
   const GURL initiating_frame_url_;
 
+  // URL of the tab that contains the initialting_frame.
+  const GURL initiating_main_frame_url_;
+
   // Tab id that associated with the PPAPI plugin, computed by
   // SessionTabHelper::IdForTab().
   int tab_id_;
@@ -1906,10 +1911,11 @@
 }
 
 void DownloadProtectionService::AddReferrerChainToPPAPIClientDownloadRequest(
-  const GURL& initiating_frame_url,
-  int tab_id,
-  bool has_user_gesture,
-  ClientDownloadRequest* out_request) {
+    const GURL& initiating_frame_url,
+    const GURL& initiating_main_frame_url,
+    int tab_id,
+    bool has_user_gesture,
+    ClientDownloadRequest* out_request) {
   if (!base::FeatureList::IsEnabled(
       SafeBrowsingNavigationObserverManager::kDownloadAttribution) ||
       !navigation_observer_manager_) {
@@ -1921,10 +1927,8 @@
       tab_id == -1);
   SafeBrowsingNavigationObserverManager::AttributionResult result =
       navigation_observer_manager_->IdentifyReferrerChainForPPAPIDownload(
-          initiating_frame_url,
-          tab_id,
-          has_user_gesture,
-          kDownloadAttributionUserGestureLimit,
+          initiating_frame_url, initiating_main_frame_url, tab_id,
+          has_user_gesture, kDownloadAttributionUserGestureLimit,
           out_request->mutable_referrer_chain());
   UMA_HISTOGRAM_COUNTS_100(
       "SafeBrowsing.ReferrerURLChainSize.PPAPIDownloadAttribution",
@@ -1932,6 +1936,7 @@
   UMA_HISTOGRAM_ENUMERATION(
       "SafeBrowsing.ReferrerAttributionResult.PPAPIDownloadAttribution", result,
       SafeBrowsingNavigationObserverManager::ATTRIBUTION_FAILURE_TYPE_MAX);
+  out_request->set_download_attribution_finch_enabled(true);
 }
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection_service.h b/chrome/browser/safe_browsing/download_protection_service.h
index 6bbbb4c..4272abc 100644
--- a/chrome/browser/safe_browsing/download_protection_service.h
+++ b/chrome/browser/safe_browsing/download_protection_service.h
@@ -308,10 +308,11 @@
   // Then add referrer chain info to ClientDownloadRequest proto. This function
   // also records UMA stats of download attribution result.
   void AddReferrerChainToPPAPIClientDownloadRequest(
-    const GURL& initiating_frame_url,
-    int tab_id,
-    bool has_user_gesture,
-    ClientDownloadRequest* out_request);
+      const GURL& initiating_frame_url,
+      const GURL& initiating_main_frame_url,
+      int tab_id,
+      bool has_user_gesture,
+      ClientDownloadRequest* out_request);
 
   // These pointers may be NULL if SafeBrowsing is disabled.
   scoped_refptr<SafeBrowsingUIManager> ui_manager_;
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc
index 7e0b419..9dd7af90 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc
@@ -31,40 +31,36 @@
     : source_url(),
       source_main_frame_url(),
       original_request_url(),
-      destination_url(),
       source_tab_id(-1),
       target_tab_id(-1),
       frame_id(-1),
       last_updated(base::Time::Now()),
       is_user_initiated(false),
-      has_committed(false),
-      has_server_redirect(false) {}
+      has_committed(false) {}
 
 NavigationEvent::NavigationEvent(NavigationEvent&& nav_event)
     : source_url(std::move(nav_event.source_url)),
       source_main_frame_url(std::move(nav_event.source_main_frame_url)),
       original_request_url(std::move(nav_event.original_request_url)),
-      destination_url(std::move(nav_event.destination_url)),
+      server_redirect_urls(std::move(nav_event.server_redirect_urls)),
       source_tab_id(std::move(nav_event.source_tab_id)),
       target_tab_id(std::move(nav_event.target_tab_id)),
       frame_id(nav_event.frame_id),
       last_updated(nav_event.last_updated),
       is_user_initiated(nav_event.is_user_initiated),
-      has_committed(nav_event.has_committed),
-      has_server_redirect(nav_event.has_server_redirect) {}
+      has_committed(nav_event.has_committed) {}
 
 NavigationEvent& NavigationEvent::operator=(NavigationEvent&& nav_event) {
   source_url = std::move(nav_event.source_url);
   source_main_frame_url = std::move(nav_event.source_main_frame_url);
   original_request_url = std::move(nav_event.original_request_url);
-  destination_url = std::move(nav_event.destination_url);
   source_tab_id = nav_event.source_tab_id;
   target_tab_id = nav_event.target_tab_id;
   frame_id = nav_event.frame_id;
   last_updated = nav_event.last_updated;
   is_user_initiated = nav_event.is_user_initiated;
   has_committed = nav_event.has_committed;
-  has_server_redirect = nav_event.has_server_redirect;
+  server_redirect_urls = std::move(nav_event.server_redirect_urls);
   return *this;
 }
 
@@ -160,7 +156,6 @@
   nav_event.original_request_url =
       SafeBrowsingNavigationObserverManager::ClearEmptyRef(
           navigation_handle->GetURL());
-  nav_event.destination_url = nav_event.original_request_url;
 
   nav_event.source_tab_id =
       SessionTabHelper::IdForTab(navigation_handle->GetWebContents());
@@ -185,10 +180,9 @@
   }
 
   NavigationEvent* nav_event = &navigation_handle_map_[navigation_handle];
-  nav_event->has_server_redirect = true;
-  nav_event->destination_url =
+  nav_event->server_redirect_urls.push_back(
       SafeBrowsingNavigationObserverManager::ClearEmptyRef(
-          navigation_handle->GetURL());
+          navigation_handle->GetURL()));
   nav_event->last_updated = base::Time::Now();
 }
 
@@ -212,7 +206,7 @@
       SessionTabHelper::IdForTab(navigation_handle->GetWebContents());
   nav_event->last_updated = base::Time::Now();
 
-  manager_->RecordNavigationEvent(nav_event->destination_url, nav_event);
+  manager_->RecordNavigationEvent(nav_event->GetDestinationUrl(), nav_event);
   navigation_handle_map_.erase(navigation_handle);
 }
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer.h b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.h
index f08f42ef..cfeccac 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer.h
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.h
@@ -33,10 +33,10 @@
                                // same as source_url, if source_url was loaded
                                // in main frame.
   GURL original_request_url;   // The original request URL of this navigation.
-  GURL destination_url;        // The actual destination url of this navigation
-                               // event. If this navigation has server side
-                               // redirect(s), actual_target_url will be
-                               // different from initial_request_url.
+  std::vector<GURL> server_redirect_urls;  // Server redirect url chain.
+                                           // Empty if there is no server
+                                           // redirect. If set, last url in this
+                                           // vector is the destination url.
   int source_tab_id;  // Which tab contains the frame with source_url. Tab ID is
                       // returned by SessionTabHelper::IdForTab. This ID is
                       // immutable for a given tab and unique across Chrome
@@ -47,7 +47,13 @@
   base::Time last_updated;  // When this NavigationEvent was last updated.
   bool is_user_initiated;  // browser_initiated || has_user_gesture.
   bool has_committed;
-  bool has_server_redirect;
+
+  const GURL& GetDestinationUrl() const {
+    if (!server_redirect_urls.empty())
+      return server_redirect_urls.back();
+    else
+      return original_request_url;
+  }
 };
 
 // Structure to keep track of resolved IP address of a host.
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
index 4846488..48c91f7 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
@@ -221,21 +221,31 @@
               actual_nav_event.source_main_frame_url);
     EXPECT_EQ(expected_original_request_url,
               actual_nav_event.original_request_url);
-    EXPECT_EQ(expected_destination_url, actual_nav_event.destination_url);
+    EXPECT_EQ(expected_destination_url, actual_nav_event.GetDestinationUrl());
     EXPECT_EQ(expected_is_user_initiated, actual_nav_event.is_user_initiated);
     EXPECT_EQ(expected_has_committed, actual_nav_event.has_committed);
     EXPECT_EQ(expected_has_server_redirect,
-              actual_nav_event.has_server_redirect);
+              !actual_nav_event.server_redirect_urls.empty());
   }
 
-  void VerifyReferrerChainEntry(const GURL& expected_url,
-                                ReferrerChainEntry::URLType expected_type,
-                                const std::string& expected_ip_address,
-                                const GURL& expected_referrer_url,
-                                const GURL& expected_referrer_main_frame_url,
-                                bool expected_is_retargeting,
-                                const ReferrerChainEntry& actual_entry) {
+  void VerifyReferrerChainEntry(
+      const GURL& expected_url,
+      const GURL& expected_main_frame_url,
+      ReferrerChainEntry::URLType expected_type,
+      const std::string& expected_ip_address,
+      const GURL& expected_referrer_url,
+      const GURL& expected_referrer_main_frame_url,
+      bool expected_is_retargeting,
+      const std::vector<GURL>& expected_server_redirects,
+      const ReferrerChainEntry& actual_entry) {
     EXPECT_EQ(expected_url.spec(), actual_entry.url());
+    if (expected_main_frame_url.is_empty()) {
+      EXPECT_FALSE(actual_entry.has_main_frame_url());
+    } else {
+      // main_frame_url only set if it is different from url.
+      EXPECT_EQ(expected_main_frame_url.spec(), actual_entry.main_frame_url());
+      EXPECT_NE(expected_main_frame_url.spec(), actual_entry.url());
+    }
     EXPECT_EQ(expected_type, actual_entry.type());
     if (expected_ip_address.empty()) {
       ASSERT_EQ(0, actual_entry.ip_addresses_size());
@@ -244,9 +254,26 @@
       EXPECT_EQ(expected_ip_address, actual_entry.ip_addresses(0));
     }
     EXPECT_EQ(expected_referrer_url.spec(), actual_entry.referrer_url());
-    EXPECT_EQ(expected_referrer_main_frame_url.spec(),
-              actual_entry.referrer_main_frame_url());
+    if (expected_referrer_main_frame_url.is_empty()) {
+      EXPECT_FALSE(actual_entry.has_referrer_main_frame_url());
+    } else {
+      // referrer_main_frame_url only set if it is different from referrer_url.
+      EXPECT_EQ(expected_referrer_main_frame_url.spec(),
+                actual_entry.referrer_main_frame_url());
+      EXPECT_NE(expected_referrer_main_frame_url.spec(),
+                actual_entry.referrer_url());
+    }
     EXPECT_EQ(expected_is_retargeting, actual_entry.is_retargeting());
+    if (expected_server_redirects.empty()) {
+      EXPECT_EQ(0, actual_entry.server_redirect_chain_size());
+    } else {
+      ASSERT_EQ(static_cast<int>(expected_server_redirects.size()),
+                actual_entry.server_redirect_chain_size());
+      for (int i = 0; i < actual_entry.server_redirect_chain_size(); i++) {
+        EXPECT_EQ(expected_server_redirects[i].spec(),
+                  actual_entry.server_redirect_chain(i).url());
+      }
+    }
   }
 
   // Identify referrer chain of a DownloadItem and populate |referrer_chain|.
@@ -273,9 +300,8 @@
     bool has_user_gesture = observer_manager_->HasUserGesture(web_contents);
     observer_manager_->OnUserGestureConsumed(web_contents, base::Time::Now());
     EXPECT_LE(observer_manager_->IdentifyReferrerChainForPPAPIDownload(
-                  initiating_frame_url,
-                  tab_id,
-                  has_user_gesture,
+                  initiating_frame_url, web_contents->GetLastCommittedURL(),
+                  tab_id, has_user_gesture,
                   2,  // kDownloadAttributionUserGestureLimit)
                   referrer_chain),
               SafeBrowsingNavigationObserverManager::SUCCESS_LANDING_REFERRER);
@@ -350,11 +376,13 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(1, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,   // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
 }
 // Click on a link and start download on the same page.
@@ -390,18 +418,22 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(2, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            initial_url,                       // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           false,        // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
   VerifyReferrerChainEntry(initial_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,   // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
 }
 
@@ -440,18 +472,22 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(2, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            initial_url,                       // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           false,        // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
   VerifyReferrerChainEntry(initial_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,   // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
 }
 
@@ -504,18 +540,22 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(2, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            initial_url,                       // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           true,         // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           true,                 // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
   VerifyReferrerChainEntry(initial_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,   // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
 }
 
@@ -566,25 +606,31 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(3, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            redirect_url,                      // referrer_url
-                           redirect_url,  // referrer_main_frame_url
-                           false,         // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
-  VerifyReferrerChainEntry(redirect_url,                         // url
+  VerifyReferrerChainEntry(redirect_url,  // url
+                           GURL(),        // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
                            test_server_ip,                       // ip_address
                            initial_url,                          // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           false,        // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
   VerifyReferrerChainEntry(initial_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,   // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(2));
 }
 
@@ -644,25 +690,31 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(3, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            redirect_url,                      // referrer_url
-                           redirect_url,  // referrer_main_frame_url
-                           false,         // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
-  VerifyReferrerChainEntry(redirect_url,                         // url
+  VerifyReferrerChainEntry(redirect_url,  // url
+                           GURL(),        // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
                            test_server_ip,                       // ip_address
                            initial_url,                          // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           true,         // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           true,                 // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
   VerifyReferrerChainEntry(initial_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,   // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(2));
 }
 
@@ -723,32 +775,40 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(4, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            second_redirect_url,               // referrer_url
-                           second_redirect_url,  // referrer_main_frame_url
+                           GURL(),               // referrer_main_frame_url
                            false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
-  VerifyReferrerChainEntry(second_redirect_url,                  // url
+  VerifyReferrerChainEntry(second_redirect_url,  // url
+                           GURL(),               // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
                            test_server_ip,                       // ip_address
                            first_redirect_url,                   // referrer_url
-                           first_redirect_url,  // referrer_main_frame_url
-                           false,               // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
-  VerifyReferrerChainEntry(first_redirect_url,                   // url
+  VerifyReferrerChainEntry(first_redirect_url,  // url
+                           GURL(),              // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
                            test_server_ip,                       // ip_address
                            initial_url,                          // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           false,        // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(2));
   VerifyReferrerChainEntry(initial_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,   // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(3));
 }
 
@@ -786,18 +846,22 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(2, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            initial_url,                       // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           false,        // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
   VerifyReferrerChainEntry(initial_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,   // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
 }
 
@@ -846,25 +910,31 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(3, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            redirect_url,                      // referrer_url
-                           redirect_url,  // referrer_main_frame_url
-                           false,         // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
-  VerifyReferrerChainEntry(redirect_url,                         // url
+  VerifyReferrerChainEntry(redirect_url,  // url
+                           GURL(),        // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
                            test_server_ip,                       // ip_address
                            initial_url,                          // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           false,        // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
   VerifyReferrerChainEntry(initial_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,   // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(2));
 }
 
@@ -926,25 +996,31 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(3, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            blank_url,                         // referrer_url
-                           blank_url,  // referrer_main_frame_url
-                           false,      // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
-  VerifyReferrerChainEntry(blank_url,                            // url
+  VerifyReferrerChainEntry(blank_url,  // url
+                           GURL(),     // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
                            "",                                   // ip_address
                            initial_url,                          // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           true,         // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           true,                 // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
   VerifyReferrerChainEntry(initial_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,   // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(2));
 }
 
@@ -1008,25 +1084,31 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(3, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            "",                                // ip_address
                            blank_url,                         // referrer_url
-                           blank_url,  // referrer_main_frame_url
-                           false,      // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
-  VerifyReferrerChainEntry(blank_url,                            // url
+  VerifyReferrerChainEntry(blank_url,  // url
+                           GURL(),     // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
                            "",                                   // ip_address
                            initial_url,                          // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           true,         // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           true,                 // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
   VerifyReferrerChainEntry(initial_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,   // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(2));
 }
 
@@ -1070,18 +1152,22 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(2, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            "",                                // ip_address
                            initial_url,                       // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           false,        // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
   VerifyReferrerChainEntry(initial_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,   // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
 }
 
@@ -1154,32 +1240,40 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(4, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            iframe_url,                        // referrer_url
                            multi_frame_test_url,  // referrer_main_frame_url
                            false,                 // is_retargeting
+                           std::vector<GURL>(),   // server redirects
                            referrer_chain.Get(0));
   VerifyReferrerChainEntry(iframe_url,                        // url
+                           multi_frame_test_url,              // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
                            multi_frame_test_url,  // referrer_main_frame_url
                            false,                 // is_retargeting
+                           std::vector<GURL>(),   // server redirects
                            referrer_chain.Get(1));
-  VerifyReferrerChainEntry(multi_frame_test_url,                 // url
+  VerifyReferrerChainEntry(multi_frame_test_url,  // url
+                           GURL(),                // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
                            test_server_ip,                       // ip_address
-                           initial_url,  // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           false,                 // is_retargeting
+                           initial_url,                          // referrer_url
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(2));
-  VerifyReferrerChainEntry(initial_url,                           // url
+  VerifyReferrerChainEntry(initial_url,  // url
+                           GURL(),       // main_frame_url
                            ReferrerChainEntry::LANDING_REFERRER,  // type
                            test_server_ip,                        // ip_address
-                           GURL(),  // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,                 // is_retargeting
+                           GURL(),               // referrer_url
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(3));
 }
 
@@ -1270,39 +1364,49 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   EXPECT_EQ(5, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            blank_url,                         // referrer_url
-                           blank_url,  // referrer_main_frame_url
-                           false,      // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
-  VerifyReferrerChainEntry(blank_url,                            // url
+  VerifyReferrerChainEntry(blank_url,  // url
+                           GURL(),     // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
                            "",                                   // ip_address
                            iframe_retargeting_url,               // referrer_url
                            multi_frame_test_url,  // referrer_main_frame_url
                            true,                  // is_retargeting
+                           std::vector<GURL>(),   // server redirects
                            referrer_chain.Get(1));
   VerifyReferrerChainEntry(iframe_retargeting_url,            // url
+                           multi_frame_test_url,              // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
                            multi_frame_test_url,  // referrer_main_frame_url
                            false,                 // is_retargeting
+                           std::vector<GURL>(),   // server redirects
                            referrer_chain.Get(2));
-  VerifyReferrerChainEntry(multi_frame_test_url,                 // url
+  VerifyReferrerChainEntry(multi_frame_test_url,  // url
+                           GURL(),                // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
                            test_server_ip,                       // ip_address
-                           initial_url,  // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           false,                 // is_retargeting
+                           initial_url,                          // referrer_url
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(3));
-  VerifyReferrerChainEntry(initial_url,                           // url
+  VerifyReferrerChainEntry(initial_url,  // url
+                           GURL(),       // main_frame_url
                            ReferrerChainEntry::LANDING_REFERRER,  // type
                            test_server_ip,                        // ip_address
-                           GURL(),  // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,                 // is_retargeting
+                           GURL(),               // referrer_url
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(4));
 }
 
@@ -1361,33 +1465,41 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   EXPECT_EQ(4, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            landing_url,                       // referrer_url
-                           landing_url,  // referrer_main_frame_url
-                           false,        // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
   VerifyReferrerChainEntry(landing_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            redirect_url,                      // referrer_url
-                           redirect_url,  // referrer_main_frame_url
-                           false,         // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
-  VerifyReferrerChainEntry(redirect_url,                         // url
+  VerifyReferrerChainEntry(redirect_url,  // url
+                           GURL(),        // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
                            test_server_ip,                       // ip_address
                            initial_url,                          // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           false,        // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(2));
   VerifyReferrerChainEntry(
       initial_url,                           // url
+      GURL(),                                // main_frame_url
       ReferrerChainEntry::LANDING_REFERRER,  // type
       test_server_ip,                        // ip_address
       GURL(),  // referrer_url is empty since this beyonds 2 clicks.
       GURL(),  // referrer_main_frame_url is empty for the same reason.
       false,   // is_retargeting
+      std::vector<GURL>(),  // server redirects
       referrer_chain.Get(3));
 }
 
@@ -1461,26 +1573,32 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   EXPECT_EQ(3, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            landing_url,                       // referrer_url
-                           landing_url,  // referrer_main_frame_url
-                           false,        // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
   VerifyReferrerChainEntry(landing_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            landing_referrer_url,              // referrer_url
-                           landing_referrer_url,  // referrer_main_frame_url
-                           false,                 // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
   VerifyReferrerChainEntry(
       landing_referrer_url,                  // url
+      GURL(),                                // main_frame_url
       ReferrerChainEntry::LANDING_REFERRER,  // type
       test_server_ip,                        // ip_address
       GURL(),  // referrer_url is empty since this beyonds 2 clicks.
       GURL(),  // referrer_main_frame_url is empty for the same reason.
       false,   // is_retargeting
+      std::vector<GURL>(),  // server redirects
       referrer_chain.Get(2));
   // page_before_landing_referrer_url is not in referrer chain.
 }
@@ -1535,26 +1653,32 @@
       &referrer_chain);
   EXPECT_EQ(3, referrer_chain.size());
   VerifyReferrerChainEntry(landing_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            redirect_url,                      // referrer_url
-                           redirect_url,  // referrer_main_frame_url
-                           false,         // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
-  VerifyReferrerChainEntry(redirect_url,                         // url
+  VerifyReferrerChainEntry(redirect_url,  // url
+                           GURL(),        // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
                            test_server_ip,                       // ip_address
                            initial_url,                          // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           false,        // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
   VerifyReferrerChainEntry(
       initial_url,                           // url
+      GURL(),                                // main_frame_url
       ReferrerChainEntry::LANDING_REFERRER,  // type
       test_server_ip,                        // ip_address
       GURL(),  // referrer_url is empty since this beyonds 2 clicks.
       GURL(),  // referrer_main_frame_url is empty for the same reason.
       false,   // is_retargeting
+      std::vector<GURL>(),  // server redirects
       referrer_chain.Get(2));
 }
 
@@ -1606,26 +1730,32 @@
       browser()->tab_strip_model()->GetActiveWebContents(),
       &referrer_chain);
   EXPECT_EQ(3, referrer_chain.size());
-  VerifyReferrerChainEntry(hosting_url,                       // url
+  VerifyReferrerChainEntry(hosting_url,  // url
+                           GURL(),       // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
-                           test_server_ip,                    // ip_address
-                           redirect_url,                      // referrer_url
-                           redirect_url,  // referrer_main_frame_url
-                           false,         // is_retargeting
+                           test_server_ip,                       // ip_address
+                           redirect_url,                         // referrer_url
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(0));
-  VerifyReferrerChainEntry(redirect_url,                         // url
+  VerifyReferrerChainEntry(redirect_url,  // url
+                           GURL(),        // main_frame_url
                            ReferrerChainEntry::CLIENT_REDIRECT,  // type
                            test_server_ip,                       // ip_address
                            landing_url,                          // referrer_url
-                           landing_url,  // referrer_main_frame_url
-                           false,        // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
   VerifyReferrerChainEntry(landing_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),  // no more referrer before landing_url
                            GURL(),
-                           false,   // is_retargeting
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(2));
 }
 
@@ -1663,11 +1793,64 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(1, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
                            GURL(),  // referrer_main_frame_url
                            false,   // is_retargeting
+                           {request_url, download_url},  // server redirects
+                           referrer_chain.Get(0));
+}
+
+// 2 consecutive server-side redirects.
+IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, TwoServerRedirects) {
+  GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL);
+  GURL destination_url = embedded_test_server()->GetURL(kDownloadItemURL);
+  GURL redirect_url = embedded_test_server()->GetURL("/server-redirect?" +
+                                                     destination_url.spec());
+  GURL request_url =
+      embedded_test_server()->GetURL("/server-redirect?" + redirect_url.spec());
+  ui_test_utils::NavigateToURL(browser(), request_url);
+  std::string test_server_ip(embedded_test_server()->host_port_pair().host());
+  auto nav_map = navigation_map();
+  ASSERT_TRUE(nav_map);
+  ASSERT_EQ(2U, nav_map->size());
+  ASSERT_EQ(1U, nav_map->at(destination_url).size());
+  ASSERT_EQ(1U, nav_map->at(initial_url).size());
+  VerifyNavigationEvent(GURL(),       // source_url
+                        GURL(),       // source_main_frame_url
+                        initial_url,  // original_request_url
+                        initial_url,  // destination_url
+                        true,         // is_user_initiated,
+                        true,         // has_committed
+                        false,        // has_server_redirect
+                        nav_map->at(initial_url).at(0));
+  VerifyNavigationEvent(GURL(),           // source_url
+                        GURL(),           // source_main_frame_url
+                        request_url,      // original_request_url
+                        destination_url,  // destination_url
+                        true,             // is_user_initiated,
+                        false,            // has_committed
+                        true,             // has_server_redirect
+                        nav_map->at(destination_url).at(0));
+  const auto redirect_vector =
+      nav_map->at(destination_url).at(0).server_redirect_urls;
+  ASSERT_EQ(2U, redirect_vector.size());
+  EXPECT_EQ(redirect_url, redirect_vector.at(0));
+  EXPECT_EQ(destination_url, redirect_vector.at(1));
+
+  ReferrerChain referrer_chain;
+  IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
+  ASSERT_EQ(1, referrer_chain.size());
+  VerifyReferrerChainEntry(destination_url,                   // url
+                           GURL(),                            // main_frame_url
+                           ReferrerChainEntry::DOWNLOAD_URL,  // type
+                           test_server_ip,                    // ip_address
+                           GURL(),                            // referrer_url
+                           GURL(),  // referrer_main_frame_url
+                           false,   // is_retargeting
+                           {request_url, redirect_url, destination_url},
                            referrer_chain.Get(0));
 }
 
@@ -1715,18 +1898,22 @@
   IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
   ASSERT_EQ(2, referrer_chain.size());
   VerifyReferrerChainEntry(download_url,                      // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::DOWNLOAD_URL,  // type
                            test_server_ip,                    // ip_address
                            initial_url,                       // referrer_url
-                           initial_url,  // referrer_main_frame_url
-                           true,         // is_retargeting
+                           GURL(),  // referrer_main_frame_url
+                           true,    // is_retargeting
+                           {request_url, download_url},  // server redirects
                            referrer_chain.Get(0));
   VerifyReferrerChainEntry(initial_url,                       // url
+                           GURL(),                            // main_frame_url
                            ReferrerChainEntry::LANDING_PAGE,  // type
                            test_server_ip,                    // ip_address
                            GURL(),                            // referrer_url
-                           GURL(),  // referrer_main_frame_url
-                           false,   // is_retargeting
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
                            referrer_chain.Get(1));
 }
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
index e3fd42f..a003bac7 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
@@ -175,7 +175,7 @@
     // host_to_ip_map already contains this key.
     // If this IP is already in the vector, we update its timestamp.
     for (auto& vector_entry : insert_result.first->second) {
-      if (vector_entry.ip == host) {
+      if (vector_entry.ip == ip) {
         vector_entry.timestamp = base::Time::Now();
         return;
       }
@@ -217,7 +217,7 @@
     return NAVIGATION_EVENT_NOT_FOUND;
   }
   AttributionResult result = SUCCESS;
-  AddToReferrerChain(out_referrer_chain, nav_event,
+  AddToReferrerChain(out_referrer_chain, nav_event, GURL(),
                      ReferrerChainEntry::DOWNLOAD_URL);
   int user_gesture_count = 0;
   GetRemainingReferrerChain(
@@ -232,6 +232,7 @@
 SafeBrowsingNavigationObserverManager::AttributionResult
 SafeBrowsingNavigationObserverManager::IdentifyReferrerChainForPPAPIDownload(
     const GURL& initiating_frame_url,
+    const GURL& initiating_main_frame_url,
     int tab_id,
     bool has_user_gesture,
     int user_gesture_count_limit,
@@ -253,15 +254,13 @@
   // page of the PPAPI download.
   if (has_user_gesture) {
     user_gesture_count = 1;
-    AddToReferrerChain(out_referrer_chain, nav_event,
-                       GetURLTypeAndAdjustAttributionResult(
-                          user_gesture_count == user_gesture_count_limit,
-                          &result));
+    AddToReferrerChain(
+        out_referrer_chain, nav_event, initiating_main_frame_url,
+        GetURLTypeAndAdjustAttributionResult(
+            user_gesture_count == user_gesture_count_limit, &result));
   } else {
-    AddToReferrerChain(out_referrer_chain, nav_event,
-                       nav_event->has_server_redirect
-                           ? ReferrerChainEntry::SERVER_REDIRECT
-                           : ReferrerChainEntry::CLIENT_REDIRECT);
+    AddToReferrerChain(out_referrer_chain, nav_event, initiating_main_frame_url,
+                       ReferrerChainEntry::CLIENT_REDIRECT);
   }
 
   GetRemainingReferrerChain(
@@ -314,7 +313,6 @@
       SafeBrowsingNavigationObserverManager::ClearEmptyRef(
           source_contents->GetLastCommittedURL());
   nav_event.original_request_url = target_url;
-  nav_event.destination_url = target_url;
   nav_event.target_tab_id = SessionTabHelper::IdForTab(target_contents);
   nav_event.frame_id = rfh ? rfh->GetFrameTreeNodeId() : -1;
   auto it = user_gesture_map_.find(source_contents);
@@ -335,7 +333,9 @@
 void SafeBrowsingNavigationObserverManager::CleanUpNavigationEvents() {
   // Remove any stale NavigationEnvent, if it is older than
   // kNavigationFootprintTTLInSecond.
+  std::size_t remove_count = 0;
   for (auto it = navigation_map_.begin(); it != navigation_map_.end();) {
+    std::size_t size_before_removal = it->second.size();
     it->second.erase(std::remove_if(it->second.begin(), it->second.end(),
                                     [](const NavigationEvent& nav_event) {
                                       return IsEventExpired(
@@ -343,11 +343,16 @@
                                           kNavigationFootprintTTLInSecond);
                                     }),
                      it->second.end());
-    if (it->second.size() == 0)
+    std::size_t size_after_removal = it->second.size();
+    remove_count += (size_before_removal - size_after_removal);
+    if (size_after_removal == 0)
       it = navigation_map_.erase(it);
     else
       ++it;
   }
+  UMA_HISTOGRAM_COUNTS_10000(
+      "SafeBrowsing.NavigationObserver.NavigationEventCleanUpCount",
+      remove_count);
 }
 
 void SafeBrowsingNavigationObserverManager::CleanUpUserGestures() {
@@ -360,7 +365,9 @@
 }
 
 void SafeBrowsingNavigationObserverManager::CleanUpIpAddresses() {
+  std::size_t remove_count = 0;
   for (auto it = host_to_ip_map_.begin(); it != host_to_ip_map_.end();) {
+    std::size_t size_before_removal = it->second.size();
     it->second.erase(std::remove_if(it->second.begin(), it->second.end(),
                                     [](const ResolvedIPAddress& resolved_ip) {
                                       return IsEventExpired(
@@ -368,11 +375,15 @@
                                           kNavigationFootprintTTLInSecond);
                                     }),
                      it->second.end());
-    if (it->second.size() == 0)
+    std::size_t size_after_removal = it->second.size();
+    remove_count += (size_before_removal - size_after_removal);
+    if (size_after_removal == 0)
       it = host_to_ip_map_.erase(it);
     else
       ++it;
   }
+  UMA_HISTOGRAM_COUNTS_10000(
+      "SafeBrowsing.NavigationObserver.IPAddressCleanUpCount", remove_count);
 }
 
 bool SafeBrowsingNavigationObserverManager::IsCleanUpScheduled() const {
@@ -407,7 +418,7 @@
   // the vector in reverse order to get the latest match.
   for (auto rit = it->second.rbegin(); rit != it->second.rend(); ++rit) {
     // If tab id is not valid, we only compare url, otherwise we compare both.
-    if (rit->destination_url == search_url &&
+    if (rit->GetDestinationUrl() == search_url &&
         (target_tab_id == -1 || rit->target_tab_id == target_tab_id)) {
       // If both source_url and source_main_frame_url are empty, and this
       // navigation is not triggered by user, a retargeting navigation probably
@@ -417,7 +428,7 @@
           !rit->is_user_initiated) {
         // If there is a server redirection immediately after retargeting, we
         // need to adjust our search url to the original request.
-        if (rit->has_server_redirect){
+        if (!rit->server_redirect_urls.empty()) {
           NavigationEvent* retargeting_nav_event =
               FindNavigationEvent(rit->original_request_url,
                                   GURL(),
@@ -425,8 +436,8 @@
           if (!retargeting_nav_event)
             return nullptr;
           // Adjust retargeting navigation event's attributes.
-          retargeting_nav_event->has_server_redirect = true;
-          retargeting_nav_event->destination_url = search_url;
+          retargeting_nav_event->server_redirect_urls.push_back(
+              std::move(search_url));
           return retargeting_nav_event;
         } else {
           continue;
@@ -442,28 +453,49 @@
 void SafeBrowsingNavigationObserverManager::AddToReferrerChain(
     ReferrerChain* referrer_chain,
     NavigationEvent* nav_event,
+    const GURL& destination_main_frame_url,
     ReferrerChainEntry::URLType type) {
-  ReferrerChainEntry referrer_chain_entry;
-  referrer_chain_entry.set_url(nav_event->destination_url.spec());
-  referrer_chain_entry.set_type(type);
-  auto ip_it = host_to_ip_map_.find(nav_event->destination_url.host());
+  std::unique_ptr<ReferrerChainEntry> referrer_chain_entry =
+      base::MakeUnique<ReferrerChainEntry>();
+  const GURL destination_url = nav_event->GetDestinationUrl();
+  referrer_chain_entry->set_url(destination_url.spec());
+  if (destination_main_frame_url.is_valid() &&
+      destination_url != destination_main_frame_url)
+    referrer_chain_entry->set_main_frame_url(destination_main_frame_url.spec());
+  referrer_chain_entry->set_type(type);
+  auto ip_it = host_to_ip_map_.find(destination_url.host());
   if (ip_it != host_to_ip_map_.end()) {
     for (ResolvedIPAddress entry : ip_it->second) {
-      referrer_chain_entry.add_ip_addresses(entry.ip);
+      referrer_chain_entry->add_ip_addresses(entry.ip);
     }
   }
   // Since we only track navigation to landing referrer, we will not log the
   // referrer of the landing referrer page.
   if (type != ReferrerChainEntry::LANDING_REFERRER) {
-    referrer_chain_entry.set_referrer_url(nav_event->source_url.spec());
-    referrer_chain_entry.set_referrer_main_frame_url(
-        nav_event->source_main_frame_url.spec());
+    referrer_chain_entry->set_referrer_url(nav_event->source_url.spec());
+    // Only set |referrer_main_frame_url| if it is diff from |referrer_url|.
+    if (nav_event->source_main_frame_url.is_valid() &&
+        nav_event->source_url != nav_event->source_main_frame_url) {
+      referrer_chain_entry->set_referrer_main_frame_url(
+          nav_event->source_main_frame_url.spec());
+    }
   }
-  referrer_chain_entry.set_is_retargeting(nav_event->source_tab_id !=
-                                          nav_event->target_tab_id);
-  referrer_chain_entry.set_navigation_time_msec(
+  referrer_chain_entry->set_is_retargeting(nav_event->source_tab_id !=
+                                           nav_event->target_tab_id);
+  referrer_chain_entry->set_navigation_time_msec(
       nav_event->last_updated.ToJavaTime());
-  referrer_chain->Add()->Swap(&referrer_chain_entry);
+  if (!nav_event->server_redirect_urls.empty()) {
+    // The first entry in |server_redirect_chain| should be the original request
+    // url.
+    ReferrerChainEntry::ServerRedirect* server_redirect =
+        referrer_chain_entry->add_server_redirect_chain();
+    server_redirect->set_url(nav_event->original_request_url.spec());
+    for (const GURL& redirect : nav_event->server_redirect_urls) {
+      server_redirect = referrer_chain_entry->add_server_redirect_chain();
+      server_redirect->set_url(redirect.spec());
+    }
+  }
+  referrer_chain->Add()->Swap(referrer_chain_entry.get());
 }
 
 void SafeBrowsingNavigationObserverManager::GetRemainingReferrerChain(
@@ -472,7 +504,7 @@
     int user_gesture_count_limit,
     ReferrerChain* out_referrer_chain,
     SafeBrowsingNavigationObserverManager::AttributionResult* out_result) {
-
+  GURL last_main_frame_url_traced(last_nav_event_traced->source_main_frame_url);
   while (current_user_gesture_count < user_gesture_count_limit) {
     // Back trace to the next nav_event that was initiated by the user.
     while (!last_nav_event_traced->is_user_initiated) {
@@ -483,9 +515,9 @@
       if (!last_nav_event_traced)
         return;
       AddToReferrerChain(out_referrer_chain, last_nav_event_traced,
-                         last_nav_event_traced->has_server_redirect
-                             ? ReferrerChainEntry::SERVER_REDIRECT
-                             : ReferrerChainEntry::CLIENT_REDIRECT);
+                         last_main_frame_url_traced,
+                         ReferrerChainEntry::CLIENT_REDIRECT);
+      last_main_frame_url_traced = last_nav_event_traced->source_main_frame_url;
     }
 
     current_user_gesture_count++;
@@ -508,11 +540,12 @@
     if (!last_nav_event_traced)
       return;
 
-    AddToReferrerChain(out_referrer_chain, last_nav_event_traced,
-                       GetURLTypeAndAdjustAttributionResult(
-                          current_user_gesture_count ==
-                              user_gesture_count_limit,
-                          out_result));
+    AddToReferrerChain(
+        out_referrer_chain, last_nav_event_traced, last_main_frame_url_traced,
+        GetURLTypeAndAdjustAttributionResult(
+            current_user_gesture_count == user_gesture_count_limit,
+            out_result));
+    last_main_frame_url_traced = last_nav_event_traced->source_main_frame_url;
   }
 }
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h
index 1321c43..f8d2910 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h
@@ -118,6 +118,7 @@
   // to |out_referrer_chain|.
   AttributionResult IdentifyReferrerChainForPPAPIDownload(
       const GURL& initiating_frame_url,
+      const GURL& initiating_main_frame_url,
       int tab_id,
       bool has_user_gesture,
       int user_gesture_count_limit,
@@ -198,6 +199,7 @@
 
   void AddToReferrerChain(ReferrerChain* referrer_chain,
                           NavigationEvent* nav_event,
+                          const GURL& destination_main_frame_url,
                           ReferrerChainEntry::URLType type);
 
   // Helper function to get the remaining referrer chain when we've already
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_unittest.cc
index f38dcf8e..87ad2a3a 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_unittest.cc
@@ -2,15 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/test/histogram_tester.h"
 #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer.h"
 #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "content/public/test/test_renderer_host.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/window_open_disposition.h"
 
+namespace {
+
+const char kNavigationEventCleanUpHistogramName[] =
+    "SafeBrowsing.NavigationObserver.NavigationEventCleanUpCount";
+const char kIPAddressCleanUpHistogramName[] =
+    "SafeBrowsing.NavigationObserver.IPAddressCleanUpCount";
+}
+
 namespace safe_browsing {
 
 class SBNavigationObserverTest : public BrowserWithTestWindowTest {
@@ -43,13 +53,13 @@
               actual_nav_event.source_main_frame_url);
     EXPECT_EQ(expected_original_request_url,
               actual_nav_event.original_request_url);
-    EXPECT_EQ(expected_destination_url, actual_nav_event.destination_url);
+    EXPECT_EQ(expected_destination_url, actual_nav_event.GetDestinationUrl());
     EXPECT_EQ(expected_source_tab, actual_nav_event.source_tab_id);
     EXPECT_EQ(expected_target_tab, actual_nav_event.target_tab_id);
     EXPECT_EQ(expected_is_user_initiated, actual_nav_event.is_user_initiated);
     EXPECT_EQ(expected_has_committed, actual_nav_event.has_committed);
     EXPECT_EQ(expected_has_server_redirect,
-              actual_nav_event.has_server_redirect);
+              !actual_nav_event.server_redirect_urls.empty());
   }
 
   SafeBrowsingNavigationObserverManager::NavigationMap* navigation_map() {
@@ -64,10 +74,14 @@
     return &navigation_observer_manager_->host_to_ip_map_;
   }
 
+  void RecordHostToIpMapping(const std::string& host, const std::string& ip) {
+    navigation_observer_manager_->RecordHostToIpMapping(host, ip);
+  }
+
   NavigationEvent CreateNavigationEvent(const GURL& destination_url,
                                         const base::Time& timestamp) {
     NavigationEvent nav_event;
-    nav_event.destination_url = destination_url;
+    nav_event.original_request_url = destination_url;
     nav_event.last_updated = timestamp;
     return nav_event;
   }
@@ -103,8 +117,8 @@
   CommitPendingLoad(controller);
   int tab_id = SessionTabHelper::IdForTab(controller->GetWebContents());
   auto nav_map = navigation_map();
-  ASSERT_EQ(std::size_t(1), nav_map->size());
-  ASSERT_EQ(std::size_t(1), nav_map->at(GURL("http://foo/1")).size());
+  ASSERT_EQ(1U, nav_map->size());
+  ASSERT_EQ(1U, nav_map->at(GURL("http://foo/1")).size());
   VerifyNavigationEvent(GURL(),                // source_url
                         GURL(),                // source_main_frame_url
                         GURL("http://foo/1"),  // original_request_url
@@ -128,8 +142,8 @@
   int tab_id = SessionTabHelper::IdForTab(
       browser()->tab_strip_model()->GetWebContentsAt(0));
   auto nav_map = navigation_map();
-  ASSERT_EQ(std::size_t(1), nav_map->size());
-  ASSERT_EQ(std::size_t(1), nav_map->at(redirect).size());
+  ASSERT_EQ(1U, nav_map->size());
+  ASSERT_EQ(1U, nav_map->at(redirect).size());
   VerifyNavigationEvent(GURL("http://foo/0"),       // source_url
                         GURL("http://foo/0"),       // source_main_frame_url
                         GURL("http://foo/3"),       // original_request_url
@@ -169,17 +183,22 @@
       CreateNavigationEvent(url_0, one_hour_ago));
   navigation_map()->at(url_1).push_back(
       CreateNavigationEvent(url_0, one_hour_ago));
-  ASSERT_EQ(std::size_t(2), navigation_map()->size());
-  ASSERT_EQ(std::size_t(4), navigation_map()->at(url_0).size());
-  ASSERT_EQ(std::size_t(2), navigation_map()->at(url_1).size());
+  ASSERT_EQ(2U, navigation_map()->size());
+  ASSERT_EQ(4U, navigation_map()->at(url_0).size());
+  ASSERT_EQ(2U, navigation_map()->at(url_1).size());
+
+  base::HistogramTester histograms;
+  histograms.ExpectTotalCount(kNavigationEventCleanUpHistogramName, 0);
 
   // Cleans up navigation events.
   CleanUpNavigationEvents();
 
   // Verifies all stale and invalid navigation events are removed.
-  ASSERT_EQ(std::size_t(1), navigation_map()->size());
+  ASSERT_EQ(1U, navigation_map()->size());
   EXPECT_EQ(navigation_map()->end(), navigation_map()->find(url_1));
-  EXPECT_EQ(std::size_t(2), navigation_map()->at(url_0).size());
+  EXPECT_EQ(2U, navigation_map()->at(url_0).size());
+  EXPECT_THAT(histograms.GetAllSamples(kNavigationEventCleanUpHistogramName),
+              testing::ElementsAre(base::Bucket(4, 1)));
 }
 
 TEST_F(SBNavigationObserverTest, TestCleanUpStaleUserGestures) {
@@ -201,13 +220,13 @@
   user_gesture_map()->insert(std::make_pair(content0, now));
   user_gesture_map()->insert(std::make_pair(content1, one_minute_ago));
   user_gesture_map()->insert(std::make_pair(content2, in_an_hour));
-  ASSERT_EQ(std::size_t(3), user_gesture_map()->size());
+  ASSERT_EQ(3U, user_gesture_map()->size());
 
   // Cleans up user_gesture_map()
   CleanUpUserGestures();
 
   // Verifies all stale and invalid user gestures are removed.
-  ASSERT_EQ(std::size_t(1), user_gesture_map()->size());
+  ASSERT_EQ(1U, user_gesture_map()->size());
   EXPECT_NE(user_gesture_map()->end(), user_gesture_map()->find(content0));
   EXPECT_EQ(now, user_gesture_map()->at(content0));
 }
@@ -231,16 +250,57 @@
       std::make_pair(host_1, std::vector<ResolvedIPAddress>()));
   host_to_ip_map()->at(host_1).push_back(
       ResolvedIPAddress(in_an_hour, "3.3.3.3"));
-  ASSERT_EQ(std::size_t(2), host_to_ip_map()->size());
+  ASSERT_EQ(2U, host_to_ip_map()->size());
+
+  base::HistogramTester histograms;
+  histograms.ExpectTotalCount(kIPAddressCleanUpHistogramName, 0);
 
   // Cleans up host_to_ip_map()
   CleanUpIpAddresses();
 
   // Verifies all stale and invalid IP addresses are removed.
-  ASSERT_EQ(std::size_t(1), host_to_ip_map()->size());
+  ASSERT_EQ(1U, host_to_ip_map()->size());
   EXPECT_EQ(host_to_ip_map()->end(), host_to_ip_map()->find(host_1));
-  ASSERT_EQ(std::size_t(1), host_to_ip_map()->at(host_0).size());
+  ASSERT_EQ(1U, host_to_ip_map()->at(host_0).size());
   EXPECT_EQ(now, host_to_ip_map()->at(host_0).front().timestamp);
+  EXPECT_THAT(histograms.GetAllSamples(kIPAddressCleanUpHistogramName),
+              testing::ElementsAre(base::Bucket(2, 1)));
+}
+
+TEST_F(SBNavigationObserverTest, TestRecordHostToIpMapping) {
+  // Setup host_to_ip_map().
+  base::Time now = base::Time::Now();  // Fresh
+  base::Time one_hour_ago =
+      base::Time::FromDoubleT(now.ToDoubleT() - 60.0 * 60.0);  // Stale
+  std::string host_0 = GURL("http://foo/0").host();
+  host_to_ip_map()->insert(
+      std::make_pair(host_0, std::vector<ResolvedIPAddress>()));
+  host_to_ip_map()->at(host_0).push_back(ResolvedIPAddress(now, "1.1.1.1"));
+  host_to_ip_map()->at(host_0).push_back(
+      ResolvedIPAddress(one_hour_ago, "2.2.2.2"));
+
+  // Record a host-IP pair, where host is already in the map, and IP has
+  // never been seen before.
+  RecordHostToIpMapping(host_0, "3.3.3.3");
+  ASSERT_EQ(1U, host_to_ip_map()->size());
+  EXPECT_EQ(3U, host_to_ip_map()->at(host_0).size());
+  EXPECT_EQ("3.3.3.3", host_to_ip_map()->at(host_0).at(2).ip);
+
+  // Record a host-IP pair which is already in the map. It should simply update
+  // its timestamp.
+  ASSERT_EQ(now, host_to_ip_map()->at(host_0).at(0).timestamp);
+  RecordHostToIpMapping(host_0, "1.1.1.1");
+  ASSERT_EQ(1U, host_to_ip_map()->size());
+  EXPECT_EQ(3U, host_to_ip_map()->at(host_0).size());
+  EXPECT_LT(now, host_to_ip_map()->at(host_0).at(2).timestamp);
+
+  // Record a host-ip pair, neither of which has been seen before.
+  std::string host_1 = GURL("http://bar/1").host();
+  RecordHostToIpMapping(host_1, "9.9.9.9");
+  ASSERT_EQ(2U, host_to_ip_map()->size());
+  EXPECT_EQ(3U, host_to_ip_map()->at(host_0).size());
+  EXPECT_EQ(1U, host_to_ip_map()->at(host_1).size());
+  EXPECT_EQ("9.9.9.9", host_to_ip_map()->at(host_1).at(0).ip);
 }
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 1196f4f..09c30ee 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/sync/chrome_sync_client.h"
 
-#include <memory>
 #include <utility>
 
 #include "base/bind.h"
diff --git a/chrome/browser/sync/chrome_sync_client_unittest.cc b/chrome/browser/sync/chrome_sync_client_unittest.cc
index 5f9b34e1..eba8a49b 100644
--- a/chrome/browser/sync/chrome_sync_client_unittest.cc
+++ b/chrome/browser/sync/chrome_sync_client_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/sync/chrome_sync_client.h"
 
-#include <memory>
 #include <string>
 
 #include "chrome/common/url_constants.h"
diff --git a/chrome/browser/sync/glue/extensions_activity_monitor.cc b/chrome/browser/sync/glue/extensions_activity_monitor.cc
index bb48f56c..c537aa0 100644
--- a/chrome/browser/sync/glue/extensions_activity_monitor.cc
+++ b/chrome/browser/sync/glue/extensions_activity_monitor.cc
@@ -6,7 +6,6 @@
 
 #include "components/sync/base/extensions_activity.h"
 #include "content/public/browser/browser_thread.h"
-#include "extensions/features/features.h"
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "chrome/browser/chrome_notification_types.h"
diff --git a/chrome/browser/sync/glue/synced_tab_delegate_android.h b/chrome/browser/sync/glue/synced_tab_delegate_android.h
index 4ed64f1c..21d7fa4 100644
--- a/chrome/browser/sync/glue/synced_tab_delegate_android.h
+++ b/chrome/browser/sync/glue/synced_tab_delegate_android.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_SYNC_GLUE_SYNCED_TAB_DELEGATE_ANDROID_H_
 #define CHROME_BROWSER_SYNC_GLUE_SYNCED_TAB_DELEGATE_ANDROID_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
diff --git a/chrome/browser/sync/profile_sync_service_factory_unittest.cc b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
index cf641806..b831543 100644
--- a/chrome/browser/sync/profile_sync_service_factory_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
@@ -6,7 +6,6 @@
 
 #include <stddef.h>
 
-#include <memory>
 #include <vector>
 
 #include "base/command_line.h"
diff --git a/chrome/browser/sync/test/integration/migration_waiter.cc b/chrome/browser/sync/test/integration/migration_waiter.cc
index 3e9163d..37db9b30 100644
--- a/chrome/browser/sync/test/integration/migration_waiter.cc
+++ b/chrome/browser/sync/test/integration/migration_waiter.cc
@@ -4,8 +4,6 @@
 
 #include "chrome/browser/sync/test/integration/migration_waiter.h"
 
-#include <string>
-
 #include "base/logging.h"
 #include "chrome/browser/sync/test/integration/migration_watcher.h"
 
diff --git a/chrome/browser/sync/test/integration/multi_client_status_change_checker.cc b/chrome/browser/sync/test/integration/multi_client_status_change_checker.cc
index 1b8868a5..6d03381e 100644
--- a/chrome/browser/sync/test/integration/multi_client_status_change_checker.cc
+++ b/chrome/browser/sync/test/integration/multi_client_status_change_checker.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h"
 
 #include "base/logging.h"
-#include "base/scoped_observer.h"
 #include "components/browser_sync/profile_sync_service.h"
 
 MultiClientStatusChangeChecker::MultiClientStatusChangeChecker(
diff --git a/chrome/browser/sync/test/integration/passwords_helper.cc b/chrome/browser/sync/test/integration/passwords_helper.cc
index 84b6cfaf..c666e53d 100644
--- a/chrome/browser/sync/test/integration/passwords_helper.cc
+++ b/chrome/browser/sync/test/integration/passwords_helper.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/sync/test/integration/passwords_helper.h"
 
 #include <sstream>
-#include <string>
 #include <utility>
 
 #include "base/compiler_specific.h"
diff --git a/chrome/browser/sync/test/integration/sync_integration_test_util.cc b/chrome/browser/sync/test/integration/sync_integration_test_util.cc
index 9ce060f..42ef3e24 100644
--- a/chrome/browser/sync/test/integration/sync_integration_test_util.cc
+++ b/chrome/browser/sync/test/integration/sync_integration_test_util.cc
@@ -4,10 +4,7 @@
 
 #include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
 
-#include <string>
-
 #include "base/strings/stringprintf.h"
-#include "chrome/browser/sync/test/integration/fake_server_match_status_checker.h"
 #include "components/browser_sync/profile_sync_service.h"
 
 ServerCountMatchStatusChecker::ServerCountMatchStatusChecker(
diff --git a/chrome/browser/ui/cocoa/view_id_util.mm b/chrome/browser/ui/cocoa/view_id_util.mm
index 6dd19ada..f97c795388 100644
--- a/chrome/browser/ui/cocoa/view_id_util.mm
+++ b/chrome/browser/ui/cocoa/view_id_util.mm
@@ -9,7 +9,6 @@
 #include <map>
 #include <utility>
 
-#include "base/lazy_instance.h"
 #include "base/logging.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
@@ -21,7 +20,10 @@
 // rather than using a separated map.
 typedef std::map<NSView*, ViewID> ViewIDMap;
 
-static base::LazyInstance<ViewIDMap> g_view_id_map = LAZY_INSTANCE_INITIALIZER;
+ViewIDMap* GetViewIDMap() {
+  static auto view_id_map = new ViewIDMap();
+  return view_id_map;
+}
 
 // Returns the view's nearest descendant (including itself) with a specific
 // ViewID, or nil if no subview has that ViewID.
@@ -46,12 +48,12 @@
   DCHECK(viewID != VIEW_ID_NONE);
   // We handle VIEW_ID_TAB_0 to VIEW_ID_TAB_LAST in GetView() function directly.
   DCHECK(!((viewID >= VIEW_ID_TAB_0) && (viewID <= VIEW_ID_TAB_LAST)));
-  g_view_id_map.Get()[view] = viewID;
+  (*GetViewIDMap())[view] = viewID;
 }
 
 void UnsetID(NSView* view) {
   DCHECK(view);
-  g_view_id_map.Get().erase(view);
+  GetViewIDMap()->erase(view);
 }
 
 NSView* GetView(NSWindow* window, ViewID viewID) {
@@ -81,7 +83,7 @@
 @implementation NSView (ViewID)
 
 - (ViewID)viewID {
-  ViewIDMap* map = g_view_id_map.Pointer();
+  const ViewIDMap* map = GetViewIDMap();
   ViewIDMap::const_iterator iter = map->find(self);
   return iter != map->end() ? iter->second : VIEW_ID_NONE;
 }
diff --git a/chrome/browser/ui/sync/browser_synced_window_delegate.cc b/chrome/browser/ui/sync/browser_synced_window_delegate.cc
index 57232ef..26f812a 100644
--- a/chrome/browser/ui/sync/browser_synced_window_delegate.cc
+++ b/chrome/browser/ui/sync/browser_synced_window_delegate.cc
@@ -10,7 +10,6 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/sync/tab_contents_synced_tab_delegate.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "components/sessions/core/session_id.h"
 
 BrowserSyncedWindowDelegate::BrowserSyncedWindowDelegate(Browser* browser)
     : browser_(browser) {}
diff --git a/chrome/browser/ui/sync/one_click_signin_links_delegate.h b/chrome/browser/ui/sync/one_click_signin_links_delegate.h
index 57c0d55..3355446 100644
--- a/chrome/browser/ui/sync/one_click_signin_links_delegate.h
+++ b/chrome/browser/ui/sync/one_click_signin_links_delegate.h
@@ -17,6 +17,7 @@
  protected:
   OneClickSigninLinksDelegate() {}
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(OneClickSigninLinksDelegate);
 };
 
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_observer.cc b/chrome/browser/ui/sync/one_click_signin_sync_observer.cc
index 1606d38..443830b 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_observer.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_observer.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/sync/one_click_signin_sync_observer.h"
 
+#include <string>
+
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc b/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc
index 7fcba1d3..8d0bff8 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc
@@ -10,7 +10,6 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
@@ -47,7 +46,7 @@
   // navigation start is a sufficient signal for the purposes of this test.
   // Listening for this call also has the advantage of being synchronous.
   MOCK_METHOD1(DidStartNavigation, void(content::NavigationHandle*));
-  // TODO: remove this method when PlzNavigate is turned on by default.
+  // TODO(jam): remove this method when PlzNavigate is turned on by default.
   MOCK_METHOD2(DidStartNavigationToPendingEntry,
                void(const GURL&, content::ReloadType));
 };
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
index 75b3376..1ad06fa 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/policy/cloud/user_policy_signin_service.h"
 #include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter_unittest.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter_unittest.cc
index aa78d980..9c19239 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter_unittest.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter_unittest.cc
@@ -4,11 +4,8 @@
 
 #include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
 
-#include <memory>
-
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
-#include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
diff --git a/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc b/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
index 5c81cb0..d6dd307 100644
--- a/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
+++ b/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
@@ -5,10 +5,10 @@
 #include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h"
 
 #include <memory>
+#include <string>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/callback.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
diff --git a/chrome/browser/ui/sync/sync_promo_ui.h b/chrome/browser/ui/sync/sync_promo_ui.h
index 1af94bc..1acb3a2 100644
--- a/chrome/browser/ui/sync/sync_promo_ui.h
+++ b/chrome/browser/ui/sync/sync_promo_ui.h
@@ -13,7 +13,6 @@
   // Returns true if the sync promo should be visible.
   // |profile| is the profile for which the promo would be displayed.
   static bool ShouldShowSyncPromo(Profile* profile);
-
 };
 
 #endif  // CHROME_BROWSER_UI_SYNC_SYNC_PROMO_UI_H_
diff --git a/chrome/browser/ui/sync/tab_contents_synced_tab_delegate.h b/chrome/browser/ui/sync/tab_contents_synced_tab_delegate.h
index c5c6416..38e8a2e 100644
--- a/chrome/browser/ui/sync/tab_contents_synced_tab_delegate.h
+++ b/chrome/browser/ui/sync/tab_contents_synced_tab_delegate.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_SYNC_TAB_CONTENTS_SYNCED_TAB_DELEGATE_H_
 #define CHROME_BROWSER_UI_SYNC_TAB_CONTENTS_SYNCED_TAB_DELEGATE_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
diff --git a/chrome/browser/ui/views/infobars/infobar_container_view.cc b/chrome/browser/ui/views/infobars/infobar_container_view.cc
index 82f94a0e..bbe5606 100644
--- a/chrome/browser/ui/views/infobars/infobar_container_view.cc
+++ b/chrome/browser/ui/views/infobars/infobar_container_view.cc
@@ -11,7 +11,7 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/canvas.h"
-#include "ui/gfx/skia_util.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/views/view_targeter.h"
 
 namespace {
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index b8483264..3ae347c 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -519,12 +519,24 @@
     { "configurePinTooShort", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_TOO_SHORT} ,
     { "configurePinTooLong", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_TOO_LONG} ,
     { "configurePinWeakPin", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_WEAK_PIN },
+    { "lockScreenAddFingerprint",
+      IDS_SETTINGS_PEOPLE_LOCK_SCREEN_ADD_FINGERPRINT_BUTTON},
+    { "lockScreenCannotAddFingerprint",
+      IDS_SETTINGS_PEOPLE_LOCK_SCREEN_CANNOT_ADD_NEW_FINGERPRINT},
     { "lockScreenChangePinButton",
       IDS_SETTINGS_PEOPLE_LOCK_SCREEN_CHANGE_PIN_BUTTON},
+    { "lockScreenFingerprintEnable",
+      IDS_SETTINGS_PEOPLE_LOCK_SCREEN_ENABLE_FINGERPRINT_CHECKBOX_LABEL},
+    { "lockScreenFingerprintNewName",
+      IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NEW_FINGERPRINT_DEFAULT_NAME},
+    { "lockScreenFingerprintWarning",
+      IDS_SETTINGS_PEOPLE_LOCK_SCREEN_FINGERPRINT_LESS_SECURE},
     { "lockScreenNone", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NONE },
     { "lockScreenPasswordOnly", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_PASSWORD_ONLY },
     { "lockScreenPinOrPassword",
       IDS_SETTINGS_PEOPLE_LOCK_SCREEN_PIN_OR_PASSWORD },
+    { "lockScreenRegisteredFingerprints",
+      IDS_SETTINGS_PEOPLE_LOCK_SCREEN_REGISTERED_FINGERPRINTS_LABEL},
     { "lockScreenSetupPinButton",
       IDS_SETTINGS_PEOPLE_LOCK_SCREEN_SETUP_PIN_BUTTON },
     { "lockScreenTitle", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_TITLE },
@@ -770,6 +782,8 @@
 
   values->SetBoolean("showQuickUnlockSettings",
                      chromeos::IsPinUnlockEnabled(profile->GetPrefs()));
+  values->SetBoolean("fingerprintUnlockEnabled",
+                     chromeos::IsFingerprintUnlockEnabled());
   if (chromeos::IsPinUnlockEnabled(profile->GetPrefs())) {
     values->SetString(
         "enableScreenlock",
diff --git a/chrome/browser/ui/webui/options/options_ui.cc b/chrome/browser/ui/webui/options/options_ui.cc
index bfd84cf..91aca4e 100644
--- a/chrome/browser/ui/webui/options/options_ui.cc
+++ b/chrome/browser/ui/webui/options/options_ui.cc
@@ -139,6 +139,8 @@
 constexpr char kLockScreenJSPath[] = "people_page/lock_screen.js";
 constexpr char kSetupPinHTMLPath[] = "people_page/setup_pin_dialog.html";
 constexpr char kSetupPinJSPath[] = "people_page/setup_pin_dialog.js";
+constexpr char kFingerprintListHTMLPath[] = "people_page/fingerprint_list.html";
+constexpr char kFingerprintListJSPath[] = "people_page/fingerprint_list.js";
 constexpr char kSettingsRouteHTMLPath[] = "route.html";
 constexpr char kSettingsRouteJSPath[] = "route.js";
 constexpr char kSettingsSharedCSSHTMLPath[] = "settings_shared_css.html";
@@ -269,6 +271,8 @@
 void OptionsUIHTMLSource::CreateDataSourceMap() {
 #if defined(OS_CHROMEOS)
   path_to_idr_map_[kIconsHTMLPath] = IDR_OPTIONS_ICONS_HTML;
+
+  // These are part of the LockScreen UI.
   path_to_idr_map_[kPinKeyboardHTMLPath] = IDR_OPTIONS_PIN_KEYBOARD_HTML;
   path_to_idr_map_[kPinKeyboardJSPath] = IDR_OPTIONS_PIN_KEYBOARD_JS;
   path_to_idr_map_[kPasswordPromptDialogHTMLPath] =
@@ -287,6 +291,10 @@
   path_to_idr_map_[kLockScreenJSPath] = IDR_OPTIONS_LOCK_SCREEN_JS;
   path_to_idr_map_[kSetupPinHTMLPath] = IDR_OPTIONS_SETUP_PIN_DIALOG_HTML;
   path_to_idr_map_[kSetupPinJSPath] = IDR_OPTIONS_SETUP_PIN_DIALOG_JS;
+  path_to_idr_map_[kFingerprintListHTMLPath] =
+      IDR_OPTIONS_FINGERPRINT_LIST_HTML;
+  path_to_idr_map_[kFingerprintListJSPath] = IDR_OPTIONS_FINGERPRINT_LIST_JS;
+
   path_to_idr_map_[kSettingsRouteHTMLPath] = IDR_OPTIONS_ROUTE_HTML;
   path_to_idr_map_[kSettingsRouteJSPath] = IDR_OPTIONS_ROUTE_JS;
   path_to_idr_map_[kSettingsSharedCSSHTMLPath] = IDR_SETTINGS_SHARED_CSS_HTML;
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 80fd859..8351265a 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -1096,12 +1096,24 @@
     {"configurePinTooLong", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_TOO_LONG},
     {"configurePinWeakPin", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_WEAK_PIN},
     {"enableScreenlock", IDS_SETTINGS_PEOPLE_ENABLE_SCREENLOCK},
+    {"lockScreenAddFingerprint",
+     IDS_SETTINGS_PEOPLE_LOCK_SCREEN_ADD_FINGERPRINT_BUTTON},
+    {"lockScreenCannotAddFingerprint",
+     IDS_SETTINGS_PEOPLE_LOCK_SCREEN_CANNOT_ADD_NEW_FINGERPRINT},
     {"lockScreenChangePinButton",
      IDS_SETTINGS_PEOPLE_LOCK_SCREEN_CHANGE_PIN_BUTTON},
     {"lockScreenNone", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NONE},
+    {"lockScreenFingerprintEnable",
+     IDS_SETTINGS_PEOPLE_LOCK_SCREEN_ENABLE_FINGERPRINT_CHECKBOX_LABEL},
+    {"lockScreenFingerprintNewName",
+     IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NEW_FINGERPRINT_DEFAULT_NAME},
+    {"lockScreenFingerprintWarning",
+     IDS_SETTINGS_PEOPLE_LOCK_SCREEN_FINGERPRINT_LESS_SECURE},
     {"lockScreenPasswordOnly", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_PASSWORD_ONLY},
     {"lockScreenPinOrPassword",
      IDS_SETTINGS_PEOPLE_LOCK_SCREEN_PIN_OR_PASSWORD},
+    {"lockScreenRegisteredFingerprints",
+     IDS_SETTINGS_PEOPLE_LOCK_SCREEN_REGISTERED_FINGERPRINTS_LABEL},
     {"lockScreenSetupPinButton",
      IDS_SETTINGS_PEOPLE_LOCK_SCREEN_SETUP_PIN_BUTTON},
     {"lockScreenTitle", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_TITLE},
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index 7a1f403..3a38cae 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -155,6 +155,8 @@
   html_source->AddBoolean("stylusAllowed", ash::IsPaletteFeatureEnabled());
   html_source->AddBoolean("pinUnlockEnabled",
                           chromeos::IsPinUnlockEnabled(profile->GetPrefs()));
+  html_source->AddBoolean("fingerprintUnlockEnabled",
+                          chromeos::IsFingerprintUnlockEnabled());
   html_source->AddBoolean("androidAppsAllowed",
                           arc::IsArcAllowedForProfile(profile) &&
                               !arc::IsArcOptInVerificationDisabled());
diff --git a/chrome/browser/ui/webui/vr_shell/vr_shell_ui_message_handler.cc b/chrome/browser/ui/webui/vr_shell/vr_shell_ui_message_handler.cc
index 0ac26da..f8314db 100644
--- a/chrome/browser/ui/webui/vr_shell/vr_shell_ui_message_handler.cc
+++ b/chrome/browser/ui/webui/vr_shell/vr_shell_ui_message_handler.cc
@@ -36,6 +36,10 @@
       "doAction", base::Bind(&VrShellUIMessageHandler::HandleDoAction,
                              base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
+      "setContentCssSize",
+      base::Bind(&VrShellUIMessageHandler::HandleSetContentCssSize,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
       "setUiCssSize", base::Bind(&VrShellUIMessageHandler::HandleSetUiCssSize,
                                  base::Unretained(this)));
 }
@@ -71,14 +75,30 @@
   }
 }
 
+void VrShellUIMessageHandler::HandleSetContentCssSize(
+    const base::ListValue* args) {
+  if (!vr_shell_)
+    return;
+  SetSize(args, false);
+}
+
 void VrShellUIMessageHandler::HandleSetUiCssSize(const base::ListValue* args) {
+  if (!vr_shell_)
+    return;
+  SetSize(args, true);
+}
+
+void VrShellUIMessageHandler::SetSize(const base::ListValue* args,
+                                      bool for_ui) {
   CHECK(args->GetSize() == 3);
   double width, height, dpr;
   CHECK(args->GetDouble(0, &width));
   CHECK(args->GetDouble(1, &height));
   CHECK(args->GetDouble(2, &dpr));
-  if (vr_shell_) {
+  if (for_ui) {
     vr_shell_->SetUiCssSize(width, height, dpr);
+  } else  {
+    vr_shell_->SetContentCssSize(width, height, dpr);
   }
 }
 
diff --git a/chrome/browser/ui/webui/vr_shell/vr_shell_ui_message_handler.h b/chrome/browser/ui/webui/vr_shell/vr_shell_ui_message_handler.h
index 667ee3d..be0825e 100644
--- a/chrome/browser/ui/webui/vr_shell/vr_shell_ui_message_handler.h
+++ b/chrome/browser/ui/webui/vr_shell/vr_shell_ui_message_handler.h
@@ -34,7 +34,9 @@
   void HandleDomLoaded(const base::ListValue* args);
   void HandleUpdateScene(const base::ListValue* args);
   void HandleDoAction(const base::ListValue* args);
+  void HandleSetContentCssSize(const base::ListValue* args);
   void HandleSetUiCssSize(const base::ListValue* args);
+  void SetSize(const base::ListValue* args, bool for_ui);
 
   base::WeakPtr<vr_shell::VrShell> vr_shell_;
 
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 15a6efb..810c6db 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -247,10 +247,14 @@
 const base::Feature kOptInImeMenu{"OptInImeMenu",
                                   base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Enables or disables PIN quick unlock settings integration.
+// Enables or disables PIN quick unlock.
 const base::Feature kQuickUnlockPin{"QuickUnlockPin",
                                     base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Enables or disables fingerprint quick unlock.
+const base::Feature kQuickUnlockFingerprint{"QuickUnlockFingerprint",
+                                            base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables or disables emoji, handwriting and voice input on opt-in IME menu.
 const base::Feature kEHVInputOnImeMenu{"EmojiHandwritingVoiceInput",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 340aa7a..38bd2606 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -146,6 +146,8 @@
 
 extern const base::Feature kQuickUnlockPin;
 
+extern const base::Feature kQuickUnlockFingerprint;
+
 extern const base::Feature kEHVInputOnImeMenu;
 
 extern const base::Feature kCrosCompUpdates;
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 4c599779..e4cd9d0 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -256,14 +256,12 @@
 extern const char kAuthAndroidNegotiateAccountType[];
 extern const char kDisableAppLink[];
 extern const char kDisableContextualSearch[];
-extern const char kDisableVrShell[];
 extern const char kEnableAccessibilityTabSwitcher[];
 extern const char kEnableAppLink[];
 extern const char kEnableContextualSearch[];
 extern const char kEnableContextualSearchContextualCardsBarIntegration[];
 extern const char kEnableHostedMode[];
 extern const char kEnableHungRendererInfoBar[];
-extern const char kEnableVrShell[];
 extern const char kForceShowUpdateMenuBadge[];
 extern const char kForceShowUpdateMenuItem[];
 extern const char kForceShowUpdateMenuItemCustomSummary[];
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index cdb94ce..d670a3e 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -944,6 +944,10 @@
 const char kPinUnlockMaximumLength[] = "pin_unlock_maximum_length";
 // Boolean pref indicating whether users are allowed to set easy pins.
 const char kPinUnlockWeakPinsAllowed[] = "pin_unlock_weak_pins_allowed";
+
+// Boolean pref indicating whether fingerprint unlock is enabled.
+const char kEnableQuickUnlockFingerprint[] =
+    "settings.enable_quick_unlock_fingerprint";
 #endif  // defined(OS_CHROMEOS)
 
 // A boolean pref set to true if a Home button to open the Home pages should be
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 3a2daef..3cc7fde 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -318,6 +318,7 @@
 extern const char kPinUnlockMinimumLength[];
 extern const char kPinUnlockMaximumLength[];
 extern const char kPinUnlockWeakPinsAllowed[];
+extern const char kEnableQuickUnlockFingerprint[];
 #endif  // defined(OS_CHROMEOS)
 extern const char kShowHomeButton[];
 extern const char kSpeechRecognitionFilterProfanities[];
diff --git a/chrome/common/safe_browsing/csd.proto b/chrome/common/safe_browsing/csd.proto
index cfdb94e..4089e56 100644
--- a/chrome/common/safe_browsing/csd.proto
+++ b/chrome/common/safe_browsing/csd.proto
@@ -386,6 +386,9 @@
   // order, i.e. download url comes first in this list, and landing referrer
   // comes last.
   repeated ReferrerChainEntry referrer_chain = 36;
+
+  // Whether DownloadAttribution Finch experiment is enabled for this ping.
+  optional bool download_attribution_finch_enabled = 39;
 }
 
 message ReferrerChainEntry {
@@ -394,14 +397,24 @@
     LANDING_PAGE = 2;
     LANDING_REFERRER = 3;
     CLIENT_REDIRECT = 4;
-    SERVER_REDIRECT = 5;
+    DEPRECATED_SERVER_REDIRECT = 5;  // Deprecated
+  }
+
+  message ServerRedirect {
+    // [required] server redirect url
+    optional string url = 1;
+
+    // Additional fields for future expansion.
   }
 
   // [required] The url of this Entry.
   optional string url = 1;
 
+  // Only set if it is different from |url|.
+  optional string main_frame_url = 9;
+
   // Type of URLs, such as download url, download referrer, etc.
-  optional URLType type = 2;
+  optional URLType type = 2 [default = CLIENT_REDIRECT];
 
   // IP addresses corresponding to this host.
   repeated string ip_addresses = 3;
@@ -410,13 +423,19 @@
   optional string referrer_url = 4;
 
   // Main frame URL of referrer.
+  // Only set if it is different from |referrer_url|.
   optional string referrer_main_frame_url = 5;
 
   // If this URL loads in a different tab/frame from previous one.
   optional bool is_retargeting = 6;
 
   optional double navigation_time_msec = 7;
-}  // End of URLChainEntry
+
+  // Set only if server redirects happened in navigation.
+  // The first entry in |server_redirect_chain| should be the original request
+  // url, and the last entry should be the same as |url|.
+  repeated ServerRedirect server_redirect_chain = 8;
+}  // End of ReferrerChainEntry
 
 message ClientDownloadResponse {
   enum Verdict {
diff --git a/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
index 104f0559..a4334ea 100644
--- a/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
+++ b/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
@@ -34,7 +34,9 @@
 using base::Time;
 using base::TimeDelta;
 using sync_pb::AutofillSpecifics;
+using sync_pb::EntityMetadata;
 using sync_pb::EntitySpecifics;
+using sync_pb::ModelTypeState;
 using syncer::DataBatch;
 using syncer::EntityChange;
 using syncer::EntityChangeList;
@@ -132,20 +134,18 @@
       db_.AddTable(&table_);
       db_.Init(temp_dir_.GetPath().AppendASCII("SyncTestWebDatabase"));
       backend_.SetWebDatabase(&db_);
-
-      sync_pb::ModelTypeState model_type_state;
-      model_type_state.set_initial_sync_done(true);
-      table_.UpdateModelTypeState(syncer::AUTOFILL, model_type_state);
-
-      bridge_.reset(new AutocompleteSyncBridge(
-          &backend_,
-          base::Bind(
-              &AutocompleteSyncBridgeTest::CreateModelTypeChangeProcessor,
-              base::Unretained(this))));
+      ResetBridge();
     }
   }
   ~AutocompleteSyncBridgeTest() override {}
 
+  void ResetBridge() {
+    bridge_.reset(new AutocompleteSyncBridge(
+        &backend_,
+        base::Bind(&AutocompleteSyncBridgeTest::CreateModelTypeChangeProcessor,
+                   base::Unretained(this))));
+  }
+
   void SaveSpecificsToTable(
       const std::vector<AutofillSpecifics>& specifics_list) {
     std::vector<AutofillEntry> new_entries;
@@ -582,8 +582,23 @@
 }
 
 TEST_F(AutocompleteSyncBridgeTest, LoadMetadataCalled) {
-  EXPECT_NE(processor()->metadata(), nullptr);
+  EXPECT_NE(nullptr, processor()->metadata());
+  EXPECT_FALSE(
+      processor()->metadata()->GetModelTypeState().initial_sync_done());
+  EXPECT_EQ(0u, processor()->metadata()->TakeAllMetadata().size());
+
+  ModelTypeState model_type_state;
+  model_type_state.set_initial_sync_done(true);
+  EXPECT_TRUE(
+      table()->UpdateModelTypeState(syncer::AUTOFILL, model_type_state));
+  EXPECT_TRUE(
+      table()->UpdateSyncMetadata(syncer::AUTOFILL, "key", EntityMetadata()));
+
+  ResetBridge();
+
+  EXPECT_NE(nullptr, processor()->metadata());
   EXPECT_TRUE(processor()->metadata()->GetModelTypeState().initial_sync_done());
+  EXPECT_EQ(1u, processor()->metadata()->TakeAllMetadata().size());
 }
 
 TEST_F(AutocompleteSyncBridgeTest, MergeSyncDataEmpty) {
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc
index 503eb0f..cdcfde8 100644
--- a/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -11,8 +11,7 @@
 #include <limits>
 #include <map>
 #include <set>
-#include <string>
-#include <vector>
+#include <utility>
 
 #include "base/command_line.h"
 #include "base/guid.h"
@@ -36,7 +35,6 @@
 #include "components/autofill/core/common/form_field_data.h"
 #include "components/os_crypt/os_crypt.h"
 #include "components/sync/base/model_type.h"
-#include "components/sync/model/metadata_batch.h"
 #include "components/sync/protocol/entity_metadata.pb.h"
 #include "components/sync/protocol/model_type_state.pb.h"
 #include "components/webdata/common/web_database.h"
@@ -1686,7 +1684,7 @@
   syncer::EntityMetadataMap metadata_records;
   if (GetAllSyncEntityMetadata(model_type, &metadata_records)) {
     for (const auto& pair : metadata_records) {
-      // todo(pnoland): add batch transfer of metadata map
+      // TODO(pnoland): Add batch transfer of metadata map.
       metadata_batch->AddMetadata(pair.first, pair.second);
     }
   } else {
@@ -1762,7 +1760,7 @@
       "SELECT value FROM autofill_model_type_state WHERE id=1"));
 
   if (!s.Step()) {
-    return false;
+    return true;
   }
 
   std::string serialized_state = s.ColumnString(0);
@@ -2527,4 +2525,4 @@
   return transaction.Commit();
 }
 
-}  // namespace autofill
\ No newline at end of file
+}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_table.h b/components/autofill/core/browser/webdata/autofill_table.h
index 2f5fff15..dc08b9b5 100644
--- a/components/autofill/core/browser/webdata/autofill_table.h
+++ b/components/autofill/core/browser/webdata/autofill_table.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "base/gtest_prod_util.h"
@@ -23,11 +24,6 @@
 class Time;
 }
 
-namespace sync_pb {
-class EntityMetadata;
-class ModelTypeState;
-}
-
 namespace autofill {
 
 class AutofillChange;
diff --git a/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/components/autofill/core/browser/webdata/autofill_table_unittest.cc
index cd93d29..2d784bb1e 100644
--- a/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -2,14 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <stddef.h>
+#include "components/autofill/core/browser/webdata/autofill_table.h"
 
 #include <map>
 #include <set>
-#include <string>
 #include <tuple>
 #include <utility>
-#include <vector>
 
 #include "base/command_line.h"
 #include "base/files/file_util.h"
@@ -29,7 +27,6 @@
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/webdata/autofill_change.h"
 #include "components/autofill/core/browser/webdata/autofill_entry.h"
-#include "components/autofill/core/browser/webdata/autofill_table.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #include "components/autofill/core/common/autofill_switches.h"
 #include "components/autofill/core/common/autofill_util.h"
@@ -44,6 +41,10 @@
 using base::ASCIIToUTF16;
 using base::Time;
 using base::TimeDelta;
+using sync_pb::EntityMetadata;
+using sync_pb::ModelTypeState;
+using syncer::EntityMetadataMap;
+using syncer::MetadataBatch;
 
 namespace autofill {
 
@@ -2021,8 +2022,16 @@
   }
 }
 
-TEST_F(AutofillTableTest, GetAllSyncMetadata) {
-  sync_pb::EntityMetadata metadata;
+TEST_F(AutofillTableTest, AutofillNoMetadata) {
+  MetadataBatch metadata_batch;
+  EXPECT_TRUE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
+  EXPECT_EQ(0u, metadata_batch.TakeAllMetadata().size());
+  EXPECT_EQ(ModelTypeState().SerializeAsString(),
+            metadata_batch.GetModelTypeState().SerializeAsString());
+}
+
+TEST_F(AutofillTableTest, AutofillGetAllSyncMetadata) {
+  EntityMetadata metadata;
   std::string storage_key = "storage_key";
   std::string storage_key2 = "storage_key2";
   metadata.set_sequence_number(1);
@@ -2030,7 +2039,7 @@
   EXPECT_TRUE(
       table_->UpdateSyncMetadata(syncer::AUTOFILL, storage_key, metadata));
 
-  sync_pb::ModelTypeState model_type_state;
+  ModelTypeState model_type_state;
   model_type_state.set_initial_sync_done(true);
 
   EXPECT_TRUE(table_->UpdateModelTypeState(syncer::AUTOFILL, model_type_state));
@@ -2039,12 +2048,12 @@
   EXPECT_TRUE(
       table_->UpdateSyncMetadata(syncer::AUTOFILL, storage_key2, metadata));
 
-  syncer::MetadataBatch metadata_batch;
+  MetadataBatch metadata_batch;
   EXPECT_TRUE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
 
   EXPECT_TRUE(metadata_batch.GetModelTypeState().initial_sync_done());
 
-  syncer::EntityMetadataMap metadata_records = metadata_batch.TakeAllMetadata();
+  EntityMetadataMap metadata_records = metadata_batch.TakeAllMetadata();
 
   EXPECT_EQ(metadata_records.size(), 2u);
   EXPECT_EQ(metadata_records[storage_key].sequence_number(), 1);
@@ -2058,11 +2067,11 @@
   EXPECT_FALSE(metadata_batch.GetModelTypeState().initial_sync_done());
 }
 
-TEST_F(AutofillTableTest, WriteThenDeleteSyncMetadata) {
-  sync_pb::EntityMetadata metadata;
-  syncer::MetadataBatch metadata_batch;
+TEST_F(AutofillTableTest, AutofillWriteThenDeleteSyncMetadata) {
+  EntityMetadata metadata;
+  MetadataBatch metadata_batch;
   std::string storage_key = "storage_key";
-  sync_pb::ModelTypeState model_type_state;
+  ModelTypeState model_type_state;
 
   model_type_state.set_initial_sync_done(true);
 
@@ -2077,32 +2086,35 @@
   // It shouldn't be there any more.
   EXPECT_TRUE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
 
-  syncer::EntityMetadataMap metadata_records = metadata_batch.TakeAllMetadata();
+  EntityMetadataMap metadata_records = metadata_batch.TakeAllMetadata();
   EXPECT_EQ(metadata_records.size(), 0u);
 
   // Now delete the model type state.
   EXPECT_TRUE(table_->ClearModelTypeState(syncer::AUTOFILL));
-  EXPECT_FALSE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
+  EXPECT_TRUE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
+  EXPECT_EQ(ModelTypeState().SerializeAsString(),
+            metadata_batch.GetModelTypeState().SerializeAsString());
 }
 
-TEST_F(AutofillTableTest, CorruptSyncMetadata) {
-  syncer::MetadataBatch metadata_batch;
-  sync_pb::ModelTypeState state;
-  std::string storage_key = "storage_key";
-
+TEST_F(AutofillTableTest, AutofillCorruptSyncMetadata) {
+  MetadataBatch metadata_batch;
   sql::Statement s(db_->GetSQLConnection()->GetUniqueStatement(
       "INSERT OR REPLACE INTO autofill_sync_metadata "
       "(storage_key, value) VALUES(?, ?)"));
-  s.BindString(0, storage_key);
+  s.BindString(0, "storage_key");
   s.BindString(1, "unparseable");
+  EXPECT_TRUE(s.Run());
 
-  sql::Statement s2(db_->GetSQLConnection()->GetUniqueStatement(
+  EXPECT_FALSE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
+}
+
+TEST_F(AutofillTableTest, AutofillCorruptModelTypeState) {
+  MetadataBatch metadata_batch;
+  sql::Statement s(db_->GetSQLConnection()->GetUniqueStatement(
       "INSERT OR REPLACE INTO autofill_model_type_state "
       "(rowid, value) VALUES(1, ?)"));
-  s2.BindString(0, "unparseable");
-
+  s.BindString(0, "unparseable");
   EXPECT_TRUE(s.Run());
-  EXPECT_TRUE(s2.Run());
 
   EXPECT_FALSE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
 }
diff --git a/components/browser_sync/PRESUBMIT.py b/components/browser_sync/PRESUBMIT.py
index ae61c433..c9212e9 100644
--- a/components/browser_sync/PRESUBMIT.py
+++ b/components/browser_sync/PRESUBMIT.py
@@ -12,11 +12,16 @@
 
 BROWSER_SYNC_SOURCE_FILES = (r'^components[\\/]browser_sync[\\/].*\.(cc|h)$',)
 
+# The wrapper around lint that is called below disables a set of filters if the
+# passed filter evaluates to false. Pass a junk filter to avoid this behavior.
+LINT_FILTERS = ['+fake/filter']
+
 def CheckChangeLintsClean(input_api, output_api):
   source_filter = lambda x: input_api.FilterSourceFile(
     x, white_list=BROWSER_SYNC_SOURCE_FILES, black_list=None)
   return input_api.canned_checks.CheckChangeLintsClean(
-      input_api, output_api, source_filter, lint_filters=[], verbose_level=1)
+      input_api, output_api, source_filter, lint_filters=LINT_FILTERS,
+      verbose_level=1)
 
 def CheckChanges(input_api, output_api):
   results = []
diff --git a/components/crash/core/common/objc_zombie.mm b/components/crash/core/common/objc_zombie.mm
index 7246b9b..c984dba 100644
--- a/components/crash/core/common/objc_zombie.mm
+++ b/components/crash/core/common/objc_zombie.mm
@@ -14,7 +14,6 @@
 
 #include "base/debug/crash_logging.h"
 #include "base/debug/stack_trace.h"
-#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/strings/stringprintf.h"
@@ -74,7 +73,10 @@
 BOOL g_zombieAllObjects = NO;
 
 // Protects |g_zombieCount|, |g_zombieIndex|, and |g_zombies|.
-base::LazyInstance<base::Lock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER;
+base::Lock& GetLock() {
+  static auto lock = new base::Lock();
+  return *lock;
+}
 
 // How many zombies to keep before freeing, and the current head of
 // the circular buffer.
@@ -140,7 +142,7 @@
 
   // Don't involve the lock when creating zombies without a treadmill.
   if (g_zombieCount > 0) {
-    base::AutoLock pin(g_lock.Get());
+    base::AutoLock pin(GetLock());
 
     // Check the count again in a thread-safe manner.
     if (g_zombieCount > 0) {
@@ -163,7 +165,7 @@
 BOOL GetZombieRecord(id object, ZombieRecord* record) {
   // Holding the lock is reasonable because this should be fast, and
   // the process is going to crash presently anyhow.
-  base::AutoLock pin(g_lock.Get());
+  base::AutoLock pin(GetLock());
   for (size_t i = 0; i < g_zombieCount; ++i) {
     if (g_zombies[i].object == object) {
       *record = g_zombies[i];
@@ -346,7 +348,7 @@
   ZombieRecord* oldZombies = g_zombies;
 
   {
-    base::AutoLock pin(g_lock.Get());
+    base::AutoLock pin(GetLock());
 
     // Save the old index in case zombies need to be transferred.
     size_t oldIndex = g_zombieIndex;
@@ -417,7 +419,7 @@
   ZombieRecord* oldZombies = g_zombies;
 
   {
-    base::AutoLock pin(g_lock.Get());  // In case any -dealloc are in progress.
+    base::AutoLock pin(GetLock());  // In case any -dealloc are in progress.
     g_zombieCount = 0;
     g_zombies = NULL;
   }
diff --git a/components/exo/buffer.cc b/components/exo/buffer.cc
index 430e66c..aa53bedb 100644
--- a/components/exo/buffer.cc
+++ b/components/exo/buffer.cc
@@ -524,6 +524,10 @@
   return gpu_memory_buffer_->GetSize();
 }
 
+gfx::BufferFormat Buffer::GetFormat() const {
+  return gpu_memory_buffer_->GetFormat();
+}
+
 std::unique_ptr<base::trace_event::TracedValue> Buffer::AsTracedValue() const {
   std::unique_ptr<base::trace_event::TracedValue> value(
       new base::trace_event::TracedValue());
diff --git a/components/exo/buffer.h b/components/exo/buffer.h
index 7ca10624..38be8a99 100644
--- a/components/exo/buffer.h
+++ b/components/exo/buffer.h
@@ -67,6 +67,9 @@
   // Returns the size of the buffer.
   gfx::Size GetSize() const;
 
+  // Returns the format of the buffer.
+  gfx::BufferFormat GetFormat() const;
+
   // Returns a trace value representing the state of the buffer.
   std::unique_ptr<base::trace_event::TracedValue> AsTracedValue() const;
 
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index fc958c4..f97b7a4 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -67,6 +67,22 @@
   return FindListEntry(list, key) != list.end();
 }
 
+// Helper function that returns true if |format| may have an alpha channel.
+// Note: False positives are allowed but false negatives are not.
+bool FormatHasAlpha(gfx::BufferFormat format) {
+  switch (format) {
+    case gfx::BufferFormat::BGR_565:
+    case gfx::BufferFormat::RGBX_8888:
+    case gfx::BufferFormat::BGRX_8888:
+    case gfx::BufferFormat::YVU_420:
+    case gfx::BufferFormat::YUV_420_BIPLANAR:
+    case gfx::BufferFormat::UYVY_422:
+      return false;
+    default:
+      return true;
+  }
+}
+
 class CustomWindowDelegate : public aura::WindowDelegate {
  public:
   explicit CustomWindowDelegate(Surface* surface) : surface_(surface) {}
@@ -417,10 +433,14 @@
     has_pending_layer_changes_ = true;
 
   if (has_pending_contents_) {
-    if (pending_buffer_.buffer() &&
-        (current_resource_.size != pending_buffer_.buffer()->GetSize())) {
-      has_pending_layer_changes_ = true;
-    } else if (!pending_buffer_.buffer() && !current_resource_.size.IsEmpty()) {
+    if (pending_buffer_.buffer()) {
+      if (current_resource_.size != pending_buffer_.buffer()->GetSize())
+        has_pending_layer_changes_ = true;
+      // Whether layer fills bounds opaquely or not might have changed.
+      if (current_resource_has_alpha_ !=
+          FormatHasAlpha(pending_buffer_.buffer()->GetFormat()))
+        has_pending_layer_changes_ = true;
+    } else if (!current_resource_.size.IsEmpty()) {
       has_pending_layer_changes_ = true;
     }
   }
@@ -471,6 +491,7 @@
                         content_size_),
         surface_reference_factory_);
     window_->layer()->SetFillsBoundsOpaquely(
+        !current_resource_has_alpha_ ||
         state_.blend_mode == SkBlendMode::kSrc ||
         state_.opaque_region.contains(
             gfx::RectToSkIRect(gfx::Rect(content_size_))));
@@ -732,13 +753,17 @@
 }
 
 void Surface::UpdateResource(bool client_usage) {
-  if (!current_buffer_.buffer() ||
-      !current_buffer_.buffer()->ProduceTransferableResource(
+  if (current_buffer_.buffer() &&
+      current_buffer_.buffer()->ProduceTransferableResource(
           compositor_frame_sink_holder_.get(), next_resource_id_++,
           state_.only_visible_on_secure_output, client_usage,
           &current_resource_)) {
+    current_resource_has_alpha_ =
+        FormatHasAlpha(current_buffer_.buffer()->GetFormat());
+  } else {
     current_resource_.id = 0;
     current_resource_.size = gfx::Size();
+    current_resource_has_alpha_ = false;
   }
 }
 
@@ -802,7 +827,8 @@
           render_pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>();
       float vertex_opacity[4] = {1.0, 1.0, 1.0, 1.0};
       gfx::Rect opaque_rect;
-      if (state_.blend_mode == SkBlendMode::kSrc ||
+      if (!current_resource_has_alpha_ ||
+          state_.blend_mode == SkBlendMode::kSrc ||
           state_.opaque_region.contains(gfx::RectToSkIRect(quad_rect))) {
         opaque_rect = quad_rect;
       } else if (state_.opaque_region.isRect()) {
diff --git a/components/exo/surface.h b/components/exo/surface.h
index e50733e..14d7da0 100644
--- a/components/exo/surface.h
+++ b/components/exo/surface.h
@@ -361,6 +361,9 @@
   // The last resource that was sent to a surface.
   cc::TransferableResource current_resource_;
 
+  // Whether the last resource that was sent to a surface has an alpha channel.
+  bool current_resource_has_alpha_ = false;
+
   // This is true if a call to Commit() as been made but
   // CommitSurfaceHierarchy() has not yet been called.
   bool needs_commit_surface_hierarchy_ = false;
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc
index f48ea71..1112715 100644
--- a/components/exo/surface_unittest.cc
+++ b/components/exo/surface_unittest.cc
@@ -93,14 +93,71 @@
   EXPECT_TRUE(frame_time.is_null());
 }
 
+const cc::CompositorFrame& GetFrameFromSurface(Surface* surface) {
+  cc::SurfaceId surface_id = surface->GetSurfaceId();
+  cc::SurfaceManager* surface_manager =
+      aura::Env::GetInstance()->context_factory_private()->GetSurfaceManager();
+  const cc::CompositorFrame& frame =
+      surface_manager->GetSurfaceForId(surface_id)->GetEligibleFrame();
+  return frame;
+}
+
 TEST_F(SurfaceTest, SetOpaqueRegion) {
+  gfx::Size buffer_size(1, 1);
+  std::unique_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
   std::unique_ptr<Surface> surface(new Surface);
 
-  // Setting a non-empty opaque region should succeed.
-  surface->SetOpaqueRegion(SkRegion(SkIRect::MakeWH(256, 256)));
+  // Attaching a buffer with alpha channel.
+  surface->Attach(buffer.get());
 
-  // Setting an empty opaque region should succeed.
+  // Setting an opaque region that contains the buffer size doesn't require
+  // draw with blending.
+  surface->SetOpaqueRegion(SkRegion(SkIRect::MakeWH(256, 256)));
+  surface->Commit();
+  RunAllPendingInMessageLoop();
+
+  {
+    const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
+    ASSERT_EQ(1u, frame.render_pass_list.size());
+    ASSERT_EQ(1u, frame.render_pass_list.back()->quad_list.size());
+    EXPECT_FALSE(frame.render_pass_list.back()
+                     ->quad_list.back()
+                     ->ShouldDrawWithBlending());
+  }
+
+  // Setting an empty opaque region requires draw with blending.
   surface->SetOpaqueRegion(SkRegion(SkIRect::MakeEmpty()));
+  surface->Commit();
+  RunAllPendingInMessageLoop();
+
+  {
+    const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
+    ASSERT_EQ(1u, frame.render_pass_list.size());
+    ASSERT_EQ(1u, frame.render_pass_list.back()->quad_list.size());
+    EXPECT_TRUE(frame.render_pass_list.back()
+                    ->quad_list.back()
+                    ->ShouldDrawWithBlending());
+  }
+
+  std::unique_ptr<Buffer> buffer_without_alpha(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(
+          buffer_size, gfx::BufferFormat::RGBX_8888)));
+
+  // Attaching a buffer without an alpha channel doesn't require draw with
+  // blending.
+  surface->Attach(buffer_without_alpha.get());
+  surface->Commit();
+  RunAllPendingInMessageLoop();
+
+  {
+    const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
+    ASSERT_EQ(1u, frame.render_pass_list.size());
+    ASSERT_EQ(1u, frame.render_pass_list.back()->quad_list.size());
+    EXPECT_FALSE(frame.render_pass_list.back()
+                     ->quad_list.back()
+                     ->ShouldDrawWithBlending());
+  }
 }
 
 TEST_F(SurfaceTest, SetInputRegion) {
@@ -192,15 +249,6 @@
   EXPECT_EQ(crop_size.ToString(), surface->content_size().ToString());
 }
 
-const cc::CompositorFrame& GetFrameFromSurface(Surface* surface) {
-  cc::SurfaceId surface_id = surface->GetSurfaceId();
-  cc::SurfaceManager* surface_manager =
-      aura::Env::GetInstance()->context_factory_private()->GetSurfaceManager();
-  const cc::CompositorFrame& frame =
-      surface_manager->GetSurfaceForId(surface_id)->GetEligibleFrame();
-  return frame;
-}
-
 TEST_F(SurfaceTest, SetBlendMode) {
   gfx::Size buffer_size(1, 1);
   std::unique_ptr<Buffer> buffer(
diff --git a/components/exo/test/exo_test_helper.cc b/components/exo/test/exo_test_helper.cc
index ed68406..d729b75 100644
--- a/components/exo/test/exo_test_helper.cc
+++ b/components/exo/test/exo_test_helper.cc
@@ -61,12 +61,12 @@
 ExoTestHelper::~ExoTestHelper() {}
 
 std::unique_ptr<gfx::GpuMemoryBuffer> ExoTestHelper::CreateGpuMemoryBuffer(
-    const gfx::Size& size) {
+    const gfx::Size& size,
+    gfx::BufferFormat format) {
   return aura::Env::GetInstance()
       ->context_factory()
       ->GetGpuMemoryBufferManager()
-      ->CreateGpuMemoryBuffer(size, gfx::BufferFormat::RGBA_8888,
-                              gfx::BufferUsage::GPU_READ,
+      ->CreateGpuMemoryBuffer(size, format, gfx::BufferUsage::GPU_READ,
                               gpu::kNullSurfaceHandle);
 }
 
diff --git a/components/exo/test/exo_test_helper.h b/components/exo/test/exo_test_helper.h
index 11bc8d7..1ae8cb6e 100644
--- a/components/exo/test/exo_test_helper.h
+++ b/components/exo/test/exo_test_helper.h
@@ -9,6 +9,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "ui/gfx/buffer_types.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -48,7 +49,8 @@
 
   // Creates a GpuMemoryBuffer instance that can be used for tests.
   std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
-      const gfx::Size& size);
+      const gfx::Size& size,
+      gfx::BufferFormat format = gfx::BufferFormat::RGBA_8888);
 
   // Creates window of size (width, height) at center of screen.
   ExoTestWindow CreateWindow(int width, int height, bool is_modal);
diff --git a/components/metrics/net/network_metrics_provider.cc b/components/metrics/net/network_metrics_provider.cc
index cd2f4f5..bf56530 100644
--- a/components/metrics/net/network_metrics_provider.cc
+++ b/components/metrics/net/network_metrics_provider.cc
@@ -18,7 +18,6 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/task_runner_util.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "net/base/net_errors.h"
 #include "net/nqe/network_quality_estimator.h"
diff --git a/components/ntp_tiles/most_visited_sites_unittest.cc b/components/ntp_tiles/most_visited_sites_unittest.cc
index d660682b..9c16609 100644
--- a/components/ntp_tiles/most_visited_sites_unittest.cc
+++ b/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -21,7 +21,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/test/sequenced_worker_pool_owner.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "components/history/core/browser/top_sites.h"
 #include "components/history/core/browser/top_sites_observer.h"
 #include "components/ntp_tiles/icon_cacher.h"
diff --git a/components/sync/PRESUBMIT.py b/components/sync/PRESUBMIT.py
index b9b669f..276449b 100644
--- a/components/sync/PRESUBMIT.py
+++ b/components/sync/PRESUBMIT.py
@@ -61,6 +61,10 @@
 
 SYNC_SOURCE_FILES = (r'^components[\\/]sync[\\/].*\.(cc|h)$',)
 
+# The wrapper around lint that is called below disables a set of filters if the
+# passed filter evaluates to false. Pass a junk filter to avoid this behavior.
+LINT_FILTERS = ['+fake/filter']
+
 def CheckModelTypeInfoMap(input_api, output_api, model_type_file):
   """Checks the kModelTypeInfoMap in model_type.cc follows conventions.
   Checks that the kModelTypeInfoMap follows the below rules:
@@ -366,9 +370,9 @@
 def CheckChangeLintsClean(input_api, output_api):
   source_filter = lambda x: input_api.FilterSourceFile(
     x, white_list=SYNC_SOURCE_FILES, black_list=None)
-
   return input_api.canned_checks.CheckChangeLintsClean(
-      input_api, output_api, source_filter, lint_filters=[], verbose_level=1)
+      input_api, output_api, source_filter, lint_filters=LINT_FILTERS,
+      verbose_level=1)
 
 def CheckChanges(input_api, output_api):
   results = []
diff --git a/components/sync/base/hash_util_unittest.cc b/components/sync/base/hash_util_unittest.cc
index e43dd52..c0925e89 100644
--- a/components/sync/base/hash_util_unittest.cc
+++ b/components/sync/base/hash_util_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "components/sync/base/hash_util.h"
 
-#include "components/sync/base/model_type.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace syncer {
diff --git a/components/sync/base/sync_features.h b/components/sync/base/sync_features.h
index 7abca4c..e3b0a67 100644
--- a/components/sync/base/sync_features.h
+++ b/components/sync/base/sync_features.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 COMPONENETS_SYNC_BASE_SYNC_FEATURES_H_
-#define COMPONENETS_SYNC_BASE_SYNC_FEATURES_H_
+#ifndef COMPONENTS_SYNC_BASE_SYNC_FEATURES_H_
+#define COMPONENTS_SYNC_BASE_SYNC_FEATURES_H_
 
 #include "base/feature_list.h"
 
@@ -13,4 +13,4 @@
 
 }  // namespace syncer
 
-#endif  // COMPONENETS_SYNC_BASE_SYNC_FEATURES_H_
+#endif  // COMPONENTS_SYNC_BASE_SYNC_FEATURES_H_
diff --git a/components/sync/device_info/device_info_sync_bridge.cc b/components/sync/device_info/device_info_sync_bridge.cc
index 9490815..caba3632 100644
--- a/components/sync/device_info/device_info_sync_bridge.cc
+++ b/components/sync/device_info/device_info_sync_bridge.cc
@@ -18,7 +18,6 @@
 #include "components/sync/device_info/device_info_util.h"
 #include "components/sync/model/entity_change.h"
 #include "components/sync/model/metadata_batch.h"
-#include "components/sync/model/model_error.h"
 #include "components/sync/model/mutable_data_batch.h"
 #include "components/sync/protocol/model_type_state.pb.h"
 #include "components/sync/protocol/sync.pb.h"
diff --git a/components/sync/driver/generic_change_processor_unittest.cc b/components/sync/driver/generic_change_processor_unittest.cc
index c29dd7f..1bc4628e 100644
--- a/components/sync/driver/generic_change_processor_unittest.cc
+++ b/components/sync/driver/generic_change_processor_unittest.cc
@@ -20,7 +20,6 @@
 #include "components/sync/engine/attachments/fake_attachment_uploader.h"
 #include "components/sync/engine/sync_encryption_handler.h"
 #include "components/sync/model/attachments/attachment_id.h"
-#include "components/sync/model/attachments/attachment_service.h"
 #include "components/sync/model/data_type_error_handler_mock.h"
 #include "components/sync/model/fake_syncable_service.h"
 #include "components/sync/model/sync_change.h"
diff --git a/components/sync/driver/glue/sync_backend_host_core.cc b/components/sync/driver/glue/sync_backend_host_core.cc
index 0751ba2..4708a23 100644
--- a/components/sync/driver/glue/sync_backend_host_core.cc
+++ b/components/sync/driver/glue/sync_backend_host_core.cc
@@ -10,7 +10,6 @@
 #include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
-#include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
diff --git a/components/sync/driver/model_type_controller.cc b/components/sync/driver/model_type_controller.cc
index 7bced2e..4c5d56f 100644
--- a/components/sync/driver/model_type_controller.cc
+++ b/components/sync/driver/model_type_controller.cc
@@ -10,7 +10,6 @@
 #include "base/bind_helpers.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
-#include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/sync/base/bind_to_task_runner.h"
 #include "components/sync/base/data_type_histogram.h"
diff --git a/components/sync/driver/model_type_controller_unittest.cc b/components/sync/driver/model_type_controller_unittest.cc
index ba3610c..fad3071 100644
--- a/components/sync/driver/model_type_controller_unittest.cc
+++ b/components/sync/driver/model_type_controller_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/sequenced_task_runner.h"
diff --git a/components/sync/driver/resources/about.js b/components/sync/driver/resources/about.js
index f562c80..cebf496e 100644
--- a/components/sync/driver/resources/about.js
+++ b/components/sync/driver/resources/about.js
@@ -41,8 +41,14 @@
     var type_status_array = chrome.sync.aboutInfo.type_status;
     type_status_array.forEach(function(row) {
       if (row.name == modelType) {
-        row.num_entries = counters.numEntriesAndTombstones;
-        row.num_live = counters.numEntries;
+        // There are three types of counters, only "status" counters have these
+        // fields. Keep the old values if updated fields are not present.
+        if (counters.numEntriesAndTombstones) {
+          row.num_entries = counters.numEntriesAndTombstones;
+        }
+        if (counters.numEntries) {
+          row.num_live = counters.numEntries;
+        }
       }
     });
     jstProcess(
diff --git a/components/sync/engine/attachments/fake_attachment_downloader_unittest.cc b/components/sync/engine/attachments/fake_attachment_downloader_unittest.cc
index 200d6aa..cc5498bb 100644
--- a/components/sync/engine/attachments/fake_attachment_downloader_unittest.cc
+++ b/components/sync/engine/attachments/fake_attachment_downloader_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "components/sync/engine/attachments/fake_attachment_downloader.h"
 
+#include <memory>
 #include <utility>
 #include <vector>
 
diff --git a/components/sync/engine/attachments/in_memory_attachment_store.cc b/components/sync/engine/attachments/in_memory_attachment_store.cc
index 9069464..7a82b55 100644
--- a/components/sync/engine/attachments/in_memory_attachment_store.cc
+++ b/components/sync/engine/attachments/in_memory_attachment_store.cc
@@ -5,6 +5,7 @@
 #include "components/sync/engine/attachments/in_memory_attachment_store.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
diff --git a/components/sync/engine/attachments/on_disk_attachment_store.cc b/components/sync/engine/attachments/on_disk_attachment_store.cc
index 4afc78b5a..5ad339d4 100644
--- a/components/sync/engine/attachments/on_disk_attachment_store.cc
+++ b/components/sync/engine/attachments/on_disk_attachment_store.cc
@@ -6,7 +6,6 @@
 
 #include <stdint.h>
 
-#include <memory>
 #include <utility>
 
 #include "base/bind.h"
diff --git a/components/sync/engine/browser_thread_model_worker.cc b/components/sync/engine/browser_thread_model_worker.cc
index b1a90f22..3b29d85 100644
--- a/components/sync/engine/browser_thread_model_worker.cc
+++ b/components/sync/engine/browser_thread_model_worker.cc
@@ -6,7 +6,6 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 
 using base::SingleThreadTaskRunner;
diff --git a/components/sync/engine/browser_thread_model_worker_unittest.cc b/components/sync/engine/browser_thread_model_worker_unittest.cc
index f05d2b8..f4417e9 100644
--- a/components/sync/engine/browser_thread_model_worker_unittest.cc
+++ b/components/sync/engine/browser_thread_model_worker_unittest.cc
@@ -10,7 +10,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
 #include "base/test/test_timeouts.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
diff --git a/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc b/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc
index d7ebb76..2e7c2b9 100644
--- a/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc
+++ b/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc
@@ -4,8 +4,6 @@
 
 #include "components/sync/engine/cycle/sync_cycle_snapshot.h"
 
-#include <memory>
-
 #include "base/test/values_test_util.h"
 #include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/sync/engine/engine_components_factory_impl.cc b/components/sync/engine/engine_components_factory_impl.cc
index dd913f9..68fc139 100644
--- a/components/sync/engine/engine_components_factory_impl.cc
+++ b/components/sync/engine/engine_components_factory_impl.cc
@@ -4,6 +4,9 @@
 
 #include "components/sync/engine/engine_components_factory_impl.h"
 
+#include <map>
+#include <utility>
+
 #include "base/memory/ptr_util.h"
 #include "components/sync/engine_impl/backoff_delay_provider.h"
 #include "components/sync/engine_impl/cycle/sync_cycle_context.h"
diff --git a/components/sync/engine/sync_backend_registrar_unittest.cc b/components/sync/engine/sync_backend_registrar_unittest.cc
index 678aff2..5c42d6e 100644
--- a/components/sync/engine/sync_backend_registrar_unittest.cc
+++ b/components/sync/engine/sync_backend_registrar_unittest.cc
@@ -4,8 +4,6 @@
 
 #include "components/sync/engine/sync_backend_registrar.h"
 
-#include <memory>
-
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
diff --git a/components/sync/engine/ui_model_worker_unittest.cc b/components/sync/engine/ui_model_worker_unittest.cc
index 25483532..9411a67a 100644
--- a/components/sync/engine/ui_model_worker_unittest.cc
+++ b/components/sync/engine/ui_model_worker_unittest.cc
@@ -10,7 +10,6 @@
 #include "base/bind_helpers.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "base/test/test_timeouts.h"
 #include "base/threading/platform_thread.h"
diff --git a/components/sync/engine_impl/cycle/non_blocking_type_debug_info_emitter.cc b/components/sync/engine_impl/cycle/non_blocking_type_debug_info_emitter.cc
index 3674784..a3b5bdf 100644
--- a/components/sync/engine_impl/cycle/non_blocking_type_debug_info_emitter.cc
+++ b/components/sync/engine_impl/cycle/non_blocking_type_debug_info_emitter.cc
@@ -4,11 +4,6 @@
 
 #include "components/sync/engine_impl/cycle/non_blocking_type_debug_info_emitter.h"
 
-#include <vector>
-
-#include "components/sync/engine/cycle/status_counters.h"
-#include "components/sync/engine/cycle/type_debug_info_observer.h"
-
 namespace syncer {
 
 NonBlockingTypeDebugInfoEmitter::NonBlockingTypeDebugInfoEmitter(
@@ -19,14 +14,10 @@
 NonBlockingTypeDebugInfoEmitter::~NonBlockingTypeDebugInfoEmitter() {}
 
 void NonBlockingTypeDebugInfoEmitter::EmitStatusCountersUpdate() {
-  // TODO(gangwu): this function is to show Total Entries on "Types" tab on
-  // chrome://sync-internals, we decide to show zero right now, because it is
-  // hard to let emitter to get object of SharedModelTypeProcessor or
-  // ModelTypeStore, and also people can get the numbers from "about" tab on
-  // chrome://sync-internals.
-  StatusCounters counters;
-  for (auto& observer : *type_debug_info_observers_)
-    observer.OnStatusCountersUpdated(type_, counters);
+  // TODO(gangwu): Allow driving emission of status counters from here. This is
+  // tricky because we do not have access to SharedModelTypeProcessor or
+  // ModelTypeStore currently. This method is fairly redundant since counters
+  // are also emitted from the UI thread, unclear how important this is.
 }
 
 }  // namespace syncer
diff --git a/components/sync/engine_impl/cycle/nudge_tracker.cc b/components/sync/engine_impl/cycle/nudge_tracker.cc
index 1cf2391..15e83e1c 100644
--- a/components/sync/engine_impl/cycle/nudge_tracker.cc
+++ b/components/sync/engine_impl/cycle/nudge_tracker.cc
@@ -4,6 +4,7 @@
 
 #include "components/sync/engine_impl/cycle/nudge_tracker.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/memory/ptr_util.h"
diff --git a/components/sync/engine_impl/loopback_server/loopback_connection_manager.cc b/components/sync/engine_impl/loopback_server/loopback_connection_manager.cc
index d218b8f..ee1bd0f 100644
--- a/components/sync/engine_impl/loopback_server/loopback_connection_manager.cc
+++ b/components/sync/engine_impl/loopback_server/loopback_connection_manager.cc
@@ -3,8 +3,6 @@
 // found in the LICENSE file.
 #include "components/sync/engine_impl/loopback_server/loopback_connection_manager.h"
 
-#include <string>
-
 namespace syncer {
 
 LoopbackConnectionManager::LoopbackConnectionManager(
diff --git a/components/sync/engine_impl/loopback_server/loopback_server.cc b/components/sync/engine_impl/loopback_server/loopback_server.cc
index 88eb7ca..8022b5b 100644
--- a/components/sync/engine_impl/loopback_server/loopback_server.cc
+++ b/components/sync/engine_impl/loopback_server/loopback_server.cc
@@ -4,15 +4,10 @@
 
 #include "components/sync/engine_impl/loopback_server/loopback_server.h"
 
-#include <stdint.h>
-
 #include <algorithm>
 #include <limits>
-#include <memory>
 #include <set>
-#include <string>
 #include <utility>
-#include <vector>
 
 #include "base/files/file_util.h"
 #include "base/guid.h"
@@ -23,7 +18,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/lock.h"
-#include "components/sync/base/model_type.h"
 #include "components/sync/engine_impl/loopback_server/persistent_bookmark_entity.h"
 #include "components/sync/engine_impl/loopback_server/persistent_permanent_entity.h"
 #include "components/sync/engine_impl/loopback_server/persistent_tombstone_entity.h"
diff --git a/components/sync/engine_impl/loopback_server/loopback_server.h b/components/sync/engine_impl/loopback_server/loopback_server.h
index 20af7bc..a69c99e 100644
--- a/components/sync/engine_impl/loopback_server/loopback_server.h
+++ b/components/sync/engine_impl/loopback_server/loopback_server.h
@@ -27,7 +27,7 @@
 // A loopback version of the Sync server used for local profile serialization.
 class LoopbackServer {
  public:
-  LoopbackServer(const base::FilePath& persistent_file);
+  explicit LoopbackServer(const base::FilePath& persistent_file);
   virtual ~LoopbackServer();
 
   // Handles a /command POST (with the given |request|) to the server. Three
diff --git a/components/sync/engine_impl/loopback_server/loopback_server_entity.cc b/components/sync/engine_impl/loopback_server/loopback_server_entity.cc
index db5a193..c6e20fe 100644
--- a/components/sync/engine_impl/loopback_server/loopback_server_entity.cc
+++ b/components/sync/engine_impl/loopback_server/loopback_server_entity.cc
@@ -4,11 +4,7 @@
 
 #include "components/sync/engine_impl/loopback_server/loopback_server_entity.h"
 
-#include <stdint.h>
-
 #include <limits>
-#include <memory>
-#include <string>
 #include <vector>
 
 #include "base/guid.h"
@@ -19,12 +15,10 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "components/sync/base/model_type.h"
 #include "components/sync/engine_impl/loopback_server/persistent_bookmark_entity.h"
 #include "components/sync/engine_impl/loopback_server/persistent_permanent_entity.h"
 #include "components/sync/engine_impl/loopback_server/persistent_tombstone_entity.h"
 #include "components/sync/engine_impl/loopback_server/persistent_unique_client_entity.h"
-#include "components/sync/protocol/sync.pb.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_status_code.h"
 
diff --git a/components/sync/engine_impl/loopback_server/loopback_server_entity.h b/components/sync/engine_impl/loopback_server/loopback_server_entity.h
index 92b564e..2ad2547 100644
--- a/components/sync/engine_impl/loopback_server/loopback_server_entity.h
+++ b/components/sync/engine_impl/loopback_server/loopback_server_entity.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <map>
+#include <memory>
 #include <string>
 
 #include "components/sync/base/model_type.h"
diff --git a/components/sync/engine_impl/loopback_server/persistent_bookmark_entity.cc b/components/sync/engine_impl/loopback_server/persistent_bookmark_entity.cc
index 16728a9..f1e7377 100644
--- a/components/sync/engine_impl/loopback_server/persistent_bookmark_entity.cc
+++ b/components/sync/engine_impl/loopback_server/persistent_bookmark_entity.cc
@@ -4,15 +4,7 @@
 
 #include "components/sync/engine_impl/loopback_server/persistent_bookmark_entity.h"
 
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
 #include "base/guid.h"
-#include "components/sync/base/model_type.h"
-#include "components/sync/engine_impl/loopback_server/loopback_server_entity.h"
-#include "components/sync/protocol/sync.pb.h"
 
 using std::string;
 
diff --git a/components/sync/engine_impl/loopback_server/persistent_permanent_entity.cc b/components/sync/engine_impl/loopback_server/persistent_permanent_entity.cc
index decea55..e85aa022 100644
--- a/components/sync/engine_impl/loopback_server/persistent_permanent_entity.cc
+++ b/components/sync/engine_impl/loopback_server/persistent_permanent_entity.cc
@@ -4,14 +4,8 @@
 
 #include "components/sync/engine_impl/loopback_server/persistent_permanent_entity.h"
 
-#include <memory>
-#include <string>
-
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
-#include "components/sync/base/model_type.h"
-#include "components/sync/engine_impl/loopback_server/loopback_server_entity.h"
-#include "components/sync/protocol/sync.pb.h"
 
 using std::string;
 
diff --git a/components/sync/engine_impl/loopback_server/persistent_tombstone_entity.cc b/components/sync/engine_impl/loopback_server/persistent_tombstone_entity.cc
index 0d5b88d..a32b134c 100644
--- a/components/sync/engine_impl/loopback_server/persistent_tombstone_entity.cc
+++ b/components/sync/engine_impl/loopback_server/persistent_tombstone_entity.cc
@@ -4,13 +4,6 @@
 
 #include "components/sync/engine_impl/loopback_server/persistent_tombstone_entity.h"
 
-#include <memory>
-#include <string>
-
-#include "components/sync/base/model_type.h"
-#include "components/sync/engine_impl/loopback_server/loopback_server_entity.h"
-#include "components/sync/protocol/sync.pb.h"
-
 using std::string;
 
 using syncer::ModelType;
diff --git a/components/sync/engine_impl/loopback_server/persistent_unique_client_entity.cc b/components/sync/engine_impl/loopback_server/persistent_unique_client_entity.cc
index 402d817..9a2b872 100644
--- a/components/sync/engine_impl/loopback_server/persistent_unique_client_entity.cc
+++ b/components/sync/engine_impl/loopback_server/persistent_unique_client_entity.cc
@@ -4,14 +4,7 @@
 
 #include "components/sync/engine_impl/loopback_server/persistent_unique_client_entity.h"
 
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
 #include "base/guid.h"
-#include "components/sync/base/model_type.h"
-#include "components/sync/engine_impl/loopback_server/loopback_server_entity.h"
 #include "components/sync/engine_impl/loopback_server/persistent_permanent_entity.h"
 #include "components/sync/protocol/sync.pb.h"
 
diff --git a/components/sync/engine_impl/sync_manager_impl_unittest.cc b/components/sync/engine_impl/sync_manager_impl_unittest.cc
index 8bf15f9..d7f0c79 100644
--- a/components/sync/engine_impl/sync_manager_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_manager_impl_unittest.cc
@@ -5,7 +5,6 @@
 #include "components/sync/engine_impl/sync_manager_impl.h"
 
 #include <cstddef>
-#include <memory>
 #include <utility>
 
 #include "base/callback.h"
diff --git a/components/sync/engine_impl/test_entry_factory.cc b/components/sync/engine_impl/test_entry_factory.cc
index 1321a87..5d197c81 100644
--- a/components/sync/engine_impl/test_entry_factory.cc
+++ b/components/sync/engine_impl/test_entry_factory.cc
@@ -5,7 +5,6 @@
 #include "components/sync/engine_impl/test_entry_factory.h"
 
 #include "components/sync/base/hash_util.h"
-#include "components/sync/base/model_type.h"
 #include "components/sync/syncable/directory.h"
 #include "components/sync/syncable/entry.h"
 #include "components/sync/syncable/model_neutral_mutable_entry.h"
diff --git a/components/sync/model/fake_model_type_sync_bridge.cc b/components/sync/model/fake_model_type_sync_bridge.cc
index 1c6e6f9..d7c1c2f1 100644
--- a/components/sync/model/fake_model_type_sync_bridge.cc
+++ b/components/sync/model/fake_model_type_sync_bridge.cc
@@ -9,7 +9,6 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "components/sync/base/hash_util.h"
-#include "components/sync/model/model_error.h"
 #include "components/sync/model/mutable_data_batch.h"
 #include "components/sync/model_impl/in_memory_metadata_change_list.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/sync/model/recording_model_type_change_processor.cc b/components/sync/model/recording_model_type_change_processor.cc
index 13c1850..0d37974 100644
--- a/components/sync/model/recording_model_type_change_processor.cc
+++ b/components/sync/model/recording_model_type_change_processor.cc
@@ -4,7 +4,8 @@
 
 #include "components/sync/model/recording_model_type_change_processor.h"
 
-#include "components/sync/model/fake_model_type_change_processor.h"
+#include <utility>
+
 #include "components/sync/model/metadata_batch.h"
 
 namespace syncer {
diff --git a/components/sync/model/recording_model_type_change_processor.h b/components/sync/model/recording_model_type_change_processor.h
index d0789b4e..6fe9180 100644
--- a/components/sync/model/recording_model_type_change_processor.h
+++ b/components/sync/model/recording_model_type_change_processor.h
@@ -5,6 +5,11 @@
 #ifndef COMPONENTS_SYNC_MODEL_RECORDING_MODEL_TYPE_CHANGE_PROCESSOR_H_
 #define COMPONENTS_SYNC_MODEL_RECORDING_MODEL_TYPE_CHANGE_PROCESSOR_H_
 
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+
 #include "components/sync/model/fake_model_type_change_processor.h"
 
 namespace syncer {
@@ -34,7 +39,7 @@
 
   const std::set<std::string>& delete_set() const { return delete_set_; }
 
-  const MetadataBatch* metadata() const { return metadata_.get(); }
+  MetadataBatch* metadata() const { return metadata_.get(); }
 
  private:
   std::multimap<std::string, std::unique_ptr<EntityData>> put_multimap_;
diff --git a/components/sync/model_impl/attachments/task_queue_unittest.cc b/components/sync/model_impl/attachments/task_queue_unittest.cc
index 413433c..634a5de 100644
--- a/components/sync/model_impl/attachments/task_queue_unittest.cc
+++ b/components/sync/model_impl/attachments/task_queue_unittest.cc
@@ -6,7 +6,6 @@
 
 #include <vector>
 
-#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/timer/mock_timer.h"
diff --git a/components/sync/model_impl/model_type_store_impl.cc b/components/sync/model_impl/model_type_store_impl.cc
index a4d02948..e4d7fcf 100644
--- a/components/sync/model_impl/model_type_store_impl.cc
+++ b/components/sync/model_impl/model_type_store_impl.cc
@@ -4,7 +4,6 @@
 
 #include "components/sync/model_impl/model_type_store_impl.h"
 
-#include <string>
 #include <utility>
 
 #include "base/bind.h"
diff --git a/components/sync/model_impl/model_type_store_impl_unittest.cc b/components/sync/model_impl/model_type_store_impl_unittest.cc
index 0f5c187..f959251 100644
--- a/components/sync/model_impl/model_type_store_impl_unittest.cc
+++ b/components/sync/model_impl/model_type_store_impl_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "components/sync/model_impl/model_type_store_impl.h"
 
+#include <map>
 #include <utility>
 
 #include "base/bind.h"
diff --git a/components/sync/model_impl/shared_model_type_processor.cc b/components/sync/model_impl/shared_model_type_processor.cc
index 5081f13..614321d 100644
--- a/components/sync/model_impl/shared_model_type_processor.cc
+++ b/components/sync/model_impl/shared_model_type_processor.cc
@@ -82,6 +82,7 @@
                      weak_ptr_factory_.GetWeakPtr()));
     }
   } else {
+    DCHECK_EQ(0u, batch->TakeAllMetadata().size());
     // First time syncing; initialize metadata.
     model_type_state_.mutable_progress_marker()->set_data_type_id(
         GetSpecificsFieldNumberFromModelType(type_));
diff --git a/components/sync/protocol/proto_memory_estimations.cc b/components/sync/protocol/proto_memory_estimations.cc
index f759f986..af9b102 100644
--- a/components/sync/protocol/proto_memory_estimations.cc
+++ b/components/sync/protocol/proto_memory_estimations.cc
@@ -6,6 +6,8 @@
 
 #include "components/sync/protocol/proto_memory_estimations.h"
 
+#include <string>
+
 #include "base/trace_event/memory_usage_estimator.h"
 #include "components/sync/protocol/proto_visitors.h"
 
diff --git a/components/sync/protocol/proto_value_conversions.cc b/components/sync/protocol/proto_value_conversions.cc
index d2ed4fcb..95897e2 100644
--- a/components/sync/protocol/proto_value_conversions.cc
+++ b/components/sync/protocol/proto_value_conversions.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include <string>
+#include <utility>
 
 #include "base/base64.h"
 #include "base/memory/ptr_util.h"
diff --git a/components/sync_bookmarks/PRESUBMIT.py b/components/sync_bookmarks/PRESUBMIT.py
index 33378623..db47db9 100644
--- a/components/sync_bookmarks/PRESUBMIT.py
+++ b/components/sync_bookmarks/PRESUBMIT.py
@@ -13,11 +13,16 @@
 SYNC_BOOKMARKS_SOURCE_FILES = (
   r'^components[\\/]sync_bookmarks[\\/].*\.(cc|h)$',)
 
+# The wrapper around lint that is called below disables a set of filters if the
+# passed filter evaluates to false. Pass a junk filter to avoid this behavior.
+LINT_FILTERS = ['+fake/filter']
+
 def CheckChangeLintsClean(input_api, output_api):
   source_filter = lambda x: input_api.FilterSourceFile(
     x, white_list=SYNC_BOOKMARKS_SOURCE_FILES, black_list=None)
   return input_api.canned_checks.CheckChangeLintsClean(
-      input_api, output_api, source_filter, lint_filters=[], verbose_level=1)
+      input_api, output_api, source_filter, lint_filters=LINT_FILTERS,
+      verbose_level=1)
 
 def CheckChanges(input_api, output_api):
   results = []
diff --git a/components/sync_sessions/PRESUBMIT.py b/components/sync_sessions/PRESUBMIT.py
index 39f2f9ac..ae142e0 100644
--- a/components/sync_sessions/PRESUBMIT.py
+++ b/components/sync_sessions/PRESUBMIT.py
@@ -12,11 +12,16 @@
 
 SYNC_SESSIONS_SOURCE_FILES = (r'^components[\\/]sync_sessions[\\/].*\.(cc|h)$',)
 
+# The wrapper around lint that is called below disables a set of filters if the
+# passed filter evaluates to false. Pass a junk filter to avoid this behavior.
+LINT_FILTERS = ['+fake/filter']
+
 def CheckChangeLintsClean(input_api, output_api):
   source_filter = lambda x: input_api.FilterSourceFile(
     x, white_list=SYNC_SESSIONS_SOURCE_FILES, black_list=None)
   return input_api.canned_checks.CheckChangeLintsClean(
-      input_api, output_api, source_filter, lint_filters=[], verbose_level=1)
+      input_api, output_api, source_filter, lint_filters=LINT_FILTERS,
+      verbose_level=1)
 
 def CheckChanges(input_api, output_api):
   results = []
diff --git a/components/sync_sessions/revisit/page_revisit_broadcaster.cc b/components/sync_sessions/revisit/page_revisit_broadcaster.cc
index 19837833..cfeca0b 100644
--- a/components/sync_sessions/revisit/page_revisit_broadcaster.cc
+++ b/components/sync_sessions/revisit/page_revisit_broadcaster.cc
@@ -4,9 +4,7 @@
 
 #include "components/sync_sessions/revisit/page_revisit_broadcaster.h"
 
-#include <memory>
 #include <string>
-#include <vector>
 
 #include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
diff --git a/components/sync_sessions/revisit/page_revisit_broadcaster.h b/components/sync_sessions/revisit/page_revisit_broadcaster.h
index 7bae4f0..150320c 100644
--- a/components/sync_sessions/revisit/page_revisit_broadcaster.h
+++ b/components/sync_sessions/revisit/page_revisit_broadcaster.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_SYNC_SESSIONS_REVISIT_PAGE_REVISIT_BROADCASTER_H_
 #define COMPONENTS_SYNC_SESSIONS_REVISIT_PAGE_REVISIT_BROADCASTER_H_
 
+#include <memory>
 #include <vector>
 
 #include "base/macros.h"
diff --git a/components/sync_sessions/synced_tab_delegate.h b/components/sync_sessions/synced_tab_delegate.h
index aa81540..9781578 100644
--- a/components/sync_sessions/synced_tab_delegate.h
+++ b/components/sync_sessions/synced_tab_delegate.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_SYNC_SESSIONS_SYNCED_TAB_DELEGATE_H__
 #define COMPONENTS_SYNC_SESSIONS_SYNCED_TAB_DELEGATE_H__
 
+#include <memory>
 #include <string>
 #include <vector>
 
diff --git a/components/ukm/ukm_service.cc b/components/ukm/ukm_service.cc
index e050b4bb..42bb7ad3 100644
--- a/components/ukm/ukm_service.cc
+++ b/components/ukm/ukm_service.cc
@@ -14,7 +14,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "components/metrics/metrics_log.h"
 #include "components/metrics/metrics_log_uploader.h"
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index c61d97f..f0f2743d 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -57,6 +57,7 @@
 #include "content/public/common/service_names.mojom.h"
 #include "gpu/command_buffer/service/gpu_preferences.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/config/gpu_driver_bug_list.h"
 #include "gpu/ipc/host/shader_disk_cache.h"
 #include "gpu/ipc/service/switches.h"
 #include "ipc/ipc_channel_handle.h"
@@ -1056,6 +1057,11 @@
       browser_command_line, switches::kGLSwitchesCopiedFromGpuProcessHost,
       switches::kGLSwitchesCopiedFromGpuProcessHostNumSwitches);
 
+  std::vector<const char*> gpu_workarounds;
+  gpu::GpuDriverBugList::AppendAllWorkarounds(&gpu_workarounds);
+  cmd_line->CopySwitchesFrom(browser_command_line,
+      gpu_workarounds.data(), gpu_workarounds.size());
+
   GetContentClient()->browser()->AppendExtraCommandLineSwitches(
       cmd_line.get(), process_->GetData().id);
 
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc b/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc
index 375da42c..eaf04a7 100644
--- a/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc
+++ b/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc
@@ -53,11 +53,13 @@
 const int kRenderFrameId = 31415;
 const int kSharedMemoryCount = 11;
 const char kSecurityOrigin[] = "http://localhost";
+#if BUILDFLAG(ENABLE_WEBRTC)
 #if defined(OS_WIN)
 const wchar_t kBaseFileName[] = L"some_file_name";
 #else
 const char kBaseFileName[] = "some_file_name";
-#endif
+#endif  // defined(OS_WIN)
+#endif  // BUILDFLAG(ENABLE_WEBRTC)
 
 url::Origin SecurityOrigin() {
   return url::Origin(GURL(kSecurityOrigin));
diff --git a/content/test/gpu/gpu_tests/gpu_process_integration_test.py b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
index 89691ed..225c3dd 100644
--- a/content/test/gpu/gpu_tests/gpu_process_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
@@ -115,7 +115,8 @@
              ('GpuProcess_identify_active_gpu2', 'chrome:gpu'),
              ('GpuProcess_identify_active_gpu3', 'chrome:gpu'),
              ('GpuProcess_identify_active_gpu4', 'chrome:gpu'),
-             ('GpuProcess_software_gpu_process', 'about:blank'))
+             ('GpuProcess_software_gpu_process', 'about:blank'),
+             ('GpuProcess_disabling_workarounds_works', 'chrome:gpu'))
 
     # The earlier has_transparent_visuals_gpu_process and
     # no_transparent_visuals_gpu_process tests became no-ops in
@@ -526,6 +527,17 @@
     self._Navigate(test_path)
     self._VerifyGpuProcessPresent()
 
+  def _GpuProcess_disabling_workarounds_works(self, test_path):
+    self.RestartBrowserIfNecessaryWithArgs([
+      '--gpu-testing-vendor-id=0xbad9',
+      '--gpu-testing-device-id=0xbad9',
+      '--use_gpu_driver_workaround_for_testing=0'])
+    self._Navigate(test_path)
+    workarounds, _ = (
+      self._CompareAndCaptureDriverBugWorkarounds())
+    if 'use_gpu_driver_workaround_for_testing' in workarounds:
+      self.fail('use_gpu_driver_workaround_for_testing erroneously present')
+
 def load_tests(loader, tests, pattern):
   del loader, tests, pattern  # Unused.
   return gpu_integration_test.LoadAllTestsInModule(sys.modules[__name__])
diff --git a/gpu/config/gpu_driver_bug_list.cc b/gpu/config/gpu_driver_bug_list.cc
index 7ab68a10..edd9dcf 100644
--- a/gpu/config/gpu_driver_bug_list.cc
+++ b/gpu/config/gpu_driver_bug_list.cc
@@ -94,5 +94,17 @@
   }
 }
 
+// static
+void GpuDriverBugList::AppendAllWorkarounds(
+    std::vector<const char*>* workarounds) {
+  workarounds->resize(workarounds->size() +
+      NUMBER_OF_GPU_DRIVER_BUG_WORKAROUND_TYPES);
+
+#define GPU_OP(type, name) workarounds->push_back(#name);
+  GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)
+#undef GPU_OP
+}
+
+
 }  // namespace gpu
 
diff --git a/gpu/config/gpu_driver_bug_list.h b/gpu/config/gpu_driver_bug_list.h
index 8db219f..0ec839e 100644
--- a/gpu/config/gpu_driver_bug_list.h
+++ b/gpu/config/gpu_driver_bug_list.h
@@ -28,6 +28,11 @@
       std::set<int>* workarounds,
       const base::CommandLine& command_line);
 
+  // Append |workarounds| with the full list of workarounds.
+  // This is needed for correctly passing flags down from
+  // the browser process to the GPU process.
+  static void AppendAllWorkarounds(std::vector<const char*>* workarounds);
+
  private:
   GpuDriverBugList();
 
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc
index dc2c7a8..2ff6190a 100644
--- a/gpu/config/gpu_driver_bug_list_json.cc
+++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -19,7 +19,7 @@
 {
   "name": "gpu driver bug list",
   // Please update the version number whenever you change this file.
-  "version": "9.29",
+  "version": "9.30",
   "entries": [
     {
       "id": 1,
@@ -2324,6 +2324,9 @@
         "use_virtualized_gl_contexts"
       ]
     },
+)  // LONG_STRING_CONST macro
+// Avoid C2026 (string too big) error on VisualStudio.
+LONG_STRING_CONST(
     {
       "id": 214,
       "description": "Certain versions of Qualcomm driver don't setup scissor state correctly when FBO0 is bound.",
@@ -2333,6 +2336,16 @@
       "features": [
         "force_update_scissor_state_when_binding_fbo0"
       ]
+    },
+    {
+      "id": 215,
+      "description": "Fake no-op GPU driver bug workaround for testing",
+      "cr_bugs": [682912],
+      "vendor_id": "0xbad9",
+      "device_id": ["0xbad9"],
+      "features": [
+        "use_gpu_driver_workaround_for_testing"
+      ]
     }
   ]
   // Please update the version number at beginning of this file whenever you
diff --git a/ios/chrome/browser/reading_list/BUILD.gn b/ios/chrome/browser/reading_list/BUILD.gn
index 4a869ce..40d5ac3 100644
--- a/ios/chrome/browser/reading_list/BUILD.gn
+++ b/ios/chrome/browser/reading_list/BUILD.gn
@@ -26,6 +26,7 @@
   ]
   deps = [
     "//base",
+    "//components/browser_sync",
     "//components/dom_distiller/ios",
     "//components/favicon/core",
     "//components/favicon/ios",
diff --git a/ios/chrome/browser/reading_list/reading_list_model_factory.cc b/ios/chrome/browser/reading_list/reading_list_model_factory.cc
index b6e2c0c..e396d61 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_factory.cc
+++ b/ios/chrome/browser/reading_list/reading_list_model_factory.cc
@@ -9,6 +9,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/singleton.h"
+#include "components/browser_sync/profile_sync_service.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/reading_list/core/reading_list_switches.h"
@@ -19,6 +20,7 @@
 #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
 #include "ios/chrome/common/channel_info.h"
 #include "ios/web/public/web_thread.h"
 
@@ -62,23 +64,18 @@
 
 std::unique_ptr<KeyedService> ReadingListModelFactory::BuildServiceInstanceFor(
     web::BrowserState* context) const {
-  scoped_refptr<base::SequencedTaskRunner> background_task_runner =
-      web::WebThread::GetBlockingPool()->GetSequencedTaskRunner(
-          web::WebThread::GetBlockingPool()->GetSequenceToken());
+  ios::ChromeBrowserState* chrome_browser_state =
+      ios::ChromeBrowserState::FromBrowserState(context);
+  browser_sync::ProfileSyncService* profile_sync_service =
+      IOSChromeProfileSyncServiceFactory::GetForBrowserState(
+          chrome_browser_state);
 
-  base::FilePath database_dir(
-      context->GetStatePath().Append(FILE_PATH_LITERAL("readinglist")));
-
-  // TODO(crbug.com/664920): use a shared location for the store.
   std::unique_ptr<ReadingListStore> store = base::MakeUnique<ReadingListStore>(
-      base::Bind(&syncer::ModelTypeStore::CreateStore, syncer::READING_LIST,
-                 database_dir.AsUTF8Unsafe(), background_task_runner),
+      profile_sync_service->GetModelTypeStoreFactory(syncer::READING_LIST),
       base::Bind(&syncer::ModelTypeChangeProcessor::Create,
                  base::BindRepeating(&syncer::ReportUnrecoverableError,
                                      GetChannel())));
 
-  ios::ChromeBrowserState* chrome_browser_state =
-      ios::ChromeBrowserState::FromBrowserState(context);
   std::unique_ptr<KeyedService> reading_list_model =
       base::MakeUnique<ReadingListModelImpl>(std::move(store),
                                              chrome_browser_state->GetPrefs());
diff --git a/ios/chrome/browser/sync/BUILD.gn b/ios/chrome/browser/sync/BUILD.gn
index 3dabba1..14f9eed6 100644
--- a/ios/chrome/browser/sync/BUILD.gn
+++ b/ios/chrome/browser/sync/BUILD.gn
@@ -67,6 +67,7 @@
   allow_circular_includes_from = [
     "//ios/chrome/browser/history",
     "//ios/chrome/browser/passwords",
+    "//ios/chrome/browser/reading_list",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/sync/glue",
     "//ios/chrome/browser/sync/sessions",
diff --git a/ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory_unittest.cc b/ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory_unittest.cc
index a6514e3b..b82fa5c 100644
--- a/ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory_unittest.cc
+++ b/ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory_unittest.cc
@@ -6,10 +6,9 @@
 
 #include <stddef.h>
 
-#include <memory>
+#include <vector>
 
 #include "base/command_line.h"
-#include "base/macros.h"
 #include "components/browser_sync/browser_sync_switches.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/reading_list/core/reading_list_switches.h"
diff --git a/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.cc b/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.cc
index f83e9782..e861a942 100644
--- a/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.cc
+++ b/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.cc
@@ -4,6 +4,8 @@
 
 #include "ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "components/browser_sync/profile_sync_service_mock.h"
diff --git a/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.h b/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.h
index 341c040..2d59185 100644
--- a/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.h
+++ b/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.h
@@ -5,6 +5,7 @@
 #ifndef IOS_CHROME_BROWSER_SYNC_IOS_CHROME_SYNCED_TAB_DELEGATE_H_
 #define IOS_CHROME_BROWSER_SYNC_IOS_CHROME_SYNCED_TAB_DELEGATE_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
diff --git a/ios/chrome/browser/sync/sync_setup_service.cc b/ios/chrome/browser/sync/sync_setup_service.cc
index d496363..601e1f58 100644
--- a/ios/chrome/browser/sync/sync_setup_service.cc
+++ b/ios/chrome/browser/sync/sync_setup_service.cc
@@ -6,7 +6,6 @@
 
 #include <stdio.h>
 
-#include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/stop_source.h"
diff --git a/ios/chrome/browser/tabs/tab_model_order_controller_unittest.mm b/ios/chrome/browser/tabs/tab_model_order_controller_unittest.mm
index 450d8a3..bde32a3 100644
--- a/ios/chrome/browser/tabs/tab_model_order_controller_unittest.mm
+++ b/ios/chrome/browser/tabs/tab_model_order_controller_unittest.mm
@@ -5,11 +5,13 @@
 #include "base/mac/scoped_nsautorelease_pool.h"
 #include "base/memory/ptr_util.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#include "ios/chrome/browser/browser_state/test_chrome_browser_state_manager.h"
 #import "ios/chrome/browser/sessions/session_window.h"
 #import "ios/chrome/browser/sessions/test_session_service.h"
 #import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/tabs/tab_model_order_controller.h"
+#include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_state_manager.h"
 #include "ios/web/public/referrer.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
 #include "ios/web/public/web_thread.h"
@@ -21,7 +23,10 @@
 class TabModelOrderControllerTest : public PlatformTest {
  protected:
   TabModelOrderControllerTest()
-      : thread_bundle_(web::TestWebThreadBundle::IO_MAINLOOP) {}
+      : thread_bundle_(web::TestWebThreadBundle::IO_MAINLOOP),
+        scoped_browser_state_manager_(
+            base::MakeUnique<TestChromeBrowserStateManager>(base::FilePath())) {
+  }
 
   void SetUp() override {
     DCHECK_CURRENTLY_ON(web::WebThread::UI);
@@ -78,6 +83,7 @@
   GURL url_;
   web::Referrer referrer_;
   web::TestWebThreadBundle thread_bundle_;
+  IOSChromeScopedTestingChromeBrowserStateManager scoped_browser_state_manager_;
   base::scoped_nsobject<SessionWindowIOS> sessionWindow_;
   std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
   base::scoped_nsobject<Tab> dummy_tab_;
diff --git a/ios/chrome/browser/ui/static_content/static_html_native_content.mm b/ios/chrome/browser/ui/static_content/static_html_native_content.mm
index 10b55bb..5c151b9 100644
--- a/ios/chrome/browser/ui/static_content/static_html_native_content.mm
+++ b/ios/chrome/browser/ui/static_content/static_html_native_content.mm
@@ -119,6 +119,10 @@
   return [_staticHTMLViewController webView];
 }
 
+- (void)setDelegate:(id<CRWNativeContentDelegate>)delegate {
+  [_staticHTMLViewController setDelegate:delegate];
+}
+
 - (NSString*)title {
   return [_staticHTMLViewController title];
 }
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index 356dd718..2aaff9e 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -26,6 +26,7 @@
   "//mojo/common/typemaps.gni",
   "//mojo/public/cpp/bindings/tests/chromium_typemaps.gni",
   "//net/interfaces/typemaps.gni",
+  "//services/memory_instrumentation/public/cpp/typemaps.gni",
   "//services/service_manager/public/cpp/typemaps.gni",
   "//services/ui/gpu/interfaces/typemaps.gni",
   "//services/ui/public/interfaces/ime/typemaps.gni",
diff --git a/net/cert/cert_verify_proc_android.cc b/net/cert/cert_verify_proc_android.cc
index 0ce19d63..a59ab28 100644
--- a/net/cert/cert_verify_proc_android.cc
+++ b/net/cert/cert_verify_proc_android.cc
@@ -297,13 +297,6 @@
       verify_result->verified_cert = verified_cert;
   }
 
-  // Extract the algorithm information from the certs
-  X509Certificate::OSCertHandles chain;
-  const X509Certificate::OSCertHandles& intermediates =
-      verify_result->verified_cert->GetIntermediateCertificates();
-  chain.push_back(verify_result->verified_cert->os_cert_handle());
-  chain.insert(chain.end(), intermediates.begin(), intermediates.end());
-
   // Extract the public key hashes.
   for (size_t i = 0; i < verified_chain.size(); i++) {
     base::StringPiece spki_bytes;
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index c8831644..7cff730 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -405,6 +405,9 @@
   DCHECK_NE(job_type_, PRECONNECT);
   DCHECK(!delegate_->for_websockets());
 
+  UMA_HISTOGRAM_TIMES("Net.HttpStreamFactoryJob.StreamReadyCallbackTime",
+                      base::TimeTicks::Now() - job_stream_ready_start_time_);
+
   MaybeCopyConnectionAttemptsFromSocketOrHandle();
 
   delegate_->OnStreamReady(this, server_ssl_config_);
@@ -623,6 +626,7 @@
         }
       } else {
         DCHECK(stream_.get());
+        job_stream_ready_start_time_ = base::TimeTicks::Now();
         base::ThreadTaskRunnerHandle::Get()->PostTask(
             FROM_HERE,
             base::Bind(&Job::OnStreamReadyCallback, ptr_factory_.GetWeakPtr()));
diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h
index 6917b0e..a04e8e3 100644
--- a/net/http/http_stream_factory_impl_job.h
+++ b/net/http/http_stream_factory_impl_job.h
@@ -475,6 +475,8 @@
   // Only used if |new_spdy_session_| is non-NULL.
   bool spdy_session_direct_;
 
+  base::TimeTicks job_stream_ready_start_time_;
+
   // Type of stream that is requested.
   HttpStreamRequest::StreamType stream_type_;
 
diff --git a/pdf/pdfium/pdfium_page.cc b/pdf/pdfium/pdfium_page.cc
index 39db69e..e8070f2 100644
--- a/pdf/pdfium/pdfium_page.cc
+++ b/pdf/pdfium/pdfium_page.cc
@@ -180,7 +180,8 @@
   int text_run_font_size = FPDFText_GetFontSize(text_page, char_index);
   pp::FloatRect text_run_bounds =
       GetFloatCharRectInPixels(page, text_page, char_index);
-  char_index++;
+  if (char_index < chars_count)
+    char_index++;
   while (char_index < chars_count) {
     unsigned int character = FPDFText_GetUnicode(text_page, char_index);
 
diff --git a/services/BUILD.gn b/services/BUILD.gn
index ddb175f1..39efe0d 100644
--- a/services/BUILD.gn
+++ b/services/BUILD.gn
@@ -16,6 +16,7 @@
 service_test("service_unittests") {
   deps = [
     "//services/image_decoder:tests",
+    "//services/memory_instrumentation:tests",
   ]
 
   if (is_android) {
diff --git a/services/memory_instrumentation/BUILD.gn b/services/memory_instrumentation/BUILD.gn
new file mode 100644
index 0000000..144268ab
--- /dev/null
+++ b/services/memory_instrumentation/BUILD.gn
@@ -0,0 +1,31 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("lib") {
+  sources = [
+    "coordinator_impl.cc",
+    "coordinator_impl.h",
+  ]
+
+  public_deps = [
+    "//base",
+    "//services/memory_instrumentation/public/cpp",
+    "//services/memory_instrumentation/public/interfaces",
+  ]
+}
+
+source_set("tests") {
+  testonly = true
+
+  sources = [
+    "coordinator_impl_unittest.cc",
+  ]
+
+  deps = [
+    ":lib",
+    "//base",
+    "//mojo/public/cpp/bindings",
+    "//testing/gtest",
+  ]
+}
diff --git a/services/memory_instrumentation/coordinator_impl.cc b/services/memory_instrumentation/coordinator_impl.cc
new file mode 100644
index 0000000..90d3e30c
--- /dev/null
+++ b/services/memory_instrumentation/coordinator_impl.cc
@@ -0,0 +1,186 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/memory_instrumentation/coordinator_impl.h"
+
+#include "base/bind_helpers.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_request_args.h"
+#include "services/memory_instrumentation/public/interfaces/memory_instrumentation.mojom.h"
+
+namespace memory_instrumentation {
+
+namespace {
+
+base::LazyInstance<CoordinatorImpl>::Leaky g_coordinator =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// static
+CoordinatorImpl* CoordinatorImpl::GetInstance() {
+  return g_coordinator.Pointer();
+}
+
+// TODO(chiniforooshan): Initialize the global MemoryDumpManager instance here.
+// This is how the global MemoryDumpManager gets a reference to the delegate on
+// the service (read the browser) process for service process memory dumps. This
+// can be done when the delegate implementation is landed.
+CoordinatorImpl::CoordinatorImpl()
+    : failed_memory_dump_count_(0) {}
+
+CoordinatorImpl::~CoordinatorImpl() {}
+
+void CoordinatorImpl::BindCoordinatorRequest(
+    mojom::CoordinatorRequest request) {
+  bindings_.AddBinding(this, std::move(request));
+}
+
+CoordinatorImpl::QueuedMemoryDumpRequest::QueuedMemoryDumpRequest(
+    const base::trace_event::MemoryDumpRequestArgs args,
+    const RequestGlobalMemoryDumpCallback callback)
+    : args(args), callback(callback) {}
+
+CoordinatorImpl::QueuedMemoryDumpRequest::~QueuedMemoryDumpRequest() {}
+
+void CoordinatorImpl::RequestGlobalMemoryDump(
+    const base::trace_event::MemoryDumpRequestArgs& args,
+    const RequestGlobalMemoryDumpCallback& callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  bool another_dump_already_in_progress = !queued_memory_dump_requests_.empty();
+
+  // If this is a periodic memory dump request and there already is another
+  // request in the queue with the same level of detail, there's no point in
+  // enqueuing this request.
+  if (another_dump_already_in_progress &&
+      args.dump_type == base::trace_event::MemoryDumpType::PERIODIC_INTERVAL) {
+    for (const auto& request : queued_memory_dump_requests_) {
+      if (request.args.level_of_detail == args.level_of_detail) {
+        VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix << " ("
+                << base::trace_event::MemoryDumpTypeToString(args.dump_type)
+                << ") skipped because another dump request with the same "
+                   "level of detail ("
+                << base::trace_event::MemoryDumpLevelOfDetailToString(
+                       args.level_of_detail)
+                << ") is already in the queue";
+        callback.Run(args.dump_guid, false /* success */);
+        return;
+      }
+    }
+  }
+
+  queued_memory_dump_requests_.emplace_back(args, callback);
+
+  // If another dump is already in progress, this dump will automatically be
+  // scheduled when the other dump finishes.
+  if (another_dump_already_in_progress)
+    return;
+
+  PerformNextQueuedGlobalMemoryDump();
+}
+
+void CoordinatorImpl::RegisterProcessLocalDumpManager(
+    mojom::ProcessLocalDumpManagerPtr process_manager) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  process_manager.set_connection_error_handler(
+      base::Bind(&CoordinatorImpl::UnregisterProcessLocalDumpManager,
+                 base::Unretained(this),
+                 process_manager.get()));
+  auto result = process_managers_.insert(
+      std::make_pair<mojom::ProcessLocalDumpManager*,
+                     mojom::ProcessLocalDumpManagerPtr>(
+          process_manager.get(), std::move(process_manager)));
+  DCHECK(result.second);
+}
+
+void CoordinatorImpl::UnregisterProcessLocalDumpManager(
+    mojom::ProcessLocalDumpManager* process_manager) {
+  DCHECK(process_managers_.erase(process_manager) == 1);
+
+  // Check if we are waiting for an ack from this process-local manager.
+  if (pending_process_managers_.find(process_manager) !=
+      pending_process_managers_.end()) {
+    DCHECK(!queued_memory_dump_requests_.empty());
+    OnProcessMemoryDumpResponse(
+        process_manager,
+        queued_memory_dump_requests_.front().args.dump_guid,
+        false /* success */);
+  }
+}
+
+void CoordinatorImpl::PerformNextQueuedGlobalMemoryDump() {
+  DCHECK(!queued_memory_dump_requests_.empty());
+  const base::trace_event::MemoryDumpRequestArgs& args =
+      queued_memory_dump_requests_.front().args;
+
+  // No need to treat the service process different than other processes. The
+  // service process will register itself as a ProcessLocalDumpManager and will
+  // be treated like other process-local managers.
+  pending_process_managers_.clear();
+  failed_memory_dump_count_ = 0;
+  for (const auto& key_value : process_managers_) {
+    pending_process_managers_.insert(key_value.first);
+    key_value.second->RequestProcessMemoryDump(
+        args,
+        base::Bind(&CoordinatorImpl::OnProcessMemoryDumpResponse,
+                   base::Unretained(this),
+                   key_value.first));
+  }
+  // Run the callback in case there are no process-local managers.
+  FinalizeGlobalMemoryDumpIfAllManagersReplied();
+}
+
+void CoordinatorImpl::OnProcessMemoryDumpResponse(
+    mojom::ProcessLocalDumpManager* process_manager,
+    uint64_t dump_guid,
+    bool success) {
+  auto it = pending_process_managers_.find(process_manager);
+
+  DCHECK(!queued_memory_dump_requests_.empty());
+  if (queued_memory_dump_requests_.front().args.dump_guid != dump_guid ||
+      it == pending_process_managers_.end()) {
+    VLOG(1) << "Received unexpected memory dump response: " << dump_guid;
+    return;
+  }
+  pending_process_managers_.erase(it);
+
+  if (!success) {
+    ++failed_memory_dump_count_;
+    VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix
+            << " failed because of NACK from provider";
+  }
+  FinalizeGlobalMemoryDumpIfAllManagersReplied();
+}
+
+void CoordinatorImpl::FinalizeGlobalMemoryDumpIfAllManagersReplied() {
+  if (pending_process_managers_.size() > 0)
+    return;
+
+  DCHECK(!queued_memory_dump_requests_.empty());
+  {
+    const auto& callback = queued_memory_dump_requests_.front().callback;
+    const bool global_success = failed_memory_dump_count_ == 0;
+    callback.Run(queued_memory_dump_requests_.front().args.dump_guid,
+                 global_success);
+  }
+  queued_memory_dump_requests_.pop_front();
+
+  // Schedule the next queued dump (if applicable).
+  if (!queued_memory_dump_requests_.empty()) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &CoordinatorImpl::PerformNextQueuedGlobalMemoryDump,
+            base::Unretained(this)));
+  }
+}
+
+}  // namespace memory_instrumentation
diff --git a/services/memory_instrumentation/coordinator_impl.h b/services/memory_instrumentation/coordinator_impl.h
new file mode 100644
index 0000000..ab76df1
--- /dev/null
+++ b/services/memory_instrumentation/coordinator_impl.h
@@ -0,0 +1,87 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_MEMORY_INSTRUMENTATION_COORDINATOR_IMPL_H_
+#define SERVICES_MEMORY_INSTRUMENTATION_COORDINATOR_IMPL_H_
+
+#include <list>
+#include <set>
+#include <unordered_map>
+
+#include "base/lazy_instance.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
+#include "base/trace_event/memory_dump_request_args.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/memory_instrumentation/public/cpp/coordinator.h"
+#include "services/memory_instrumentation/public/interfaces/memory_instrumentation.mojom.h"
+
+namespace memory_instrumentation {
+
+class CoordinatorImpl : public Coordinator, public mojom::Coordinator {
+ public:
+  static CoordinatorImpl* GetInstance();
+
+  // Coordinator
+  void BindCoordinatorRequest(mojom::CoordinatorRequest) override;
+
+ private:
+  friend class CoordinatorImplTest;  // For testing
+  friend struct base::DefaultLazyInstanceTraits<CoordinatorImpl>;
+
+  struct QueuedMemoryDumpRequest {
+    QueuedMemoryDumpRequest(
+        const base::trace_event::MemoryDumpRequestArgs args,
+        const RequestGlobalMemoryDumpCallback callback);
+    ~QueuedMemoryDumpRequest();
+    const base::trace_event::MemoryDumpRequestArgs args;
+    const RequestGlobalMemoryDumpCallback callback;
+  };
+
+  CoordinatorImpl();
+  ~CoordinatorImpl() override;
+
+  // mojom::Coordinator
+  void RegisterProcessLocalDumpManager(
+      mojom::ProcessLocalDumpManagerPtr process_manager) override;
+
+  // Broadcasts a dump request to all the process-local managers registered and
+  // notifies when all of them have completed, or the global dump attempt
+  // failed. This is in the mojom::Coordinator interface.
+  void RequestGlobalMemoryDump(
+      const base::trace_event::MemoryDumpRequestArgs& args,
+      const RequestGlobalMemoryDumpCallback& callback) override;
+
+  // Called when a process-local manager gets disconnected.
+  void UnregisterProcessLocalDumpManager(
+      mojom::ProcessLocalDumpManager* process_manager);
+
+  // Callback of RequestProcessMemoryDump.
+  void OnProcessMemoryDumpResponse(
+      mojom::ProcessLocalDumpManager* process_manager,
+      uint64_t dump_guid,
+      bool success);
+
+  void PerformNextQueuedGlobalMemoryDump();
+  void FinalizeGlobalMemoryDumpIfAllManagersReplied();
+
+  mojo::BindingSet<mojom::Coordinator> bindings_;
+
+  // Registered ProcessLocalDumpManagers.
+  std::unordered_map<mojom::ProcessLocalDumpManager*,
+                     mojom::ProcessLocalDumpManagerPtr> process_managers_;
+
+  // Pending process managers for RequestGlobalMemoryDump.
+  std::set<mojom::ProcessLocalDumpManager*> pending_process_managers_;
+  int failed_memory_dump_count_;
+  std::list<QueuedMemoryDumpRequest> queued_memory_dump_requests_;
+
+  base::ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(CoordinatorImpl);
+};
+
+}  // namespace memory_instrumentation
+#endif  // SERVICES_MEMORY_INFSTRUMENTATION_COORDINATOR_IMPL_H_
diff --git a/services/memory_instrumentation/coordinator_impl_unittest.cc b/services/memory_instrumentation/coordinator_impl_unittest.cc
new file mode 100644
index 0000000..5b91a2b
--- /dev/null
+++ b/services/memory_instrumentation/coordinator_impl_unittest.cc
@@ -0,0 +1,146 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind_helpers.h"
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/trace_event/memory_dump_request_args.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/memory_instrumentation/coordinator_impl.h"
+#include "services/memory_instrumentation/public/interfaces/memory_instrumentation.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace memory_instrumentation {
+
+class CoordinatorImplTest : public testing::Test {
+ public:
+  CoordinatorImplTest() { }
+  void SetUp() override {
+    dump_response_args_ = {static_cast<uint64_t>(-1), false};
+  }
+
+  void RegisterProcessLocalDumpManager(
+      mojom::ProcessLocalDumpManagerPtr process_manager) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(&CoordinatorImpl::RegisterProcessLocalDumpManager,
+                   base::Unretained(&coordinator_),
+                   base::Passed(&process_manager)));
+  }
+
+  void RequestGlobalMemoryDump(base::trace_event::MemoryDumpRequestArgs args,
+                               base::Closure closure) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &CoordinatorImpl::RequestGlobalMemoryDump,
+            base::Unretained(&coordinator_),
+            args,
+            base::Bind(&CoordinatorImplTest::OnGlobalMemoryDumpResponse,
+                       base::Unretained(this), closure)));
+  }
+
+  void OnGlobalMemoryDumpResponse(base::Closure closure,
+                                  uint64_t dump_guid, bool success) {
+    dump_response_args_ = {dump_guid, success};
+    closure.Run();
+  }
+
+ protected:
+  struct DumpResponseArgs {
+    uint64_t dump_guid;
+    bool success;
+  };
+
+  DumpResponseArgs dump_response_args_;
+
+ private:
+  CoordinatorImpl coordinator_;
+  base::MessageLoop message_loop_;
+};
+
+class MockDumpManager : mojom::ProcessLocalDumpManager {
+ public:
+  MockDumpManager(CoordinatorImplTest* test_coordinator, int expected_calls)
+      : binding_(this), expected_calls_(expected_calls) {
+    // Register to the coordinator.
+    mojom::ProcessLocalDumpManagerPtr process_manager;
+    binding_.Bind(mojo::MakeRequest(&process_manager));
+    test_coordinator->RegisterProcessLocalDumpManager(
+        std::move(process_manager));
+  }
+
+  ~MockDumpManager() override {
+    EXPECT_EQ(0, expected_calls_);
+  }
+
+  void RequestProcessMemoryDump(
+      const base::trace_event::MemoryDumpRequestArgs& args,
+      const RequestProcessMemoryDumpCallback& callback) override {
+    expected_calls_--;
+    callback.Run(args.dump_guid, true);
+  }
+
+ private:
+  mojo::Binding<mojom::ProcessLocalDumpManager> binding_;
+  int expected_calls_;
+};
+
+TEST_F(CoordinatorImplTest, NoProcessLocalManagers) {
+  base::RunLoop run_loop;
+  base::trace_event::MemoryDumpRequestArgs args = {
+      1234,
+      base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
+      base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+  RequestGlobalMemoryDump(args, run_loop.QuitClosure());
+  run_loop.Run();
+  EXPECT_EQ(static_cast<uint64_t>(1234), dump_response_args_.dump_guid);
+  EXPECT_TRUE(dump_response_args_.success);
+}
+
+TEST_F(CoordinatorImplTest, SeveralProcessLocalManagers) {
+  base::RunLoop run_loop;
+
+  MockDumpManager dump_manager_1(this, 1);
+  MockDumpManager dump_manager_2(this, 1);
+  base::trace_event::MemoryDumpRequestArgs args = {
+      2345,
+      base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
+      base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+  RequestGlobalMemoryDump(args, run_loop.QuitClosure());
+
+  run_loop.Run();
+
+  EXPECT_EQ(static_cast<uint64_t>(2345), dump_response_args_.dump_guid);
+  EXPECT_TRUE(dump_response_args_.success);
+}
+
+TEST_F(CoordinatorImplTest, FaultyProcessLocalManager) {
+  base::RunLoop run_loop;
+
+  MockDumpManager dump_manager_1(this, 1);
+  std::unique_ptr<MockDumpManager> dump_manager_2(new MockDumpManager(this, 0));
+  base::trace_event::MemoryDumpRequestArgs args = {
+      3456,
+      base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
+      base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+  RequestGlobalMemoryDump(args, run_loop.QuitClosure());
+  // One of the process-local managers dies after a global dump is requested and
+  // before it receives the corresponding process dump request. The coordinator
+  // should detect that one of its clients is disconnected and claim the global
+  // dump attempt has failed.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind([](std::unique_ptr<MockDumpManager> dm) { },
+                 base::Passed(&dump_manager_2)));
+
+  run_loop.Run();
+
+  EXPECT_EQ(static_cast<uint64_t>(3456), dump_response_args_.dump_guid);
+  EXPECT_FALSE(dump_response_args_.success);
+}
+}  // namespace memory_instrumentation
diff --git a/services/memory_instrumentation/public/cpp/BUILD.gn b/services/memory_instrumentation/public/cpp/BUILD.gn
index 403c247..99a22d62 100644
--- a/services/memory_instrumentation/public/cpp/BUILD.gn
+++ b/services/memory_instrumentation/public/cpp/BUILD.gn
@@ -2,13 +2,28 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+source_set("cpp") {
+  sources = [
+    "coordinator.h",
+  ]
+
+  deps = [
+    ":struct_traits",
+  ]
+
+  public_deps = [
+    "//services/memory_instrumentation/public/interfaces",
+  ]
+}
+
 source_set("struct_traits") {
   sources = [
     "memory_instrumentation_traits.cc",
     "memory_instrumentation_traits.h",
   ]
 
-  deps = [
+  public_deps = [
+    "//base",
     "//services/memory_instrumentation/public/interfaces",
   ]
 }
diff --git a/services/memory_instrumentation/public/cpp/coordinator.h b/services/memory_instrumentation/public/cpp/coordinator.h
new file mode 100644
index 0000000..9c75396d
--- /dev/null
+++ b/services/memory_instrumentation/public/cpp/coordinator.h
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_MEMORY_INSTRUMENTATION_PUBLIC_CPP_COORDINATOR_H_
+#define SERVICES_MEMORY_INSTRUMENTATION_PUBLIC_CPP_COORDINATOR_H_
+
+#include "services/memory_instrumentation/public/interfaces/memory_instrumentation.mojom.h"
+
+namespace memory_instrumentation {
+
+class Coordinator {
+ public:
+  // Binds a CoordinatorRequest to this Coordinator instance.
+  virtual void BindCoordinatorRequest(mojom::CoordinatorRequest) = 0;
+};
+
+}  // namespace memory_instrumentation
+
+#endif  // SERVICES_MEMORY_INSTRUMENTATION_PUBLIC_CPP_COORDINATOR_H_
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 74bff0c5..fa58096 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2409,6 +2409,26 @@
             ]
         }
     ],
+    "TranslateRankerLogging": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "ios",
+                "linux",
+                "mac",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "TranslateRankerLogging",
+                    "enable_features": [
+                        "TranslateRankerLogging"
+                    ]
+                }
+            ]
+        }
+    ],
     "TranslateUiLangTrial": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/fast/dom/geometry-interface-dom-quad.html b/third_party/WebKit/LayoutTests/fast/dom/geometry-interface-dom-quad.html
index 4ab3e500..7cf3781 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/geometry-interface-dom-quad.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/geometry-interface-dom-quad.html
@@ -8,7 +8,7 @@
   var p2 = new DOMPoint(5, 6, 7, 8);
   var p3 = new DOMPoint(9, 10, 11, 12);
   var p4 = new DOMPoint(13, 14, 15, 16);
-  var quad =  new DOMQuad(p1, p2, p3, p4);
+  var quad = new DOMQuad(p1, p2, p3, p4);
   assert_dom_point_equals(quad.p1, p1);
   assert_dom_point_equals(quad.p2, p2);
   assert_dom_point_equals(quad.p3, p3);
@@ -32,11 +32,38 @@
   var expect_p2 = new DOMPoint(90, 20, 0, 1);
   var expect_p3 = new DOMPoint(90, 70, 0, 1);
   var expect_p4 = new DOMPoint(10, 70, 0, 1);
-  var quad =  DOMQuad.fromRect({x: 10, y: 20, width: 80, height: 50});
+  var quad = DOMQuad.fromRect({x: 10, y: 20, width: 80, height: 50});
   assert_dom_point_equals(quad.p1, expect_p1, "p1");
   assert_dom_point_equals(quad.p2, expect_p2, "p2");
   assert_dom_point_equals(quad.p3, expect_p3, "p3");
   assert_dom_point_equals(quad.p4, expect_p4, "p4");
 }, "DOMQuad() fromRect");
 
+test(() => {
+  var expect_p1 = new DOMPoint(0, 1, 2, 3);
+  var expect_p2 = new DOMPoint(4, 5, 6, 7);
+  var expect_p3 = new DOMPoint(8, 9, 10, 11);
+  var expect_p4 = new DOMPoint(12, 13, 14, 15);
+  var quad = DOMQuad.fromQuad({p1: {x: 0, y: 1, z: 2, w: 3},
+                                      p2: {x: 4, y: 5, z: 6, w: 7},
+                                      p3: {x: 8, y: 9, z: 10, w: 11},
+                                      p4: {x: 12, y: 13, z: 14, w: 15}});
+  assert_dom_point_equals(quad.p1, expect_p1, "p1");
+  assert_dom_point_equals(quad.p2, expect_p2, "p2");
+  assert_dom_point_equals(quad.p3, expect_p3, "p3");
+  assert_dom_point_equals(quad.p4, expect_p4, "p4");
+}, "DOMQuad() fromQuad");
+
+test(() => {
+  var expect_p1 = new DOMPoint(0, 0, 0, 1);
+  var expect_p2 = new DOMPoint(0, 0, 0, 1);
+  var expect_p3 = new DOMPoint(0, 0, 0, 1);
+  var expect_p4 = new DOMPoint(0, 0, 0, 1);
+  var quad = DOMQuad.fromQuad({});
+  assert_dom_point_equals(quad.p1, expect_p1, "p1");
+  assert_dom_point_equals(quad.p2, expect_p2, "p2");
+  assert_dom_point_equals(quad.p3, expect_p3, "p3");
+  assert_dom_point_equals(quad.p4, expect_p4, "p4");
+}, "DOMQuad() fromQuad - parameter of fromQuad function does not have any point.");
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
index 5765c5d..3b20845 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
@@ -720,14 +720,20 @@
     }
 }
 
-InspectorTest.clickJavaScriptSourceFrameBreakpoint = function(sourceFrame, lineNumber, index)
+InspectorTest.clickJavaScriptSourceFrameBreakpoint = function(sourceFrame, lineNumber, index, next)
 {
     var textEditor = sourceFrame._textEditor;
     var lineLength = textEditor.line(lineNumber).length;
     var lineRange = new Common.TextRange(lineNumber, 0, lineNumber, lineLength);
     var bookmarks = textEditor.bookmarks(lineRange, Sources.JavaScriptSourceFrame.BreakpointDecoration._bookmarkSymbol);
     bookmarks.sort((bookmark1, bookmark2) => bookmark1.position().startColumn - bookmark2.position().startColumn);
-    bookmarks[index][Sources.JavaScriptSourceFrame.BreakpointDecoration._elementSymbolForTest].click();
+    var bookmark = bookmarks[index];
+    if (bookmark) {
+        bookmark[Sources.JavaScriptSourceFrame.BreakpointDecoration._elementSymbolForTest].click();
+    } else {
+        InspectorTest.addResult(`Could not click on Javascript breakpoint - lineNumber: ${lineNumber}, index: ${index}`);
+        next();
+    }
 }
 
 };
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-skip-step-in.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-skip-step-in.html
index 4d9a96c..1977578 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-skip-step-in.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-skip-step-in.html
@@ -37,7 +37,7 @@
 function test4()
 {
     debugger;
-    Framework.safeRun(Framework.doSomeWork, callback); // Should NOT step into callback (otherwise too many StepIns)
+    Framework.safeRun(Framework.doSomeWork, callback); // Should step into callback
 }
 
 function test5()
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-inline-breakpoint-decorations.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-inline-breakpoint-decorations.html
index ed16e80..0ec8830 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-inline-breakpoint-decorations.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-inline-breakpoint-decorations.html
@@ -84,21 +84,21 @@
             {
                 InspectorTest.addResult("Click by second breakpoint");
                 waitAndDumpDecorations(javaScriptSourceFrame).then(clickByFirstLocation);
-                InspectorTest.clickJavaScriptSourceFrameBreakpoint(javaScriptSourceFrame, 3, 1);
+                InspectorTest.clickJavaScriptSourceFrameBreakpoint(javaScriptSourceFrame, 3, 1, next);
             }
 
             function clickByFirstLocation()
             {
                 InspectorTest.addResult("Click by first breakpoint");
                 waitAndDumpDecorations(javaScriptSourceFrame).then(clickBySecondLocationAgain);
-                InspectorTest.clickJavaScriptSourceFrameBreakpoint(javaScriptSourceFrame, 3, 0);
+                InspectorTest.clickJavaScriptSourceFrameBreakpoint(javaScriptSourceFrame, 3, 0, next);
             }
 
             function clickBySecondLocationAgain()
             {
                 InspectorTest.addResult("Click by second breakpoint");
                 waitAndDumpDecorations(javaScriptSourceFrame).then(() => next());
-                InspectorTest.clickJavaScriptSourceFrameBreakpoint(javaScriptSourceFrame, 3, 1);
+                InspectorTest.clickJavaScriptSourceFrameBreakpoint(javaScriptSourceFrame, 3, 1, next);
             }
         },
 
@@ -126,8 +126,8 @@
             {
                 InspectorTest.addResult("Click by first inline breakpoints");
                 waitAndDumpDecorations(javaScriptSourceFrame).then(() => next());
-                InspectorTest.clickJavaScriptSourceFrameBreakpoint(javaScriptSourceFrame, 3, 0);
-                InspectorTest.clickJavaScriptSourceFrameBreakpoint(javaScriptSourceFrame, 4, 0);
+                InspectorTest.clickJavaScriptSourceFrameBreakpoint(javaScriptSourceFrame, 3, 0, next);
+                InspectorTest.clickJavaScriptSourceFrameBreakpoint(javaScriptSourceFrame, 4, 0, next);
             }
         }
     ]);
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-all-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-all-expected.png
index 6fbb50ed..54e582a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-expected.png
index 6c8fc95..1874913 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-out-of-flow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-out-of-flow-expected.png
index 793575f..63653af 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-out-of-flow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-out-of-flow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-all-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-all-expected.png
index 124028a..a0faa0a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-expected.png
index f54e0391..c26b284 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-out-of-flow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-out-of-flow-expected.png
index 6cd07771..1239886 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-out-of-flow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-out-of-flow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-all-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-all-expected.png
index 2d83a31f..d8d1a31 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-expected.png
index 2049a2c..45c4260 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-out-of-flow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-out-of-flow-expected.png
index 81cb2e29..766c669 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-out-of-flow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-out-of-flow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic-expected.txt
index 446e589..951d2c4 100644
--- a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic-expected.txt
@@ -6,8 +6,9 @@
 PASS context.suspend() rejected correctly (with TypeError: Failed to execute 'suspend' on 'OfflineAudioContext': 1 argument required, but only 0 present.).
 PASS context.suspend(-1.0) rejected correctly (with InvalidStateError: negative suspend time (-1) is not allowed).
 PASS context.suspend(2.0) rejected correctly (with InvalidStateError: cannot schedule a suspend at frame 88192 (2 seconds) because it is greater than or equal to the total render duration of 44100 frames).
-PASS Scheduling a suspend in the past rejected correctly (with InvalidStateError: cannot schedule a suspend at frame 17536 (0.399229 seconds) because it is earlier than the current frame of 22016 (0.499229 seconds)).
+PASS Scheduling a suspend in the past rejected correctly (with InvalidStateError: suspend(0.399229) failed to suspend at frame 17536 because it is earlier than the current frame of 22016 (0.499229 seconds)).
 PASS Scheduling a suspend in the future resolved correctly.
+PASS Scheduling a suspend after the render completion rejected correctly (with InvalidStateError: suspend(1) failed to suspend at frame 44032 because it is earlier than the current frame of 44100 (1 seconds)).
 PASS Scheduling a suspend at frame 128 was successful.
 PASS Scheduling another suspend at the same rendering quantum rejected correctly (with InvalidStateError: cannot schedule more than one suspend at frame 128 (0.00435374 seconds)).
 PASS Scheduling a suspend at 4.5 seconds.
diff --git a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic.html
index eb1ab235..ba06bce 100644
--- a/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic.html
@@ -49,6 +49,17 @@
         context.startRendering().then(done);
       });
 
+      // Task: suspending after rendering is finished must be rejected with the
+      // properly clamped frame/time information.
+      audit.defineTask('suspend-after-render-completion', function (done) {
+        var context = new OfflineAudioContext(
+            1, sampleRate * renderDuration, sampleRate);
+        context.startRendering().then(function () {
+            Should('Scheduling a suspend after the render completion',
+              context.suspend(renderDuration)).beRejected();
+        }).then(done);
+      });
+
       // Task: Calling multiple suspends at the same rendering quantum should
       // reject the promise.
       audit.defineTask('identical-suspend-time', function (done) {
@@ -123,6 +134,7 @@
       audit.runTasks(
         'suspend-invalid-argument',
         'suspend-in-the-past',
+        'suspend-after-render-completion',
         'identical-suspend-time',
         'resume-before-suspend',
         'resume-without-suspend',
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 1e3472d..50e669f 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -1149,6 +1149,7 @@
     method matrixTransform
     method toJSON
 interface DOMQuad
+    static method fromQuad
     static method fromRect
     attribute @@toStringTag
     getter p1
diff --git a/third_party/WebKit/Source/build/scripts/json5_generator.py b/third_party/WebKit/Source/build/scripts/json5_generator.py
index 00f4e9a..4c7a63d 100644
--- a/third_party/WebKit/Source/build/scripts/json5_generator.py
+++ b/third_party/WebKit/Source/build/scripts/json5_generator.py
@@ -164,14 +164,23 @@
         return entry
 
     def _validate_parameter(self, parameter, value):
-        valid_values = parameter.get("valid_values")
-        if valid_values and value not in valid_values:
-            raise Exception("Unknown value: '%s'\nKnown values: %s" %
-                            (value, valid_values))
         valid_type = parameter.get("valid_type")
         if valid_type and type(value).__name__ != valid_type:
             raise Exception("Incorrect type: '%s'\nExpected type: %s" %
                             (type(value).__name__, valid_type))
+        valid_values = parameter.get("valid_values")
+        if not valid_values:
+            return
+        # If valid_values is a list of simple items and not list of list, then
+        # validate each item in the value list against valid_values.
+        if valid_type == "list" and type(valid_values[0]) is not list:
+            for item in value:
+                if item not in valid_values:
+                    raise Exception("Unknown value: '%s'\nKnown values: %s" %
+                                    (item, valid_values))
+        elif value not in valid_values:
+            raise Exception("Unknown value: '%s'\nKnown values: %s" %
+                            (value, valid_values))
 
 
 class Writer(object):
diff --git a/third_party/WebKit/Source/core/dom/DOMQuad.cpp b/third_party/WebKit/Source/core/dom/DOMQuad.cpp
index 1b87a219..853e0740 100644
--- a/third_party/WebKit/Source/core/dom/DOMQuad.cpp
+++ b/third_party/WebKit/Source/core/dom/DOMQuad.cpp
@@ -6,6 +6,7 @@
 
 #include "bindings/core/v8/V8ObjectBuilder.h"
 #include "core/dom/DOMPoint.h"
+#include "core/dom/DOMQuadInit.h"
 #include "core/dom/DOMRectInit.h"
 
 namespace blink {
@@ -21,6 +22,13 @@
   return new DOMQuad(other.x(), other.y(), other.width(), other.height());
 }
 
+DOMQuad* DOMQuad::fromQuad(const DOMQuadInit& other) {
+  return new DOMQuad(other.hasP1() ? other.p1() : DOMPointInit(),
+                     other.hasP2() ? other.p2() : DOMPointInit(),
+                     other.hasP3() ? other.p3() : DOMPointInit(),
+                     other.hasP3() ? other.p4() : DOMPointInit());
+}
+
 DOMQuad::DOMQuad(const DOMPointInit& p1,
                  const DOMPointInit& p2,
                  const DOMPointInit& p3,
diff --git a/third_party/WebKit/Source/core/dom/DOMQuad.h b/third_party/WebKit/Source/core/dom/DOMQuad.h
index 19ef067..b2219d10 100644
--- a/third_party/WebKit/Source/core/dom/DOMQuad.h
+++ b/third_party/WebKit/Source/core/dom/DOMQuad.h
@@ -13,6 +13,7 @@
 
 class DOMPoint;
 class DOMPointInit;
+class DOMQuadInit;
 class DOMRectInit;
 
 class CORE_EXPORT DOMQuad : public GarbageCollected<DOMQuad>,
@@ -25,6 +26,7 @@
                          const DOMPointInit& p3,
                          const DOMPointInit& p4);
   static DOMQuad* fromRect(const DOMRectInit&);
+  static DOMQuad* fromQuad(const DOMQuadInit&);
 
   DOMPoint* p1() const { return m_p1; }
   DOMPoint* p2() const { return m_p2; }
diff --git a/third_party/WebKit/Source/core/dom/DOMQuad.idl b/third_party/WebKit/Source/core/dom/DOMQuad.idl
index c0729a9e..7c605263 100644
--- a/third_party/WebKit/Source/core/dom/DOMQuad.idl
+++ b/third_party/WebKit/Source/core/dom/DOMQuad.idl
@@ -12,7 +12,7 @@
 ]
 interface DOMQuad {
     [NewObject] static DOMQuad fromRect(optional DOMRectInit other);
-    // TODO(hs1217.lee): [NewObject] static DOMQuad fromQuad(optional DOMQuadInit other);
+    [NewObject] static DOMQuad fromQuad(optional DOMQuadInit other);
 
     [SameObject] readonly attribute DOMPoint p1;
     [SameObject] readonly attribute DOMPoint p2;
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
index 8c70b95..0f183ce 100644
--- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
@@ -77,42 +77,47 @@
   }
 }
 
-static int computeUnderlineOffset(const ComputedStyle& style,
-                                  const FontMetrics& fontMetrics,
-                                  const InlineTextBox* inlineTextBox,
-                                  const float textDecorationThickness) {
+static int computeUnderlineOffsetForRoman(const FontMetrics& fontMetrics,
+                                          const float textDecorationThickness) {
   // Compute the gap between the font and the underline. Use at least one
   // pixel gap, if underline is thick then use a bigger gap.
   int gap = 0;
 
   // Underline position of zero means draw underline on Baseline Position,
   // in Blink we need at least 1-pixel gap to adding following check.
-  // Positive underline Position means underline should be drawn above baselin e
+  // Positive underline Position means underline should be drawn above baseline
   // and negative value means drawing below baseline, negating the value as in
-  // Blink
-  // downward Y-increases.
+  // Blink downward Y-increases.
 
   if (fontMetrics.underlinePosition())
     gap = -fontMetrics.underlinePosition();
   else
     gap = std::max<int>(1, ceilf(textDecorationThickness / 2.f));
 
+  // Position underline near the alphabetic baseline.
+  return fontMetrics.ascent() + gap;
+}
+
+static int computeUnderlineOffset(const ComputedStyle& style,
+                                  const FontMetrics& fontMetrics,
+                                  const InlineTextBox* inlineTextBox,
+                                  const float textDecorationThickness) {
   // FIXME: We support only horizontal text for now.
   switch (style.getTextUnderlinePosition()) {
+    default:
+      NOTREACHED();
+    // Fall through.
     case TextUnderlinePositionAuto:
-      return fontMetrics.ascent() +
-             gap;  // Position underline near the alphabetic baseline.
+      return computeUnderlineOffsetForRoman(fontMetrics,
+                                            textDecorationThickness);
     case TextUnderlinePositionUnder: {
-      // Position underline relative to the under edge of the lowest element's
+      // Position underline at the under edge of the lowest element's
       // content box.
       LayoutUnit offset = computeUnderlineOffsetForUnder(style, inlineTextBox);
       offset = inlineTextBox->logicalHeight() + std::max(offset, LayoutUnit());
-      return offset.toInt() + gap;
+      return offset.toInt();
     }
   }
-
-  NOTREACHED();
-  return fontMetrics.ascent() + gap;
 }
 
 static bool shouldSetDecorationAntialias(
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
index f4b885c..a692caa 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
@@ -340,6 +340,7 @@
     overflow: auto;
     position: relative;
     background-color: #f3f3f3;
+    -webkit-user-select: text;
 }
 
 .timeline-details-view-body > div {
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-async/async-callstack-in-console-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-async/async-callstack-in-console-expected.txt
new file mode 100644
index 0000000..372acb7
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-async/async-callstack-in-console-expected.txt
@@ -0,0 +1,62 @@
+CONSOLE MESSAGE: line 11: console.clear
+CONSOLE MESSAGE: line 17: console.trace
+CONSOLE ERROR: line 24: Uncaught Error: foo
+CONSOLE MESSAGE: line 29: console.trace
+CONSOLE ERROR: line 37: Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('http://www.example.com') does not match the recipient window's origin ('').
+Tests asynchronous call stacks printed in console.
+
+
+Set timer for test function.
+async-callstack-in-console.html:11 Console was cleared
+async-callstack-in-console.html:17 console.trace
+
+timeout1 @ async-callstack-in-console.html:17
+
+setTimeout (async)
+
+testFunction @ async-callstack-in-console.html:12
+async-callstack-in-console.html:24 Uncaught Error: foo
+    at timeout2 (async-callstack-in-console.html:24)
+
+timeout2 @ async-callstack-in-console.html:24
+
+setTimeout (async)
+
+timeout1 @ async-callstack-in-console.html:18
+
+setTimeout (async)
+
+testFunction @ async-callstack-in-console.html:12
+async-callstack-in-console.html:29 console.trace
+
+timeout3 @ async-callstack-in-console.html:29
+
+setTimeout (async)
+
+timeout2 @ async-callstack-in-console.html:23
+
+setTimeout (async)
+
+timeout1 @ async-callstack-in-console.html:18
+
+setTimeout (async)
+
+testFunction @ async-callstack-in-console.html:12
+async-callstack-in-console.html:37 Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('http://www.example.com') does not match the recipient window's origin ('file://').
+
+tryPostMessage @ async-callstack-in-console.html:37
+
+timeout3 @ async-callstack-in-console.html:31
+
+setTimeout (async)
+
+timeout2 @ async-callstack-in-console.html:23
+
+setTimeout (async)
+
+timeout1 @ async-callstack-in-console.html:18
+
+setTimeout (async)
+
+testFunction @ async-callstack-in-console.html:12
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-async/async-callstack-promises-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-async/async-callstack-promises-expected.txt
new file mode 100644
index 0000000..cf369f6
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-async/async-callstack-promises-expected.txt
@@ -0,0 +1,243 @@
+Tests asynchronous call stacks for Promises.
+
+Set timer for test function.
+Captured call stacks in no particular order:
+Call stack:
+    0) afterJSONStringifyAndParse (async-callstack-promises.html:97)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) doTestChainedPromises (async-callstack-promises.html:93)
+    3) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) catchCallback (async-callstack-promises.html:118)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) chained1 (async-callstack-promises.html:110)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) doTestThrowFromChain (async-callstack-promises.html:109)
+    3) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) catchCallback (async-callstack-promises.html:130)
+    [Promise.reject]
+    0) rejectPromise (async-callstack-promises.html:16)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:19)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) chained3 (async-callstack-promises.html:126)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) chained2 (async-callstack-promises.html:124)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) chained1 (async-callstack-promises.html:122)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) doTestThrowFromChain (async-callstack-promises.html:121)
+    3) testFunctionTimeout (async-callstack-promises.html:50)
+
+Call stack:
+    0) chained1 (async-callstack-promises.html:80)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) doTestChainedPromises (async-callstack-promises.html:79)
+    3) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) chained2 (async-callstack-promises.html:83)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) chained1 (async-callstack-promises.html:81)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) doTestChainedPromises (async-callstack-promises.html:79)
+    3) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) chained3 (async-callstack-promises.html:86)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) chained1 (async-callstack-promises.html:81)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) doTestChainedPromises (async-callstack-promises.html:79)
+    3) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) chained4 (async-callstack-promises.html:89)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) chained1 (async-callstack-promises.html:81)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) doTestChainedPromises (async-callstack-promises.html:79)
+    3) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) errorCallback (async-callstack-promises.html:60)
+    [Promise.reject]
+    0) doTestPromiseResolveAndReject (async-callstack-promises.html:137)
+    1) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) errorCallback (async-callstack-promises.html:60)
+    [Promise.reject]
+    0) doTestSettledPromises (async-callstack-promises.html:74)
+    1) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) promiseCallback (async-callstack-promises.html:67)
+    1) doTestPromiseConstructor (async-callstack-promises.html:65)
+    2) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) thenCallback (async-callstack-promises.html:55)
+    [Promise.resolve]
+    0) doTestPromiseResolveAndReject (async-callstack-promises.html:136)
+    1) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) thenCallback (async-callstack-promises.html:55)
+    [Promise.resolve]
+    0) doTestSettledPromises (async-callstack-promises.html:73)
+    1) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) thenCallback (async-callstack-promises.html:55)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) chained4 (async-callstack-promises.html:90)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) chained1 (async-callstack-promises.html:81)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) doTestChainedPromises (async-callstack-promises.html:79)
+    3) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) thenCallback (async-callstack-promises.html:55)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) doTestPromiseAll (async-callstack-promises.html:103)
+    3) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-breakpoints/nodejs-set-breakpoint-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-breakpoints/nodejs-set-breakpoint-expected.txt
index 973ecd3..1d53b06 100644
--- a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-breakpoints/nodejs-set-breakpoint-expected.txt
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-breakpoints/nodejs-set-breakpoint-expected.txt
@@ -2,8 +2,6 @@
 Verify that front-end is able to set breakpoint for node.js scripts.
 
 Setting breakpoint:
-error: Request Debugger.getPossibleBreakpoints failed. {"code":-32601,"message":"'Debugger.getPossibleBreakpoints' wasn't found"}
-error: Request Debugger.getPossibleBreakpoints failed. {"code":-32601,"message":"'Debugger.getPossibleBreakpoints' wasn't found"}
 Script execution paused.
 Successfully paused on breakpoint
 Script execution resumed.
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-breakpoints/possible-breakpoints-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-breakpoints/possible-breakpoints-expected.txt
new file mode 100644
index 0000000..2c1c2e7
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-breakpoints/possible-breakpoints-expected.txt
@@ -0,0 +1,7 @@
+Checks that BreakpointManager.possibleBreakpoints returns correct locations
+
+Locations for first line
+All locations
+Existing location by position
+Not existing location by position
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-breakpoints/use-possible-breakpoints-to-resolve-breakpoint-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-breakpoints/use-possible-breakpoints-to-resolve-breakpoint-expected.txt
new file mode 100644
index 0000000..005b4ad
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-breakpoints/use-possible-breakpoints-to-resolve-breakpoint-expected.txt
@@ -0,0 +1,10 @@
+Checks that locations are correctly resolved for gutter click.
+
+3: breakpointAdded(3, 0)
+4: breakpointAdded(4, 0)
+5: breakpointAdded(5, 0)
+6: breakpointAdded(6, 0)
+11: breakpointAdded(11, 0)
+12: breakpointAdded(12, 0)
+13: breakpointAdded(13, 0)
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-frameworks/frameworks-skip-step-in-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-frameworks/frameworks-skip-step-in-expected.txt
new file mode 100644
index 0000000..e066ecf
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-frameworks/frameworks-skip-step-in-expected.txt
@@ -0,0 +1,39 @@
+
+Tests the skip stack frames feature when stepping.
+
+Set timer for test function.
+Call stack:
+    0) test1 (frameworks-skip-step-in.html:23)
+    1) testFunction (frameworks-skip-step-in.html:11)
+
+Call stack:
+    0) test2 (frameworks-skip-step-in.html:29)
+    1) testFunction (frameworks-skip-step-in.html:11)
+
+Call stack:
+    0) callback (frameworks-skip-step-in.html:16)
+  * 1) Framework.safeRun (framework.js:8)
+  * 2) Framework.safeRun (framework.js:10)
+    3) test3 (frameworks-skip-step-in.html:34)
+    4) testFunction (frameworks-skip-step-in.html:11)
+
+Call stack:
+    0) test4 (frameworks-skip-step-in.html:41)
+    1) testFunction (frameworks-skip-step-in.html:11)
+
+Call stack:
+    0) callback (frameworks-skip-step-in.html:16)
+  * 1) Framework.safeRun (framework.js:8)
+  * 2) Framework.safeRun (framework.js:13)
+  * 3) Framework.safeRun (framework.js:10)
+    4) test5 (frameworks-skip-step-in.html:46)
+    5) testFunction (frameworks-skip-step-in.html:11)
+
+Call stack:
+    0) callback (frameworks-skip-step-in.html:16)
+  * 1) Framework.safeRun (framework.js:8)
+  * 2) Framework.safeRun (framework.js:10)
+    3) test6 (frameworks-skip-step-in.html:52)
+    4) testFunction (frameworks-skip-step-in.html:11)
+
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt
new file mode 100644
index 0000000..d01eacb
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt
@@ -0,0 +1,25 @@
+
+Tests that stepping into blackboxed framework will not pause on setTimeout() inside the framework.
+
+Set timer for test function.
+Call stack:
+    0) stop (frameworks-step-into-skips-setTimeout.html:25)
+    1) callback (frameworks-step-into-skips-setTimeout.html:19)
+  * 2) Framework_scheduleUntilDone (framework.js:142)
+
+Executing StepOut...
+Call stack:
+    0) callback (frameworks-step-into-skips-setTimeout.html:20)
+  * 1) Framework_scheduleUntilDone (framework.js:142)
+
+Executing StepInto...
+Call stack:
+    0) callback (frameworks-step-into-skips-setTimeout.html:21)
+  * 1) Framework_scheduleUntilDone (framework.js:142)
+
+Executing StepInto...
+Call stack:
+    0) callback (frameworks-step-into-skips-setTimeout.html:17)
+  * 1) Framework_scheduleUntilDone (framework.js:142)
+
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-frameworks/frameworks-steppings-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-frameworks/frameworks-steppings-expected.txt
new file mode 100644
index 0000000..8eb5cfc
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-frameworks/frameworks-steppings-expected.txt
@@ -0,0 +1,136 @@
+
+Tests stepping into/over/out with framework black-boxing.
+
+Set timer for test function.
+Call stack:
+    0) testFunction (frameworks-steppings.html:10)
+
+Executing StepInto...
+Executing StepInto...
+Call stack:
+    0) callback1 (frameworks-steppings.html:12)
+  * 1) Framework.safeRun (framework.js:8)
+    2) testFunction (frameworks-steppings.html:11)
+
+Executing StepInto...
+Call stack:
+    0) callback2 (frameworks-steppings.html:18)
+  * 1) Framework.safeRun (framework.js:8)
+  * 2) Framework.safeRun (framework.js:10)
+    3) callback1 (frameworks-steppings.html:12)
+  * 4) Framework.safeRun (framework.js:8)
+    5) testFunction (frameworks-steppings.html:11)
+
+Executing StepInto...
+Call stack:
+    0) callback2 (frameworks-steppings.html:19)
+  * 1) Framework.safeRun (framework.js:8)
+  * 2) Framework.safeRun (framework.js:10)
+    3) callback1 (frameworks-steppings.html:12)
+  * 4) Framework.safeRun (framework.js:8)
+    5) testFunction (frameworks-steppings.html:11)
+
+Executing StepInto...
+Call stack:
+    0) callback3 (frameworks-steppings.html:24)
+  * 1) Framework.safeRun (framework.js:8)
+  * 2) Framework.safeRun (framework.js:13)
+  * 3) Framework.safeRun (framework.js:10)
+    4) callback2 (frameworks-steppings.html:19)
+  * 5) Framework.safeRun (framework.js:8)
+  * 6) Framework.safeRun (framework.js:10)
+    7) callback1 (frameworks-steppings.html:12)
+  * 8) Framework.safeRun (framework.js:8)
+    9) testFunction (frameworks-steppings.html:11)
+
+Executing StepInto...
+Executing StepInto...
+Executing StepInto...
+Executing StepInto...
+Call stack:
+    0) callback4 (frameworks-steppings.html:32)
+  * 1) Framework_bound (framework.js:105)
+  * 2) Framework_bound (framework.js:105)
+  * 3) Framework_bound (framework.js:105)
+  * 4) Framework.safeRun (framework.js:8)
+    5) callback3 (frameworks-steppings.html:27)
+  * 6) Framework.safeRun (framework.js:8)
+  * 7) Framework.safeRun (framework.js:13)
+  * 8) Framework.safeRun (framework.js:10)
+    9) callback2 (frameworks-steppings.html:19)
+  * 10) Framework.safeRun (framework.js:8)
+  * 11) Framework.safeRun (framework.js:10)
+    12) callback1 (frameworks-steppings.html:12)
+  * 13) Framework.safeRun (framework.js:8)
+    14) testFunction (frameworks-steppings.html:11)
+
+Executing StepInto...
+Call stack:
+    0) callback4 (frameworks-steppings.html:36)
+  * 1) Framework_bound (framework.js:105)
+  * 2) Framework_bound (framework.js:105)
+  * 3) Framework_bound (framework.js:105)
+  * 4) Framework.safeRun (framework.js:8)
+    5) callback3 (frameworks-steppings.html:27)
+  * 6) Framework.safeRun (framework.js:8)
+  * 7) Framework.safeRun (framework.js:13)
+  * 8) Framework.safeRun (framework.js:10)
+    9) callback2 (frameworks-steppings.html:19)
+  * 10) Framework.safeRun (framework.js:8)
+  * 11) Framework.safeRun (framework.js:10)
+    12) callback1 (frameworks-steppings.html:12)
+  * 13) Framework.safeRun (framework.js:8)
+    14) testFunction (frameworks-steppings.html:11)
+
+Executing StepInto...
+Executing StepInto...
+Call stack:
+    0) callback4 (frameworks-steppings.html:40)
+  * 1) Framework_bound (framework.js:105)
+  * 2) Framework_bound (framework.js:105)
+  * 3) Framework_bound (framework.js:105)
+  * 4) Framework.safeRun (framework.js:8)
+    5) callback3 (frameworks-steppings.html:27)
+  * 6) Framework.safeRun (framework.js:8)
+  * 7) Framework.safeRun (framework.js:13)
+  * 8) Framework.safeRun (framework.js:10)
+    9) callback2 (frameworks-steppings.html:19)
+  * 10) Framework.safeRun (framework.js:8)
+  * 11) Framework.safeRun (framework.js:10)
+    12) callback1 (frameworks-steppings.html:12)
+  * 13) Framework.safeRun (framework.js:8)
+    14) testFunction (frameworks-steppings.html:11)
+
+Executing StepInto...
+Call stack:
+    0) callback3 (frameworks-steppings.html:28)
+  * 1) Framework.safeRun (framework.js:8)
+  * 2) Framework.safeRun (framework.js:13)
+  * 3) Framework.safeRun (framework.js:10)
+    4) callback2 (frameworks-steppings.html:19)
+  * 5) Framework.safeRun (framework.js:8)
+  * 6) Framework.safeRun (framework.js:10)
+    7) callback1 (frameworks-steppings.html:12)
+  * 8) Framework.safeRun (framework.js:8)
+    9) testFunction (frameworks-steppings.html:11)
+
+Executing StepOut...
+Call stack:
+    0) callback2 (frameworks-steppings.html:20)
+  * 1) Framework.safeRun (framework.js:8)
+  * 2) Framework.safeRun (framework.js:10)
+    3) callback1 (frameworks-steppings.html:12)
+  * 4) Framework.safeRun (framework.js:8)
+    5) testFunction (frameworks-steppings.html:11)
+
+Executing StepOver...
+Call stack:
+    0) callback1 (frameworks-steppings.html:13)
+  * 1) Framework.safeRun (framework.js:8)
+    2) testFunction (frameworks-steppings.html:11)
+
+Executing StepInto...
+Call stack:
+    0) testFunction (frameworks-steppings.html:14)
+
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-pause/debugger-eval-while-paused-throws-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-pause/debugger-eval-while-paused-throws-expected.txt
new file mode 100644
index 0000000..511c1d8
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-pause/debugger-eval-while-paused-throws-expected.txt
@@ -0,0 +1,32 @@
+Tests that evaluation in console that throws works fine when script is paused.
+
+Set timer for test function.
+Dumping console messages:
+
+injectedFunction()
+VM:6 Uncaught Error: injectedObj.func
+    at Object.func (<anonymous>:6:23)
+    at injectedFunction (<anonymous>:9:28)
+    at eval (eval at evaluate, <anonymous>:1:1)
+    at testFunction (test.js:23:5)
+func @ VM:6
+injectedFunction @ VM:9
+(anonymous) @ VM:1
+testFunction @ test.js:18
+localObj.func()
+test.js:15 Uncaught Error: localObj.func
+    at Object.func (test.js:20:19)
+    at eval (eval at evaluate, <anonymous>:1:10)
+    at testFunction (test.js:23:5)
+func @ test.js:15
+(anonymous) @ VM:1
+testFunction @ test.js:18
+globalObj.func()
+test.js:6 Uncaught Error: globalObj.func
+    at Object.func (test.js:11:15)
+    at eval (eval at evaluate, <anonymous>:1:11)
+    at testFunction (test.js:23:5)
+func @ test.js:6
+(anonymous) @ VM:1
+testFunction @ test.js:18
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-ui/debugger-save-to-temp-var-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-ui/debugger-save-to-temp-var-expected.txt
new file mode 100644
index 0000000..b642947
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-ui/debugger-save-to-temp-var-expected.txt
@@ -0,0 +1,29 @@
+Tests saving objects to temporary variables while paused.
+
+Set timer for test function.
+Number of expressions: 11
+Names [temp3..temp7] are reserved
+
+temp1
+42
+temp2
+"foo string"
+temp8
+NaN
+temp9
+Infinity
+temp10
+-Infinity
+temp11
+-0
+temp12
+[1, 2, NaN, -0, null, undefined]
+temp13
+Object {foo: "bar"}
+temp14
+[1, 2, 3, 4]
+temp15
+function func() {}
+temp16
+Error: errr
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-ui/function-generator-details-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-ui/function-generator-details-expected.txt
new file mode 100644
index 0000000..0ad0a51
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-ui/function-generator-details-expected.txt
@@ -0,0 +1,72 @@
+Tests that Debugger.getGeneratorObjectDetails command returns correct result.
+
+
+Running: testIterNotStarted
+iterNotStarted: type = object, subtype = generator
+[[GeneratorStatus]] = suspended
+[[GeneratorFunction]] = function* gen()
+{
+    yield 1;
+    yield 2;
+    yield 3;
+}
+[[GeneratorReceiver]] = Window
+lineNumber = 13
+columnNumber = 13
+script is valid: yes
+
+Running: testIterSuspended
+iterSuspended: type = object, subtype = generator
+[[GeneratorStatus]] = suspended
+[[GeneratorFunction]] = function* gen()
+{
+    yield 1;
+    yield 2;
+    yield 3;
+}
+[[GeneratorReceiver]] = Window
+lineNumber = 15
+columnNumber = 4
+script is valid: yes
+
+Running: testIterClosed
+iterClosed: type = object, subtype = generator
+[[GeneratorStatus]] = closed
+[[GeneratorFunction]] = function* gen()
+{
+    yield 1;
+    yield 2;
+    yield 3;
+}
+[[GeneratorReceiver]] = Window
+lineNumber = 13
+columnNumber = 13
+script is valid: yes
+
+Running: testIterObjGenerator
+iterObjGenerator: type = object, subtype = generator
+[[GeneratorStatus]] = suspended
+[[GeneratorFunction]] = function* ()
+    {
+        yield 11;
+        yield 12;
+        yield 13;
+    }
+[[GeneratorReceiver]] = Object
+lineNumber = 24
+columnNumber = 8
+script is valid: yes
+
+Running: testAnonymousGenIter
+anonymousGenIter: type = object, subtype = generator
+[[GeneratorStatus]] = suspended
+[[GeneratorFunction]] = function* () {
+    yield 21;
+    yield 22;
+    yield 23;
+}
+[[GeneratorReceiver]] = Window
+lineNumber = 38
+columnNumber = 4
+script is valid: yes
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-ui/watch-expressions-preserve-expansion-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-ui/watch-expressions-preserve-expansion-expected.txt
new file mode 100644
index 0000000..0794d3d
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger-ui/watch-expressions-preserve-expansion-expected.txt
@@ -0,0 +1,265 @@
+Test that watch expressions expansion state is restored after update.
+
+Bug 99304
+Watch expressions added.
+expanded foo [object Object]
+expanded bar [object Object]
+expanded [[Scopes]] [object Object]
+expanded 0 [object Object]
+expanded a [object Object]
+expanded [200 .. 299] 
+expanded 299 [object Object]
+Watch expressions expanded.
+globalObject: Object
+    foo: Object
+      bar: Object
+      __proto__: Object
+    __proto__: Object
+windowAlias: Window
+array: Array[300]
+    [0 .. 99]
+    [100 .. 199]
+    [200 .. 299]
+      200: 200
+      201: 201
+      202: 202
+      203: 203
+      204: 204
+      205: 205
+      206: 206
+      207: 207
+      208: 208
+      209: 209
+      210: 210
+      211: 211
+      212: 212
+      213: 213
+      214: 214
+      215: 215
+      216: 216
+      217: 217
+      218: 218
+      219: 219
+      220: 220
+      221: 221
+      222: 222
+      223: 223
+      224: 224
+      225: 225
+      226: 226
+      227: 227
+      228: 228
+      229: 229
+      230: 230
+      231: 231
+      232: 232
+      233: 233
+      234: 234
+      235: 235
+      236: 236
+      237: 237
+      238: 238
+      239: 239
+      240: 240
+      241: 241
+      242: 242
+      243: 243
+      244: 244
+      245: 245
+      246: 246
+      247: 247
+      248: 248
+      249: 249
+      250: 250
+      251: 251
+      252: 252
+      253: 253
+      254: 254
+      255: 255
+      256: 256
+      257: 257
+      258: 258
+      259: 259
+      260: 260
+      261: 261
+      262: 262
+      263: 263
+      264: 264
+      265: 265
+      266: 266
+      267: 267
+      268: 268
+      269: 269
+      270: 270
+      271: 271
+      272: 272
+      273: 273
+      274: 274
+      275: 275
+      276: 276
+      277: 277
+      278: 278
+      279: 279
+      280: 280
+      281: 281
+      282: 282
+      283: 283
+      284: 284
+      285: 285
+      286: 286
+      287: 287
+      288: 288
+      289: 289
+      290: 290
+      291: 291
+      292: 292
+      293: 293
+      294: 294
+      295: 295
+      296: 296
+      297: 297
+      298: 298
+      299: 299
+    length: 300
+    __proto__: Array[0]
+func: function () {return a + b;}
+    arguments: null
+    caller: null
+    length: 0
+    name: 
+    prototype: Object
+    __proto__: function () {}
+    [[FunctionLocation]]: Object
+    [[Scopes]]: Scopes[2]
+      0: Closure
+        a: 10
+        b: 100
+      1: Global
+Page reloaded.
+Watch expressions after page reload:
+globalObject: Object
+    foo: Object
+      bar: Object
+      __proto__: Object
+    __proto__: Object
+windowAlias: Window
+array: Array[300]
+    [0 .. 99]
+    [100 .. 199]
+    [200 .. 299]
+      200: 200
+      201: 201
+      202: 202
+      203: 203
+      204: 204
+      205: 205
+      206: 206
+      207: 207
+      208: 208
+      209: 209
+      210: 210
+      211: 211
+      212: 212
+      213: 213
+      214: 214
+      215: 215
+      216: 216
+      217: 217
+      218: 218
+      219: 219
+      220: 220
+      221: 221
+      222: 222
+      223: 223
+      224: 224
+      225: 225
+      226: 226
+      227: 227
+      228: 228
+      229: 229
+      230: 230
+      231: 231
+      232: 232
+      233: 233
+      234: 234
+      235: 235
+      236: 236
+      237: 237
+      238: 238
+      239: 239
+      240: 240
+      241: 241
+      242: 242
+      243: 243
+      244: 244
+      245: 245
+      246: 246
+      247: 247
+      248: 248
+      249: 249
+      250: 250
+      251: 251
+      252: 252
+      253: 253
+      254: 254
+      255: 255
+      256: 256
+      257: 257
+      258: 258
+      259: 259
+      260: 260
+      261: 261
+      262: 262
+      263: 263
+      264: 264
+      265: 265
+      266: 266
+      267: 267
+      268: 268
+      269: 269
+      270: 270
+      271: 271
+      272: 272
+      273: 273
+      274: 274
+      275: 275
+      276: 276
+      277: 277
+      278: 278
+      279: 279
+      280: 280
+      281: 281
+      282: 282
+      283: 283
+      284: 284
+      285: 285
+      286: 286
+      287: 287
+      288: 288
+      289: 289
+      290: 290
+      291: 291
+      292: 292
+      293: 293
+      294: 294
+      295: 295
+      296: 296
+      297: 297
+      298: 298
+      299: 299
+    length: 300
+    __proto__: Array[0]
+func: function () {return a + b;}
+    arguments: null
+    caller: null
+    length: 0
+    name: 
+    prototype: Object
+    __proto__: function () {}
+    [[FunctionLocation]]: Object
+    [[Scopes]]: Scopes[2]
+      0: Closure
+        a: 10
+        b: 100
+      1: Global
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/debugger-scope-minified-variables-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/debugger-scope-minified-variables-expected.txt
new file mode 100644
index 0000000..9b2573e
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/debugger-scope-minified-variables-expected.txt
@@ -0,0 +1,18 @@
+Tests resolving variable names via source maps.
+
+Set timer for test function.
+Script execution paused.
+
+Scope variables sidebar pane:
+Catch
+    error: "boom!"
+Local
+    longMap: Map
+    longObject: Object
+    parameter1: 100
+    parameter2: "hello"
+    this: Window
+WindowGlobal
+    <section collapsed>
+Script execution resumed.
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/properties-special-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/properties-special-expected.txt
new file mode 100644
index 0000000..ccb6bc58
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/properties-special-expected.txt
@@ -0,0 +1,38 @@
+CONSOLE MESSAGE: line 10: true
+CONSOLE MESSAGE: line 11: function (a,b) { return a + b; }
+CONSOLE MESSAGE: line 12: function () { [native code] }
+CONSOLE MESSAGE: line 13: function* () { yeild [1,2,3] }
+Tests how debugger presents special properties of closures, bound functions and object wrappers.
+
+properties-special.html:10 Boolean
+    __proto__: Boolean
+    [[PrimitiveValue]]: true
+properties-special.html:11 function anonymous(a,b)
+    arguments: null
+    caller: null
+    length: 2
+    name: ""
+    prototype: Object
+    __proto__: function ()
+    [[FunctionLocation]]: properties-special.html:11
+    [[Scopes]]: Scopes[1]
+properties-special.html:12 function bound ()
+    arguments: (...)
+    caller: (...)
+    length: 1
+    name: "bound "
+    __proto__: function ()
+    [[TargetFunction]]: function (a,b)
+    [[BoundThis]]: Object
+    [[BoundArgs]]: Array[1]
+properties-special.html:13 function* anonymous()
+    arguments: (...)
+    caller: (...)
+    length: 0
+    name: ""
+    prototype: Generator
+    __proto__: GeneratorFunction
+    [[FunctionLocation]]: properties-special.html:13
+    [[IsGenerator]]: true
+    [[Scopes]]: Scopes[1]
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/rethrow-error-from-bindings-crash-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/rethrow-error-from-bindings-crash-expected.txt
new file mode 100644
index 0000000..9e8fd33
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/rethrow-error-from-bindings-crash-expected.txt
@@ -0,0 +1,40 @@
+CONSOLE MESSAGE: line 11: console.clear
+CONSOLE ERROR: line 25: Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
+CONSOLE ERROR: line 20: Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
+CONSOLE ERROR: line 25: Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
+CONSOLE ERROR: line 20: Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
+CONSOLE ERROR: line 25: Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
+CONSOLE ERROR: line 20: Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
+CONSOLE ERROR: line 25: Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
+CONSOLE ERROR: line 20: Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
+Tests that pausing on uncaught exceptions thrown from C++ bindings will not crash.
+
+Set timer for test function.
+rethrow-error-from-bindings-crash.html:11 Console was cleared
+rethrow-error-from-bindings-crash.html:25 Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
+    at f2 (rethrow-error-from-bindings-crash.html:25)
+    at testFunction (rethrow-error-from-bindings-crash.html:15)
+f2 @ rethrow-error-from-bindings-crash.html:25
+testFunction @ rethrow-error-from-bindings-crash.html:15
+rethrow-error-from-bindings-crash.html:20 Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
+    at f1 (rethrow-error-from-bindings-crash.html:20)
+f1 @ rethrow-error-from-bindings-crash.html:20
+rethrow-error-from-bindings-crash.html:25 Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
+    at f2 (rethrow-error-from-bindings-crash.html:25)
+f2 @ rethrow-error-from-bindings-crash.html:25
+rethrow-error-from-bindings-crash.html:20 Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
+    at f1 (rethrow-error-from-bindings-crash.html:20)
+f1 @ rethrow-error-from-bindings-crash.html:20
+rethrow-error-from-bindings-crash.html:25 Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
+    at f2 (rethrow-error-from-bindings-crash.html:25)
+f2 @ rethrow-error-from-bindings-crash.html:25
+rethrow-error-from-bindings-crash.html:20 Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
+    at f1 (rethrow-error-from-bindings-crash.html:20)
+f1 @ rethrow-error-from-bindings-crash.html:20
+rethrow-error-from-bindings-crash.html:25 Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
+    at f2 (rethrow-error-from-bindings-crash.html:25)
+f2 @ rethrow-error-from-bindings-crash.html:25
+rethrow-error-from-bindings-crash.html:20 Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
+    at f1 (rethrow-error-from-bindings-crash.html:20)
+f1 @ rethrow-error-from-bindings-crash.html:20
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/source-frame-breakpoint-decorations-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/source-frame-breakpoint-decorations-expected.txt
new file mode 100644
index 0000000..42bc8e4
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/source-frame-breakpoint-decorations-expected.txt
@@ -0,0 +1,38 @@
+Checks that JavaScriptSourceFrame show breakpoints correctly
+
+
+Running: testAddRemoveBreakpoint
+Setting breakpoint
+breakpoint at 2
+Toggle breakpoint
+
+Running: testTwoBreakpointsResolvedInOneLine
+Setting breakpoint
+breakpoint at 2
+Toggle breakpoint
+
+Running: testDecorationInGutter
+Adding regular disabled breakpoint
+breakpoint at 2 disabled
+Adding conditional disabled breakpoint
+breakpoint at 0 disabled conditional
+breakpoint at 2 disabled
+Adding regular enabled breakpoint
+breakpoint at 2
+  inline breakpoint at (2, 0) disabled
+  inline breakpoint at (2, 4)
+Adding conditional enabled breakpoint
+breakpoint at 2
+  inline breakpoint at (2, 0) disabled
+  inline breakpoint at (2, 4)
+Disable breakpoints
+breakpoint at 0 disabled
+breakpoint at 2 disabled
+  inline breakpoint at (2, 0) disabled
+  inline breakpoint at (2, 4) disabled
+Enable breakpoints
+breakpoint at 0 disabled
+breakpoint at 2
+Remove breakpoints
+breakpoint at 0 disabled
+
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/source-frame-inline-breakpoint-decorations-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/source-frame-inline-breakpoint-decorations-expected.txt
new file mode 100644
index 0000000..87b24e6
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/sources/debugger/source-frame-inline-breakpoint-decorations-expected.txt
@@ -0,0 +1,27 @@
+Checks that JavaScriptSourceFrame show inline breakpoints correctly
+
+
+Running: testAddRemoveBreakpoint
+Setting breakpoint
+breakpoint at 4
+Toggle breakpoint
+breakpoint at 4
+
+Running: testAddRemoveBreakpointInLineWithOneLocation
+Setting breakpoint
+breakpoint at 4
+breakpoint at 5
+Toggle breakpoint
+breakpoint at 4
+
+Running: clickByInlineBreakpoint
+Setting breakpoint
+breakpoint at 4
+Click by second breakpoint
+Could not click on Javascript breakpoint - lineNumber: 3, index: 1
+
+Running: toggleBreakpointInAnotherLineWontRemoveExisting
+Setting breakpoint in line 4
+Click by first breakpoint
+Could not click on Javascript breakpoint - lineNumber: 3, index: 0
+
diff --git a/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.cpp b/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.cpp
index b841030..39e70ed 100644
--- a/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.cpp
@@ -257,13 +257,15 @@
 
   // The specified suspend time is in the past; reject the promise.
   if (frame < currentSampleFrame()) {
+    size_t currentFrameClamped = std::min(currentSampleFrame(), length());
+    double currentTimeClamped =
+        std::min(currentTime(), length() / static_cast<double>(sampleRate()));
     resolver->reject(DOMException::create(
         InvalidStateError,
-        "cannot schedule a suspend at frame " + String::number(frame) + " (" +
-            String::number(when) +
-            " seconds) because it is earlier than the current frame of " +
-            String::number(currentSampleFrame()) + " (" +
-            String::number(currentTime()) + " seconds)"));
+        "suspend(" + String::number(when) + ") failed to suspend at frame " +
+            String::number(frame) + " because it is earlier than the current " +
+            "frame of " + String::number(currentFrameClamped) + " (" +
+            String::number(currentTimeClamped) + " seconds)"));
     return promise;
   }
 
diff --git a/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.h b/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.h
index aaf705a..3499829 100644
--- a/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.h
+++ b/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.h
@@ -49,7 +49,7 @@
 
   DECLARE_VIRTUAL_TRACE();
 
-  unsigned length() const { return m_totalRenderFrames; }
+  size_t length() const { return m_totalRenderFrames; }
 
   ScriptPromise startOfflineRendering(ScriptState*);
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp
index 24afc52f..fe601869 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp
@@ -27,7 +27,7 @@
   text.append(" userScrollable=");
   if (m_userScrollableHorizontal && m_userScrollableVertical)
     text.append("both");
-  else if (!m_userScrollableHorizontal && !m_userScrollableHorizontal)
+  else if (!m_userScrollableHorizontal && !m_userScrollableVertical)
     text.append("none");
   else
     text.append(m_userScrollableHorizontal ? "horizontal" : "vertical");
diff --git a/third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp b/third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp
index 85f01cb..43055af 100644
--- a/third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp
+++ b/third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp
@@ -38,6 +38,7 @@
 #include "platform/geometry/IntPoint.h"
 #include "platform/geometry/IntRect.h"
 #include "platform/graphics/GraphicsLayer.h"
+#include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
 #include "platform/testing/URLTestHelpers.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebLayer.h"
@@ -54,9 +55,13 @@
 
 namespace blink {
 
-class ScrollingCoordinatorTest : public testing::Test {
+class ScrollingCoordinatorTest : public testing::Test,
+                                 public testing::WithParamInterface<bool>,
+                                 private ScopedRootLayerScrollingForTest {
  public:
-  ScrollingCoordinatorTest() : m_baseURL("http://www.test.com/") {
+  ScrollingCoordinatorTest()
+      : ScopedRootLayerScrollingForTest(GetParam()),
+        m_baseURL("http://www.test.com/") {
     m_helper.initialize(true, nullptr, &m_mockWebViewClient, nullptr,
                         &configureSettings);
     webViewImpl()->resize(IntSize(320, 240));
@@ -84,6 +89,11 @@
     FrameTestHelpers::loadFrame(webViewImpl()->mainFrame(), url);
   }
 
+  void loadHTML(const std::string& html) {
+    FrameTestHelpers::loadHTMLString(webViewImpl()->mainFrame(), html,
+                                     URLTestHelpers::toKURL("about:blank"));
+  }
+
   void forceFullCompositingUpdate() {
     webViewImpl()->updateAllLifecyclePhases();
   }
@@ -95,13 +105,9 @@
   }
 
   WebLayer* getRootScrollLayer() {
-    PaintLayerCompositor* compositor =
-        frame()->contentLayoutItem().compositor();
-    DCHECK(compositor);
-    DCHECK(compositor->scrollLayer());
-
-    WebLayer* webScrollLayer = compositor->scrollLayer()->platformLayer();
-    return webScrollLayer;
+    GraphicsLayer* layer =
+        frame()->view()->layoutViewportScrollableArea()->layerForScrolling();
+    return layer ? layer->platformLayer() : nullptr;
   }
 
   WebViewImpl* webViewImpl() const { return m_helper.webView(); }
@@ -113,9 +119,6 @@
     return webViewImpl()->layerTreeView();
   }
 
-  void styleRelatedMainThreadScrollingReasonTest(const std::string&,
-                                                 const uint32_t);
-
  protected:
   std::string m_baseURL;
   FrameTestHelpers::TestWebViewClient m_mockWebViewClient;
@@ -130,8 +133,11 @@
   FrameTestHelpers::WebViewHelper m_helper;
 };
 
-TEST_F(ScrollingCoordinatorTest, fastScrollingByDefault) {
-  navigateTo("about:blank");
+INSTANTIATE_TEST_CASE_P(All, ScrollingCoordinatorTest, ::testing::Bool());
+
+TEST_P(ScrollingCoordinatorTest, fastScrollingByDefault) {
+  webViewImpl()->resize(WebSize(800, 600));
+  loadHTML("<div id='spacer' style='height: 1000px'></div>");
   forceFullCompositingUpdate();
 
   // Make sure the scrolling coordinator is active.
@@ -143,6 +149,7 @@
 
   // Fast scrolling should be enabled by default.
   WebLayer* rootScrollLayer = getRootScrollLayer();
+  ASSERT_TRUE(rootScrollLayer);
   ASSERT_TRUE(rootScrollLayer->scrollable());
   ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
   ASSERT_EQ(WebEventListenerProperties::Nothing,
@@ -158,8 +165,9 @@
   ASSERT_FALSE(innerViewportScrollLayer->shouldScrollOnMainThread());
 }
 
-TEST_F(ScrollingCoordinatorTest, fastScrollingCanBeDisabledWithSetting) {
-  navigateTo("about:blank");
+TEST_P(ScrollingCoordinatorTest, fastScrollingCanBeDisabledWithSetting) {
+  webViewImpl()->resize(WebSize(800, 600));
+  loadHTML("<div id='spacer' style='height: 1000px'></div>");
   webViewImpl()->settings()->setThreadedScrollingEnabled(false);
   forceFullCompositingUpdate();
 
@@ -172,6 +180,7 @@
 
   // Main scrolling should be enabled with the setting override.
   WebLayer* rootScrollLayer = getRootScrollLayer();
+  ASSERT_TRUE(rootScrollLayer);
   ASSERT_TRUE(rootScrollLayer->scrollable());
   ASSERT_TRUE(rootScrollLayer->shouldScrollOnMainThread());
 
@@ -182,7 +191,7 @@
   ASSERT_TRUE(innerViewportScrollLayer->shouldScrollOnMainThread());
 }
 
-TEST_F(ScrollingCoordinatorTest, fastFractionalScrollingDiv) {
+TEST_P(ScrollingCoordinatorTest, fastFractionalScrollingDiv) {
   bool origFractionalOffsetsEnabled =
       RuntimeEnabledFeatures::fractionalScrollOffsetsEnabled();
   RuntimeEnabledFeatures::setFractionalScrollOffsetsEnabled(true);
@@ -242,13 +251,14 @@
   return graphicsLayer->platformLayer();
 }
 
-TEST_F(ScrollingCoordinatorTest, fastScrollingForFixedPosition) {
+TEST_P(ScrollingCoordinatorTest, fastScrollingForFixedPosition) {
   registerMockedHttpURLLoad("fixed-position.html");
   navigateTo(m_baseURL + "fixed-position.html");
   forceFullCompositingUpdate();
 
   // Fixed position should not fall back to main thread scrolling.
   WebLayer* rootScrollLayer = getRootScrollLayer();
+  ASSERT_TRUE(rootScrollLayer);
   ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
 
   Document* document = frame()->document();
@@ -334,13 +344,14 @@
   }
 }
 
-TEST_F(ScrollingCoordinatorTest, fastScrollingForStickyPosition) {
+TEST_P(ScrollingCoordinatorTest, fastScrollingForStickyPosition) {
   registerMockedHttpURLLoad("sticky-position.html");
   navigateTo(m_baseURL + "sticky-position.html");
   forceFullCompositingUpdate();
 
   // Sticky position should not fall back to main thread scrolling.
   WebLayer* rootScrollLayer = getRootScrollLayer();
+  ASSERT_TRUE(rootScrollLayer);
   EXPECT_FALSE(rootScrollLayer->shouldScrollOnMainThread());
 
   Document* document = frame()->document();
@@ -440,7 +451,7 @@
   }
 }
 
-TEST_F(ScrollingCoordinatorTest, touchEventHandler) {
+TEST_P(ScrollingCoordinatorTest, touchEventHandler) {
   registerMockedHttpURLLoad("touch-event-handler.html");
   navigateTo(m_baseURL + "touch-event-handler.html");
   forceFullCompositingUpdate();
@@ -450,7 +461,7 @@
                 WebEventListenerClass::TouchStartOrMove));
 }
 
-TEST_F(ScrollingCoordinatorTest, touchEventHandlerPassive) {
+TEST_P(ScrollingCoordinatorTest, touchEventHandlerPassive) {
   registerMockedHttpURLLoad("touch-event-handler-passive.html");
   navigateTo(m_baseURL + "touch-event-handler-passive.html");
   forceFullCompositingUpdate();
@@ -460,7 +471,7 @@
                 WebEventListenerClass::TouchStartOrMove));
 }
 
-TEST_F(ScrollingCoordinatorTest, touchEventHandlerBoth) {
+TEST_P(ScrollingCoordinatorTest, touchEventHandlerBoth) {
   registerMockedHttpURLLoad("touch-event-handler-both.html");
   navigateTo(m_baseURL + "touch-event-handler-both.html");
   forceFullCompositingUpdate();
@@ -470,7 +481,7 @@
                 WebEventListenerClass::TouchStartOrMove));
 }
 
-TEST_F(ScrollingCoordinatorTest, wheelEventHandler) {
+TEST_P(ScrollingCoordinatorTest, wheelEventHandler) {
   registerMockedHttpURLLoad("wheel-event-handler.html");
   navigateTo(m_baseURL + "wheel-event-handler.html");
   forceFullCompositingUpdate();
@@ -480,7 +491,7 @@
                 WebEventListenerClass::MouseWheel));
 }
 
-TEST_F(ScrollingCoordinatorTest, wheelEventHandlerPassive) {
+TEST_P(ScrollingCoordinatorTest, wheelEventHandlerPassive) {
   registerMockedHttpURLLoad("wheel-event-handler-passive.html");
   navigateTo(m_baseURL + "wheel-event-handler-passive.html");
   forceFullCompositingUpdate();
@@ -490,7 +501,7 @@
                 WebEventListenerClass::MouseWheel));
 }
 
-TEST_F(ScrollingCoordinatorTest, wheelEventHandlerBoth) {
+TEST_P(ScrollingCoordinatorTest, wheelEventHandlerBoth) {
   registerMockedHttpURLLoad("wheel-event-handler-both.html");
   navigateTo(m_baseURL + "wheel-event-handler-both.html");
   forceFullCompositingUpdate();
@@ -500,7 +511,7 @@
                 WebEventListenerClass::MouseWheel));
 }
 
-TEST_F(ScrollingCoordinatorTest, scrollEventHandler) {
+TEST_P(ScrollingCoordinatorTest, scrollEventHandler) {
   registerMockedHttpURLLoad("scroll-event-handler.html");
   navigateTo(m_baseURL + "scroll-event-handler.html");
   forceFullCompositingUpdate();
@@ -508,7 +519,7 @@
   ASSERT_TRUE(webLayerTreeView()->haveScrollEventHandlers());
 }
 
-TEST_F(ScrollingCoordinatorTest, updateEventHandlersDuringTeardown) {
+TEST_P(ScrollingCoordinatorTest, updateEventHandlersDuringTeardown) {
   registerMockedHttpURLLoad("scroll-event-handler-window.html");
   navigateTo(m_baseURL + "scroll-event-handler-window.html");
   forceFullCompositingUpdate();
@@ -518,16 +529,17 @@
   frame()->document()->shutdown();
 }
 
-TEST_F(ScrollingCoordinatorTest, clippedBodyTest) {
+TEST_P(ScrollingCoordinatorTest, clippedBodyTest) {
   registerMockedHttpURLLoad("clipped-body.html");
   navigateTo(m_baseURL + "clipped-body.html");
   forceFullCompositingUpdate();
 
   WebLayer* rootScrollLayer = getRootScrollLayer();
+  ASSERT_TRUE(rootScrollLayer);
   ASSERT_EQ(0u, rootScrollLayer->nonFastScrollableRegion().size());
 }
 
-TEST_F(ScrollingCoordinatorTest, overflowScrolling) {
+TEST_P(ScrollingCoordinatorTest, overflowScrolling) {
   registerMockedHttpURLLoad("overflow-scrolling.html");
   navigateTo(m_baseURL + "overflow-scrolling.html");
   forceFullCompositingUpdate();
@@ -573,7 +585,7 @@
 #endif
 }
 
-TEST_F(ScrollingCoordinatorTest, overflowHidden) {
+TEST_P(ScrollingCoordinatorTest, overflowHidden) {
   registerMockedHttpURLLoad("overflow-hidden.html");
   navigateTo(m_baseURL + "overflow-hidden.html");
   forceFullCompositingUpdate();
@@ -634,7 +646,7 @@
   ASSERT_TRUE(webScrollLayer->userScrollableVertical());
 }
 
-TEST_F(ScrollingCoordinatorTest, iframeScrolling) {
+TEST_P(ScrollingCoordinatorTest, iframeScrolling) {
   registerMockedHttpURLLoad("iframe-scrolling.html");
   registerMockedHttpURLLoad("iframe-scrolling-inner.html");
   navigateTo(m_baseURL + "iframe-scrolling.html");
@@ -660,10 +672,12 @@
 
   PaintLayerCompositor* innerCompositor = innerLayoutViewItem.compositor();
   ASSERT_TRUE(innerCompositor->inCompositingMode());
-  ASSERT_TRUE(innerCompositor->scrollLayer());
 
-  GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
-  ASSERT_EQ(innerFrameView, scrollLayer->getScrollableArea());
+  GraphicsLayer* scrollLayer =
+      innerFrameView->layoutViewportScrollableArea()->layerForScrolling();
+  ASSERT_TRUE(scrollLayer);
+  ASSERT_EQ(innerFrameView->layoutViewportScrollableArea(),
+            scrollLayer->getScrollableArea());
 
   WebLayer* webScrollLayer = scrollLayer->platformLayer();
   ASSERT_TRUE(webScrollLayer->scrollable());
@@ -678,7 +692,7 @@
 #endif
 }
 
-TEST_F(ScrollingCoordinatorTest, rtlIframe) {
+TEST_P(ScrollingCoordinatorTest, rtlIframe) {
   registerMockedHttpURLLoad("rtl-iframe.html");
   registerMockedHttpURLLoad("rtl-iframe-inner.html");
   navigateTo(m_baseURL + "rtl-iframe.html");
@@ -704,21 +718,26 @@
 
   PaintLayerCompositor* innerCompositor = innerLayoutViewItem.compositor();
   ASSERT_TRUE(innerCompositor->inCompositingMode());
-  ASSERT_TRUE(innerCompositor->scrollLayer());
 
-  GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
-  ASSERT_EQ(innerFrameView, scrollLayer->getScrollableArea());
+  GraphicsLayer* scrollLayer =
+      innerFrameView->layoutViewportScrollableArea()->layerForScrolling();
+  ASSERT_TRUE(scrollLayer);
+  ASSERT_EQ(innerFrameView->layoutViewportScrollableArea(),
+            scrollLayer->getScrollableArea());
 
   WebLayer* webScrollLayer = scrollLayer->platformLayer();
   ASSERT_TRUE(webScrollLayer->scrollable());
 
   int expectedScrollPosition =
-      958 +
-      (innerFrameView->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
+      958 + (innerFrameView->layoutViewportScrollableArea()
+                     ->verticalScrollbar()
+                     ->isOverlayScrollbar()
+                 ? 0
+                 : 15);
   ASSERT_EQ(expectedScrollPosition, webScrollLayer->scrollPositionDouble().x);
 }
 
-TEST_F(ScrollingCoordinatorTest, setupScrollbarLayerShouldNotCrash) {
+TEST_P(ScrollingCoordinatorTest, setupScrollbarLayerShouldNotCrash) {
   registerMockedHttpURLLoad("setup_scrollbar_layer_crash.html");
   navigateTo(m_baseURL + "setup_scrollbar_layer_crash.html");
   forceFullCompositingUpdate();
@@ -726,7 +745,7 @@
   // an empty document by javascript.
 }
 
-TEST_F(ScrollingCoordinatorTest,
+TEST_P(ScrollingCoordinatorTest,
        scrollbarsForceMainThreadOrHaveWebScrollbarLayer) {
   registerMockedHttpURLLoad("trivial-scroller.html");
   navigateTo(m_baseURL + "trivial-scroller.html");
@@ -753,10 +772,10 @@
 }
 
 #if OS(MACOSX) || OS(ANDROID)
-TEST_F(ScrollingCoordinatorTest,
+TEST_P(ScrollingCoordinatorTest,
        DISABLED_setupScrollbarLayerShouldSetScrollLayerOpaque)
 #else
-TEST_F(ScrollingCoordinatorTest, setupScrollbarLayerShouldSetScrollLayerOpaque)
+TEST_P(ScrollingCoordinatorTest, setupScrollbarLayerShouldSetScrollLayerOpaque)
 #endif
 {
   registerMockedHttpURLLoad("wide_document.html");
@@ -767,7 +786,7 @@
   ASSERT_TRUE(frameView);
 
   GraphicsLayer* scrollbarGraphicsLayer =
-      frameView->layerForHorizontalScrollbar();
+      frameView->layoutViewportScrollableArea()->layerForHorizontalScrollbar();
   ASSERT_TRUE(scrollbarGraphicsLayer);
 
   WebLayer* platformLayer = scrollbarGraphicsLayer->platformLayer();
@@ -782,19 +801,16 @@
   ASSERT_EQ(platformLayer->opaque(), contentsLayer->opaque());
 }
 
-TEST_F(ScrollingCoordinatorTest,
+TEST_P(ScrollingCoordinatorTest,
        FixedPositionLosingBackingShouldTriggerMainThreadScroll) {
   webViewImpl()->settings()->setPreferCompositingToLCDTextEnabled(false);
   registerMockedHttpURLLoad("fixed-position-losing-backing.html");
   navigateTo(m_baseURL + "fixed-position-losing-backing.html");
   forceFullCompositingUpdate();
 
-  WebLayer* scrollLayer = frame()
-                              ->page()
-                              ->deprecatedLocalMainFrame()
-                              ->view()
-                              ->layerForScrolling()
-                              ->platformLayer();
+  WebLayer* scrollLayer = getRootScrollLayer();
+  ASSERT_TRUE(scrollLayer);
+
   Document* document = frame()->document();
   Element* fixedPos = document->getElementById("fixed");
 
@@ -812,7 +828,7 @@
   EXPECT_TRUE(scrollLayer->shouldScrollOnMainThread());
 }
 
-TEST_F(ScrollingCoordinatorTest, CustomScrollbarShouldTriggerMainThreadScroll) {
+TEST_P(ScrollingCoordinatorTest, CustomScrollbarShouldTriggerMainThreadScroll) {
   webViewImpl()->settings()->setPreferCompositingToLCDTextEnabled(true);
   webViewImpl()->setDeviceScaleFactor(2.f);
   registerMockedHttpURLLoad("custom_scrollbar.html");
@@ -853,7 +869,7 @@
       MainThreadScrollingReason::kCustomScrollbarScrolling);
 }
 
-TEST_F(ScrollingCoordinatorTest,
+TEST_P(ScrollingCoordinatorTest,
        BackgroundAttachmentFixedShouldTriggerMainThreadScroll) {
   registerMockedHttpURLLoad("iframe-background-attachment-fixed.html");
   registerMockedHttpURLLoad("iframe-background-attachment-fixed-inner.html");
@@ -879,10 +895,12 @@
 
   PaintLayerCompositor* innerCompositor = innerLayoutViewItem.compositor();
   ASSERT_TRUE(innerCompositor->inCompositingMode());
-  ASSERT_TRUE(innerCompositor->scrollLayer());
 
-  GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
-  ASSERT_EQ(innerFrameView, scrollLayer->getScrollableArea());
+  GraphicsLayer* scrollLayer =
+      innerFrameView->layoutViewportScrollableArea()->layerForScrolling();
+  ASSERT_TRUE(scrollLayer);
+  ASSERT_EQ(innerFrameView->layoutViewportScrollableArea(),
+            scrollLayer->getScrollableArea());
 
   WebLayer* webScrollLayer = scrollLayer->platformLayer();
   ASSERT_TRUE(webScrollLayer->scrollable());
@@ -901,7 +919,9 @@
   layoutObject = iframe->layoutObject();
   ASSERT_TRUE(layoutObject);
 
-  scrollLayer = layoutObject->frameView()->layerForScrolling();
+  scrollLayer = layoutObject->frameView()
+                    ->layoutViewportScrollableArea()
+                    ->layerForScrolling();
   ASSERT_TRUE(scrollLayer);
 
   webScrollLayer = scrollLayer->platformLayer();
@@ -922,7 +942,9 @@
   layoutObject = iframe->layoutObject();
   ASSERT_TRUE(layoutObject);
 
-  scrollLayer = layoutObject->frameView()->layerForScrolling();
+  scrollLayer = layoutObject->frameView()
+                    ->layoutViewportScrollableArea()
+                    ->layerForScrolling();
   ASSERT_TRUE(scrollLayer);
 
   webScrollLayer = scrollLayer->platformLayer();
@@ -933,7 +955,7 @@
 
 // Upon resizing the content size, the main thread scrolling reason
 // kHasNonLayerViewportConstrainedObject should be updated on all frames
-TEST_F(ScrollingCoordinatorTest,
+TEST_P(ScrollingCoordinatorTest,
        RecalculateMainThreadScrollingReasonsUponResize) {
   webViewImpl()->settings()->setPreferCompositingToLCDTextEnabled(false);
   registerMockedHttpURLLoad("has-non-layer-viewport-constrained-objects.html");
@@ -947,29 +969,23 @@
   LayoutObject* layoutObject = element->layoutObject();
   ASSERT_TRUE(layoutObject);
 
-  GraphicsLayer* scrollLayer = layoutObject->frameView()->layerForScrolling();
-  ASSERT_TRUE(scrollLayer);
+  GraphicsLayer* scrollLayer = layoutObject->frameView()
+                                   ->layoutViewportScrollableArea()
+                                   ->layerForScrolling();
+  WebLayer* webScrollLayer;
 
-  WebLayer* webScrollLayer = scrollLayer->platformLayer();
-  ASSERT_TRUE(webScrollLayer->scrollable());
-  ASSERT_FALSE(
-      webScrollLayer->mainThreadScrollingReasons() &
-      MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects);
-
-  Element* iframe = frame()->document()->getElementById("iframe");
-  ASSERT_TRUE(iframe);
-
-  layoutObject = iframe->layoutObject();
-  ASSERT_TRUE(layoutObject);
-
-  scrollLayer = layoutObject->frameView()->layerForScrolling();
-  ASSERT_TRUE(scrollLayer);
-
-  webScrollLayer = scrollLayer->platformLayer();
-  ASSERT_TRUE(webScrollLayer->scrollable());
-  ASSERT_FALSE(
-      webScrollLayer->mainThreadScrollingReasons() &
-      MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects);
+  if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
+    // When RLS is enabled, the LayoutView won't have a scrolling contents
+    // because it does not overflow.
+    ASSERT_FALSE(scrollLayer);
+  } else {
+    ASSERT_TRUE(scrollLayer);
+    webScrollLayer = scrollLayer->platformLayer();
+    ASSERT_TRUE(webScrollLayer->scrollable());
+    ASSERT_FALSE(
+        webScrollLayer->mainThreadScrollingReasons() &
+        MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects);
+  }
 
   // When the div becomes to scrollable it should scroll on main thread
   element->setAttribute("style",
@@ -980,19 +996,9 @@
   layoutObject = element->layoutObject();
   ASSERT_TRUE(layoutObject);
 
-  scrollLayer = layoutObject->frameView()->layerForScrolling();
-  ASSERT_TRUE(scrollLayer);
-
-  webScrollLayer = scrollLayer->platformLayer();
-  ASSERT_TRUE(webScrollLayer->scrollable());
-  ASSERT_TRUE(
-      webScrollLayer->mainThreadScrollingReasons() &
-      MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects);
-
-  layoutObject = iframe->layoutObject();
-  ASSERT_TRUE(layoutObject);
-
-  scrollLayer = layoutObject->frameView()->layerForScrolling();
+  scrollLayer = layoutObject->frameView()
+                    ->layoutViewportScrollableArea()
+                    ->layerForScrolling();
   ASSERT_TRUE(scrollLayer);
 
   webScrollLayer = scrollLayer->platformLayer();
@@ -1010,26 +1016,21 @@
   layoutObject = element->layoutObject();
   ASSERT_TRUE(layoutObject);
 
-  scrollLayer = layoutObject->frameView()->layerForScrolling();
-  ASSERT_TRUE(scrollLayer);
-
-  webScrollLayer = scrollLayer->platformLayer();
-  ASSERT_TRUE(webScrollLayer->scrollable());
-  ASSERT_FALSE(
-      webScrollLayer->mainThreadScrollingReasons() &
-      MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects);
-
-  layoutObject = iframe->layoutObject();
-  ASSERT_TRUE(layoutObject);
-
-  scrollLayer = layoutObject->frameView()->layerForScrolling();
-  ASSERT_TRUE(scrollLayer);
-
-  webScrollLayer = scrollLayer->platformLayer();
-  ASSERT_TRUE(webScrollLayer->scrollable());
-  ASSERT_FALSE(
-      webScrollLayer->mainThreadScrollingReasons() &
-      MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects);
+  scrollLayer = layoutObject->frameView()
+                    ->layoutViewportScrollableArea()
+                    ->layerForScrolling();
+  if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
+    // When RLS is enabled, the LayoutView won't have a scrolling contents
+    // because it does not overflow.
+    ASSERT_FALSE(scrollLayer);
+  } else {
+    ASSERT_TRUE(scrollLayer);
+    webScrollLayer = scrollLayer->platformLayer();
+    ASSERT_TRUE(webScrollLayer->scrollable());
+    ASSERT_FALSE(
+        webScrollLayer->mainThreadScrollingReasons() &
+        MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects);
+  }
 }
 
 class StyleRelatedMainThreadScrollingReasonTest
@@ -1092,28 +1093,32 @@
   }
 };
 
-TEST_F(StyleRelatedMainThreadScrollingReasonTest, TransparentTest) {
+INSTANTIATE_TEST_CASE_P(All,
+                        StyleRelatedMainThreadScrollingReasonTest,
+                        ::testing::Bool());
+
+TEST_P(StyleRelatedMainThreadScrollingReasonTest, TransparentTest) {
   testStyle("transparent", MainThreadScrollingReason::kHasOpacityAndLCDText);
 }
 
-TEST_F(StyleRelatedMainThreadScrollingReasonTest, TransformTest) {
+TEST_P(StyleRelatedMainThreadScrollingReasonTest, TransformTest) {
   testStyle("transform", MainThreadScrollingReason::kHasTransformAndLCDText);
 }
 
-TEST_F(StyleRelatedMainThreadScrollingReasonTest, BackgroundNotOpaqueTest) {
+TEST_P(StyleRelatedMainThreadScrollingReasonTest, BackgroundNotOpaqueTest) {
   testStyle("background-not-opaque",
             MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText);
 }
 
-TEST_F(StyleRelatedMainThreadScrollingReasonTest, BorderRadiusTest) {
+TEST_P(StyleRelatedMainThreadScrollingReasonTest, BorderRadiusTest) {
   testStyle("border-radius", MainThreadScrollingReason::kHasBorderRadius);
 }
 
-TEST_F(StyleRelatedMainThreadScrollingReasonTest, ClipTest) {
+TEST_P(StyleRelatedMainThreadScrollingReasonTest, ClipTest) {
   testStyle("clip", MainThreadScrollingReason::kHasClipRelatedProperty);
 }
 
-TEST_F(StyleRelatedMainThreadScrollingReasonTest, ClipPathTest) {
+TEST_P(StyleRelatedMainThreadScrollingReasonTest, ClipPathTest) {
   uint32_t reason = MainThreadScrollingReason::kHasClipRelatedProperty;
   webViewImpl()->settings()->setPreferCompositingToLCDTextEnabled(false);
   Document* document = frame()->document();
@@ -1148,13 +1153,13 @@
   ASSERT_FALSE(frameView->mainThreadScrollingReasons() & reason);
 }
 
-TEST_F(StyleRelatedMainThreadScrollingReasonTest, LCDTextEnabledTest) {
+TEST_P(StyleRelatedMainThreadScrollingReasonTest, LCDTextEnabledTest) {
   testStyle("transparent border-radius",
             MainThreadScrollingReason::kHasOpacityAndLCDText |
                 MainThreadScrollingReason::kHasBorderRadius);
 }
 
-TEST_F(StyleRelatedMainThreadScrollingReasonTest, BoxShadowTest) {
+TEST_P(StyleRelatedMainThreadScrollingReasonTest, BoxShadowTest) {
   testStyle("box-shadow",
             MainThreadScrollingReason::kHasBoxShadowFromNonRootLayer);
 }
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index d123a03..bc04711ad 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -7761,6 +7761,16 @@
   webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
   webViewImpl->updateAllLifecyclePhases();
 
+  WebLayer* webScrollLayer = webViewImpl->mainFrameImpl()
+                                 ->frame()
+                                 ->view()
+                                 ->layoutViewportScrollableArea()
+                                 ->layerForScrolling()
+                                 ->platformLayer();
+  ASSERT_TRUE(webScrollLayer->scrollable());
+  ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
+  ASSERT_TRUE(webScrollLayer->userScrollableVertical());
+
   Document* document = webViewImpl->mainFrameImpl()->frame()->document();
   UserGestureIndicator gesture(DocumentUserGestureToken::create(document));
   Fullscreen::requestFullscreen(*document->documentElement());
@@ -7780,8 +7790,12 @@
             Fullscreen::fullscreenElementFrom(*document));
 
   // Verify that the main frame is still scrollable.
-  WebLayer* webScrollLayer =
-      webViewImpl->compositor()->scrollLayer()->platformLayer();
+  webScrollLayer = webViewImpl->mainFrameImpl()
+                       ->frame()
+                       ->view()
+                       ->layoutViewportScrollableArea()
+                       ->layerForScrolling()
+                       ->platformLayer();
   ASSERT_TRUE(webScrollLayer->scrollable());
   ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
   ASSERT_TRUE(webScrollLayer->userScrollableVertical());
diff --git a/third_party/WebKit/Source/web/tests/data/has-non-layer-viewport-constrained-objects.html b/third_party/WebKit/Source/web/tests/data/has-non-layer-viewport-constrained-objects.html
index 50796f6..f2919be 100644
--- a/third_party/WebKit/Source/web/tests/data/has-non-layer-viewport-constrained-objects.html
+++ b/third_party/WebKit/Source/web/tests/data/has-non-layer-viewport-constrained-objects.html
@@ -1,4 +1,2 @@
 <div style="position:fixed;">Fixed obj</div>
-<div id="scrollable" style="overflow: scroll; height:200px; will-change:transform;">
-  <iframe id="iframe"></iframe>
-</div>
+<div id="scrollable" style="overflow: scroll; height:200px; will-change:transform;"></div>
diff --git a/third_party/WebKit/Source/web/tests/data/iframe-background-attachment-fixed-inner.html b/third_party/WebKit/Source/web/tests/data/iframe-background-attachment-fixed-inner.html
index 38843967..5dc4b2d 100644
--- a/third_party/WebKit/Source/web/tests/data/iframe-background-attachment-fixed-inner.html
+++ b/third_party/WebKit/Source/web/tests/data/iframe-background-attachment-fixed-inner.html
@@ -3,8 +3,7 @@
 .background-attachment-fixed {
   background-image: url("white-1x1.png");
   background-attachment: fixed;
-  height: 2000px;
 }
 </style>
 
-<div id="scrollable" style="will-change:transform;" class="background-attachment-fixed" />
+<div id="scrollable" style="will-change:transform; height: 2000px;" class="background-attachment-fixed" />
diff --git a/tools/chrome_proxy/webdriver/bypass.py b/tools/chrome_proxy/webdriver/bypass.py
new file mode 100644
index 0000000..d7d1b0c
--- /dev/null
+++ b/tools/chrome_proxy/webdriver/bypass.py
@@ -0,0 +1,27 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import common
+from common import TestDriver
+from common import IntegrationTest
+
+
+class Bypass(IntegrationTest):
+
+  # Ensure Chrome does not use Data Saver for block=0, which uses the default
+  # proxy retry delay.
+  def testBypass(self):
+    with TestDriver() as t:
+      t.AddChromeArg('--enable-spdy-proxy-auth')
+      t.LoadURL('http://check.googlezip.net/block/')
+      for response in t.GetHTTPResponses():
+        self.assertNotHasChromeProxyViaHeader(response)
+
+      # Load another page and check that Data Saver is not used.
+      t.LoadURL('http://check.googlezip.net/test.html')
+      for response in t.GetHTTPResponses():
+        self.assertNotHasChromeProxyViaHeader(response)
+
+if __name__ == '__main__':
+  IntegrationTest.RunAllTests()
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 7f458b6..2ea45cf 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -32524,10 +32524,7 @@
 </histogram>
 
 <histogram name="Net.HttpStreamFactoryJob.StreamReadyCallbackTime" units="ms">
-  <obsolete>
-    Deprecated 08/2016. No longer tracked.
-  </obsolete>
-  <owner>rtenneti@chromium.org</owner>
+  <owner>zhongyi@chromium.org</owner>
   <summary>Time it takes for OnStreamReadyCallback to be called.</summary>
 </histogram>
 
@@ -55201,6 +55198,23 @@
   </summary>
 </histogram>
 
+<histogram name="SafeBrowsing.NavigationObserver.IPAddressCleanUpCount">
+  <owner>jialiul@chromium.org</owner>
+  <summary>
+    Count of how many ResolvedIPAddresses get removed in each periodic clean up.
+    This is a rough estimation of the number of IPs associated with main frame
+    and sub-frame navigations every two minutes.
+  </summary>
+</histogram>
+
+<histogram name="SafeBrowsing.NavigationObserver.NavigationEventCleanUpCount">
+  <owner>jialiul@chromium.org</owner>
+  <summary>
+    Count of how many NavigationEvents get removed in each periodic clean up.
+    This is a rough estimation of the number of navigations every two minutes.
+  </summary>
+</histogram>
+
 <histogram name="SafeBrowsing.NotificationImageReporter.NetError"
     enum="NetErrorCodes">
   <owner>nparker@chromium.org</owner>
@@ -95739,6 +95753,7 @@
   <int value="-1497338981" label="disable-accelerated-overflow-scroll"/>
   <int value="-1491417046" label="enable-fullscreen-toolbar-reveal"/>
   <int value="-1490298774" label="enable-captive-portal-bypass-proxy-option"/>
+  <int value="-1488744539" label="QuickUnlockFingerprint:enabled"/>
   <int value="-1482685863" label="enable-request-tablet-site"/>
   <int value="-1480926949" label="MaterialDesignBookmarks:enabled"/>
   <int value="-1478876902" label="disable-permission-action-reporting"/>
@@ -96135,6 +96150,7 @@
   <int value="365467768" label="prefetch-search-results"/>
   <int value="368854020" label="ash-screen-rotation-animation"/>
   <int value="370486304" label="enable-origin-chip-on-srp"/>
+  <int value="372460068" label="QuickUnlockFingerprint:disabled"/>
   <int value="377093001" label="WebRtcHWH264Encoding:disabled"/>
   <int value="379326303" label="enable-add-to-shelf"/>
   <int value="379428799" label="security-chip-animation"/>
diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
index 45e9692a..aa7b063 100644
--- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
+++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
@@ -9,8 +9,9 @@
 #include <CoreVideo/CoreVideo.h>
 #include <GLES2/gl2extchromium.h>
 
+#include <utility>
+
 #include "base/command_line.h"
-#include "base/lazy_instance.h"
 #include "base/mac/sdk_forward_declarations.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -142,21 +143,20 @@
   SolidColorContents(SkColor color, IOSurfaceRef io_surface);
   ~SolidColorContents();
 
+  static std::map<SkColor, SolidColorContents*>* GetMap();
+
   SkColor color_ = 0;
   base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
-  static base::LazyInstance<std::map<SkColor, SolidColorContents*>> map_;
 };
 
-base::LazyInstance<std::map<SkColor, CARendererLayerTree::SolidColorContents*>>
-    CARendererLayerTree::SolidColorContents::map_;
-
 // static
 scoped_refptr<CARendererLayerTree::SolidColorContents>
 CARendererLayerTree::SolidColorContents::Get(SkColor color) {
   const int kSolidColorContentsSize = 16;
 
-  auto found = map_.Get().find(color);
-  if (found != map_.Get().end())
+  auto map = GetMap();
+  auto found = map->find(color);
+  if (found != map->end())
     return found->second;
 
   IOSurfaceRef io_surface = CreateIOSurface(
@@ -188,15 +188,24 @@
     SkColor color,
     IOSurfaceRef io_surface)
     : color_(color), io_surface_(io_surface) {
-  DCHECK(map_.Get().find(color_) == map_.Get().end());
-  map_.Get()[color_] = this;
+  auto map = GetMap();
+  DCHECK(map->find(color_) == map->end());
+  map->insert(std::make_pair(color_, this));
 }
 
 CARendererLayerTree::SolidColorContents::~SolidColorContents() {
-  auto found = map_.Get().find(color_);
-  DCHECK(found != map_.Get().end());
+  auto map = GetMap();
+  auto found = map->find(color_);
+  DCHECK(found != map->end());
   DCHECK(found->second == this);
-  map_.Get().erase(color_);
+  map->erase(color_);
+}
+
+// static
+std::map<SkColor, CARendererLayerTree::SolidColorContents*>*
+CARendererLayerTree::SolidColorContents::GetMap() {
+  static auto map = new std::map<SkColor, SolidColorContents*>();
+  return map;
 }
 
 CARendererLayerTree::CARendererLayerTree(
diff --git a/ui/accelerated_widget_mac/io_surface_context.h b/ui/accelerated_widget_mac/io_surface_context.h
index c673560..cf7770d 100644
--- a/ui/accelerated_widget_mac/io_surface_context.h
+++ b/ui/accelerated_widget_mac/io_surface_context.h
@@ -10,7 +10,6 @@
 #include <map>
 #include <memory>
 
-#include "base/lazy_instance.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/memory/ref_counted.h"
 #include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h"
@@ -61,12 +60,6 @@
   base::ScopedTypeRef<CGLContextObj> cgl_context_;
 
   bool poisoned_;
-
-  // The global map from window number and window ordering to
-  // context data.
-  typedef std::map<Type, IOSurfaceContext*> TypeMap;
-  static base::LazyInstance<TypeMap> type_map_;
-  static TypeMap* type_map();
 };
 
 }  // namespace ui
diff --git a/ui/accelerated_widget_mac/io_surface_context.mm b/ui/accelerated_widget_mac/io_surface_context.mm
index 21d854c..382403e 100644
--- a/ui/accelerated_widget_mac/io_surface_context.mm
+++ b/ui/accelerated_widget_mac/io_surface_context.mm
@@ -16,14 +16,27 @@
 
 namespace ui {
 
+namespace {
+
+// The global map from window number and window ordering to context data.
+using TypeMap = std::map<IOSurfaceContext::Type, IOSurfaceContext*>;
+
+TypeMap* GetTypeMap() {
+  static auto type_map = new TypeMap();
+  return type_map;
+}
+
+}  // namespace
+
 // static
 scoped_refptr<IOSurfaceContext>
 IOSurfaceContext::Get(Type type) {
   TRACE_EVENT0("browser", "IOSurfaceContext::Get");
 
   // Return the context for this type, if it exists.
-  TypeMap::iterator found = type_map()->find(type);
-  if (found != type_map()->end()) {
+  auto type_map = GetTypeMap();
+  TypeMap::iterator found = type_map->find(type);
+  if (found != type_map->end()) {
     DCHECK(!found->second->poisoned_);
     return found->second;
   }
@@ -51,8 +64,8 @@
   // Create all contexts in the same share group so that the textures don't
   // need to be recreated when transitioning contexts.
   CGLContextObj share_context = NULL;
-  if (!type_map()->empty())
-    share_context = type_map()->begin()->second->cgl_context();
+  if (!type_map->empty())
+    share_context = type_map->begin()->second->cgl_context();
   error = CGLCreateContext(
       pixel_format, share_context, cgl_context.InitializeInto());
   if (error != kCGLNoError) {
@@ -67,19 +80,19 @@
   if (poisoned_)
     return;
 
-  for (TypeMap::iterator it = type_map()->begin();
-       it != type_map()->end();
-       ++it) {
+  auto type_map = GetTypeMap();
+  for (TypeMap::iterator it = type_map->begin(); it != type_map->end(); ++it) {
     it->second->poisoned_ = true;
   }
-  type_map()->clear();
+  type_map->clear();
 }
 
 IOSurfaceContext::IOSurfaceContext(
     Type type, base::ScopedTypeRef<CGLContextObj> cgl_context)
     : type_(type), cgl_context_(cgl_context), poisoned_(false) {
-  DCHECK(type_map()->find(type_) == type_map()->end());
-  type_map()->insert(std::make_pair(type_, this));
+  auto type_map = GetTypeMap();
+  DCHECK(type_map->find(type_) == type_map->end());
+  type_map->insert(std::make_pair(type_, this));
 
   ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
 }
@@ -87,13 +100,14 @@
 IOSurfaceContext::~IOSurfaceContext() {
   ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
 
+  auto type_map = GetTypeMap();
   if (!poisoned_) {
-    DCHECK(type_map()->find(type_) != type_map()->end());
-    DCHECK(type_map()->find(type_)->second == this);
-    type_map()->erase(type_);
+    DCHECK(type_map->find(type_) != type_map->end());
+    DCHECK(type_map->find(type_)->second == this);
+    type_map->erase(type_);
   } else {
-    TypeMap::const_iterator found = type_map()->find(type_);
-    if (found != type_map()->end())
+    TypeMap::const_iterator found = type_map->find(type_);
+    if (found != type_map->end())
       DCHECK(found->second != this);
   }
 }
@@ -105,14 +119,4 @@
   PoisonContextAndSharegroup();
 }
 
-// static
-IOSurfaceContext::TypeMap*
-    IOSurfaceContext::type_map() {
-  return type_map_.Pointer();
-}
-
-// static
-base::LazyInstance<IOSurfaceContext::TypeMap>
-    IOSurfaceContext::type_map_;
-
 }  // namespace ui
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index b9f0a4a3a..e443d4f 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -166,8 +166,6 @@
     "selection_model.h",
     "sequential_id_generator.cc",
     "sequential_id_generator.h",
-    "shadow_util.cc",
-    "shadow_util.h",
     "shadow_value.cc",
     "shadow_value.h",
     "skbitmap_operations.cc",
@@ -233,6 +231,10 @@
       "paint_throbber.h",
       "scoped_canvas.cc",
       "scoped_canvas.h",
+      "shadow_util.cc",
+      "shadow_util.h",
+      "skia_paint_util.cc",
+      "skia_paint_util.h",
     ]
   }
 
@@ -402,13 +404,11 @@
     ]
   }
 
-  if (!use_aura) {
-    if (!toolkit_views) {
-      sources -= [
-        "nine_image_painter.cc",
-        "nine_image_painter.h",
-      ]
-    }
+  if ((!use_aura && !toolkit_views) || is_ios) {
+    sources -= [
+      "nine_image_painter.cc",
+      "nine_image_painter.h",
+    ]
   }
 
   if (use_x11) {
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc
index 58a3b57..64bec26 100644
--- a/ui/gfx/canvas.cc
+++ b/ui/gfx/canvas.cc
@@ -22,6 +22,7 @@
 #include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/scoped_canvas.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/transform.h"
 
diff --git a/ui/gfx/image/image_skia_operations.cc b/ui/gfx/image/image_skia_operations.cc
index 700a458..a9ce580 100644
--- a/ui/gfx/image/image_skia_operations.cc
+++ b/ui/gfx/image/image_skia_operations.cc
@@ -25,6 +25,7 @@
 #include "ui/gfx/image/image_skia_rep.h"
 #include "ui/gfx/image/image_skia_source.h"
 #include "ui/gfx/skbitmap_operations.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/gfx/skia_util.h"
 
 namespace gfx {
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc
index 3b36ea0..d081c168 100644
--- a/ui/gfx/render_text.cc
+++ b/ui/gfx/render_text.cc
@@ -30,6 +30,7 @@
 #include "ui/gfx/platform_font.h"
 #include "ui/gfx/render_text_harfbuzz.h"
 #include "ui/gfx/scoped_canvas.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/switches.h"
 #include "ui/gfx/text_elider.h"
diff --git a/ui/gfx/shadow_util.cc b/ui/gfx/shadow_util.cc
index 238181a..88b19fae0 100644
--- a/ui/gfx/shadow_util.cc
+++ b/ui/gfx/shadow_util.cc
@@ -14,6 +14,7 @@
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/image/canvas_image_source.h"
 #include "ui/gfx/shadow_value.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/gfx/skia_util.h"
 
 namespace gfx {
diff --git a/ui/gfx/skia_paint_util.cc b/ui/gfx/skia_paint_util.cc
new file mode 100644
index 0000000..fbac6636
--- /dev/null
+++ b/ui/gfx/skia_paint_util.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/skia_paint_util.h"
+
+#include "third_party/skia/include/core/SkColorFilter.h"
+#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
+#include "third_party/skia/include/effects/SkGradientShader.h"
+#include "third_party/skia/include/effects/SkLayerDrawLooper.h"
+#include "ui/gfx/image/image_skia_rep.h"
+
+namespace gfx {
+
+sk_sp<SkShader> CreateImageRepShader(const gfx::ImageSkiaRep& image_rep,
+                                     SkShader::TileMode tile_mode,
+                                     const SkMatrix& local_matrix) {
+  return CreateImageRepShaderForScale(image_rep, tile_mode, local_matrix,
+                                      image_rep.scale());
+}
+
+sk_sp<SkShader> CreateImageRepShaderForScale(const gfx::ImageSkiaRep& image_rep,
+                                             SkShader::TileMode tile_mode,
+                                             const SkMatrix& local_matrix,
+                                             SkScalar scale) {
+  // Unscale matrix by |scale| such that the bitmap is drawn at the
+  // correct density.
+  // Convert skew and translation to pixel coordinates.
+  // Thus, for |bitmap_scale| = 2:
+  //   x scale = 2, x translation = 1 DIP,
+  // should be converted to
+  //   x scale = 1, x translation = 2 pixels.
+  SkMatrix shader_scale = local_matrix;
+  shader_scale.preScale(scale, scale);
+  shader_scale.setScaleX(local_matrix.getScaleX() / scale);
+  shader_scale.setScaleY(local_matrix.getScaleY() / scale);
+
+  return SkShader::MakeBitmapShader(image_rep.sk_bitmap(), tile_mode, tile_mode,
+                                    &shader_scale);
+}
+
+sk_sp<SkShader> CreateGradientShader(int start_point,
+                                     int end_point,
+                                     SkColor start_color,
+                                     SkColor end_color) {
+  SkColor grad_colors[2] = {start_color, end_color};
+  SkPoint grad_points[2];
+  grad_points[0].iset(0, start_point);
+  grad_points[1].iset(0, end_point);
+
+  return SkGradientShader::MakeLinear(grad_points, grad_colors, NULL, 2,
+                                      SkShader::kClamp_TileMode);
+}
+
+// TODO(estade): remove. Only exists to support legacy CreateShadowDrawLooper.
+static SkScalar DeprecatedRadiusToSigma(double radius) {
+  // This captures historically what skia did under the hood. Now skia accepts
+  // sigma, not radius, so we perform the conversion.
+  return radius > 0 ? SkDoubleToScalar(0.57735f * radius + 0.5) : 0;
+}
+
+// This is copied from
+// third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.h
+static SkScalar RadiusToSigma(double radius) {
+  return radius > 0 ? SkDoubleToScalar(0.288675f * radius + 0.5f) : 0;
+}
+
+sk_sp<SkDrawLooper> CreateShadowDrawLooper(
+    const std::vector<ShadowValue>& shadows) {
+  if (shadows.empty())
+    return nullptr;
+
+  SkLayerDrawLooper::Builder looper_builder;
+
+  looper_builder.addLayer();  // top layer of the original.
+
+  SkLayerDrawLooper::LayerInfo layer_info;
+  layer_info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit;
+  layer_info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit;
+  layer_info.fColorMode = SkBlendMode::kSrc;
+
+  for (size_t i = 0; i < shadows.size(); ++i) {
+    const ShadowValue& shadow = shadows[i];
+
+    layer_info.fOffset.set(SkIntToScalar(shadow.x()),
+                           SkIntToScalar(shadow.y()));
+
+    SkPaint* paint = looper_builder.addLayer(layer_info);
+    // SkBlurMaskFilter's blur radius defines the range to extend the blur from
+    // original mask, which is half of blur amount as defined in ShadowValue.
+    // Note that because this function uses DeprecatedRadiusToSigma, it actually
+    // creates a draw looper with roughly twice the desired blur.
+    paint->setMaskFilter(SkBlurMaskFilter::Make(
+        kNormal_SkBlurStyle, DeprecatedRadiusToSigma(shadow.blur() / 2),
+        SkBlurMaskFilter::kHighQuality_BlurFlag));
+    paint->setColorFilter(
+        SkColorFilter::MakeModeFilter(shadow.color(), SkBlendMode::kSrcIn));
+  }
+
+  return looper_builder.detach();
+}
+
+sk_sp<SkDrawLooper> CreateShadowDrawLooperCorrectBlur(
+    const std::vector<ShadowValue>& shadows) {
+  if (shadows.empty())
+    return nullptr;
+
+  SkLayerDrawLooper::Builder looper_builder;
+
+  looper_builder.addLayer();  // top layer of the original.
+
+  SkLayerDrawLooper::LayerInfo layer_info;
+  layer_info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit;
+  layer_info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit;
+  layer_info.fColorMode = SkBlendMode::kSrc;
+
+  for (size_t i = 0; i < shadows.size(); ++i) {
+    const ShadowValue& shadow = shadows[i];
+
+    layer_info.fOffset.set(SkIntToScalar(shadow.x()),
+                           SkIntToScalar(shadow.y()));
+
+    SkPaint* paint = looper_builder.addLayer(layer_info);
+    // SkBlurMaskFilter's blur radius defines the range to extend the blur from
+    // original mask, which is half of blur amount as defined in ShadowValue.
+    paint->setMaskFilter(SkBlurMaskFilter::Make(
+        kNormal_SkBlurStyle, RadiusToSigma(shadow.blur() / 2),
+        SkBlurMaskFilter::kHighQuality_BlurFlag));
+    paint->setColorFilter(
+        SkColorFilter::MakeModeFilter(shadow.color(), SkBlendMode::kSrcIn));
+  }
+
+  return looper_builder.detach();
+}
+
+}  // namespace gfx
diff --git a/ui/gfx/skia_paint_util.h b/ui/gfx/skia_paint_util.h
new file mode 100644
index 0000000..2ec10ff
--- /dev/null
+++ b/ui/gfx/skia_paint_util.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_SKIA_PAINT_UTIL_H_
+#define UI_GFX_SKIA_PAINT_UTIL_H_
+
+#include <vector>
+
+#include "third_party/skia/include/core/SkShader.h"
+#include "ui/gfx/gfx_export.h"
+#include "ui/gfx/shadow_value.h"
+
+class SkDrawLooper;
+class SkMatrix;
+
+namespace gfx {
+
+class ImageSkiaRep;
+
+// Creates a bitmap shader for the image rep with the image rep's scale factor.
+// Sets the created shader's local matrix such that it displays the image rep at
+// the correct scale factor.
+// The shader's local matrix should not be changed after the shader is created.
+// TODO(pkotwicz): Allow shader's local matrix to be changed after the shader
+// is created.
+//
+GFX_EXPORT sk_sp<SkShader> CreateImageRepShader(
+    const gfx::ImageSkiaRep& image_rep,
+    SkShader::TileMode tile_mode,
+    const SkMatrix& local_matrix);
+
+// Creates a bitmap shader for the image rep with the passed in scale factor.
+GFX_EXPORT sk_sp<SkShader> CreateImageRepShaderForScale(
+    const gfx::ImageSkiaRep& image_rep,
+    SkShader::TileMode tile_mode,
+    const SkMatrix& local_matrix,
+    SkScalar scale);
+
+// Creates a vertical gradient shader. The caller owns the shader.
+// Example usage to avoid leaks:
+GFX_EXPORT sk_sp<SkShader> CreateGradientShader(int start_point,
+                                                int end_point,
+                                                SkColor start_color,
+                                                SkColor end_color);
+
+// Creates a draw looper to generate |shadows|. The caller owns the draw looper.
+// NULL is returned if |shadows| is empty since no draw looper is needed in
+// this case.
+// DEPRECATED: See below. TODO(estade): remove this: crbug.com/624175
+GFX_EXPORT sk_sp<SkDrawLooper> CreateShadowDrawLooper(
+    const std::vector<ShadowValue>& shadows);
+
+// Creates a draw looper to generate |shadows|. This creates a looper with the
+// correct amount of blur. Callers of the existing CreateShadowDrawLooper may
+// rely on the wrong amount of blur being applied but new code should use this
+// function.
+GFX_EXPORT sk_sp<SkDrawLooper> CreateShadowDrawLooperCorrectBlur(
+    const std::vector<ShadowValue>& shadows);
+
+}  // namespace gfx
+
+#endif  // UI_GFX_SKIA_UTIL_H_
diff --git a/ui/gfx/skia_util.cc b/ui/gfx/skia_util.cc
index 963e081..6f7818d9 100644
--- a/ui/gfx/skia_util.cc
+++ b/ui/gfx/skia_util.cc
@@ -10,7 +10,6 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/numerics/safe_math.h"
 #include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColorFilter.h"
 #include "third_party/skia/include/core/SkColorPriv.h"
 #include "third_party/skia/include/core/SkUnPreMultiply.h"
 #include "third_party/skia/include/effects/SkBlurMaskFilter.h"
@@ -104,128 +103,6 @@
   flattened->set(8, SkMScalarToScalar(transform.matrix().get(3, 3)));
 }
 
-sk_sp<SkShader> CreateImageRepShader(const gfx::ImageSkiaRep& image_rep,
-                                            SkShader::TileMode tile_mode,
-                                            const SkMatrix& local_matrix) {
-  return CreateImageRepShaderForScale(image_rep, tile_mode, local_matrix,
-                                      image_rep.scale());
-}
-
-sk_sp<SkShader> CreateImageRepShaderForScale(
-    const gfx::ImageSkiaRep& image_rep,
-    SkShader::TileMode tile_mode,
-    const SkMatrix& local_matrix,
-    SkScalar scale) {
-  // Unscale matrix by |scale| such that the bitmap is drawn at the
-  // correct density.
-  // Convert skew and translation to pixel coordinates.
-  // Thus, for |bitmap_scale| = 2:
-  //   x scale = 2, x translation = 1 DIP,
-  // should be converted to
-  //   x scale = 1, x translation = 2 pixels.
-  SkMatrix shader_scale = local_matrix;
-  shader_scale.preScale(scale, scale);
-  shader_scale.setScaleX(local_matrix.getScaleX() / scale);
-  shader_scale.setScaleY(local_matrix.getScaleY() / scale);
-
-  return SkShader::MakeBitmapShader(
-      image_rep.sk_bitmap(), tile_mode, tile_mode, &shader_scale);
-}
-
-sk_sp<SkShader> CreateGradientShader(int start_point,
-                                            int end_point,
-                                            SkColor start_color,
-                                            SkColor end_color) {
-  SkColor grad_colors[2] = { start_color, end_color};
-  SkPoint grad_points[2];
-  grad_points[0].iset(0, start_point);
-  grad_points[1].iset(0, end_point);
-
-  return SkGradientShader::MakeLinear(
-      grad_points, grad_colors, NULL, 2, SkShader::kClamp_TileMode);
-}
-
-// TODO(estade): remove. Only exists to support legacy CreateShadowDrawLooper.
-static SkScalar DeprecatedRadiusToSigma(double radius) {
-  // This captures historically what skia did under the hood. Now skia accepts
-  // sigma, not radius, so we perform the conversion.
-  return radius > 0 ? SkDoubleToScalar(0.57735f * radius + 0.5) : 0;
-}
-
-// This is copied from
-// third_party/WebKit/Source/platform/graphics/skia/SkiaUtils.h
-static SkScalar RadiusToSigma(double radius) {
-  return radius > 0 ? SkDoubleToScalar(0.288675f * radius + 0.5f) : 0;
-}
-
-sk_sp<SkDrawLooper> CreateShadowDrawLooper(
-    const std::vector<ShadowValue>& shadows) {
-  if (shadows.empty())
-    return nullptr;
-
-  SkLayerDrawLooper::Builder looper_builder;
-
-  looper_builder.addLayer();  // top layer of the original.
-
-  SkLayerDrawLooper::LayerInfo layer_info;
-  layer_info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit;
-  layer_info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit;
-  layer_info.fColorMode = SkBlendMode::kSrc;
-
-  for (size_t i = 0; i < shadows.size(); ++i) {
-    const ShadowValue& shadow = shadows[i];
-
-    layer_info.fOffset.set(SkIntToScalar(shadow.x()),
-                           SkIntToScalar(shadow.y()));
-
-    SkPaint* paint = looper_builder.addLayer(layer_info);
-    // SkBlurMaskFilter's blur radius defines the range to extend the blur from
-    // original mask, which is half of blur amount as defined in ShadowValue.
-    // Note that because this function uses DeprecatedRadiusToSigma, it actually
-    // creates a draw looper with roughly twice the desired blur.
-    paint->setMaskFilter(SkBlurMaskFilter::Make(
-        kNormal_SkBlurStyle, DeprecatedRadiusToSigma(shadow.blur() / 2),
-        SkBlurMaskFilter::kHighQuality_BlurFlag));
-    paint->setColorFilter(
-        SkColorFilter::MakeModeFilter(shadow.color(), SkBlendMode::kSrcIn));
-  }
-
-  return looper_builder.detach();
-}
-
-sk_sp<SkDrawLooper> CreateShadowDrawLooperCorrectBlur(
-    const std::vector<ShadowValue>& shadows) {
-  if (shadows.empty())
-    return nullptr;
-
-  SkLayerDrawLooper::Builder looper_builder;
-
-  looper_builder.addLayer();  // top layer of the original.
-
-  SkLayerDrawLooper::LayerInfo layer_info;
-  layer_info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit;
-  layer_info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit;
-  layer_info.fColorMode = SkBlendMode::kSrc;
-
-  for (size_t i = 0; i < shadows.size(); ++i) {
-    const ShadowValue& shadow = shadows[i];
-
-    layer_info.fOffset.set(SkIntToScalar(shadow.x()),
-                           SkIntToScalar(shadow.y()));
-
-    SkPaint* paint = looper_builder.addLayer(layer_info);
-    // SkBlurMaskFilter's blur radius defines the range to extend the blur from
-    // original mask, which is half of blur amount as defined in ShadowValue.
-    paint->setMaskFilter(SkBlurMaskFilter::Make(
-        kNormal_SkBlurStyle, RadiusToSigma(shadow.blur() / 2),
-        SkBlurMaskFilter::kHighQuality_BlurFlag));
-    paint->setColorFilter(
-        SkColorFilter::MakeModeFilter(shadow.color(), SkBlendMode::kSrcIn));
-  }
-
-  return looper_builder.detach();
-}
-
 bool BitmapsAreEqual(const SkBitmap& bitmap1, const SkBitmap& bitmap2) {
   void* addr1 = NULL;
   void* addr2 = NULL;
diff --git a/ui/gfx/skia_util.h b/ui/gfx/skia_util.h
index fbd1909..76a999f 100644
--- a/ui/gfx/skia_util.h
+++ b/ui/gfx/skia_util.h
@@ -16,16 +16,14 @@
 #include "ui/gfx/gfx_export.h"
 
 class SkBitmap;
-class SkDrawLooper;
+class SkMatrix;
 
 namespace gfx {
 
-class ImageSkiaRep;
 class Point;
 class PointF;
 class Rect;
 class RectF;
-class ShadowValue;
 class Transform;
 
 // Convert between Skia and gfx types.
@@ -46,46 +44,6 @@
 GFX_EXPORT void TransformToFlattenedSkMatrix(const gfx::Transform& transform,
                                              SkMatrix* flattened);
 
-// Creates a bitmap shader for the image rep with the image rep's scale factor.
-// Sets the created shader's local matrix such that it displays the image rep at
-// the correct scale factor.
-// The shader's local matrix should not be changed after the shader is created.
-// TODO(pkotwicz): Allow shader's local matrix to be changed after the shader
-// is created.
-//
-GFX_EXPORT sk_sp<SkShader> CreateImageRepShader(
-    const gfx::ImageSkiaRep& image_rep,
-    SkShader::TileMode tile_mode,
-    const SkMatrix& local_matrix);
-
-// Creates a bitmap shader for the image rep with the passed in scale factor.
-GFX_EXPORT sk_sp<SkShader> CreateImageRepShaderForScale(
-    const gfx::ImageSkiaRep& image_rep,
-    SkShader::TileMode tile_mode,
-    const SkMatrix& local_matrix,
-    SkScalar scale);
-
-// Creates a vertical gradient shader. The caller owns the shader.
-// Example usage to avoid leaks:
-GFX_EXPORT sk_sp<SkShader> CreateGradientShader(int start_point,
-                                                int end_point,
-                                                SkColor start_color,
-                                                SkColor end_color);
-
-// Creates a draw looper to generate |shadows|. The caller owns the draw looper.
-// NULL is returned if |shadows| is empty since no draw looper is needed in
-// this case.
-// DEPRECATED: See below. TODO(estade): remove this: crbug.com/624175
-GFX_EXPORT sk_sp<SkDrawLooper> CreateShadowDrawLooper(
-    const std::vector<ShadowValue>& shadows);
-
-// Creates a draw looper to generate |shadows|. This creates a looper with the
-// correct amount of blur. Callers of the existing CreateShadowDrawLooper may
-// rely on the wrong amount of blur being applied but new code should use this
-// function.
-GFX_EXPORT sk_sp<SkDrawLooper> CreateShadowDrawLooperCorrectBlur(
-    const std::vector<ShadowValue>& shadows);
-
 // Returns true if the two bitmaps contain the same pixels.
 GFX_EXPORT bool BitmapsAreEqual(const SkBitmap& bitmap1,
                                 const SkBitmap& bitmap2);
diff --git a/ui/gl/gl_gl_api_implementation.cc b/ui/gl/gl_gl_api_implementation.cc
index cc4453e..ecd5881 100644
--- a/ui/gl/gl_gl_api_implementation.cc
+++ b/ui/gl/gl_gl_api_implementation.cc
@@ -437,20 +437,29 @@
 }
 
 void RealGLApi::glClearDepthFn(GLclampd depth) {
-  if (driver_->fn.glClearDepthFn) {
-    GLApiBase::glClearDepthFn(depth);
-  } else {
+  // OpenGL ES only has glClearDepthf, forward the parameters from glClearDepth.
+  // Many mock tests expect only glClearDepth is called so don't make the
+  // interception when testing with mocks.
+  if (version_->is_es && GetGLImplementation() != kGLImplementationMockGL) {
     DCHECK(driver_->fn.glClearDepthfFn);
     GLApiBase::glClearDepthfFn(static_cast<GLclampf>(depth));
+  } else {
+    DCHECK(driver_->fn.glClearDepthFn);
+    GLApiBase::glClearDepthFn(depth);
   }
 }
 
 void RealGLApi::glDepthRangeFn(GLclampd z_near, GLclampd z_far) {
-  if (driver_->fn.glDepthRangeFn) {
-    GLApiBase::glDepthRangeFn(z_near, z_far);
-  } else {
+  // OpenGL ES only has glDepthRangef, forward the parameters from glDepthRange.
+  // Many mock tests expect only glDepthRange is called so don't make the
+  // interception when testing with mocks.
+  if (version_->is_es && GetGLImplementation() != kGLImplementationMockGL) {
+    DCHECK(driver_->fn.glDepthRangefFn);
     GLApiBase::glDepthRangefFn(static_cast<GLclampf>(z_near),
                                static_cast<GLclampf>(z_far));
+  } else {
+    DCHECK(driver_->fn.glDepthRangeFn);
+    GLApiBase::glDepthRangeFn(z_near, z_far);
   }
 }
 
diff --git a/ui/native_theme/native_theme_mac.mm b/ui/native_theme/native_theme_mac.mm
index 36a58dc..bcb69cc 100644
--- a/ui/native_theme/native_theme_mac.mm
+++ b/ui/native_theme/native_theme_mac.mm
@@ -19,6 +19,7 @@
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/shadow_value.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/native_theme/common_theme.h"
 
diff --git a/ui/views/animation/ink_drop_painted_layer_delegates.cc b/ui/views/animation/ink_drop_painted_layer_delegates.cc
index c098c83..135e249 100644
--- a/ui/views/animation/ink_drop_painted_layer_delegates.cc
+++ b/ui/views/animation/ink_drop_painted_layer_delegates.cc
@@ -15,6 +15,7 @@
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/gfx/skia_util.h"
 
 namespace views {
diff --git a/ui/views/bubble/bubble_border.cc b/ui/views/bubble/bubble_border.cc
index 0aed6ef..67b2acf 100644
--- a/ui/views/bubble/bubble_border.cc
+++ b/ui/views/bubble/bubble_border.cc
@@ -18,7 +18,7 @@
 #include "ui/gfx/path.h"
 #include "ui/gfx/scoped_canvas.h"
 #include "ui/gfx/shadow_value.h"
-#include "ui/gfx/skia_util.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/resources/grit/ui_resources.h"
 #include "ui/views/painter.h"
 #include "ui/views/resources/grit/views_resources.h"
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index d27aa9d..80c41c0 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -51,7 +51,7 @@
 // The MD spec states that the center of the "x" should be 16x16 from the top
 // right of the dialog.
 constexpr int kClosePaddingRightMd = 4;
-constexpr int kClosePaddingTopMd = 5;
+constexpr int kClosePaddingTopMd = 4;
 
 // Get the |vertical| or horizontal amount that |available_bounds| overflows
 // |window_bounds|.
diff --git a/ui/views/controls/button/toggle_button.cc b/ui/views/controls/button/toggle_button.cc
index 37c2ce1..349acde 100644
--- a/ui/views/controls/button/toggle_button.cc
+++ b/ui/views/controls/button/toggle_button.cc
@@ -12,6 +12,7 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/shadow_value.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/views/animation/ink_drop_impl.h"
 #include "ui/views/animation/ink_drop_ripple.h"
 #include "ui/views/border.h"
diff --git a/ui/views/controls/button/vector_icon_button.cc b/ui/views/controls/button/vector_icon_button.cc
index 848700a..c3e1ba2 100644
--- a/ui/views/controls/button/vector_icon_button.cc
+++ b/ui/views/controls/button/vector_icon_button.cc
@@ -22,13 +22,12 @@
 }  // namespace
 
 VectorIconButton::VectorIconButton(VectorIconButtonDelegate* delegate)
-    : views::ImageButton(delegate),
+    : ImageButton(delegate),
       delegate_(delegate),
       id_(gfx::VectorIconId::VECTOR_ICON_NONE) {
   SetInkDropMode(InkDropMode::ON);
   set_has_ink_drop_action_on_click(true);
-  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                    views::ImageButton::ALIGN_MIDDLE);
+  SetImageAlignment(ImageButton::ALIGN_CENTER, ImageButton::ALIGN_MIDDLE);
   SetFocusPainter(nullptr);
 }
 
@@ -36,39 +35,49 @@
 
 void VectorIconButton::SetIcon(gfx::VectorIconId id) {
   id_ = id;
+  icon_ = nullptr;
 
-  if (!border()) {
-    SetBorder(
-        views::CreateEmptyBorder(kButtonExtraTouchSize, kButtonExtraTouchSize,
-                                 kButtonExtraTouchSize, kButtonExtraTouchSize));
-  }
+  OnSetIcon();
 }
 
 void VectorIconButton::SetIcon(const gfx::VectorIcon& icon) {
+  id_ = gfx::VectorIconId::VECTOR_ICON_NONE;
   icon_ = &icon;
-  SetIcon(gfx::VectorIconId::VECTOR_ICON_NONE);
+
+  OnSetIcon();
 }
 
 void VectorIconButton::OnThemeChanged() {
+  UpdateImagesAndColors();
+}
+
+void VectorIconButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
+  UpdateImagesAndColors();
+}
+
+void VectorIconButton::OnSetIcon() {
+  if (!border())
+    SetBorder(CreateEmptyBorder(gfx::Insets(kButtonExtraTouchSize)));
+
+  UpdateImagesAndColors();
+}
+
+void VectorIconButton::UpdateImagesAndColors() {
   SkColor icon_color =
       color_utils::DeriveDefaultIconColor(delegate_->GetVectorIconBaseColor());
   SkColor disabled_color = SkColorSetA(icon_color, 0xff / 2);
   if (icon_) {
-    SetImage(views::CustomButton::STATE_NORMAL,
+    SetImage(CustomButton::STATE_NORMAL,
              gfx::CreateVectorIcon(*icon_, icon_color));
-    SetImage(views::CustomButton::STATE_DISABLED,
+    SetImage(CustomButton::STATE_DISABLED,
              gfx::CreateVectorIcon(*icon_, disabled_color));
   } else {
-    SetImage(views::CustomButton::STATE_NORMAL,
+    SetImage(CustomButton::STATE_NORMAL,
              gfx::CreateVectorIcon(id_, icon_color));
-    SetImage(views::CustomButton::STATE_DISABLED,
+    SetImage(CustomButton::STATE_DISABLED,
              gfx::CreateVectorIcon(id_, disabled_color));
   }
   set_ink_drop_base_color(icon_color);
 }
 
-void VectorIconButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
-  OnThemeChanged();
-}
-
 }  // namespace views
diff --git a/ui/views/controls/button/vector_icon_button.h b/ui/views/controls/button/vector_icon_button.h
index 8a99ae0e..b0aa025 100644
--- a/ui/views/controls/button/vector_icon_button.h
+++ b/ui/views/controls/button/vector_icon_button.h
@@ -36,6 +36,12 @@
   void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
 
  private:
+  // Performs the work common to both SetIcon() variants.
+  void OnSetIcon();
+
+  // Called when something may have affected the button's images or colors.
+  void UpdateImagesAndColors();
+
   VectorIconButtonDelegate* delegate_;
   // TODO(estade): remove |id_| in favor of |icon_| once all callers have been
   // updated.
diff --git a/ui/views/shadow_border.cc b/ui/views/shadow_border.cc
index 1f19c01..3bc065b 100644
--- a/ui/views/shadow_border.cc
+++ b/ui/views/shadow_border.cc
@@ -8,7 +8,7 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/skia_util.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/views/view.h"
 
 namespace views {
diff --git a/url/url_canon.h b/url/url_canon.h
index ff66c6e3..d093f359 100644
--- a/url/url_canon.h
+++ b/url/url_canon.h
@@ -118,8 +118,9 @@
   }
 
   void ReserveSizeIfNeeded(int estimated_size) {
+    // Reserve a bit extra to account for escaped chars.
     if (estimated_size > buffer_len_)
-      Resize(estimated_size);
+      Resize(estimated_size + 8);
   }
 
  protected:
diff --git a/url/url_canon_relative.cc b/url/url_canon_relative.cc
index 8259056..851368d 100644
--- a/url/url_canon_relative.cc
+++ b/url/url_canon_relative.cc
@@ -288,7 +288,7 @@
   // possible escaped characters.
   output->ReserveSizeIfNeeded(
       base_parsed.path.begin +
-      std::max(path.end(), std::max(query.end(), ref.end())) + 8);
+      std::max(path.end(), std::max(query.end(), ref.end())));
   output->Append(base_url, base_parsed.path.begin);
 
   if (path.len > 0) {
@@ -406,7 +406,7 @@
   // base URL.
   output->ReserveSizeIfNeeded(
       replacements.components().Length() +
-      base_parsed.CountCharactersBefore(Parsed::USERNAME, false) + 8);
+      base_parsed.CountCharactersBefore(Parsed::USERNAME, false));
   return ReplaceStandardURL(base_url, base_parsed, replacements,
                             query_converter, output, out_parsed);
 }
diff --git a/url/url_canon_stdstring.cc b/url/url_canon_stdstring.cc
index 366a2e0..c81a0a98 100644
--- a/url/url_canon_stdstring.cc
+++ b/url/url_canon_stdstring.cc
@@ -9,7 +9,6 @@
 StdStringCanonOutput::StdStringCanonOutput(std::string* str)
     : CanonOutput(), str_(str) {
   cur_len_ = static_cast<int>(str_->size());  // Append to existing data.
-  str_->resize(str_->capacity());
   buffer_ = str_->empty() ? NULL : &(*str_)[0];
   buffer_len_ = static_cast<int>(str_->size());
 }
diff --git a/url/url_canon_stdstring.h b/url/url_canon_stdstring.h
index 662cac7..f36f3a9b 100644
--- a/url/url_canon_stdstring.h
+++ b/url/url_canon_stdstring.h
@@ -23,8 +23,7 @@
 // throughout the lifetime of this object.
 //
 // The given string will be appended to; any existing data in the string will
-// be preserved. The caller should reserve() the amount of data in the string
-// they expect to be written. We will resize if necessary, but that's slow.
+// be preserved.
 //
 // Note that when canonicalization is complete, the string will likely have
 // unused space at the end because we make the string very big to start out
diff --git a/url/url_util.cc b/url/url_util.cc
index 9a2cce4..d5c27d1 100644
--- a/url/url_util.cc
+++ b/url/url_util.cc
@@ -193,9 +193,7 @@
                     CharsetConverter* charset_converter,
                     CanonOutput* output,
                     Parsed* output_parsed) {
-  // Reserve enough room in the output for the input, plus some extra so that
-  // we have room if we have to escape a few things without reallocating.
-  output->ReserveSizeIfNeeded(spec_len + 8);
+  output->ReserveSizeIfNeeded(spec_len);
 
   // Remove any whitespace from the middle of the relative URL if necessary.
   // Possibly this will result in copying to the new buffer.
@@ -423,7 +421,7 @@
   // in callers below, and the code checks to see which components are being
   // replaced, and with what length. If this ends up being a hot spot it should
   // be changed.
-  output->ReserveSizeIfNeeded(spec_len + 8);
+  output->ReserveSizeIfNeeded(spec_len);
 
   // If we get here, then we know the scheme doesn't need to be replaced, so can
   // just key off the scheme in the spec to know how to do the replacements.