diff --git a/DEPS b/DEPS
index 8af4764..5ddc193 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # 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': 'e330eb2c0e6bab83add6986119864b546bf0b0a7',
+  'skia_revision': 'b92234a3210bce532f103d71002f4e04d336a182',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '727e25bf208915a47e5c708e660743f2596ef971',
+  'v8_revision': '7595f86e695fb9ef3f80ed1ae94bbb922a290bc6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -124,7 +124,7 @@
 
 deps = {
   'src/breakpad/src':
-    Var('chromium_git') + '/breakpad/breakpad/src.git' + '@' + 'efa6d5c1c84e2fcacf6a2eafcf9010f98ef3a4d7',
+    Var('chromium_git') + '/breakpad/breakpad/src.git' + '@' + '5c09282c5becdc7b8b3daaff950cdfcd45b615b3',
 
   'src/buildtools':
     Var('chromium_git') + '/chromium/buildtools.git' + '@' +  Var('buildtools_revision'),
diff --git a/WATCHLISTS b/WATCHLISTS
index 779401b..a6cd5cd 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1512,7 +1512,8 @@
                  'rouslan+autofill@chromium.org',
                  'vabr+watchlistautofill@chromium.org',
                  'mathp+autofillwatch@chromium.org',
-                 'sebsg+autofillwatch@chromium.org'],
+                 'sebsg+autofillwatch@chromium.org',
+                 'rogerm+autofillwatch@chromium.org'],
     'background_sync': ['chasej+watch@chromium.org',
                         'iclelland+watch@chromium.org',
                         'jkarlin+watch@chromium.org',
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
index 156bb65..399edd8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -47,11 +47,20 @@
 
     private boolean mIsNtpDestroyed;
 
-    // Keep track of how many suggestions have been seen by the user so that we replace only
-    // suggestions that have not been seen, yet.
+    /**
+     * Keeps track of how many suggestions have been seen by the user so that we replace only
+     * suggestions that have not been seen, yet.
+     */
     private int mNumberOfSuggestionsSeen;
 
     /**
+     * Stores whether any suggestions have been appended to the list. In this case the list can
+     * generally be longer than what is served by the Source. Thus, the list should never be
+     * replaced again.
+     */
+    private boolean mHasAppended;
+
+    /**
      * Delegate interface that allows dismissing this section without introducing
      * a circular dependency.
      */
@@ -324,6 +333,8 @@
                 mSuggestionsList.getItemCount(), replaceExisting);
         if (!SnippetsBridge.isCategoryStatusAvailable(status)) mSuggestionsList.clear();
 
+        if (!replaceExisting) mHasAppended = true;
+
         // Remove suggestions to be replaced.
         if (replaceExisting && hasSuggestions()) {
             if (CardsVariationParameters.ignoreUpdatesForExistingSuggestions()) {
@@ -332,7 +343,7 @@
                 return;
             }
 
-            if (mNumberOfSuggestionsSeen >= getSuggestionsCount()) {
+            if (mNumberOfSuggestionsSeen >= getSuggestionsCount() || mHasAppended) {
                 Log.d(TAG, "setSuggestions: replacing existing suggestion not possible, all seen");
                 NewTabPageUma.recordUIUpdateResult(NewTabPageUma.UI_UPDATE_FAIL_ALL_SEEN);
                 return;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
index 9ed3c4b43..03020a78 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
@@ -39,7 +39,6 @@
 import org.chromium.chrome.browser.EnableFeatures;
 import org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.CategoryInfoBuilder;
 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
-import org.chromium.chrome.browser.ntp.snippets.KnownCategories;
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.offlinepages.OfflinePageItem;
@@ -63,6 +62,7 @@
     @Rule
     public DisableHistogramsRule mDisableHistogramsRule = new DisableHistogramsRule();
 
+    private static final int TEST_CATEGORY_ID = 42;
     @Mock
     private SuggestionsSection.Delegate mDelegate;
     @Mock
@@ -189,7 +189,7 @@
         List<SnippetArticle> snippets = createDummySuggestions(suggestionCount);
 
         SuggestionsCategoryInfo info =
-                new CategoryInfoBuilder(42)
+                new CategoryInfoBuilder(TEST_CATEGORY_ID)
                 .withMoreAction()
                 .withReloadAction()
                 .showIfEmpty()
@@ -270,7 +270,7 @@
 
         // Spy so that VerifyAction can check methods being called.
         SuggestionsCategoryInfo info =
-                spy(new CategoryInfoBuilder(42)
+                spy(new CategoryInfoBuilder(TEST_CATEGORY_ID)
                         .withMoreAction()
                         .withReloadAction()
                         .withViewAllAction()
@@ -296,7 +296,7 @@
 
         // Spy so that VerifyAction can check methods being called.
         SuggestionsCategoryInfo info =
-                spy(new CategoryInfoBuilder(42)
+                spy(new CategoryInfoBuilder(TEST_CATEGORY_ID)
                         .withMoreAction()
                         .withReloadAction()
                         .showIfEmpty()
@@ -319,8 +319,8 @@
         // When only Reload is enabled, it only shows when we have no suggestions.
 
         // Spy so that VerifyAction can check methods being called.
-        SuggestionsCategoryInfo info =
-                spy(new CategoryInfoBuilder(42).withReloadAction().showIfEmpty().build());
+        SuggestionsCategoryInfo info = spy(
+                new CategoryInfoBuilder(TEST_CATEGORY_ID).withReloadAction().showIfEmpty().build());
         SuggestionsSection section = createSection(info);
 
         assertTrue(section.getActionItem().isVisible());
@@ -339,8 +339,8 @@
         // When only FetchMore is enabled, it only shows when we have suggestions.
 
         // Spy so that VerifyAction can check methods being called.
-        SuggestionsCategoryInfo info =
-                spy(new CategoryInfoBuilder(42).withMoreAction().showIfEmpty().build());
+        SuggestionsCategoryInfo info = spy(
+                new CategoryInfoBuilder(TEST_CATEGORY_ID).withMoreAction().showIfEmpty().build());
         SuggestionsSection section = createSection(info);
 
         assertFalse(section.getActionItem().isVisible());
@@ -359,7 +359,8 @@
         // Test where no action is enabled.
 
         // Spy so that VerifyAction can check methods being called.
-        SuggestionsCategoryInfo info = spy(new CategoryInfoBuilder(42).showIfEmpty().build());
+        SuggestionsCategoryInfo info =
+                spy(new CategoryInfoBuilder(TEST_CATEGORY_ID).showIfEmpty().build());
         SuggestionsSection section = createSection(info);
 
         assertFalse(section.getActionItem().isVisible());
@@ -376,8 +377,8 @@
     @Feature({"Ntp"})
     public void testFetchMoreProgressDisplay() {
         final int suggestionCount = 3;
-        SuggestionsCategoryInfo info =
-                spy(new CategoryInfoBuilder(42).withMoreAction().showIfEmpty().build());
+        SuggestionsCategoryInfo info = spy(
+                new CategoryInfoBuilder(TEST_CATEGORY_ID).withMoreAction().showIfEmpty().build());
         SuggestionsSection section = createSection(info);
         section.setSuggestions(createDummySuggestions(suggestionCount), CategoryStatus.AVAILABLE,
                 /* replaceExisting = */ true);
@@ -399,11 +400,12 @@
     @Test
     @Feature({"Ntp"})
     public void testSectionUpdatesOnNewSuggestions() {
-        SuggestionsSection section = createSectionWithSuggestions(createDummySuggestions(4));
+        SuggestionsSection section =
+                createSectionWithSuggestions(createDummySuggestions(4, TEST_CATEGORY_ID));
         assertEquals(4, section.getSuggestionsCount());
 
-        section.setSuggestions(
-                createDummySuggestions(3), CategoryStatus.AVAILABLE, /* replaceExisting = */ true);
+        section.setSuggestions(createDummySuggestions(3, TEST_CATEGORY_ID),
+                CategoryStatus.AVAILABLE, /* replaceExisting = */ true);
         assertEquals(3, section.getSuggestionsCount());
     }
 
@@ -418,11 +420,12 @@
         params.put("ignore_updates_for_existing_suggestions", "true");
         CardsVariationParameters.setTestVariationParams(params);
 
-        SuggestionsSection section = createSectionWithSuggestions(createDummySuggestions(4));
+        SuggestionsSection section =
+                createSectionWithSuggestions(createDummySuggestions(4, TEST_CATEGORY_ID));
         assertEquals(4, section.getSuggestionsCount());
 
-        section.setSuggestions(
-                createDummySuggestions(3), CategoryStatus.AVAILABLE, /* replaceExisting = */ true);
+        section.setSuggestions(createDummySuggestions(3, TEST_CATEGORY_ID),
+                CategoryStatus.AVAILABLE, /* replaceExisting = */ true);
         assertEquals(4, section.getSuggestionsCount());
     }
 
@@ -432,18 +435,18 @@
     @Test
     @Feature({"Ntp"})
     public void testSectionDoesNotUpdateFirstSuggestionOnNewSuggestionsWhenSeen() {
-        List<SnippetArticle> snippets = createDummySuggestions(4, KnownCategories.ARTICLES, "old");
+        List<SnippetArticle> snippets = createDummySuggestions(4, TEST_CATEGORY_ID, "old");
         // Copy the list when passing to the section - it may alter it but we later need it.
         SuggestionsSection section =
                 createSectionWithSuggestions(new ArrayList<>(snippets));
         assertEquals(4, section.getSuggestionsCount());
 
         // Bind the first suggestion - indicate that it is being viewed.
-        // Indices in {@code section} are off-by-one (index 0 is the header).
+        // Indices in section are off-by-one (index 0 is the header).
         bindViewHolders(section, 1, 2);
 
         List<SnippetArticle> newSnippets =
-                createDummySuggestions(3, KnownCategories.ARTICLES, "new");
+                createDummySuggestions(3, TEST_CATEGORY_ID, "new");
         // Copy the list when passing to the section - it may alter it but we later need it.
         section.setSuggestions(new ArrayList<>(newSnippets), CategoryStatus.AVAILABLE,
                 /* replaceExisting = */ true);
@@ -460,18 +463,18 @@
     @Test
     @Feature({"Ntp"})
     public void testSectionDoesNotUpdateFirstTwoSuggestionOnNewSuggestionsWhenSeen() {
-        List<SnippetArticle> snippets = createDummySuggestions(4, KnownCategories.ARTICLES, "old");
+        List<SnippetArticle> snippets = createDummySuggestions(4, TEST_CATEGORY_ID, "old");
         // Copy the list when passing to the section - it may alter it but we later need it.
         SuggestionsSection section =
                 createSectionWithSuggestions(new ArrayList<>(snippets));
         assertEquals(4, section.getSuggestionsCount());
 
         // Bind the first two suggestions - indicate that they are being viewed.
-        // Indices in {@code section} are off-by-one (index 0 is the header).
+        // Indices in section are off-by-one (index 0 is the header).
         bindViewHolders(section, 1, 3);
 
         List<SnippetArticle> newSnippets =
-                createDummySuggestions(3, KnownCategories.ARTICLES, "new");
+                createDummySuggestions(3, TEST_CATEGORY_ID, "new");
         // Copy the list when passing to the section - it may alter it but we later need it.
         section.setSuggestions(new ArrayList<>(newSnippets), CategoryStatus.AVAILABLE,
                 /* replaceExisting = */ true);
@@ -489,18 +492,18 @@
     @Test
     @Feature({"Ntp"})
     public void testSectionDoesNotUpdateOnNewSuggestionsWhenNewListIsShorter() {
-        List<SnippetArticle> snippets = createDummySuggestions(4, KnownCategories.ARTICLES, "old");
+        List<SnippetArticle> snippets = createDummySuggestions(4, TEST_CATEGORY_ID, "old");
         // Copy the list when passing to the section - it may alter it but we later need it.
         SuggestionsSection section =
                 createSectionWithSuggestions(new ArrayList<>(snippets));
         assertEquals(4, section.getSuggestionsCount());
 
         // Bind the first two suggestions - indicate that they are being viewed.
-        // Indices in {@code section} are off-by-one (index 0 is the header).
+        // Indices in section are off-by-one (index 0 is the header).
         bindViewHolders(section, 1, 3);
 
-        section.setSuggestions(
-                createDummySuggestions(1), CategoryStatus.AVAILABLE, /* replaceExisting = */ true);
+        section.setSuggestions(createDummySuggestions(1, TEST_CATEGORY_ID),
+                CategoryStatus.AVAILABLE, /* replaceExisting = */ true);
         // Even though the new list has just one suggestion, we need to keep the two seen ones
         // around.
         assertEquals(2, section.getSuggestionsCount());
@@ -515,14 +518,14 @@
     @Test
     @Feature({"Ntp"})
     public void testSectionDoesNotUpdateOnNewSuggestionsWhenCurrentListIsShorter() {
-        List<SnippetArticle> snippets = createDummySuggestions(3, KnownCategories.ARTICLES, "old");
+        List<SnippetArticle> snippets = createDummySuggestions(3, TEST_CATEGORY_ID, "old");
         // Copy the list when passing to the section - it may alter it but we later need it.
         SuggestionsSection section =
                 createSectionWithSuggestions(new ArrayList<>(snippets));
         assertEquals(3, section.getSuggestionsCount());
 
         // Bind the first two suggestions - indicate that they are being viewed.
-        // Indices in {@code section} are off-by-one (index 0 is the header).
+        // Indices in section are off-by-one (index 0 is the header).
         bindViewHolders(section, 1, 3);
 
         // Remove last two items.
@@ -531,8 +534,8 @@
 
         assertEquals(1, section.getSuggestionsCount());
 
-        section.setSuggestions(
-                createDummySuggestions(4), CategoryStatus.AVAILABLE, /* replaceExisting = */ true);
+        section.setSuggestions(createDummySuggestions(4, TEST_CATEGORY_ID),
+                CategoryStatus.AVAILABLE, /* replaceExisting = */ true);
         // We do not touch the current list if all has been seen.
         assertEquals(1, section.getSuggestionsCount());
         assertEquals(snippets.get(0), section.getSuggestionAt(1));
@@ -544,22 +547,47 @@
     @Test
     @Feature({"Ntp"})
     public void testSectionDoesNotUpdateOnNewSuggestionsWhenAllSeen() {
-        List<SnippetArticle> snippets = createDummySuggestions(4, KnownCategories.ARTICLES, "old");
+        List<SnippetArticle> snippets = createDummySuggestions(4, TEST_CATEGORY_ID, "old");
         SuggestionsSection section = createSectionWithSuggestions(snippets);
         assertEquals(4, section.getSuggestionsCount());
 
         // Bind all the suggestions - indicate that they are being viewed.
         bindViewHolders(section);
 
-        section.setSuggestions(
-                createDummySuggestions(3), CategoryStatus.AVAILABLE, /* replaceExisting = */ true);
+        section.setSuggestions(createDummySuggestions(3, TEST_CATEGORY_ID),
+                CategoryStatus.AVAILABLE, /* replaceExisting = */ true);
 
         // All old snippets should be in place.
-        assertEquals(4, section.getSuggestionsCount());
-        int index = 1;
-        for (SnippetArticle snippet : snippets) {
-            assertEquals(snippet, section.getSuggestionAt(index++));
-        }
+        verifySnippets(section, snippets);
+    }
+
+    /**
+     * Tests that the UI does not update when anything has been appended.
+     */
+    @Test
+    @Feature({"Ntp"})
+    public void testSectionDoesNotUpdateOnNewSuggestionsWhenAppended() {
+        List<SnippetArticle> snippets = createDummySuggestions(4, TEST_CATEGORY_ID, "old");
+        SuggestionsSection section = createSectionWithSuggestions(snippets);
+
+        // Append another 3 suggestions.
+        List<SnippetArticle> appendedSnippets =
+                createDummySuggestions(3, TEST_CATEGORY_ID, "appended");
+        section.setSuggestions(
+                appendedSnippets, CategoryStatus.AVAILABLE, /* replaceExisting = */ false);
+
+        // All 7 snippets should be in place.
+        snippets.addAll(appendedSnippets);
+        verifySnippets(section, snippets);
+
+        // Try to replace them with another list. Should have no effect.
+        List<SnippetArticle> newSnippets =
+                createDummySuggestions(5, TEST_CATEGORY_ID, "new");
+        section.setSuggestions(newSnippets, CategoryStatus.AVAILABLE,
+                /* replaceExisting = */ true);
+
+        // All previous snippets should be in place.
+        verifySnippets(section, snippets);
     }
 
     private SuggestionsSection createSectionWithSuggestions(List<SnippetArticle> snippets) {
@@ -570,7 +598,7 @@
     }
 
     private SuggestionsSection createSectionWithReloadAction(boolean hasReloadAction) {
-        CategoryInfoBuilder builder = new CategoryInfoBuilder(42).showIfEmpty();
+        CategoryInfoBuilder builder = new CategoryInfoBuilder(TEST_CATEGORY_ID).showIfEmpty();
         if (hasReloadAction) builder.withReloadAction();
         return createSection(builder.build());
     }
@@ -607,4 +635,13 @@
                         : never())
                 .fetchSuggestions(anyInt(), any(String[].class));
     }
+
+    private static void verifySnippets(SuggestionsSection section, List<SnippetArticle> snippets) {
+        assertEquals(snippets.size(), section.getSuggestionsCount());
+        // Indices in section are off-by-one (index 0 is the header).
+        int index = 1;
+        for (SnippetArticle snippet : snippets) {
+            assertEquals(snippet, section.getSuggestionAt(index++));
+        }
+    }
 }
diff --git a/chrome/browser/android/feedback/screenshot_task.cc b/chrome/browser/android/feedback/screenshot_task.cc
index 4e8d3e2..0381101 100644
--- a/chrome/browser/android/feedback/screenshot_task.cc
+++ b/chrome/browser/android/feedback/screenshot_task.cc
@@ -31,7 +31,7 @@
 
 void SnapshotCallback(JNIEnv* env,
                       const JavaRef<jobject>& callback,
-                      scoped_refptr<base::RefCountedBytes> png_data) {
+                      scoped_refptr<base::RefCountedMemory> png_data) {
   jbyteArray jbytes = nullptr;
   if (png_data.get()) {
     size_t size = png_data->size();
@@ -50,7 +50,7 @@
   WindowAndroid* window_android = reinterpret_cast<WindowAndroid*>(
       native_window_android);
   gfx::Rect window_bounds(window_width, window_height);
-  ui::GrabWindowSnapshotAsync(
+  ui::GrabWindowSnapshotAsyncPNG(
       window_android, window_bounds, base::ThreadTaskRunnerHandle::Get(),
       base::Bind(&SnapshotCallback, env,
                  ScopedJavaGlobalRef<jobject>(env, jcallback)));
diff --git a/chrome/browser/chromeos/login/screenshot_testing/screenshot_tester.cc b/chrome/browser/chromeos/login/screenshot_testing/screenshot_tester.cc
index 4849de4..92dc8336 100644
--- a/chrome/browser/chromeos/login/screenshot_testing/screenshot_tester.cc
+++ b/chrome/browser/chromeos/login/screenshot_testing/screenshot_tester.cc
@@ -187,10 +187,9 @@
     LOG(ERROR) << "Can't create directory" << image_path.DirName().value();
     return false;
   }
-  if (static_cast<size_t>(
-          base::WriteFile(image_path,
-                          reinterpret_cast<char*>(&(png_data->data()[0])),
-                          png_data->size())) != png_data->size()) {
+  if (static_cast<size_t>(base::WriteFile(
+          image_path, reinterpret_cast<const char*>(png_data->front()),
+          png_data->size())) != png_data->size()) {
     LOG(ERROR) << "Can't save screenshot " << image_path.BaseName().value()
                << ".";
     return false;
@@ -200,10 +199,9 @@
   return true;
 }
 
-void ScreenshotTester::ReturnScreenshot(const PNGFile& screenshot,
-                                        PNGFile png_data) {
+void ScreenshotTester::ReturnScreenshot(PNGFile* screenshot, PNGFile png_data) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  screenshot->data() = png_data->data();
+  *screenshot = png_data;
   content::BrowserThread::PostTask(
       content::BrowserThread::UI, FROM_HERE, run_loop_quitter_);
 }
@@ -212,13 +210,11 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   aura::Window* primary_window = ash::Shell::GetPrimaryRootWindow();
   gfx::Rect rect = primary_window->bounds();
-  PNGFile screenshot = new base::RefCountedBytes;
-  ui::GrabWindowSnapshotAsync(primary_window,
-                              rect,
-                              content::BrowserThread::GetBlockingPool(),
-                              base::Bind(&ScreenshotTester::ReturnScreenshot,
-                                         weak_factory_.GetWeakPtr(),
-                                         screenshot));
+  PNGFile screenshot;
+  ui::GrabWindowSnapshotAsyncPNG(
+      primary_window, rect, content::BrowserThread::GetBlockingPool(),
+      base::Bind(&ScreenshotTester::ReturnScreenshot,
+                 weak_factory_.GetWeakPtr(), &screenshot));
   base::RunLoop run_loop;
   run_loop_quitter_ = run_loop.QuitClosure();
   run_loop.Run();
@@ -240,7 +236,7 @@
   if (golden_screenshot_size == -1) {
     CHECK(false) << "Can't get golden screenshot size";
   }
-  PNGFile png_data = new base::RefCountedBytes;
+  scoped_refptr<base::RefCountedBytes> png_data = new base::RefCountedBytes;
   png_data->data().resize(golden_screenshot_size);
   base::ReadFile(image_path,
                  reinterpret_cast<char*>(&(png_data->data()[0])),
@@ -252,9 +248,7 @@
 SkBitmap ScreenshotTester::ProcessImageForComparison(const PNGFile& image) {
   CHECK(image.get());
   SkBitmap current_bitmap;
-  gfx::PNGCodec::Decode(reinterpret_cast<unsigned char*>(&(image->data()[0])),
-                        image->data().size(),
-                        &current_bitmap);
+  gfx::PNGCodec::Decode(image->front(), image->size(), &current_bitmap);
   EraseIgnoredAreas(current_bitmap);
   return current_bitmap;
 }
@@ -329,11 +323,12 @@
 
   testing_result.similarity = result.result;
 
-  testing_result.diff_image = new base::RefCountedBytes;
-  testing_result.diff_image->data().resize(result.rgbDiffBitmap.getSize());
-  CHECK(gfx::PNGCodec::EncodeBGRASkBitmap(
-      result.rgbDiffBitmap, false, &testing_result.diff_image->data()))
+  scoped_refptr<base::RefCountedBytes> diff_image(new base::RefCountedBytes);
+  diff_image->data().resize(result.rgbDiffBitmap.getSize());
+  CHECK(gfx::PNGCodec::EncodeBGRASkBitmap(result.rgbDiffBitmap, false,
+                                          &diff_image->data()))
       << "Could not encode difference to PNG";
+  testing_result.diff_image = diff_image;
 
   return testing_result;
 }
diff --git a/chrome/browser/chromeos/login/screenshot_testing/screenshot_tester.h b/chrome/browser/chromeos/login/screenshot_testing/screenshot_tester.h
index 6474157..eafd43e 100644
--- a/chrome/browser/chromeos/login/screenshot_testing/screenshot_tester.h
+++ b/chrome/browser/chromeos/login/screenshot_testing/screenshot_tester.h
@@ -24,7 +24,7 @@
   ScreenshotTester();
   virtual ~ScreenshotTester();
 
-  typedef scoped_refptr<base::RefCountedBytes> PNGFile;
+  typedef scoped_refptr<base::RefCountedMemory> PNGFile;
 
   // Contains the results of comparison
   struct Result {
@@ -106,7 +106,7 @@
   void LogComparisonResults(const ScreenshotTester::Result& result);
 
   // Saves |png_data| as a current screenshot.
-  void ReturnScreenshot(const PNGFile& screenshot, PNGFile png_data);
+  void ReturnScreenshot(PNGFile* screenshot, PNGFile png_data);
 
   // Loads golden screenshot from the disk, assuming it lies at |image_path|.
   // Fails if there is no such a file.
@@ -138,7 +138,7 @@
   base::FilePath artifacts_dir_;
 
   // |run_loop_quitter_| is used to stop waiting when
-  // ui::GrabWindowSnapshotAsync completes.
+  // ui::GrabWindowSnapshotAsyncPNG completes.
   base::Closure run_loop_quitter_;
 
   // Is true when we're in test mode:
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
index 2e0e156f..249f3d9 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
@@ -60,7 +60,7 @@
 void RunStoreScreenshotOnTaskRunner(
     const ui::GrabWindowSnapshotAsyncPNGCallback& store_screenshot_callback,
     scoped_refptr<base::TaskRunner> task_runner,
-    scoped_refptr<base::RefCountedBytes> png_data) {
+    scoped_refptr<base::RefCountedMemory> png_data) {
   task_runner->PostTask(FROM_HERE,
                         base::Bind(store_screenshot_callback, png_data));
 }
@@ -157,7 +157,7 @@
 
 void DeviceCommandScreenshotJob::StoreScreenshot(
     size_t screen,
-    scoped_refptr<base::RefCountedBytes> png_data) {
+    scoped_refptr<base::RefCountedMemory> png_data) {
   screenshots_.insert(std::make_pair(screen, png_data));
   DCHECK_LT(0, num_pending_screenshots_);
   --num_pending_screenshots_;
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h
index b1b588d..da124bd 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h
@@ -110,7 +110,7 @@
   void TerminateImpl() override;
 
   void StoreScreenshot(size_t screen,
-                       scoped_refptr<base::RefCountedBytes> png_data);
+                       scoped_refptr<base::RefCountedMemory> png_data);
 
   void StartScreenshotUpload();
 
@@ -128,7 +128,7 @@
   int num_pending_screenshots_;
 
   // Caches the already completed screenshots for the different displays.
-  std::map<int, scoped_refptr<base::RefCountedBytes>> screenshots_;
+  std::map<int, scoped_refptr<base::RefCountedMemory>> screenshots_;
 
   // The Delegate is used to acquire screenshots and create UploadJobs.
   std::unique_ptr<Delegate> screenshot_delegate_;
diff --git a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc
index fe9264c..eec0979 100644
--- a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc
@@ -42,7 +42,7 @@
     gfx::NativeWindow window,
     const gfx::Rect& source_rect,
     const ui::GrabWindowSnapshotAsyncPNGCallback& callback) {
-  ui::GrabWindowSnapshotAsync(
+  ui::GrabWindowSnapshotAsyncPNG(
       window, source_rect, blocking_task_runner_,
       base::Bind(&ScreenshotDelegate::StoreScreenshot,
                  weak_ptr_factory_.GetWeakPtr(), callback));
@@ -69,7 +69,7 @@
 
 void ScreenshotDelegate::StoreScreenshot(
     const ui::GrabWindowSnapshotAsyncPNGCallback& callback,
-    scoped_refptr<base::RefCountedBytes> png_data) {
+    scoped_refptr<base::RefCountedMemory> png_data) {
   callback.Run(png_data);
 }
 
diff --git a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h
index 1301fd2..6dbba859 100644
--- a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h
+++ b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h
@@ -21,7 +21,7 @@
 namespace policy {
 
 // An implementation of the |DeviceCommandScreenshotJob::Delegate| that uses
-// aura's GrabWindowSnapshotAsync() to acquire the window snapshot.
+// aura's GrabWindowSnapshotAsyncPNG() to acquire the window snapshot.
 class ScreenshotDelegate : public DeviceCommandScreenshotJob::Delegate {
  public:
   explicit ScreenshotDelegate(
@@ -40,7 +40,7 @@
 
  private:
   void StoreScreenshot(const ui::GrabWindowSnapshotAsyncPNGCallback& callback,
-                       scoped_refptr<base::RefCountedBytes> png_data);
+                       scoped_refptr<base::RefCountedMemory> png_data);
 
   scoped_refptr<base::TaskRunner> blocking_task_runner_;
 
diff --git a/chrome/browser/search/iframe_source.cc b/chrome/browser/search/iframe_source.cc
index 925c97e..cae15fe4 100644
--- a/chrome/browser/search/iframe_source.cc
+++ b/chrome/browser/search/iframe_source.cc
@@ -36,6 +36,10 @@
   return std::string();
 }
 
+bool IframeSource::AllowCaching() const {
+  return false;
+}
+
 bool IframeSource::ShouldServiceRequest(
     const net::URLRequest* request) const {
   const std::string& path = request->url().path();
diff --git a/chrome/browser/search/iframe_source.h b/chrome/browser/search/iframe_source.h
index 414b9ece..4618389d 100644
--- a/chrome/browser/search/iframe_source.h
+++ b/chrome/browser/search/iframe_source.h
@@ -18,6 +18,7 @@
  protected:
   // Overridden from content::URLDataSource:
   std::string GetMimeType(const std::string& path_and_query) const override;
+  bool AllowCaching() const override;
   bool ShouldDenyXFrameOptions() const override;
   bool ShouldServiceRequest(const net::URLRequest* request) const override;
 
diff --git a/chrome/browser/search/thumbnail_source.cc b/chrome/browser/search/thumbnail_source.cc
index 26afe89..cbfbb87e3 100644
--- a/chrome/browser/search/thumbnail_source.cc
+++ b/chrome/browser/search/thumbnail_source.cc
@@ -88,6 +88,10 @@
              : content::URLDataSource::TaskRunnerForRequestPath(path);
 }
 
+bool ThumbnailSource::AllowCaching() const {
+  return false;
+}
+
 bool ThumbnailSource::ShouldServiceRequest(
     const net::URLRequest* request) const {
   if (request->url().SchemeIs(chrome::kChromeSearchScheme))
diff --git a/chrome/browser/search/thumbnail_source.h b/chrome/browser/search/thumbnail_source.h
index 818df016..78e1050 100644
--- a/chrome/browser/search/thumbnail_source.h
+++ b/chrome/browser/search/thumbnail_source.h
@@ -48,6 +48,7 @@
   std::string GetMimeType(const std::string& path) const override;
   scoped_refptr<base::SingleThreadTaskRunner> TaskRunnerForRequestPath(
       const std::string& path) const override;
+  bool AllowCaching() const override;
   bool ShouldServiceRequest(const net::URLRequest* request) const override;
 
   // Extracts the |page_url| (e.g. cnn.com) and the |fallback_thumbnail_url|
diff --git a/chrome/browser/ui/webui/fallback_icon_source.cc b/chrome/browser/ui/webui/fallback_icon_source.cc
index a8781d2..c282ed08 100644
--- a/chrome/browser/ui/webui/fallback_icon_source.cc
+++ b/chrome/browser/ui/webui/fallback_icon_source.cc
@@ -55,6 +55,10 @@
   return "image/png";
 }
 
+bool FallbackIconSource::AllowCaching() const {
+  return false;
+}
+
 bool FallbackIconSource::ShouldReplaceExistingSource() const {
   // Leave the existing DataSource in place, otherwise we'll drop any pending
   // requests on the floor.
diff --git a/chrome/browser/ui/webui/fallback_icon_source.h b/chrome/browser/ui/webui/fallback_icon_source.h
index a6cf59c..381521b 100644
--- a/chrome/browser/ui/webui/fallback_icon_source.h
+++ b/chrome/browser/ui/webui/fallback_icon_source.h
@@ -66,6 +66,7 @@
       const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string&) const override;
+  bool AllowCaching() const override;
   bool ShouldReplaceExistingSource() const override;
   bool ShouldServiceRequest(const net::URLRequest* request) const override;
 
diff --git a/chrome/browser/ui/webui/favicon_source.cc b/chrome/browser/ui/webui/favicon_source.cc
index fa63fc31..fca040d 100644
--- a/chrome/browser/ui/webui/favicon_source.cc
+++ b/chrome/browser/ui/webui/favicon_source.cc
@@ -132,6 +132,10 @@
   return "image/png";
 }
 
+bool FaviconSource::AllowCaching() const {
+  return false;
+}
+
 bool FaviconSource::ShouldReplaceExistingSource() const {
   // Leave the existing DataSource in place, otherwise we'll drop any pending
   // requests on the floor.
diff --git a/chrome/browser/ui/webui/favicon_source.h b/chrome/browser/ui/webui/favicon_source.h
index cd27824..7844196 100644
--- a/chrome/browser/ui/webui/favicon_source.h
+++ b/chrome/browser/ui/webui/favicon_source.h
@@ -77,6 +77,7 @@
       const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string&) const override;
+  bool AllowCaching() const override;
   bool ShouldReplaceExistingSource() const override;
   bool ShouldServiceRequest(const net::URLRequest* request) const override;
 
diff --git a/chrome/browser/ui/webui/fileicon_source.cc b/chrome/browser/ui/webui/fileicon_source.cc
index ddb2fbee..c048f30 100644
--- a/chrome/browser/ui/webui/fileicon_source.cc
+++ b/chrome/browser/ui/webui/fileicon_source.cc
@@ -146,6 +146,10 @@
   return std::string();
 }
 
+bool FileIconSource::AllowCaching() const {
+  return false;
+}
+
 void FileIconSource::OnFileIconDataAvailable(const IconRequestDetails& details,
                                              gfx::Image* icon) {
   if (icon) {
diff --git a/chrome/browser/ui/webui/fileicon_source.h b/chrome/browser/ui/webui/fileicon_source.h
index e91f80e..6b40467 100644
--- a/chrome/browser/ui/webui/fileicon_source.h
+++ b/chrome/browser/ui/webui/fileicon_source.h
@@ -30,6 +30,7 @@
       const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string&) const override;
+  bool AllowCaching() const override;
 
  protected:
   ~FileIconSource() override;
diff --git a/chrome/browser/ui/webui/large_icon_source.cc b/chrome/browser/ui/webui/large_icon_source.cc
index b8fc09f..2924ec2 100644
--- a/chrome/browser/ui/webui/large_icon_source.cc
+++ b/chrome/browser/ui/webui/large_icon_source.cc
@@ -79,6 +79,10 @@
   return "image/png";
 }
 
+bool LargeIconSource::AllowCaching() const {
+  return false;
+}
+
 bool LargeIconSource::ShouldReplaceExistingSource() const {
   // Leave the existing DataSource in place, otherwise we'll drop any pending
   // requests on the floor.
diff --git a/chrome/browser/ui/webui/large_icon_source.h b/chrome/browser/ui/webui/large_icon_source.h
index 88d5b12..14ae4f7d 100644
--- a/chrome/browser/ui/webui/large_icon_source.h
+++ b/chrome/browser/ui/webui/large_icon_source.h
@@ -51,6 +51,7 @@
       const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string&) const override;
+  bool AllowCaching() const override;
   bool ShouldReplaceExistingSource() const override;
   bool ShouldServiceRequest(const net::URLRequest* request) const override;
 
diff --git a/chrome/browser/ui/webui/theme_source.cc b/chrome/browser/ui/webui/theme_source.cc
index 6f7d2cab..92b7601 100644
--- a/chrome/browser/ui/webui/theme_source.cc
+++ b/chrome/browser/ui/webui/theme_source.cc
@@ -179,6 +179,10 @@
              : nullptr;
 }
 
+bool ThemeSource::AllowCaching() const {
+  return false;
+}
+
 bool ThemeSource::ShouldServiceRequest(const net::URLRequest* request) const {
   return request->url().SchemeIs(chrome::kChromeSearchScheme) ?
       InstantIOContext::ShouldServiceRequest(request) :
diff --git a/chrome/browser/ui/webui/theme_source.h b/chrome/browser/ui/webui/theme_source.h
index 79d7dee..b17f7f51 100644
--- a/chrome/browser/ui/webui/theme_source.h
+++ b/chrome/browser/ui/webui/theme_source.h
@@ -28,6 +28,7 @@
   std::string GetMimeType(const std::string& path) const override;
   scoped_refptr<base::SingleThreadTaskRunner> TaskRunnerForRequestPath(
       const std::string& path) const override;
+  bool AllowCaching() const override;
   bool ShouldServiceRequest(const net::URLRequest* request) const override;
 
  private:
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index f488753..16187f3 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -238,8 +238,8 @@
   }
 
   for (size_t i = 0; i < additional_names.size(); ++i) {
-    names[existing_size + i] = additional_names[i];
-    values[existing_size + i] = additional_values[i];
+    names[existing_size + i] = WebString::fromUTF16(additional_names[i]);
+    values[existing_size + i] = WebString::fromUTF16(additional_values[i]);
   }
 
   existing_names->swap(names);
@@ -428,7 +428,8 @@
   // chrome-search: and chrome-distiller: pages  should not be accessible by
   // normal content, and should also be unable to script anything but themselves
   // (to help limit the damage that a corrupt page could cause).
-  WebString chrome_search_scheme(ASCIIToUTF16(chrome::kChromeSearchScheme));
+  WebString chrome_search_scheme(
+      WebString::fromASCII(chrome::kChromeSearchScheme));
 
   // The Instant process can only display the content but not read it.  Other
   // processes can't display it or read it.
@@ -436,7 +437,7 @@
     WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(chrome_search_scheme);
 
   WebString dom_distiller_scheme(
-      ASCIIToUTF16(dom_distiller::kDomDistillerScheme));
+      WebString::fromASCII(dom_distiller::kDomDistillerScheme));
   // TODO(nyquist): Add test to ensure this happens when the flag is set.
   WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(dom_distiller_scheme);
 
@@ -462,7 +463,7 @@
 
   for (auto& scheme : GetSchemesBypassingSecureContextCheckWhitelist()) {
     WebSecurityPolicy::addSchemeToBypassSecureContextWhitelist(
-        WebString::fromUTF8(scheme));
+        WebString::fromASCII(scheme));
   }
 
 #if defined(OS_CHROMEOS)
@@ -1045,8 +1046,7 @@
     base::string16* error_description) {
   const GURL failed_url = error.unreachableURL;
 
-  bool is_post = base::EqualsASCII(
-      base::StringPiece16(failed_request.httpMethod()), "POST");
+  bool is_post = failed_request.httpMethod().ascii() == "POST";
   bool is_ignoring_cache =
       failed_request.getCachePolicy() == WebCachePolicy::BypassingCache;
   if (error_html) {
@@ -1375,7 +1375,7 @@
     const WebURLResponse& response,
     std::map<std::string, std::string>* properties) {
   DCHECK(properties);
-  WebString header_key(ASCIIToUTF16(
+  WebString header_key(WebString::fromASCII(
       data_reduction_proxy::chrome_proxy_content_transform_header()));
   if (!response.httpHeaderField(header_key).isNull() &&
       data_reduction_proxy::IsEmptyImagePreview(
diff --git a/chrome/renderer/chrome_render_frame_observer.cc b/chrome/renderer/chrome_render_frame_observer.cc
index dc649f0..23026a0 100644
--- a/chrome/renderer/chrome_render_frame_observer.cc
+++ b/chrome/renderer/chrome_render_frame_observer.cc
@@ -304,7 +304,8 @@
   // testing purposes. See http://crbug.com/585164.
   base::string16 contents =
       WebFrameContentDumper::deprecatedDumpFrameTreeAsText(frame,
-                                                           kMaxIndexChars);
+                                                           kMaxIndexChars)
+          .utf16();
 
   UMA_HISTOGRAM_TIMES(kTranslateCaptureText,
                       base::TimeTicks::Now() - capture_begin_time);
diff --git a/chrome/renderer/chrome_render_thread_observer.cc b/chrome/renderer/chrome_render_thread_observer.cc
index 9965185..b4a01e1 100644
--- a/chrome/renderer/chrome_render_thread_observer.cc
+++ b/chrome/renderer/chrome_render_thread_observer.cc
@@ -263,7 +263,7 @@
   // that can commit synchronously.  No code should be runnable in these pages,
   // so it should not need to access anything nor should it allow javascript
   // URLs since it should never be visible to the user.
-  WebString native_scheme(base::ASCIIToUTF16(chrome::kChromeNativeScheme));
+  WebString native_scheme(WebString::fromASCII(chrome::kChromeNativeScheme));
   WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(native_scheme);
   WebSecurityPolicy::registerURLSchemeAsEmptyDocument(native_scheme);
   WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs(
diff --git a/chrome/renderer/content_settings_observer.cc b/chrome/renderer/content_settings_observer.cc
index a956b85f..3a6969565 100644
--- a/chrome/renderer/content_settings_observer.cc
+++ b/chrome/renderer/content_settings_observer.cc
@@ -216,8 +216,8 @@
   bool result = false;
   Send(new ChromeViewHostMsg_AllowDatabase(
       routing_id(), url::Origin(frame->getSecurityOrigin()).GetURL(),
-      url::Origin(frame->top()->getSecurityOrigin()).GetURL(), name,
-      display_name, &result));
+      url::Origin(frame->top()->getSecurityOrigin()).GetURL(), name.utf16(),
+      display_name.utf16(), &result));
   return result;
 }
 
@@ -275,7 +275,8 @@
   bool result = false;
   Send(new ChromeViewHostMsg_AllowIndexedDB(
       routing_id(), url::Origin(frame->getSecurityOrigin()).GetURL(),
-      url::Origin(frame->top()->getSecurityOrigin()).GetURL(), name, &result));
+      url::Origin(frame->top()->getSecurityOrigin()).GetURL(), name.utf16(),
+      &result));
   return result;
 }
 
@@ -481,8 +482,7 @@
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 const extensions::Extension* ContentSettingsObserver::GetExtension(
     const WebSecurityOrigin& origin) const {
-  if (!base::EqualsASCII(base::StringPiece16(origin.protocol()),
-                         extensions::kExtensionScheme))
+  if (origin.protocol().ascii() != extensions::kExtensionScheme)
     return NULL;
 
   const std::string extension_id = origin.host().utf8().data();
diff --git a/chrome/renderer/extensions/page_capture_custom_bindings.cc b/chrome/renderer/extensions/page_capture_custom_bindings.cc
index ec19aa36..41d48e0be 100644
--- a/chrome/renderer/extensions/page_capture_custom_bindings.cc
+++ b/chrome/renderer/extensions/page_capture_custom_bindings.cc
@@ -29,7 +29,8 @@
   CHECK(args.Length() == 2);
   CHECK(args[0]->IsString());
   CHECK(args[1]->IsInt32());
-  blink::WebString path(base::UTF8ToUTF16(*v8::String::Utf8Value(args[0])));
+  blink::WebString path(
+      blink::WebString::fromUTF8(*v8::String::Utf8Value(args[0])));
   blink::WebBlob blob =
       blink::WebBlob::createFromFile(path, args[1]->Int32Value());
   args.GetReturnValue().Set(
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc
index dd6221e4..72d0b6b 100644
--- a/chrome/renderer/searchbox/searchbox_extension.cc
+++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -506,9 +506,8 @@
     const base::string16& identity,
     bool identity_match) {
   std::string escaped_identity = base::GetQuotedJSONString(identity);
-  blink::WebString script(base::UTF8ToUTF16(base::StringPrintf(
-      kDispatchChromeIdentityCheckResult,
-      escaped_identity.c_str(),
+  blink::WebString script(blink::WebString::fromUTF8(base::StringPrintf(
+      kDispatchChromeIdentityCheckResult, escaped_identity.c_str(),
       identity_match ? "true" : "false")));
   Dispatch(frame, script);
 }
@@ -522,9 +521,8 @@
 void SearchBoxExtension::DispatchHistorySyncCheckResult(
     blink::WebFrame* frame,
     bool sync_history) {
-  blink::WebString script(base::UTF8ToUTF16(base::StringPrintf(
-      kDispatchHistorySyncCheckResult,
-      sync_history ? "true" : "false")));
+  blink::WebString script(blink::WebString::fromUTF8(base::StringPrintf(
+      kDispatchHistorySyncCheckResult, sync_history ? "true" : "false")));
   Dispatch(frame, script);
 }
 
diff --git a/chrome/renderer/web_apps.cc b/chrome/renderer/web_apps.cc
index 60d4a44b..9d7316c6 100644
--- a/chrome/renderer/web_apps.cc
+++ b/chrome/renderer/web_apps.cc
@@ -167,9 +167,9 @@
       std::string name = elem.getAttribute("name").utf8();
       WebString content = elem.getAttribute("content");
       if (name == "application-name") {
-        app_info->title = content;
+        app_info->title = content.utf16();
       } else if (name == "description") {
-        app_info->description = content;
+        app_info->description = content.utf16();
       } else if (name == "application-url") {
         std::string url = content.utf8();
         app_info->app_url = document_url.is_valid() ?
@@ -177,12 +177,10 @@
         if (!app_info->app_url.is_valid())
           app_info->app_url = GURL();
       } else if (name == "mobile-web-app-capable" &&
-                 base::LowerCaseEqualsASCII(base::StringPiece16(content),
-                                            "yes")) {
+                 base::LowerCaseEqualsASCII(content.utf16(), "yes")) {
         app_info->mobile_capable = WebApplicationInfo::MOBILE_CAPABLE;
       } else if (name == "apple-mobile-web-app-capable" &&
-                 base::LowerCaseEqualsASCII(
-                     base::StringPiece16(content), "yes") &&
+                 base::LowerCaseEqualsASCII(content.utf16(), "yes") &&
                  app_info->mobile_capable ==
                      WebApplicationInfo::MOBILE_CAPABLE_UNSPECIFIED) {
         app_info->mobile_capable = WebApplicationInfo::MOBILE_CAPABLE_APPLE;
diff --git a/chrome/renderer/worker_content_settings_client_proxy.cc b/chrome/renderer/worker_content_settings_client_proxy.cc
index 0056280..e4eb6c4f 100644
--- a/chrome/renderer/worker_content_settings_client_proxy.cc
+++ b/chrome/renderer/worker_content_settings_client_proxy.cc
@@ -48,6 +48,7 @@
 
   bool result = false;
   sync_message_filter_->Send(new ChromeViewHostMsg_AllowIndexedDB(
-      routing_id_, document_origin_url_, top_frame_origin_url_, name, &result));
+      routing_id_, document_origin_url_, top_frame_origin_url_, name.utf16(),
+      &result));
   return result;
 }
diff --git a/components/crash/content/app/fallback_crash_handler_win.cc b/components/crash/content/app/fallback_crash_handler_win.cc
index a554673..2e3310d8 100644
--- a/components/crash/content/app/fallback_crash_handler_win.cc
+++ b/components/crash/content/app/fallback_crash_handler_win.cc
@@ -9,6 +9,8 @@
 
 #include <algorithm>
 #include <map>
+#include <memory>
+#include <string>
 #include <vector>
 
 #include "base/command_line.h"
@@ -52,6 +54,10 @@
     crash_keys->insert(std::make_pair(
         "ProcessPeakWorkingSetSize",
         base::Uint64ToString(process_memory.PeakWorkingSetSize / kPageSize)));
+
+    crash_keys->insert(std::make_pair(
+        "ProcessPeakPagefileUsage",
+        base::Uint64ToString(process_memory.PeakPagefileUsage / kPageSize)));
   }
 
   // Grab system commit memory. Also best effort.
diff --git a/components/crash/content/app/fallback_crash_handler_win_unittest.cc b/components/crash/content/app/fallback_crash_handler_win_unittest.cc
index cdd68d80..13ca131 100644
--- a/components/crash/content/app/fallback_crash_handler_win_unittest.cc
+++ b/components/crash/content/app/fallback_crash_handler_win_unittest.cc
@@ -4,6 +4,11 @@
 
 #include "components/crash/content/app/fallback_crash_handler_win.h"
 
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
 #include "base/base_switches.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
@@ -116,7 +121,7 @@
 
   std::string SelfHandleAsString() const {
     return base::UintToString(base::win::HandleToUint32(self_handle_));
-  };
+  }
 
   void CreateDatabase() {
     std::unique_ptr<crashpad::CrashReportDatabase> database =
@@ -128,6 +133,7 @@
   base::ProcessHandle self_handle_;
   base::ScopedTempDir database_dir_;
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(FallbackCrashHandlerWinTest);
 };
 
@@ -239,6 +245,11 @@
   EXPECT_TRUE(base::StringToUint64(it->second, &int_value));
   EXPECT_NE(0U, int_value);
 
+  it = parameters.find("ProcessPeakPagefileUsage");
+  EXPECT_NE(parameters.end(), it);
+  EXPECT_TRUE(base::StringToUint64(it->second, &int_value));
+  EXPECT_NE(0U, int_value);
+
   it = parameters.find("SystemCommitRemaining");
   EXPECT_NE(parameters.end(), it);
   EXPECT_TRUE(base::StringToUint64(it->second, &int_value));
diff --git a/components/spellcheck/renderer/spellcheck_unittest.cc b/components/spellcheck/renderer/spellcheck_unittest.cc
index b13298ebf..3804513d 100644
--- a/components/spellcheck/renderer/spellcheck_unittest.cc
+++ b/components/spellcheck/renderer/spellcheck_unittest.cc
@@ -178,13 +178,7 @@
 // A test with a "[ROBUSTNESS]" mark shows it is a robustness test and it uses
 // grammatically incorrect string.
 // TODO(groby): Please feel free to add more tests.
-#if defined(OS_WIN) && !defined(NDEBUG)
-// Test times out on win dbg. crbug.com/678753.
-#define MAYBE_SpellCheckStrings_EN_US DISABLED_SpellCheckStrings_EN_US
-#else
-#define MAYBE_SpellCheckStrings_EN_US SpellCheckStrings_EN_US
-#endif
-TEST_F(SpellCheckTest, MAYBE_SpellCheckStrings_EN_US) {
+TEST_F(SpellCheckTest, SpellCheckStrings_EN_US) {
   static const struct {
     // A string to be tested.
     const wchar_t* input;
@@ -495,15 +489,7 @@
 
 // This test verifies our spellchecker can split a text into words and check
 // the spelling of each word in the text.
-#if defined(THREAD_SANITIZER) || defined(OS_WIN)
-// SpellCheckTest.SpellCheckText fails under ThreadSanitizer v2.
-// See http://crbug.com/217909.
-// Also fails on windows: crbug.com/678300.
-#define MAYBE_SpellCheckText DISABLED_SpellCheckText
-#else
-#define MAYBE_SpellCheckText SpellCheckText
-#endif  // THREAD_SANITIZER
-TEST_F(SpellCheckTest, MAYBE_SpellCheckText) {
+TEST_F(SpellCheckTest, SpellCheckText) {
   static const struct {
     const char* language;
     const wchar_t* input;
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index b7a73c0..50358c27 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -49,10 +49,12 @@
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/layout.h"
 #include "ui/compositor/compositor_switches.h"
+#include "ui/gfx/codec/jpeg_codec.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/skia_util.h"
+#include "ui/snapshot/snapshot.h"
 
 #define EXPECT_SIZE_EQ(expected, actual)               \
   do {                                                 \
@@ -531,10 +533,37 @@
       bitmap);
 }
 
+std::unique_ptr<SkBitmap> DecodeJPEG(std::string base64_data) {
+  std::string jpeg_data;
+  if (!base::Base64Decode(base64_data, &jpeg_data))
+    return nullptr;
+  return gfx::JPEGCodec::Decode(
+      reinterpret_cast<unsigned const char*>(jpeg_data.data()),
+      jpeg_data.size());
+}
+
+bool ColorsMatchWithinLimit(SkColor color1,
+                            SkColor color2,
+                            int32_t error_limit) {
+  auto a_distance = std::abs(static_cast<int32_t>(SkColorGetA(color1)) -
+                             static_cast<int32_t>(SkColorGetA(color2)));
+  auto r_distance = std::abs(static_cast<int32_t>(SkColorGetR(color1)) -
+                             static_cast<int32_t>(SkColorGetR(color2)));
+  auto g_distance = std::abs(static_cast<int32_t>(SkColorGetG(color1)) -
+                             static_cast<int32_t>(SkColorGetG(color2)));
+  auto b_distance = std::abs(static_cast<int32_t>(SkColorGetB(color1)) -
+                             static_cast<int32_t>(SkColorGetB(color2)));
+
+  return a_distance * a_distance + r_distance * r_distance +
+             g_distance * g_distance + b_distance * b_distance <=
+         error_limit * error_limit;
+}
+
 // Adapted from cc::ExactPixelComparator.
 bool MatchesBitmap(const SkBitmap& expected_bmp,
                    const SkBitmap& actual_bmp,
-                   const gfx::Rect& matching_mask) {
+                   const gfx::Rect& matching_mask,
+                   int error_limit) {
   // Number of pixels with an error
   int error_pixels_count = 0;
 
@@ -557,7 +586,7 @@
     for (int y = matching_mask.y(); y < matching_mask.height(); ++y) {
       SkColor actual_color = actual_bmp.getColor(x, y);
       SkColor expected_color = expected_bmp.getColor(x, y);
-      if (actual_color != expected_color) {
+      if (!ColorsMatchWithinLimit(actual_color, expected_color, error_limit)) {
         if (error_pixels_count < 10) {
           LOG(ERROR) << "Pixel (" << x << "," << y << "): expected "
                      << expected_color << " actual " << actual_color;
@@ -580,19 +609,38 @@
 
 class CaptureScreenshotTest : public DevToolsProtocolTest {
  protected:
-  void CaptureScreenshotAndCompareTo(const SkBitmap& expected_bitmap) {
-    SendCommand("Page.captureScreenshot", nullptr);
+  enum ScreenshotEncoding { ENCODING_PNG, ENCODING_JPEG };
+  void CaptureScreenshotAndCompareTo(const SkBitmap& expected_bitmap,
+                                     ScreenshotEncoding encoding) {
+    std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
+    params->SetString("format", encoding == ENCODING_PNG ? "png" : "jpeg");
+    params->SetInteger("quality", 100);
+    SendCommand("Page.captureScreenshot", std::move(params));
+
     std::string base64;
     EXPECT_TRUE(result_->GetString("data", &base64));
-    SkBitmap result_bitmap;
-    EXPECT_TRUE(DecodePNG(base64, &result_bitmap));
+    std::unique_ptr<SkBitmap> result_bitmap;
+    int error_limit = 0;
+    if (encoding == ENCODING_PNG) {
+      result_bitmap.reset(new SkBitmap());
+      EXPECT_TRUE(DecodePNG(base64, result_bitmap.get()));
+    } else {
+      result_bitmap = DecodeJPEG(base64);
+      // Even with quality 100, jpeg isn't lossless. So, we allow some skew in
+      // pixel values. Not that this assumes that there is no skew in pixel
+      // positions, so will only work reliably if all pixels have equal values.
+      error_limit = 3;
+    }
+    EXPECT_TRUE(result_bitmap);
+
     gfx::Rect matching_mask(gfx::SkIRectToRect(expected_bitmap.bounds()));
 #if defined(OS_MACOSX)
     // Mask out the corners, which may be drawn differently on Mac because of
     // rounded corners.
     matching_mask.Inset(4, 4, 4, 4);
 #endif
-    EXPECT_TRUE(MatchesBitmap(expected_bitmap, result_bitmap, matching_mask));
+    EXPECT_TRUE(MatchesBitmap(expected_bitmap, *result_bitmap, matching_mask,
+                              error_limit));
   }
 
   // Takes a screenshot of a colored box that is positioned inside the frame.
@@ -651,7 +699,7 @@
     expected_bitmap.allocN32Pixels(scaled_box_size.width(),
                                    scaled_box_size.height());
     expected_bitmap.eraseColor(SkColorSetRGB(0x00, 0x00, 0xff));
-    CaptureScreenshotAndCompareTo(expected_bitmap);
+    CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_PNG);
 
     // Reset for next screenshot.
     SendCommand("Emulation.resetViewport", nullptr);
@@ -669,13 +717,13 @@
 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, CaptureScreenshot) {
   // This test fails consistently on low-end Android devices.
   // See crbug.com/653637.
+  // TODO(eseckler): Reenable with error limit if necessary.
   if (base::SysInfo::IsLowEndDevice()) return;
 
-  shell()->LoadURL(GURL("about:blank"));
+  shell()->LoadURL(
+      GURL("data:text/html,<body style='background:#123456'></body>"));
+  WaitForLoadStop(shell()->web_contents());
   Attach();
-  EXPECT_TRUE(
-      content::ExecuteScript(shell()->web_contents()->GetRenderViewHost(),
-                             "document.body.style.background = '#123456'"));
   SkBitmap expected_bitmap;
   // We compare against the actual physical backing size rather than the
   // view size, because the view size is stored adjusted for DPI and only in
@@ -685,7 +733,30 @@
                             ->GetPhysicalBackingSize();
   expected_bitmap.allocN32Pixels(view_size.width(), view_size.height());
   expected_bitmap.eraseColor(SkColorSetRGB(0x12, 0x34, 0x56));
-  CaptureScreenshotAndCompareTo(expected_bitmap);
+  CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_PNG);
+}
+
+IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, CaptureScreenshotJpeg) {
+  // This test fails consistently on low-end Android devices.
+  // See crbug.com/653637.
+  // TODO(eseckler): Reenable with error limit if necessary.
+  if (base::SysInfo::IsLowEndDevice())
+    return;
+
+  shell()->LoadURL(
+      GURL("data:text/html,<body style='background:#123456'></body>"));
+  WaitForLoadStop(shell()->web_contents());
+  Attach();
+  SkBitmap expected_bitmap;
+  // We compare against the actual physical backing size rather than the
+  // view size, because the view size is stored adjusted for DPI and only in
+  // integer precision.
+  gfx::Size view_size = static_cast<RenderWidgetHostViewBase*>(
+                            shell()->web_contents()->GetRenderWidgetHostView())
+                            ->GetPhysicalBackingSize();
+  expected_bitmap.allocN32Pixels(view_size.width(), view_size.height());
+  expected_bitmap.eraseColor(SkColorSetRGB(0x12, 0x34, 0x56));
+  CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_JPEG);
 }
 
 // Setting frame size (through RWHV) is not supported on Android.
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index f7ec85b..740c0a2 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -9,6 +9,8 @@
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/ref_counted_memory.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
@@ -37,6 +39,8 @@
 #include "ui/gfx/codec/jpeg_codec.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/geometry/size_conversions.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_util.h"
 #include "ui/snapshot/snapshot.h"
 #include "url/gurl.h"
 
@@ -52,37 +56,27 @@
 static int kCaptureRetryLimit = 2;
 static int kMaxScreencastFramesInFlight = 2;
 
-std::string EncodeScreencastFrame(const SkBitmap& bitmap,
-                                  const std::string& format,
-                                  int quality) {
-  std::vector<unsigned char> data;
-  SkAutoLockPixels lock_image(bitmap);
-  bool encoded;
+std::string EncodeImage(const gfx::Image& image,
+                        const std::string& format,
+                        int quality) {
+  DCHECK(!image.IsEmpty());
+
+  scoped_refptr<base::RefCountedMemory> data;
   if (format == kPng) {
-    encoded = gfx::PNGCodec::Encode(
-        reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
-        gfx::PNGCodec::FORMAT_SkBitmap,
-        gfx::Size(bitmap.width(), bitmap.height()),
-        bitmap.width() * bitmap.bytesPerPixel(),
-        false, std::vector<gfx::PNGCodec::Comment>(), &data);
+    data = image.As1xPNGBytes();
   } else if (format == kJpeg) {
-    encoded = gfx::JPEGCodec::Encode(
-        reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
-        gfx::JPEGCodec::FORMAT_SkBitmap,
-        bitmap.width(),
-        bitmap.height(),
-        bitmap.width() * bitmap.bytesPerPixel(),
-        quality, &data);
-  } else {
-    encoded = false;
+    scoped_refptr<base::RefCountedBytes> bytes(new base::RefCountedBytes());
+    if (gfx::JPEG1xEncodedDataFromImage(image, quality, &bytes->data()))
+      data = bytes;
   }
 
-  if (!encoded)
+  if (!data || !data->front())
     return std::string();
 
   std::string base_64_data;
   base::Base64Encode(
-      base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()),
+      base::StringPiece(reinterpret_cast<const char*>(data->front()),
+                        data->size()),
       &base_64_data);
 
   return base_64_data;
@@ -285,15 +279,21 @@
 }
 
 void PageHandler::CaptureScreenshot(
+    Maybe<std::string> format,
+    Maybe<int> quality,
     std::unique_ptr<CaptureScreenshotCallback> callback) {
   if (!host_ || !host_->GetRenderWidgetHost()) {
     callback->sendFailure(Response::InternalError());
     return;
   }
 
+  std::string screenshot_format = format.fromMaybe(kPng);
+  int screenshot_quality = quality.fromMaybe(kDefaultScreenshotQuality);
+
   host_->GetRenderWidgetHost()->GetSnapshotFromBrowser(
-      base::Bind(&PageHandler::ScreenshotCaptured,
-          weak_factory_.GetWeakPtr(), base::Passed(std::move(callback))));
+      base::Bind(&PageHandler::ScreenshotCaptured, weak_factory_.GetWeakPtr(),
+                 base::Passed(std::move(callback)), screenshot_format,
+                 screenshot_quality));
 }
 
 Response PageHandler::StartScreencast(Maybe<std::string> format,
@@ -519,8 +519,8 @@
   base::PostTaskWithTraitsAndReplyWithResult(
       FROM_HERE, base::TaskTraits().WithShutdownBehavior(
                      base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN),
-      base::Bind(&EncodeScreencastFrame, bitmap, screencast_format_,
-                 screencast_quality_),
+      base::Bind(&EncodeImage, gfx::Image::CreateFrom1xBitmap(bitmap),
+                 screencast_format_, screencast_quality_),
       base::Bind(&PageHandler::ScreencastFrameEncoded,
                  weak_factory_.GetWeakPtr(), base::Passed(&metadata),
                  base::Time::Now()));
@@ -561,18 +561,15 @@
 
 void PageHandler::ScreenshotCaptured(
     std::unique_ptr<CaptureScreenshotCallback> callback,
-    const unsigned char* png_data,
-    size_t png_size) {
-  if (!png_data || !png_size) {
+    const std::string& format,
+    int quality,
+    const gfx::Image& image) {
+  if (image.IsEmpty()) {
     callback->sendFailure(Response::Error("Unable to capture screenshot"));
     return;
   }
 
-  std::string base_64_data;
-  base::Base64Encode(
-      base::StringPiece(reinterpret_cast<const char*>(png_data), png_size),
-      &base_64_data);
-  callback->sendSuccess(base_64_data);
+  callback->sendSuccess(EncodeImage(image, format, quality));
 }
 
 void PageHandler::OnColorPicked(int r, int g, int b, int a) {
diff --git a/content/browser/devtools/protocol/page_handler.h b/content/browser/devtools/protocol/page_handler.h
index fdb1ac5..5ebaa0c 100644
--- a/content/browser/devtools/protocol/page_handler.h
+++ b/content/browser/devtools/protocol/page_handler.h
@@ -20,6 +20,10 @@
 
 class SkBitmap;
 
+namespace gfx {
+class Image;
+}  // namespace gfx
+
 namespace content {
 
 class DevToolsSession;
@@ -65,6 +69,8 @@
   Response NavigateToHistoryEntry(int entry_id) override;
 
   void CaptureScreenshot(
+      Maybe<std::string> format,
+      Maybe<int> quality,
       std::unique_ptr<CaptureScreenshotCallback> callback) override;
   Response StartScreencast(Maybe<std::string> format,
                            Maybe<int> quality,
@@ -91,6 +97,8 @@
   void NavigationRequested(const PageNavigationThrottle* throttle);
 
  private:
+  enum EncodingFormat { PNG, JPEG };
+
   WebContentsImpl* GetWebContents();
   void NotifyScreencastVisibility(bool visible);
   void InnerSwapCompositorFrame();
@@ -101,10 +109,10 @@
                               const base::Time& timestamp,
                               const std::string& data);
 
-  void ScreenshotCaptured(
-      std::unique_ptr<CaptureScreenshotCallback> callback,
-      const unsigned char* png_data,
-      size_t png_size);
+  void ScreenshotCaptured(std::unique_ptr<CaptureScreenshotCallback> callback,
+                          const std::string& format,
+                          int quality,
+                          const gfx::Image& image);
 
   void OnColorPicked(int r, int g, int b, int a);
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 38be9707..c282dd9 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -87,6 +87,7 @@
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
+#include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/skbitmap_operations.h"
 #include "ui/snapshot/snapshot.h"
@@ -453,10 +454,6 @@
   waiting_for_screen_rects_ack_ = true;
 }
 
-void RenderWidgetHostImpl::SuppressEventsUntilKeyDown() {
-  suppress_events_until_keydown_ = true;
-}
-
 void RenderWidgetHostImpl::FlushInput() {
   input_router_->RequestNotificationWhenFlushed();
   if (synthetic_gesture_controller_)
@@ -2374,35 +2371,31 @@
   gfx::Rect snapshot_bounds(GetView()->GetViewBounds().size());
 #endif
 
-  std::vector<unsigned char> png;
-  if (ui::GrabViewSnapshot(
-      GetView()->GetNativeView(), &png, snapshot_bounds)) {
-    OnSnapshotDataReceived(snapshot_id, &png.front(), png.size());
+  gfx::Image image;
+  if (ui::GrabViewSnapshot(GetView()->GetNativeView(), snapshot_bounds,
+                           &image)) {
+    OnSnapshotReceived(snapshot_id, image);
     return;
   }
 
   ui::GrabViewSnapshotAsync(
-      GetView()->GetNativeView(),
-      snapshot_bounds,
-      base::ThreadTaskRunnerHandle::Get(),
-      base::Bind(&RenderWidgetHostImpl::OnSnapshotDataReceivedAsync,
-                 weak_factory_.GetWeakPtr(),
-                 snapshot_id));
+      GetView()->GetNativeView(), snapshot_bounds,
+      base::Bind(&RenderWidgetHostImpl::OnSnapshotReceived,
+                 weak_factory_.GetWeakPtr(), snapshot_id));
 }
 
-void RenderWidgetHostImpl::OnSnapshotDataReceived(int snapshot_id,
-                                                  const unsigned char* data,
-                                                  size_t size) {
+void RenderWidgetHostImpl::OnSnapshotReceived(int snapshot_id,
+                                              const gfx::Image& image) {
   // Any pending snapshots with a lower ID than the one received are considered
   // to be implicitly complete, and returned the same snapshot data.
   PendingSnapshotMap::iterator it = pending_browser_snapshots_.begin();
   while (it != pending_browser_snapshots_.end()) {
-      if (it->first <= snapshot_id) {
-        it->second.Run(data, size);
-        pending_browser_snapshots_.erase(it++);
-      } else {
-        ++it;
-      }
+    if (it->first <= snapshot_id) {
+      it->second.Run(image);
+      pending_browser_snapshots_.erase(it++);
+    } else {
+      ++it;
+    }
   }
 #if defined(OS_MACOSX)
   if (pending_browser_snapshots_.empty())
@@ -2410,15 +2403,6 @@
 #endif
 }
 
-void RenderWidgetHostImpl::OnSnapshotDataReceivedAsync(
-    int snapshot_id,
-    scoped_refptr<base::RefCountedBytes> png_data) {
-  if (png_data.get())
-    OnSnapshotDataReceived(snapshot_id, png_data->front(), png_data->size());
-  else
-    OnSnapshotDataReceived(snapshot_id, NULL, 0);
-}
-
 // static
 void RenderWidgetHostImpl::CompositorFrameDrawn(
     const std::vector<ui::LatencyInfo>& latency_info) {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 60cca7c..d2277a7 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -53,10 +53,6 @@
 struct ViewHostMsg_SelectionBounds_Params;
 struct ViewHostMsg_UpdateRect_Params;
 
-namespace base {
-class RefCountedBytes;
-}
-
 namespace blink {
 class WebInputEvent;
 class WebMouseEvent;
@@ -70,6 +66,7 @@
 #endif
 
 namespace gfx {
+class Image;
 class Range;
 }
 
@@ -208,9 +205,12 @@
   void NotifyScreenInfoChanged();
 
   // Forces redraw in the renderer and when the update reaches the browser
-  // grabs snapshot from the compositor. Returns PNG-encoded snapshot.
+  // grabs snapshot from the compositor. On MacOS, the snapshot is taken from
+  // the Cocoa view for end-to-end testing purposes. Returns a gfx::Image that
+  // is backed by an NSImage on MacOS or by an SkBitmap otherwise. The
+  // gfx::Image may be empty if the snapshot failed.
   using GetSnapshotFromBrowserCallback =
-      base::Callback<void(const unsigned char*, size_t)>;
+      base::Callback<void(const gfx::Image&)>;
   void GetSnapshotFromBrowser(const GetSnapshotFromBrowserCallback& callback);
 
   const NativeWebKeyboardEvent* GetLastKeyboardEvent() const;
@@ -478,10 +478,6 @@
   // Update the renderer's cache of the screen rect of the view and window.
   void SendScreenRects();
 
-  // Suppresses Char and KeyUp events until the next (Raw)KeyDown. See
-  // suppress_events_until_keydown_.
-  void SuppressEventsUntilKeyDown();
-
   // Called by the view in response to a flush request.
   void FlushInput();
 
@@ -701,13 +697,7 @@
 
   void WindowSnapshotReachedScreen(int snapshot_id);
 
-  void OnSnapshotDataReceived(int snapshot_id,
-                              const unsigned char* png,
-                              size_t size);
-
-  void OnSnapshotDataReceivedAsync(
-      int snapshot_id,
-      scoped_refptr<base::RefCountedBytes> png_data);
+  void OnSnapshotReceived(int snapshot_id, const gfx::Image& image);
 
   // 1. Grants permissions to URL (if any)
   // 2. Grants permissions to filenames
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 7a595d8..5e0d302 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1754,10 +1754,6 @@
       // Ask the system-wide IME to send all TextInputClient messages to |this|
       // object.
       input_method->SetFocusedTextInputClient(this);
-
-      // Often the application can set focus to the view in response to a key
-      // down. However, the following events shouldn't be sent to the web page.
-      host_->SuppressEventsUntilKeyDown();
     }
 
     BrowserAccessibilityManager* manager =
diff --git a/docs/mac_build_instructions.md b/docs/mac_build_instructions.md
index 5acb6c9f..646b64b 100644
--- a/docs/mac_build_instructions.md
+++ b/docs/mac_build_instructions.md
@@ -12,7 +12,7 @@
 
 ## System requirements
 
-*   A 64-bit Mac running 10.9+.
+*   A 64-bit Mac running 10.11+.
 *   [Xcode](https://developer.apple.com/xcode) 7.3+.
 *   The OS X 10.10 SDK. Run
 
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 24cf957e..2117ba50 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -16518,4 +16518,80 @@
 }
 #endif  // !defined(OS_IOS)
 
+// Test a SPDY CONNECT through an HTTPS Proxy to plaintext WebSocket Server.
+TEST_F(HttpNetworkTransactionTest, PlaintextWebsocketOverSpdyProxy) {
+  HttpRequestInfo request;
+  request.method = "GET";
+  request.url = GURL("ws://www.example.org/");
+  AddWebSocketHeaders(&request.extra_headers);
+
+  // Configure against https proxy server "proxy:70".
+  session_deps_.proxy_service = ProxyService::CreateFixed("https://proxy:70");
+  BoundTestNetLog log;
+  session_deps_.net_log = log.bound().net_log();
+  std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+  HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
+  FakeWebSocketStreamCreateHelper websocket_stream_create_helper;
+  trans.SetWebSocketHandshakeStreamCreateHelper(
+      &websocket_stream_create_helper);
+
+  // CONNECT to www.example.org:443 via SPDY
+  SpdySerializedFrame connect(spdy_util_.ConstructSpdyConnect(
+      nullptr, 0, 1, LOWEST, HostPortPair("www.example.org", 80)));
+  const char req[] =
+      "GET / HTTP/1.1\r\n"
+      "Host: www.example.org\r\n"
+      "Connection: Upgrade\r\n"
+      "Upgrade: websocket\r\n"
+      "Origin: http://www.example.org\r\n"
+      "Sec-WebSocket-Version: 13\r\n"
+      "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n";
+  SpdySerializedFrame wrapped_ws_req(
+      spdy_util_.ConstructSpdyDataFrame(1, req, strlen(req), false));
+  SpdySerializedFrame conn_resp(
+      spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+  const char resp[] =
+      "HTTP/1.1 101 Switching Protocols\r\n"
+      "Upgrade: websocket\r\n"
+      "Connection: Upgrade\r\n"
+      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n";
+  SpdySerializedFrame wrapped_ws_resp(
+      spdy_util_.ConstructSpdyDataFrame(1, resp, strlen(resp), false));
+  SpdySerializedFrame window_update(
+      spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_ws_resp.size()));
+
+  MockWrite spdy_writes[] = {
+      CreateMockWrite(connect, 0), CreateMockWrite(wrapped_ws_req, 2),
+      CreateMockWrite(window_update, 4),
+  };
+
+  MockRead spdy_reads[] = {
+      CreateMockRead(conn_resp, 1, ASYNC),
+      CreateMockRead(wrapped_ws_resp, 3, ASYNC), MockRead(ASYNC, 0, 5),
+  };
+
+  SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
+                                arraysize(spdy_writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
+
+  SSLSocketDataProvider ssl(ASYNC, OK);
+  ssl.next_proto = kProtoHTTP2;
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+
+  TestCompletionCallback callback;
+
+  int rv = trans.Start(&request, callback.callback(), log.bound());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  rv = callback.WaitForResult();
+  ASSERT_THAT(rv, IsOk());
+
+  const HttpResponseInfo* response = trans.GetResponseInfo();
+  ASSERT_TRUE(response);
+  ASSERT_TRUE(response->headers);
+  EXPECT_EQ("HTTP/1.1 101 Switching Protocols",
+            response->headers->GetStatusLine());
+}
+
 }  // namespace net
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 262741a..c8831644 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -1191,8 +1191,16 @@
   if (connection_->socket() && !connection_->is_reused())
     SetSocketMotivation();
 
-  if (!using_spdy_) {
+  if (!using_spdy_)
     DCHECK(!IsSpdyAlternative());
+
+  // While websockets over HTTP/2 are not supported, it is still valid to have
+  // websockets tunneled through HTTP/2 proxy (via CONNECT). If websockets are
+  // secure (wss://), ProxyClientSocket with established tunnel is wrapped with
+  // yet another socket (SSLClientSocket), and |using_spdy_| will be false, but
+  // for ws: scheme, ProxyClientSocket is not wrapped into anything.
+  if (!using_spdy_ ||
+      (using_spdy_ && proxy_info_.is_https() && delegate_->for_websockets())) {
     // We may get ftp scheme when fetching ftp resources through proxy.
     bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) &&
                        (request_info_.url.SchemeIs(url::kHttpScheme) ||
diff --git a/net/http2/decoder/frame_parts.cc b/net/http2/decoder/frame_parts.cc
index 33cd7bf..a2b99ba 100644
--- a/net/http2/decoder/frame_parts.cc
+++ b/net/http2/decoder/frame_parts.cc
@@ -205,7 +205,7 @@
   ASSERT_FALSE(opt_pad_length);
   ASSERT_TRUE(opt_payload_length);
   size_t total_padding_length = trailing_length + 1;
-  ASSERT_GE(opt_payload_length.value(), static_cast<int>(total_padding_length));
+  ASSERT_GE(opt_payload_length.value(), total_padding_length);
   opt_payload_length = opt_payload_length.value() - total_padding_length;
   opt_pad_length = trailing_length;
 }
@@ -265,8 +265,7 @@
   ASSERT_FALSE(opt_push_promise);
   opt_push_promise = promise;
   if (total_padding_length > 0) {
-    ASSERT_GE(opt_payload_length.value(),
-              static_cast<int>(total_padding_length));
+    ASSERT_GE(opt_payload_length.value(), total_padding_length);
     OnPadLength(total_padding_length - 1);
   } else {
     ASSERT_FALSE(header.IsPadded());
@@ -507,7 +506,7 @@
 
 AssertionResult FrameParts::AppendString(StringPiece source,
                                          string* target,
-                                         base::Optional<int>* opt_length) {
+                                         base::Optional<size_t>* opt_length) {
   source.AppendToString(target);
   if (opt_length != nullptr) {
     VERIFY_TRUE(*opt_length) << "Length is not set yet\n" << *this;
diff --git a/net/http2/decoder/frame_parts.h b/net/http2/decoder/frame_parts.h
index c64dea69..b1551728 100644
--- a/net/http2/decoder/frame_parts.h
+++ b/net/http2/decoder/frame_parts.h
@@ -127,11 +127,11 @@
   base::Optional<Http2PingFields> opt_ping;
   base::Optional<Http2GoAwayFields> opt_goaway;
 
-  base::Optional<int> opt_pad_length;
-  base::Optional<int> opt_payload_length;
-  base::Optional<int> opt_missing_length;
-  base::Optional<int> opt_altsvc_origin_length;
-  base::Optional<int> opt_altsvc_value_length;
+  base::Optional<size_t> opt_pad_length;
+  base::Optional<size_t> opt_payload_length;
+  base::Optional<size_t> opt_missing_length;
+  base::Optional<size_t> opt_altsvc_origin_length;
+  base::Optional<size_t> opt_altsvc_value_length;
 
   base::Optional<size_t> opt_window_update_increment;
 
@@ -167,7 +167,7 @@
   // called), and that target is not longer than opt_length->value().
   ::testing::AssertionResult AppendString(base::StringPiece source,
                                           std::string* target,
-                                          base::Optional<int>* opt_length);
+                                          base::Optional<size_t>* opt_length);
 };
 
 }  // namespace test
diff --git a/net/http2/decoder/http2_structure_decoder_test.cc b/net/http2/decoder/http2_structure_decoder_test.cc
index 3ff2f98..91140f9 100644
--- a/net/http2/decoder/http2_structure_decoder_test.cc
+++ b/net/http2/decoder/http2_structure_decoder_test.cc
@@ -44,14 +44,6 @@
 const bool kMayReturnZeroOnFirst = false;
 
 template <class S>
-string SerializeStructure(const S& s) {
-  Http2FrameBuilder fb;
-  fb.Append(s);
-  EXPECT_EQ(S::EncodedSize(), fb.size());
-  return fb.buffer();
-}
-
-template <class S>
 class Http2StructureDecoderTest : public RandomDecoderTest {
  protected:
   typedef S Structure;
diff --git a/net/http2/decoder/payload_decoders/payload_decoder_base_test_util.h b/net/http2/decoder/payload_decoders/payload_decoder_base_test_util.h
index 5f998e4..8eb244b60 100644
--- a/net/http2/decoder/payload_decoders/payload_decoder_base_test_util.h
+++ b/net/http2/decoder/payload_decoders/payload_decoder_base_test_util.h
@@ -395,7 +395,7 @@
   ::testing::AssertionResult VerifyDetectsPaddingTooLong(
       base::StringPiece payload,
       const Http2FrameHeader& header,
-      int expected_missing_length) {
+      size_t expected_missing_length) {
     set_frame_header(header);
     auto& listener = listener_;
     Validator validator = [header, expected_missing_length, &listener](
@@ -441,7 +441,8 @@
     // The missing length is the amount we cut off the end, unless
     // payload_length is zero, in which case the decoder knows only that 1
     // byte, the Pad Length field, is missing.
-    int missing_length = payload_length == 0 ? 1 : fb.size() - payload_length;
+    size_t missing_length =
+        payload_length == 0 ? 1 : fb.size() - payload_length;
     VLOG(1) << "missing_length=" << missing_length;
 
     const Http2FrameHeader header(payload_length, DecoderPeer::FrameType(),
diff --git a/net/http2/hpack/decoder/http2_hpack_decoder.h b/net/http2/hpack/decoder/http2_hpack_decoder.h
index 6d4b8d4..fff1320 100644
--- a/net/http2/hpack/decoder/http2_hpack_decoder.h
+++ b/net/http2/hpack/decoder/http2_hpack_decoder.h
@@ -29,6 +29,7 @@
 #include "net/http2/hpack/decoder/hpack_block_decoder.h"
 #include "net/http2/hpack/decoder/hpack_decoder_listener.h"
 #include "net/http2/hpack/decoder/hpack_decoder_state.h"
+#include "net/http2/hpack/decoder/hpack_decoder_tables.h"
 #include "net/http2/hpack/decoder/hpack_whole_entry_buffer.h"
 
 namespace net {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index da17baa..5cd3f21 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -3131,6 +3131,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "snapshot_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "sql_unittests"
       },
       {
@@ -3725,6 +3731,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "snapshot_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "sql_unittests"
       },
       {
@@ -4116,6 +4128,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "snapshot_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "sql_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 7213398..710920b 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -13,6 +13,7 @@
       "pdf_unittests",
       "printing_unittests",
       "skia_unittests",
+      "snapshot_unittests",
       "sql_unittests",
       "storage_unittests",
       "ui_base_unittests",
@@ -302,6 +303,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "snapshot_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "sql_unittests"
       },
       {
@@ -653,6 +660,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "snapshot_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "sql_unittests"
       },
       {
@@ -1005,6 +1018,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "snapshot_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "sql_unittests"
       },
       {
@@ -1345,6 +1364,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "snapshot_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "sql_unittests"
       },
       {
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 03a3d3b..a70eec7 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -762,6 +762,10 @@
     "label": "//skia:skia_unittests",
     "type": "console_test_launcher",
   },
+  "snapshot_unittests": {
+    "label": "//ui/snapshot:snapshot_unittests",
+    "type": "windowed_test_launcher",
+  },
   "sql_unittests": {
     "label": "//sql:sql_unittests",
     "type": "console_test_launcher",
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
index 0be35fe9..feab190f 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
@@ -5,14 +5,6 @@
 crbug.com/608372 http/tests/history/back-to-post.html [ Timeout ]
 crbug.com/608372 virtual/mojo-loading/http/tests/history/back-to-post.html [ Timeout ]
 
-# Ensure POST navigations are treated as different document
-# Fixed by https://codereview.chromium.org/2630413002/
-crbug.com/608372 fast/forms/submit-to-url-fragment.html [ Failure ]
-crbug.com/608372 fast/forms/xss-auditor-doesnt-crash-on-post-submit.html [ Timeout ]
-crbug.com/575210 http/tests/navigation/history-back-across-form-submission-to-fragment.html [ Timeout ]
-crbug.com/575210 virtual/stable/http/tests/navigation/history-back-across-form-submission-to-fragment.html [ Timeout ]
-crbug.com/575210 virtual/mojo-loading/http/tests/navigation/history-back-across-form-submission-to-fragment.html [ Timeout ]
-
 # Ensure same-page back-forward are handled as same-page navigations
 # Fixed by https://codereview.chromium.org/2584513003/
 crbug.com/575210 fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html [ Crash Timeout ]
@@ -20,17 +12,6 @@
 crbug.com/575210 external/wpt/html/browsers/history/the-history-interface/004.html [ Failure ]
 crbug.com/575210 external/wpt/html/browsers/history/the-location-interface/security_location_0.htm [ Failure ]
 
-# Issue with m_progressTracker->progressCompleted when navigation fails
-# Fixed by https://codereview.chromium.org/2624723002/
-crbug.com/679675 fast/css/acid2-pixel.html [ Timeout ]
-crbug.com/679675 fast/css/acid2.html [ Timeout ]
-crbug.com/679675 fast/dom/HTMLObjectElement/children-changed.html [ Timeout ]
-crbug.com/679675 fast/overflow/overflow-height-float-not-removed-crash.html [ Timeout ]
-crbug.com/679675 fast/overflow/overflow-height-float-not-removed-crash2.html [ Timeout ]
-crbug.com/679675 fast/overflow/overflow-height-float-not-removed-crash3.html [ Timeout ]
-crbug.com/679675 fast/table/giantCellspacing.html [ Timeout ]
-crbug.com/679675 virtual/spv2/fast/overflow/overflow-height-float-not-removed-crash3.html [ Timeout ]
-
 # https://crbug.com/683891: Execute BeforeUnload on subframes during browser-initiated navigations
 crbug.com/683891 external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-on-navigation-of-parent.html [ Failure ]
 
diff --git a/third_party/WebKit/LayoutTests/fast/css/null-ruleset-non-matching-media-crash.html b/third_party/WebKit/LayoutTests/fast/css/null-ruleset-non-matching-media-crash.html
new file mode 100644
index 0000000..e5663fe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/null-ruleset-non-matching-media-crash.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<style>#t1 { color: red }</style>
+<div id="t1">Should be green.</div>
+<script>
+    test(() => {
+        // Triggers synch active stylesheet update.
+        var sheet = document.styleSheets[0];
+        // Clears the previous RuleSet for rebuild.
+        sheet.insertRule("#dummy {}", 0);
+        // No Ruleset recreated since media does not match.
+        sheet.media.mediaText = "nomatch";
+        var newStyle = document.createElement("style");
+        newStyle.appendChild(document.createTextNode("div { color: green }"));
+        // New sheet triggers active stylesheet update and style recalc for #t1.
+        document.head.appendChild(newStyle);
+    }, "Check that appending a stylesheet while clearing the RuleSet of an existing sheet does not crash");
+
+    test(() => assert_equals(getComputedStyle(t1).color, "rgb(0, 128, 0)"),
+        "Check that the #t1 rule no longer applies.");
+</script>
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.cpp
index 80d5eb2..0b874b7 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.cpp
@@ -223,9 +223,6 @@
 void ScriptWrappableVisitor::writeBarrier(
     const void* srcObject,
     const TraceWrapperV8Reference<v8::Value>* dstObject) {
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-    return;
-  }
   if (!srcObject || !dstObject || dstObject->isEmpty()) {
     return;
   }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h
index 2b96684..8d81478 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h
@@ -108,9 +108,6 @@
   static void writeBarrier(const void* srcObject, const T* dstObject) {
     static_assert(!NeedsAdjustAndMark<T>::value,
                   "wrapper tracing is not supported within mixins");
-    if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-      return;
-    }
     if (!srcObject || !dstObject) {
       return;
     }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp
index b877724..bd78c6c6 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp
@@ -37,9 +37,6 @@
 
 TEST(ScriptWrappableVisitorTest, ScriptWrappableVisitorTracesWrappers) {
   V8TestingScope scope;
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-    return;
-  }
   ScriptWrappableVisitor* visitor =
       V8PerIsolateData::from(scope.isolate())->scriptWrappableVisitor();
   visitor->TracePrologue();
@@ -74,9 +71,6 @@
 
 TEST(ScriptWrappableVisitorTest, OilpanCollectObjectsNotReachableFromV8) {
   V8TestingScope scope;
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-    return;
-  }
   v8::Isolate* isolate = scope.isolate();
 
   {
@@ -97,9 +91,6 @@
 
 TEST(ScriptWrappableVisitorTest, OilpanDoesntCollectObjectsReachableFromV8) {
   V8TestingScope scope;
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-    return;
-  }
   v8::Isolate* isolate = scope.isolate();
   v8::HandleScope handleScope(isolate);
   DeathAwareScriptWrappable* object = DeathAwareScriptWrappable::create();
@@ -117,9 +108,6 @@
 
 TEST(ScriptWrappableVisitorTest, V8ReportsLiveObjectsDuringScavenger) {
   V8TestingScope scope;
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-    return;
-  }
   v8::Isolate* isolate = scope.isolate();
   v8::HandleScope handleScope(isolate);
   DeathAwareScriptWrappable* object = DeathAwareScriptWrappable::create();
@@ -143,9 +131,6 @@
 
 TEST(ScriptWrappableVisitorTest, V8ReportsLiveObjectsDuringFullGc) {
   V8TestingScope scope;
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-    return;
-  }
   v8::Isolate* isolate = scope.isolate();
   v8::HandleScope handleScope(isolate);
   DeathAwareScriptWrappable* object = DeathAwareScriptWrappable::create();
@@ -162,9 +147,6 @@
 
 TEST(ScriptWrappableVisitorTest, OilpanClearsHeadersWhenObjectDied) {
   V8TestingScope scope;
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-    return;
-  }
 
   DeathAwareScriptWrappable* object = DeathAwareScriptWrappable::create();
   ScriptWrappableVisitor* visitor =
@@ -181,9 +163,6 @@
 
 TEST(ScriptWrappableVisitorTest, OilpanClearsMarkingDequeWhenObjectDied) {
   V8TestingScope scope;
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-    return;
-  }
 
   DeathAwareScriptWrappable* object = DeathAwareScriptWrappable::create();
   ScriptWrappableVisitor* visitor =
@@ -203,9 +182,6 @@
 
 TEST(ScriptWrappableVisitorTest, NonMarkedObjectDoesNothingOnWriteBarrierHit) {
   V8TestingScope scope;
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-    return;
-  }
 
   ScriptWrappableVisitor* visitor =
       V8PerIsolateData::from(scope.isolate())->scriptWrappableVisitor();
@@ -225,9 +201,6 @@
 TEST(ScriptWrappableVisitorTest,
      MarkedObjectDoesNothingOnWriteBarrierHitWhenDependencyIsMarkedToo) {
   V8TestingScope scope;
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-    return;
-  }
 
   ScriptWrappableVisitor* visitor =
       V8PerIsolateData::from(scope.isolate())->scriptWrappableVisitor();
@@ -258,9 +231,6 @@
 TEST(ScriptWrappableVisitorTest,
      MarkedObjectMarksDependencyOnWriteBarrierHitWhenNotMarked) {
   V8TestingScope scope;
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-    return;
-  }
 
   ScriptWrappableVisitor* visitor =
       V8PerIsolateData::from(scope.isolate())->scriptWrappableVisitor();
@@ -342,8 +312,6 @@
 }  // namespace
 
 TEST(ScriptWrappableVisitorTest, NoWriteBarrierOnUnmarkedContainer) {
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled())
-    return;
   V8TestingScope scope;
   auto rawVisitor = new InterceptingScriptWrappableVisitor(scope.isolate());
   swapInNewVisitor(scope.isolate(), rawVisitor);
@@ -364,8 +332,6 @@
 }
 
 TEST(ScriptWrappableVisitorTest, WriteBarrierTriggersOnMarkedContainer) {
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled())
-    return;
   V8TestingScope scope;
   auto rawVisitor = new InterceptingScriptWrappableVisitor(scope.isolate());
   swapInNewVisitor(scope.isolate(), rawVisitor);
diff --git a/third_party/WebKit/Source/bindings/core/v8/ToV8.h b/third_party/WebKit/Source/bindings/core/v8/ToV8.h
index 2495d769..3e1503a6 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ToV8.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ToV8.h
@@ -216,29 +216,13 @@
 
 // Array
 
+// Declare the function here but define it later so it can call the ToV8()
+// overloads below.
 template <typename Sequence>
 inline v8::Local<v8::Value> toV8SequenceInternal(
     const Sequence& sequence,
     v8::Local<v8::Object> creationContext,
-    v8::Isolate* isolate) {
-  v8::Local<v8::Array> array;
-  {
-    v8::Context::Scope contextScope(creationContext->CreationContext());
-    array = v8::Array::New(isolate, sequence.size());
-  }
-  uint32_t index = 0;
-  typename Sequence::const_iterator end = sequence.end();
-  for (typename Sequence::const_iterator iter = sequence.begin(); iter != end;
-       ++iter) {
-    v8::Local<v8::Value> value = ToV8(*iter, array, isolate);
-    if (value.IsEmpty())
-      value = v8::Undefined(isolate);
-    if (!v8CallBoolean(array->CreateDataProperty(isolate->GetCurrentContext(),
-                                                 index++, value)))
-      return v8::Local<v8::Value>();
-  }
-  return array;
-}
+    v8::Isolate*);
 
 template <typename T, size_t inlineCapacity>
 inline v8::Local<v8::Value> ToV8(const Vector<T, inlineCapacity>& value,
@@ -275,6 +259,30 @@
   return object;
 }
 
+template <typename Sequence>
+inline v8::Local<v8::Value> toV8SequenceInternal(
+    const Sequence& sequence,
+    v8::Local<v8::Object> creationContext,
+    v8::Isolate* isolate) {
+  v8::Local<v8::Array> array;
+  {
+    v8::Context::Scope contextScope(creationContext->CreationContext());
+    array = v8::Array::New(isolate, sequence.size());
+  }
+  uint32_t index = 0;
+  typename Sequence::const_iterator end = sequence.end();
+  for (typename Sequence::const_iterator iter = sequence.begin(); iter != end;
+       ++iter) {
+    v8::Local<v8::Value> value = ToV8(*iter, array, isolate);
+    if (value.IsEmpty())
+      value = v8::Undefined(isolate);
+    if (!v8CallBoolean(array->CreateDataProperty(isolate->GetCurrentContext(),
+                                                 index++, value)))
+      return v8::Local<v8::Value>();
+  }
+  return array;
+}
+
 // In all cases allow script state instead of creation context + isolate.
 // Use this function only if the call site does not otherwise need the global,
 // since v8::Context::Global is heavy.
diff --git a/third_party/WebKit/Source/bindings/core/v8/ToV8Test.cpp b/third_party/WebKit/Source/bindings/core/v8/ToV8Test.cpp
index f3ce57e..b539ccf7 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ToV8Test.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ToV8Test.cpp
@@ -223,6 +223,35 @@
   EXPECT_EQ(2, two->NumberValue(context).FromJust());
 }
 
+TEST(ToV8Test, stringVectorVector) {
+  V8TestingScope scope;
+
+  Vector<String> stringVector1;
+  stringVector1.push_back("foo");
+  stringVector1.push_back("bar");
+  Vector<String> stringVector2;
+  stringVector2.push_back("quux");
+
+  Vector<Vector<String>> compoundVector;
+  compoundVector.push_back(stringVector1);
+  compoundVector.push_back(stringVector2);
+
+  EXPECT_EQ(2U, compoundVector.size());
+  TEST_TOV8("foo,bar,quux", compoundVector);
+
+  v8::Local<v8::Context> context = scope.getScriptState()->context();
+  v8::Local<v8::Object> result =
+      ToV8(compoundVector, context->Global(), scope.isolate())
+          ->ToObject(context)
+          .ToLocalChecked();
+  v8::Local<v8::Value> vector1 = result->Get(context, 0).ToLocalChecked();
+  EXPECT_TRUE(vector1->IsArray());
+  EXPECT_EQ(2U, vector1.As<v8::Array>()->Length());
+  v8::Local<v8::Value> vector2 = result->Get(context, 1).ToLocalChecked();
+  EXPECT_TRUE(vector2->IsArray());
+  EXPECT_EQ(1U, vector2.As<v8::Array>()->Length());
+}
+
 TEST(ToV8Test, heapVector) {
   V8TestingScope scope;
   HeapVector<Member<GarbageCollectedScriptWrappable>> v;
diff --git a/third_party/WebKit/Source/bindings/core/v8/TraceWrapperV8Reference.h b/third_party/WebKit/Source/bindings/core/v8/TraceWrapperV8Reference.h
index 9ba5a94d..2682234 100644
--- a/third_party/WebKit/Source/bindings/core/v8/TraceWrapperV8Reference.h
+++ b/third_party/WebKit/Source/bindings/core/v8/TraceWrapperV8Reference.h
@@ -56,7 +56,6 @@
 
   void setReference(const v8::Persistent<v8::Object>& parent,
                     v8::Isolate* isolate) {
-    DCHECK(!RuntimeEnabledFeatures::traceWrappablesEnabled());
     isolate->SetReference(parent, m_handle);
   }
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8DOMWrapper.h b/third_party/WebKit/Source/bindings/core/v8/V8DOMWrapper.h
index d026264..2d4af91 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8DOMWrapper.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8DOMWrapper.h
@@ -94,16 +94,13 @@
                     const_cast<WrapperTypeInfo*>(wrapperTypeInfo)};
   wrapper->SetAlignedPointerInInternalFields(WTF_ARRAY_LENGTH(indices), indices,
                                              values);
-  if (RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-    auto perIsolateData = V8PerIsolateData::from(isolate);
-    // We notify ScriptWrappableVisitor about the new wrapper association,
-    // so the visitor can make sure to trace the association (in case it is
-    // currently tracing).  Because of some optimizations, V8 will not
-    // necessarily detect wrappers created during its incremental marking.
-    perIsolateData->scriptWrappableVisitor()->RegisterV8Reference(
-        std::make_pair(const_cast<WrapperTypeInfo*>(wrapperTypeInfo),
-                       scriptWrappable));
-  }
+  auto perIsolateData = V8PerIsolateData::from(isolate);
+  // We notify ScriptWrappableVisitor about the new wrapper association,
+  // so the visitor can make sure to trace the association (in case it is
+  // currently tracing).  Because of some optimizations, V8 will not
+  // necessarily detect wrappers created during its incremental marking.
+  perIsolateData->scriptWrappableVisitor()->RegisterV8Reference(std::make_pair(
+      const_cast<WrapperTypeInfo*>(wrapperTypeInfo), scriptWrappable));
 }
 
 inline void V8DOMWrapper::clearNativeInfo(v8::Isolate* isolate,
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
index b740aec..ad0f11b1 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
@@ -56,28 +56,6 @@
 
 namespace blink {
 
-// FIXME: This should use opaque GC roots.
-static void addReferencesForNodeWithEventListeners(
-    v8::Isolate* isolate,
-    Node* node,
-    const v8::Persistent<v8::Object>& wrapper) {
-  ASSERT(node->hasEventListeners());
-
-  EventListenerIterator iterator(node);
-  while (EventListener* listener = iterator.nextListener()) {
-    if (listener->type() != EventListener::JSEventListenerType)
-      continue;
-    V8AbstractEventListener* v8listener =
-        static_cast<V8AbstractEventListener*>(listener);
-    if (!v8listener->hasExistingListenerObject())
-      continue;
-
-    isolate->SetReference(
-        wrapper, v8::Persistent<v8::Value>::Cast(
-                     v8listener->existingListenerObjectPersistentHandle()));
-  }
-}
-
 Node* V8GCController::opaqueRootForGC(v8::Isolate*, Node* node) {
   ASSERT(node);
   if (node->isConnected()) {
@@ -292,116 +270,6 @@
   return v8::HeapProfiler::RetainerInfos{tracer->groups(), tracer->edges()};
 }
 
-class MajorGCWrapperVisitor : public v8::PersistentHandleVisitor {
- public:
-  explicit MajorGCWrapperVisitor(v8::Isolate* isolate,
-                                 bool constructRetainedObjectInfos)
-      : m_isolate(isolate),
-        m_domObjectsWithPendingActivity(0),
-        m_liveRootGroupIdSet(false),
-        m_constructRetainedObjectInfos(constructRetainedObjectInfos) {}
-
-  void VisitPersistentHandle(v8::Persistent<v8::Value>* value,
-                             uint16_t classId) override {
-    if (classId != WrapperTypeInfo::NodeClassId &&
-        classId != WrapperTypeInfo::ObjectClassId)
-      return;
-
-    if (value->IsIndependent())
-      return;
-
-    v8::Local<v8::Object> wrapper = v8::Local<v8::Object>::New(
-        m_isolate, v8::Persistent<v8::Object>::Cast(*value));
-    DCHECK(V8DOMWrapper::hasInternalFieldsSet(wrapper));
-
-    const WrapperTypeInfo* type = toWrapperTypeInfo(wrapper);
-    if (type->isActiveScriptWrappable() &&
-        toScriptWrappable(wrapper)->hasPendingActivity()) {
-      // Enable hasPendingActivity only when the associated
-      // ExecutionContext is not yet detached. This is a work-around
-      // to avoid memory leaks caused by hasPendingActivity that keeps
-      // returning true forever. This will be okay in practice because
-      // the spec requires to stop almost all DOM activities when the
-      // associated browsing context is detached. However, the real
-      // problem is that some hasPendingActivity's are wrongly implemented
-      // and never return false.
-      // TODO(haraken): Implement correct lifetime using traceWrapper.
-      ExecutionContext* context =
-          toExecutionContext(wrapper->CreationContext());
-      if (context && !context->isContextDestroyed()) {
-        m_isolate->SetObjectGroupId(*value, liveRootId());
-        ++m_domObjectsWithPendingActivity;
-      }
-    }
-
-    if (classId == WrapperTypeInfo::NodeClassId) {
-      DCHECK(V8Node::hasInstance(wrapper, m_isolate));
-      Node* node = V8Node::toImpl(wrapper);
-      if (node->hasEventListeners())
-        addReferencesForNodeWithEventListeners(
-            m_isolate, node, v8::Persistent<v8::Object>::Cast(*value));
-      Node* root = V8GCController::opaqueRootForGC(m_isolate, node);
-      m_isolate->SetObjectGroupId(
-          *value, v8::UniqueId(reinterpret_cast<intptr_t>(root)));
-      if (m_constructRetainedObjectInfos)
-        m_groupsWhichNeedRetainerInfo.push_back(root);
-    } else if (classId == WrapperTypeInfo::ObjectClassId) {
-      if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-        type->visitDOMWrapper(m_isolate, toScriptWrappable(wrapper),
-                              v8::Persistent<v8::Object>::Cast(*value));
-      }
-    } else {
-      NOTREACHED();
-    }
-  }
-
-  void notifyFinished() {
-    if (!m_constructRetainedObjectInfos)
-      return;
-    std::sort(m_groupsWhichNeedRetainerInfo.begin(),
-              m_groupsWhichNeedRetainerInfo.end());
-    Node* alreadyAdded = 0;
-    v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler();
-    for (size_t i = 0; i < m_groupsWhichNeedRetainerInfo.size(); ++i) {
-      Node* root = m_groupsWhichNeedRetainerInfo[i];
-      if (root != alreadyAdded) {
-        profiler->SetRetainedObjectInfo(
-            v8::UniqueId(reinterpret_cast<intptr_t>(root)),
-            new RetainedDOMInfo(root));
-        alreadyAdded = root;
-      }
-    }
-    if (m_liveRootGroupIdSet) {
-      profiler->SetRetainedObjectInfo(
-          liveRootId(),
-          new SuspendableObjectsInfo(m_domObjectsWithPendingActivity));
-    }
-  }
-
- private:
-  v8::UniqueId liveRootId() {
-    const v8::Persistent<v8::Value>& liveRoot =
-        V8PerIsolateData::from(m_isolate)->ensureLiveRoot();
-    const intptr_t* idPointer = reinterpret_cast<const intptr_t*>(&liveRoot);
-    v8::UniqueId id(*idPointer);
-    if (!m_liveRootGroupIdSet) {
-      m_isolate->SetObjectGroupId(liveRoot, id);
-      m_liveRootGroupIdSet = true;
-      ++m_domObjectsWithPendingActivity;
-    }
-    return id;
-  }
-
-  v8::Isolate* m_isolate;
-  // v8 guarantees that Blink will not regain control while a v8 GC runs
-  // (=> no Oilpan GCs will be triggered), hence raw, untraced members
-  // can safely be kept here.
-  Vector<UntracedMember<Node>> m_groupsWhichNeedRetainerInfo;
-  int m_domObjectsWithPendingActivity;
-  bool m_liveRootGroupIdSet;
-  bool m_constructRetainedObjectInfos;
-};
-
 static unsigned long long usedHeapSize(v8::Isolate* isolate) {
   v8::HeapStatistics heapStatistics;
   isolate->GetHeapStatistics(&heapStatistics);
@@ -415,21 +283,6 @@
   isolate->VisitWeakHandles(&visitor);
 }
 
-void objectGroupingForMajorGC(v8::Isolate* isolate,
-                              bool constructRetainedObjectInfos) {
-  MajorGCWrapperVisitor visitor(isolate, constructRetainedObjectInfos);
-  isolate->VisitHandlesWithClassIds(&visitor);
-  visitor.notifyFinished();
-}
-
-void gcPrologueForMajorGC(v8::Isolate* isolate,
-                          bool constructRetainedObjectInfos) {
-  if (!RuntimeEnabledFeatures::traceWrappablesEnabled() ||
-      constructRetainedObjectInfos) {
-    objectGroupingForMajorGC(isolate, constructRetainedObjectInfos);
-  }
-}
-
 }  // namespace
 
 void V8GCController::gcPrologue(v8::Isolate* isolate,
@@ -466,8 +319,6 @@
       TRACE_EVENT_BEGIN2("devtools.timeline,v8", "MajorGC",
                          "usedHeapSizeBefore", usedHeapSize(isolate), "type",
                          "atomic pause");
-      gcPrologueForMajorGC(
-          isolate, flags & v8::kGCCallbackFlagConstructRetainedObjectInfos);
       break;
     case v8::kGCTypeIncrementalMarking:
       if (ThreadState::current())
@@ -476,8 +327,6 @@
       TRACE_EVENT_BEGIN2("devtools.timeline,v8", "MajorGC",
                          "usedHeapSizeBefore", usedHeapSize(isolate), "type",
                          "incremental marking");
-      gcPrologueForMajorGC(
-          isolate, flags & v8::kGCCallbackFlagConstructRetainedObjectInfos);
       break;
     case v8::kGCTypeProcessWeakCallbacks:
       TRACE_EVENT_BEGIN2("devtools.timeline,v8", "MajorGC",
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
index e9d3ec9..d66e6be 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
@@ -321,14 +321,12 @@
 static void initializeV8Common(v8::Isolate* isolate) {
   isolate->AddGCPrologueCallback(V8GCController::gcPrologue);
   isolate->AddGCEpilogueCallback(V8GCController::gcEpilogue);
-  if (RuntimeEnabledFeatures::traceWrappablesEnabled()) {
-    std::unique_ptr<ScriptWrappableVisitor> visitor(
-        new ScriptWrappableVisitor(isolate));
-    V8PerIsolateData::from(isolate)->setScriptWrappableVisitor(
-        std::move(visitor));
-    isolate->SetEmbedderHeapTracer(
-        V8PerIsolateData::from(isolate)->scriptWrappableVisitor());
-  }
+  std::unique_ptr<ScriptWrappableVisitor> visitor(
+      new ScriptWrappableVisitor(isolate));
+  V8PerIsolateData::from(isolate)->setScriptWrappableVisitor(
+      std::move(visitor));
+  isolate->SetEmbedderHeapTracer(
+      V8PerIsolateData::from(isolate)->scriptWrappableVisitor());
 
   v8::Debug::SetLiveEditEnabled(isolate, false);
 
diff --git a/third_party/WebKit/Source/core/css/ActiveStyleSheets.cpp b/third_party/WebKit/Source/core/css/ActiveStyleSheets.cpp
index cca65e7..4f3f619 100644
--- a/third_party/WebKit/Source/core/css/ActiveStyleSheets.cpp
+++ b/third_party/WebKit/Source/core/css/ActiveStyleSheets.cpp
@@ -38,18 +38,19 @@
   }
 
   if (index == oldStyleSheetCount) {
-    if (index == newStyleSheetCount) {
-      return changedRuleSets.isEmpty() ? NoActiveSheetsChanged
-                                       : ActiveSheetsChanged;
-    }
-
-    // Sheets added at the end.
+    // The old stylesheet vector is a prefix of the new vector in terms of
+    // StyleSheets. If none of the RuleSets changed, we only need to add the new
+    // sheets to the ScopedStyleResolver (ActiveSheetsAppended).
+    bool ruleSetsChangedInCommonPrefix = !changedRuleSets.isEmpty();
     for (; index < newStyleSheetCount; index++) {
       if (newStyleSheets[index].second)
         changedRuleSets.add(newStyleSheets[index].second);
     }
-    return changedRuleSets.isEmpty() ? NoActiveSheetsChanged
-                                     : ActiveSheetsAppended;
+    if (ruleSetsChangedInCommonPrefix)
+      return ActiveSheetsChanged;
+    if (changedRuleSets.isEmpty())
+      return NoActiveSheetsChanged;
+    return ActiveSheetsAppended;
   }
 
   if (index == newStyleSheetCount) {
diff --git a/third_party/WebKit/Source/core/css/ActiveStyleSheetsTest.cpp b/third_party/WebKit/Source/core/css/ActiveStyleSheetsTest.cpp
index 1cd52d0..1007d24c 100644
--- a/third_party/WebKit/Source/core/css/ActiveStyleSheetsTest.cpp
+++ b/third_party/WebKit/Source/core/css/ActiveStyleSheetsTest.cpp
@@ -328,6 +328,23 @@
   EXPECT_EQ(0u, changedRuleSets.size());
 }
 
+TEST_F(ActiveStyleSheetsTest, CompareActiveStyleSheets_DisableAndAppend) {
+  ActiveStyleSheetVector oldSheets;
+  ActiveStyleSheetVector newSheets;
+  HeapHashSet<Member<RuleSet>> changedRuleSets;
+
+  CSSStyleSheet* sheet1 = createSheet();
+  CSSStyleSheet* sheet2 = createSheet();
+
+  oldSheets.push_back(std::make_pair(sheet1, &sheet1->contents()->ruleSet()));
+  newSheets.push_back(std::make_pair(sheet1, nullptr));
+  newSheets.push_back(std::make_pair(sheet2, &sheet2->contents()->ruleSet()));
+
+  EXPECT_EQ(ActiveSheetsChanged,
+            compareActiveStyleSheets(oldSheets, newSheets, changedRuleSets));
+  EXPECT_EQ(2u, changedRuleSets.size());
+}
+
 TEST_F(ApplyRulesetsTest, AddUniversalRuleToDocument) {
   document().view()->updateAllLifecyclePhases();
 
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json
index e25a9c23..e3cfff5 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -416,8 +416,12 @@
             {
                 "name": "captureScreenshot",
                 "description": "Capture page screenshot.",
+                "parameters": [
+                    { "name": "format", "type": "string", "optional": true, "enum": ["jpeg", "png"], "description": "Image compression format (defaults to png)." },
+                    { "name": "quality", "type": "integer", "optional": true, "description": "Compression quality from range [0..100] (jpeg only)." }
+                ],
                 "returns": [
-                    { "name": "data", "type": "string", "description": "Base64-encoded image data (PNG)." }
+                    { "name": "data", "type": "string", "description": "Base64-encoded image data." }
                 ],
                 "experimental": true
             },
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index 3ecc0fc6..72c6c4c 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -1514,7 +1514,7 @@
   // We don't do this if we are submitting a form with method other than "GET",
   // explicitly reloading, currently displaying a frameset, or if the URL does
   // not have a fragment.
-  return (!isFormSubmission || equalIgnoringCase(httpMethod, HTTPNames::GET)) &&
+  return equalIgnoringCase(httpMethod, HTTPNames::GET) &&
          !isReloadLoadType(loadType) && loadType != FrameLoadTypeBackForward &&
          url.hasFragmentIdentifier() &&
          equalIgnoringFragmentIdentifier(m_frame->document()->url(), url)
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
index e554590..4fea93b 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
@@ -376,7 +376,7 @@
       this._model.deviceOutlineSetting().set(false);
     }
 
-    mainTarget.pageAgent().captureScreenshot(screenshotCaptured.bind(this));
+    mainTarget.pageAgent().captureScreenshot('png', 100, screenshotCaptured.bind(this));
 
     /**
      * @param {?Protocol.Error} error
diff --git a/third_party/WebKit/Source/modules/mediasession/MediaMetadata.cpp b/third_party/WebKit/Source/modules/mediasession/MediaMetadata.cpp
index 59ba3fc..7fdd5a2a 100644
--- a/third_party/WebKit/Source/modules/mediasession/MediaMetadata.cpp
+++ b/third_party/WebKit/Source/modules/mediasession/MediaMetadata.cpp
@@ -7,6 +7,7 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/ScriptState.h"
 #include "bindings/core/v8/ToV8.h"
+#include "core/dom/TaskRunnerHelper.h"
 #include "modules/mediasession/MediaImage.h"
 #include "modules/mediasession/MediaMetadataInit.h"
 #include "modules/mediasession/MediaSession.h"
@@ -23,7 +24,10 @@
 MediaMetadata::MediaMetadata(ScriptState* scriptState,
                              const MediaMetadataInit& metadata,
                              ExceptionState& exceptionState)
-    : m_notifySessionTimer(this, &MediaMetadata::notifySessionTimerFired) {
+    : m_notifySessionTimer(
+          TaskRunnerHelper::get(TaskType::MiscPlatformAPI, scriptState),
+          this,
+          &MediaMetadata::notifySessionTimerFired) {
   m_title = metadata.title();
   m_artist = metadata.artist();
   m_album = metadata.album();
diff --git a/third_party/WebKit/Source/modules/mediasession/MediaMetadata.h b/third_party/WebKit/Source/modules/mediasession/MediaMetadata.h
index aaf3d683..5d61670 100644
--- a/third_party/WebKit/Source/modules/mediasession/MediaMetadata.h
+++ b/third_party/WebKit/Source/modules/mediasession/MediaMetadata.h
@@ -78,7 +78,7 @@
   HeapVector<MediaImage> m_artwork;
 
   Member<MediaSession> m_session;
-  Timer<MediaMetadata> m_notifySessionTimer;
+  TaskRunnerTimer<MediaMetadata> m_notifySessionTimer;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index e8a544f..cd2b3ae4 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -249,7 +249,6 @@
 // touchscreen) in ApplyWebPreferences. "Touch events" themselves are always
 // enabled since they're a feature always supported by Chrome.
 TouchEventFeatureDetection status=stable
-TraceWrappables status=stable
 TrueColorRendering status=experimental
 TrustedEventsDefaultAction status=stable
 WebAnimationsAPI status=experimental
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index d9cf18fc..d9a2d67 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -986,8 +986,7 @@
 }
 
 void ThreadState::preGC() {
-  if (RuntimeEnabledFeatures::traceWrappablesEnabled() && m_isolate &&
-      m_performCleanup)
+  if (m_isolate && m_performCleanup)
     m_performCleanup(m_isolate);
 
   ASSERT(!isInGC());
@@ -1014,10 +1013,8 @@
 }
 
 void ThreadState::postGC(BlinkGC::GCType gcType) {
-  if (RuntimeEnabledFeatures::traceWrappablesEnabled() &&
-      m_invalidateDeadObjectsInWrappersMarkingDeque) {
+  if (m_invalidateDeadObjectsInWrappersMarkingDeque)
     m_invalidateDeadObjectsInWrappersMarkingDeque(m_isolate);
-  }
 
   ASSERT(isInGC());
   for (int i = 0; i < BlinkGC::NumberOfArenas; i++)
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc
index 07a8e08a..3beb123 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc
@@ -50,8 +50,6 @@
   // This fence will block any idle tasks from running.
   idle_queue_->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME);
   idle_queue_->SetQueuePriority(TaskQueue::BEST_EFFORT_PRIORITY);
-
-  helper_->AddTaskObserver(this);
 }
 
 IdleHelper::~IdleHelper() {
@@ -67,7 +65,6 @@
   weak_factory_.InvalidateWeakPtrs();
   // Belt & braces, might not be needed.
   idle_queue_->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME);
-  helper_->RemoveTaskObserver(this);
 }
 
 IdleHelper::Delegate::Delegate() {}
@@ -188,6 +185,9 @@
   }
 
   TRACE_EVENT0(disabled_by_default_tracing_category_, "StartIdlePeriod");
+  if (!IsInIdlePeriod(state_.idle_period_state()))
+    helper_->AddTaskObserver(this);
+
   // Use a fence to make sure any idle tasks posted after this point do not run
   // until the next idle period and unblock existing tasks.
   idle_queue_->InsertFence(TaskQueue::InsertFencePosition::NOW);
@@ -209,6 +209,8 @@
   if (!IsInIdlePeriod(state_.idle_period_state()))
     return;
 
+  helper_->RemoveTaskObserver(this);
+
   // This fence will block any idle tasks from running.
   idle_queue_->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME);
   state_.UpdateState(IdlePeriodState::NOT_IN_IDLE_PERIOD, base::TimeTicks(),
@@ -222,9 +224,9 @@
 void IdleHelper::DidProcessTask(const base::PendingTask& pending_task) {
   helper_->CheckOnValidThread();
   DCHECK(!is_shutdown_);
+  DCHECK(IsInIdlePeriod(state_.idle_period_state()));
   TRACE_EVENT0(disabled_by_default_tracing_category_, "DidProcessTask");
-  if (IsInIdlePeriod(state_.idle_period_state()) &&
-      state_.idle_period_state() !=
+  if (state_.idle_period_state() !=
           IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED &&
       helper_->scheduler_tqm_delegate()->NowTicks() >=
           state_.idle_period_deadline()) {
diff --git a/tools/nocompile_driver.py b/tools/nocompile_driver.py
index 5e5e739..598e4130 100755
--- a/tools/nocompile_driver.py
+++ b/tools/nocompile_driver.py
@@ -462,6 +462,7 @@
     finished_tests.extend(CompleteAtLeastOneTest(executing_tests))
   timings['compile_done'] = time.time()
 
+  finished_tests = sorted(finished_tests, key=lambda test: test['name'])
   for test in finished_tests:
     if test['name'] == 'NCTEST_SANITY':
       _, stderr = test['proc'].communicate()
diff --git a/tools/perf/benchmarks/power.py b/tools/perf/benchmarks/power.py
index 10c9461..8b90ed8 100644
--- a/tools/perf/benchmarks/power.py
+++ b/tools/perf/benchmarks/power.py
@@ -47,8 +47,10 @@
   def Name(cls):
     return 'power.typical_10_mobile'
 
-
-@benchmark.Enabled('android')
+# This benchmark runs only on android but it is disabled on android as well
+# because of http://crbug.com/683238
+# @benchmark.Enabled('android')
+@benchmark.Disabled('all')
 @benchmark.Disabled('android-webview')  # http://crbug.com/622300
 class PowerToughAdCases(perf_benchmark.PerfBenchmark):
   """Android power test with tough ad pages."""
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py
index 21ea4ee..aaa7463 100644
--- a/tools/perf/benchmarks/smoothness.py
+++ b/tools/perf/benchmarks/smoothness.py
@@ -480,7 +480,8 @@
 
 
 # http://crbug.com/522619 (mac/win)
-@benchmark.Disabled('win', 'mac')
+# http://crbug.com/683247 (android/linux)
+@benchmark.Disabled('win', 'mac', 'android', 'linux')
 class SmoothnessScrollingToughAdCases(_Smoothness):
   """Measures rendering statistics while scrolling advertisements."""
   page_set = page_sets.ScrollingToughAdCasesPageSet
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index 461a41e0..f1fdaa7c 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -119,6 +119,7 @@
     "image/image_util.cc",
     "image/image_util.h",
     "image/image_util_ios.mm",
+    "image/image_util_mac.mm",
     "interpolated_transform.cc",
     "interpolated_transform.h",
     "ios/NSString+CrStringDrawing.h",
diff --git a/ui/gfx/image/image_util.cc b/ui/gfx/image/image_util.cc
index d0d79b2..3fca705a 100644
--- a/ui/gfx/image/image_util.cc
+++ b/ui/gfx/image/image_util.cc
@@ -44,8 +44,18 @@
   return Image();
 }
 
-bool JPEG1xEncodedDataFromImage(const Image& image, int quality,
+// The MacOS implementation of this function is in image_utils_mac.mm.
+#if !defined(OS_MACOSX)
+bool JPEG1xEncodedDataFromImage(const Image& image,
+                                int quality,
                                 std::vector<unsigned char>* dst) {
+  return JPEG1xEncodedDataFromSkiaRepresentation(image, quality, dst);
+}
+#endif  // !defined(OS_MACOSX)
+
+bool JPEG1xEncodedDataFromSkiaRepresentation(const Image& image,
+                                             int quality,
+                                             std::vector<unsigned char>* dst) {
   const gfx::ImageSkiaRep& image_skia_rep =
       image.AsImageSkia().GetRepresentation(1.0f);
   if (image_skia_rep.scale() != 1.0f)
diff --git a/ui/gfx/image/image_util.h b/ui/gfx/image/image_util.h
index 8f17c368..cee54a3 100644
--- a/ui/gfx/image/image_util.h
+++ b/ui/gfx/image/image_util.h
@@ -33,6 +33,10 @@
                                            int quality,
                                            std::vector<unsigned char>* dst);
 
+bool JPEG1xEncodedDataFromSkiaRepresentation(const Image& image,
+                                             int quality,
+                                             std::vector<unsigned char>* dst);
+
 // Computes the width of any nearly-transparent regions at the sides of the
 // image and returns them in |left| and |right|.  This checks each column of
 // pixels from the outsides in, looking for anything with alpha above a
diff --git a/ui/gfx/image/image_util_mac.mm b/ui/gfx/image/image_util_mac.mm
new file mode 100644
index 0000000..5be20b0
--- /dev/null
+++ b/ui/gfx/image/image_util_mac.mm
@@ -0,0 +1,40 @@
+// 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/image/image_util.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/scoped_nsobject.h"
+#include "ui/gfx/image/image.h"
+
+namespace gfx {
+
+bool JPEG1xEncodedDataFromImage(const Image& image,
+                                int quality,
+                                std::vector<unsigned char>* dst) {
+  if (!image.HasRepresentation(gfx::Image::kImageRepCocoa))
+    return JPEG1xEncodedDataFromSkiaRepresentation(image, quality, dst);
+
+  NSImage* nsImage = image.ToNSImage();
+
+  CGImageRef cgImage =
+      [nsImage CGImageForProposedRect:nil context:nil hints:nil];
+  base::scoped_nsobject<NSBitmapImageRep> rep(
+      [[NSBitmapImageRep alloc] initWithCGImage:cgImage]);
+
+  float compressionFactor = quality / 100.0;
+  NSDictionary* options = @{ NSImageCompressionFactor : @(compressionFactor)};
+  NSData* data =
+      [rep representationUsingType:NSJPEGFileType properties:options];
+
+  if ([data length] == 0)
+    return false;
+
+  dst->resize([data length]);
+  [data getBytes:&dst->at(0) length:[data length]];
+  return true;
+}
+
+}  // end namespace gfx
diff --git a/ui/snapshot/BUILD.gn b/ui/snapshot/BUILD.gn
index d6ae901..4685e1b 100644
--- a/ui/snapshot/BUILD.gn
+++ b/ui/snapshot/BUILD.gn
@@ -10,6 +10,7 @@
     "screenshot_grabber.cc",
     "screenshot_grabber.h",
     "screenshot_grabber_observer.h",
+    "snapshot.cc",
     "snapshot.h",
     "snapshot_android.cc",
     "snapshot_async.cc",
@@ -84,6 +85,7 @@
     "//ui/base",
     "//ui/compositor:test_support",
     "//ui/gfx",
+    "//ui/gfx:test_support",
     "//ui/gfx/geometry",
     "//ui/gl",
   ]
diff --git a/ui/snapshot/screenshot_grabber.cc b/ui/snapshot/screenshot_grabber.cc
index 02e91df..da79cb2 100644
--- a/ui/snapshot/screenshot_grabber.cc
+++ b/ui/snapshot/screenshot_grabber.cc
@@ -43,7 +43,7 @@
 void SaveScreenshot(scoped_refptr<base::TaskRunner> ui_task_runner,
                     const ShowNotificationCallback& callback,
                     const base::FilePath& screenshot_path,
-                    scoped_refptr<base::RefCountedBytes> png_data,
+                    scoped_refptr<base::RefCountedMemory> png_data,
                     ScreenshotGrabberDelegate::FileResult result,
                     const base::FilePath& local_path) {
   DCHECK(!base::MessageLoopForUI::IsCurrent());
@@ -57,7 +57,7 @@
       // Successfully got a local file to write to, write png data.
       DCHECK_GT(static_cast<int>(png_data->size()), 0);
       if (static_cast<size_t>(base::WriteFile(
-              local_path, reinterpret_cast<char*>(&(png_data->data()[0])),
+              local_path, reinterpret_cast<const char*>(png_data->front()),
               static_cast<int>(png_data->size()))) != png_data->size()) {
         LOG(ERROR) << "Failed to save to " << local_path.value();
         screenshot_result =
@@ -168,7 +168,7 @@
 
   cursor_hider_ = ScopedCursorHider::Create(aura_window->GetRootWindow());
 #endif
-  ui::GrabWindowSnapshotAsync(
+  ui::GrabWindowSnapshotAsyncPNG(
       window, rect, blocking_task_runner_,
       base::Bind(&ScreenshotGrabber::GrabWindowSnapshotAsyncCallback,
                  factory_.GetWeakPtr(), window_identifier, screenshot_path,
@@ -209,7 +209,7 @@
     const std::string& window_identifier,
     base::FilePath screenshot_path,
     bool is_partial,
-    scoped_refptr<base::RefCountedBytes> png_data) {
+    scoped_refptr<base::RefCountedMemory> png_data) {
   DCHECK(base::MessageLoopForUI::IsCurrent());
   if (!png_data.get()) {
     if (is_partial) {
diff --git a/ui/snapshot/screenshot_grabber.h b/ui/snapshot/screenshot_grabber.h
index 555f863..7a0a947 100644
--- a/ui/snapshot/screenshot_grabber.h
+++ b/ui/snapshot/screenshot_grabber.h
@@ -84,7 +84,7 @@
       const std::string& window_identifier,
       base::FilePath screenshot_path,
       bool is_partial,
-      scoped_refptr<base::RefCountedBytes> png_data);
+      scoped_refptr<base::RefCountedMemory> png_data);
 
   // A weak pointer to the screenshot taker client.
   ScreenshotGrabberDelegate* client_;
diff --git a/ui/snapshot/snapshot.cc b/ui/snapshot/snapshot.cc
new file mode 100644
index 0000000..aaee01f1
--- /dev/null
+++ b/ui/snapshot/snapshot.cc
@@ -0,0 +1,41 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/snapshot/snapshot.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/task_runner_util.h"
+#include "ui/gfx/image/image.h"
+
+namespace ui {
+
+namespace {
+
+scoped_refptr<base::RefCountedMemory> EncodeImage(const gfx::Image& image) {
+  return image.As1xPNGBytes();
+}
+
+void EncodeImageAndSchedulePNGCallback(
+    scoped_refptr<base::TaskRunner> background_task_runner,
+    const GrabWindowSnapshotAsyncPNGCallback& callback,
+    const gfx::Image& image) {
+  base::PostTaskAndReplyWithResult(background_task_runner.get(), FROM_HERE,
+                                   base::Bind(EncodeImage, image), callback);
+}
+
+}  // namespace
+
+void GrabWindowSnapshotAsyncPNG(
+    gfx::NativeWindow window,
+    const gfx::Rect& source_rect,
+    scoped_refptr<base::TaskRunner> background_task_runner,
+    const GrabWindowSnapshotAsyncPNGCallback& callback) {
+  GrabWindowSnapshotAsync(
+      window, source_rect,
+      base::Bind(EncodeImageAndSchedulePNGCallback,
+                 std::move(background_task_runner), callback));
+}
+
+}  // namespace ui
diff --git a/ui/snapshot/snapshot.h b/ui/snapshot/snapshot.h
index 4b2733c..3c83a92 100644
--- a/ui/snapshot/snapshot.h
+++ b/ui/snapshot/snapshot.h
@@ -31,16 +31,13 @@
 // used in a result of user action. Support for async vs synchronous
 // GrabWindowSnapshot differs by platform.  To be most general, use the
 // synchronous function first and if it returns false call the async one.
-SNAPSHOT_EXPORT bool GrabWindowSnapshot(
-    gfx::NativeWindow window,
-    std::vector<unsigned char>* png_representation,
-    const gfx::Rect& snapshot_bounds);
+SNAPSHOT_EXPORT bool GrabWindowSnapshot(gfx::NativeWindow window,
+                                        const gfx::Rect& snapshot_bounds,
+                                        gfx::Image* image);
 
-SNAPSHOT_EXPORT bool GrabViewSnapshot(
-    gfx::NativeView view,
-    std::vector<unsigned char>* png_representation,
-    const gfx::Rect& snapshot_bounds);
-
+SNAPSHOT_EXPORT bool GrabViewSnapshot(gfx::NativeView view,
+                                      const gfx::Rect& snapshot_bounds,
+                                      gfx::Image* image);
 
 // These functions take a snapshot of |source_rect|, specified in layer space
 // coordinates (DIP for desktop, physical pixels for Android), and scale the
@@ -54,16 +51,21 @@
     scoped_refptr<base::TaskRunner> background_task_runner,
     const GrabWindowSnapshotAsyncCallback& callback);
 
-typedef base::Callback<void(scoped_refptr<base::RefCountedBytes> png_data)>
-    GrabWindowSnapshotAsyncPNGCallback;
 SNAPSHOT_EXPORT void GrabWindowSnapshotAsync(
     gfx::NativeWindow window,
     const gfx::Rect& source_rect,
-    scoped_refptr<base::TaskRunner> background_task_runner,
-    const GrabWindowSnapshotAsyncPNGCallback& callback);
+    const GrabWindowSnapshotAsyncCallback& callback);
+
 SNAPSHOT_EXPORT void GrabViewSnapshotAsync(
     gfx::NativeView view,
     const gfx::Rect& source_rect,
+    const GrabWindowSnapshotAsyncCallback& callback);
+
+typedef base::Callback<void(scoped_refptr<base::RefCountedMemory> png_data)>
+    GrabWindowSnapshotAsyncPNGCallback;
+SNAPSHOT_EXPORT void GrabWindowSnapshotAsyncPNG(
+    gfx::NativeWindow window,
+    const gfx::Rect& source_rect,
     scoped_refptr<base::TaskRunner> background_task_runner,
     const GrabWindowSnapshotAsyncPNGCallback& callback);
 
diff --git a/ui/snapshot/snapshot_android.cc b/ui/snapshot/snapshot_android.cc
index f687aa2..3de1f5ad 100644
--- a/ui/snapshot/snapshot_android.cc
+++ b/ui/snapshot/snapshot_android.cc
@@ -24,15 +24,14 @@
 // Sync versions are not supported in Android.  Callers should fall back
 // to the async version.
 bool GrabViewSnapshot(gfx::NativeView view,
-                      std::vector<unsigned char>* png_representation,
-                      const gfx::Rect& snapshot_bounds) {
-  return GrabWindowSnapshot(
-      view->GetWindowAndroid(), png_representation, snapshot_bounds);
+                      const gfx::Rect& snapshot_bounds,
+                      gfx::Image* image) {
+  return GrabWindowSnapshot(view->GetWindowAndroid(), snapshot_bounds, image);
 }
 
 bool GrabWindowSnapshot(gfx::NativeWindow window,
-                        std::vector<unsigned char>* png_representation,
-                        const gfx::Rect& snapshot_bounds) {
+                        const gfx::Rect& snapshot_bounds,
+                        gfx::Image* image) {
   return false;
 }
 
@@ -64,28 +63,20 @@
                                   background_task_runner));
 }
 
-void GrabWindowSnapshotAsync(
-    gfx::NativeWindow window,
-    const gfx::Rect& source_rect,
-    scoped_refptr<base::TaskRunner> background_task_runner,
-    const GrabWindowSnapshotAsyncPNGCallback& callback) {
-  MakeAsyncCopyRequest(window,
-                       source_rect,
-                       base::Bind(&SnapshotAsync::EncodeCopyOutputResult,
-                                  callback,
-                                  background_task_runner));
+void GrabWindowSnapshotAsync(gfx::NativeWindow window,
+                             const gfx::Rect& source_rect,
+                             const GrabWindowSnapshotAsyncCallback& callback) {
+  MakeAsyncCopyRequest(
+      window, source_rect,
+      base::Bind(&SnapshotAsync::RunCallbackWithCopyOutputResult, callback));
 }
 
-void GrabViewSnapshotAsync(
-    gfx::NativeView view,
-    const gfx::Rect& source_rect,
-    scoped_refptr<base::TaskRunner> background_task_runner,
-    const GrabWindowSnapshotAsyncPNGCallback& callback) {
-  MakeAsyncCopyRequest(view->GetWindowAndroid(),
-                       source_rect,
-                       base::Bind(&SnapshotAsync::EncodeCopyOutputResult,
-                                  callback,
-                                  background_task_runner));
+void GrabViewSnapshotAsync(gfx::NativeView view,
+                           const gfx::Rect& source_rect,
+                           const GrabWindowSnapshotAsyncCallback& callback) {
+  MakeAsyncCopyRequest(
+      view->GetWindowAndroid(), source_rect,
+      base::Bind(&SnapshotAsync::RunCallbackWithCopyOutputResult, callback));
 }
 
 }  // namespace ui
diff --git a/ui/snapshot/snapshot_async.cc b/ui/snapshot/snapshot_async.cc
index a4f0eb0..173f70a 100644
--- a/ui/snapshot/snapshot_async.cc
+++ b/ui/snapshot/snapshot_async.cc
@@ -10,8 +10,6 @@
 #include "base/task_runner_util.h"
 #include "skia/ext/image_operations.h"
 #include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkPixelRef.h"
-#include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/skbitmap_operations.h"
@@ -34,29 +32,6 @@
                                        static_cast<SkBitmap::Allocator*>(NULL));
 }
 
-scoped_refptr<base::RefCountedBytes> EncodeBitmap(const SkBitmap& bitmap) {
-  scoped_refptr<base::RefCountedBytes> png_data(new base::RefCountedBytes);
-  SkAutoLockPixels lock(bitmap);
-  unsigned char* pixels = reinterpret_cast<unsigned char*>(bitmap.getPixels());
-#if SK_A32_SHIFT == 24 && SK_R32_SHIFT == 16 && SK_G32_SHIFT == 8
-  gfx::PNGCodec::ColorFormat kColorFormat = gfx::PNGCodec::FORMAT_BGRA;
-#elif SK_A32_SHIFT == 24 && SK_B32_SHIFT == 16 && SK_G32_SHIFT == 8
-  gfx::PNGCodec::ColorFormat kColorFormat = gfx::PNGCodec::FORMAT_RGBA;
-#else
-#error Unknown color format
-#endif
-  if (!gfx::PNGCodec::Encode(pixels,
-                             kColorFormat,
-                             gfx::Size(bitmap.width(), bitmap.height()),
-                             base::checked_cast<int>(bitmap.rowBytes()),
-                             true,
-                             std::vector<gfx::PNGCodec::Comment>(),
-                             &png_data->data())) {
-    return scoped_refptr<base::RefCountedBytes>();
-  }
-  return png_data;
-}
-
 }  // namespace
 
 void SnapshotAsync::ScaleCopyOutputResult(
@@ -80,24 +55,15 @@
       base::Bind(&OnFrameScalingFinished, callback));
 }
 
-void SnapshotAsync::EncodeCopyOutputResult(
-    const GrabWindowSnapshotAsyncPNGCallback& callback,
-    scoped_refptr<base::TaskRunner> background_task_runner,
+void SnapshotAsync::RunCallbackWithCopyOutputResult(
+    const GrabWindowSnapshotAsyncCallback& callback,
     std::unique_ptr<cc::CopyOutputResult> result) {
   if (result->IsEmpty()) {
-    callback.Run(scoped_refptr<base::RefCountedBytes>());
+    callback.Run(gfx::Image());
     return;
   }
 
-  // TODO(sergeyu): Potentially images can be scaled on GPU before reading it
-  // from GPU. Image scaling is implemented in content::GlHelper, but it's can't
-  // be used here because it's not in content/public. Move the scaling code
-  // somewhere so that it can be reused here.
-  base::PostTaskAndReplyWithResult(
-      background_task_runner.get(),
-      FROM_HERE,
-      base::Bind(EncodeBitmap, *result->TakeBitmap()),
-      callback);
+  callback.Run(gfx::Image::CreateFrom1xBitmap(*result->TakeBitmap()));
 }
 
 }  // namespace ui
diff --git a/ui/snapshot/snapshot_async.h b/ui/snapshot/snapshot_async.h
index 364f76c2..79928e0 100644
--- a/ui/snapshot/snapshot_async.h
+++ b/ui/snapshot/snapshot_async.h
@@ -31,9 +31,8 @@
       scoped_refptr<base::TaskRunner> background_task_runner,
       std::unique_ptr<cc::CopyOutputResult> result);
 
-  static void EncodeCopyOutputResult(
-      const GrabWindowSnapshotAsyncPNGCallback& callback,
-      scoped_refptr<base::TaskRunner> background_task_runner,
+  static void RunCallbackWithCopyOutputResult(
+      const GrabWindowSnapshotAsyncCallback& callback,
       std::unique_ptr<cc::CopyOutputResult> result);
 
  private:
diff --git a/ui/snapshot/snapshot_aura.cc b/ui/snapshot/snapshot_aura.cc
index d2df3f08f..0ff547c1 100644
--- a/ui/snapshot/snapshot_aura.cc
+++ b/ui/snapshot/snapshot_aura.cc
@@ -22,14 +22,14 @@
 namespace ui {
 
 bool GrabViewSnapshot(gfx::NativeView view,
-                      std::vector<unsigned char>* png_representation,
-                      const gfx::Rect& snapshot_bounds) {
-  return GrabWindowSnapshot(view, png_representation, snapshot_bounds);
+                      const gfx::Rect& snapshot_bounds,
+                      gfx::Image* image) {
+  return GrabWindowSnapshot(view, snapshot_bounds, image);
 }
 
 bool GrabWindowSnapshot(gfx::NativeWindow window,
-                        std::vector<unsigned char>* png_representation,
-                        const gfx::Rect& snapshot_bounds) {
+                        const gfx::Rect& snapshot_bounds,
+                        gfx::Image* image) {
   // Not supported in Aura.  Callers should fall back to the async version.
   return false;
 }
@@ -94,22 +94,18 @@
                  background_task_runner));
 }
 
-void GrabWindowSnapshotAsync(
-    gfx::NativeWindow window,
-    const gfx::Rect& source_rect,
-    scoped_refptr<base::TaskRunner> background_task_runner,
-    const GrabWindowSnapshotAsyncPNGCallback& callback) {
-  MakeInitialAsyncCopyRequest(window, source_rect,
-                              base::Bind(&SnapshotAsync::EncodeCopyOutputResult,
-                                         callback, background_task_runner));
+void GrabWindowSnapshotAsync(gfx::NativeWindow window,
+                             const gfx::Rect& source_rect,
+                             const GrabWindowSnapshotAsyncCallback& callback) {
+  MakeInitialAsyncCopyRequest(
+      window, source_rect,
+      base::Bind(&SnapshotAsync::RunCallbackWithCopyOutputResult, callback));
 }
 
-void GrabViewSnapshotAsync(
-    gfx::NativeView view,
-    const gfx::Rect& source_rect,
-    scoped_refptr<base::TaskRunner> background_task_runner,
-    const GrabWindowSnapshotAsyncPNGCallback& callback) {
-  GrabWindowSnapshotAsync(view, source_rect, background_task_runner, callback);
+void GrabViewSnapshotAsync(gfx::NativeView view,
+                           const gfx::Rect& source_rect,
+                           const GrabWindowSnapshotAsyncCallback& callback) {
+  GrabWindowSnapshotAsync(view, source_rect, callback);
 }
 
 
diff --git a/ui/snapshot/snapshot_aura_unittest.cc b/ui/snapshot/snapshot_aura_unittest.cc
index 984a231b..97d4ac44 100644
--- a/ui/snapshot/snapshot_aura_unittest.cc
+++ b/ui/snapshot/snapshot_aura_unittest.cc
@@ -141,28 +141,14 @@
     aura::Window::ConvertRectToTarget(
         test_window(), root_window(), &source_rect);
 
-    scoped_refptr<base::TestSimpleTaskRunner> task_runner(
-        new base::TestSimpleTaskRunner());
     scoped_refptr<SnapshotHolder> holder(new SnapshotHolder);
     ui::GrabWindowSnapshotAsync(
-        root_window(),
-        source_rect,
-        task_runner,
+        root_window(), source_rect,
         base::Bind(&SnapshotHolder::SnapshotCallback, holder));
 
-    // Wait for copy response.
-    WaitForDraw();
-    // Run internal snapshot callback to scale/rotate response image.
-    task_runner->RunUntilIdle();
-    // Run SnapshotHolder callback.
-    helper_->RunAllPendingInMessageLoop();
-
-    if (holder->completed())
-      return holder->image();
-
-    // Callback never called.
-    NOTREACHED();
-    return gfx::Image();
+    holder->WaitForSnapshot();
+    DCHECK(holder->completed());
+    return holder->image();
   }
 
  private:
@@ -170,12 +156,13 @@
    public:
     SnapshotHolder() : completed_(false) {}
 
-    void SnapshotCallback(scoped_refptr<base::RefCountedBytes> png_data) {
+    void SnapshotCallback(const gfx::Image& image) {
       DCHECK(!completed_);
-      image_ = gfx::Image::CreateFrom1xPNGBytes(&(png_data->data()[0]),
-                                                png_data->size());
+      image_ = image;
       completed_ = true;
+      run_loop_.Quit();
     }
+    void WaitForSnapshot() { run_loop_.Run(); }
     bool completed() const {
       return completed_;
     };
@@ -186,6 +173,7 @@
 
     virtual ~SnapshotHolder() {}
 
+    base::RunLoop run_loop_;
     gfx::Image image_;
     bool completed_;
   };
@@ -231,7 +219,7 @@
 }
 
 TEST_F(SnapshotAuraTest, UIScale) {
-  const float kUIScale = 1.25f;
+  const float kUIScale = 0.5f;
   test_screen()->SetUIScale(kUIScale);
 
   gfx::Rect test_bounds(100, 100, 300, 200);
@@ -240,11 +228,12 @@
 
   // Snapshot always captures the physical pixels.
   gfx::SizeF snapshot_size(test_bounds.size());
+  snapshot_size.Scale(1 / kUIScale);
 
   gfx::Image snapshot = GrabSnapshotForTestWindow();
   EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
             snapshot.Size().ToString());
-  EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
+  EXPECT_EQ(0u, GetFailedPixelsCountWithScaleFactor(snapshot, 1 / kUIScale));
 }
 
 TEST_F(SnapshotAuraTest, DeviceScaleFactor) {
@@ -265,7 +254,7 @@
 }
 
 TEST_F(SnapshotAuraTest, RotateAndUIScale) {
-  const float kUIScale = 1.25f;
+  const float kUIScale = 0.5f;
   test_screen()->SetUIScale(kUIScale);
   test_screen()->SetDisplayRotation(display::Display::ROTATE_90);
 
@@ -275,16 +264,17 @@
 
   // Snapshot always captures the physical pixels.
   gfx::SizeF snapshot_size(test_bounds.size());
+  snapshot_size.Scale(1 / kUIScale);
 
   gfx::Image snapshot = GrabSnapshotForTestWindow();
   EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
             snapshot.Size().ToString());
-  EXPECT_EQ(0u, GetFailedPixelsCount(snapshot));
+  EXPECT_EQ(0u, GetFailedPixelsCountWithScaleFactor(snapshot, 1 / kUIScale));
 }
 
 TEST_F(SnapshotAuraTest, RotateAndUIScaleAndScaleFactor) {
   test_screen()->SetDeviceScaleFactor(2.0f);
-  const float kUIScale = 1.25f;
+  const float kUIScale = 0.5f;
   test_screen()->SetUIScale(kUIScale);
   test_screen()->SetDisplayRotation(display::Display::ROTATE_90);
 
@@ -294,12 +284,12 @@
 
   // Snapshot always captures the physical pixels.
   gfx::SizeF snapshot_size(test_bounds.size());
-  snapshot_size.Scale(2.0f);
+  snapshot_size.Scale(2.0f / kUIScale);
 
   gfx::Image snapshot = GrabSnapshotForTestWindow();
   EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(),
             snapshot.Size().ToString());
-  EXPECT_EQ(0u, GetFailedPixelsCountWithScaleFactor(snapshot, 2));
+  EXPECT_EQ(0u, GetFailedPixelsCountWithScaleFactor(snapshot, 2 / kUIScale));
 }
 
 }  // namespace ui
diff --git a/ui/snapshot/snapshot_ios.mm b/ui/snapshot/snapshot_ios.mm
index d75f204..d239b71 100644
--- a/ui/snapshot/snapshot_ios.mm
+++ b/ui/snapshot/snapshot_ios.mm
@@ -11,15 +11,15 @@
 namespace ui {
 
 bool GrabViewSnapshot(gfx::NativeView view,
-                      std::vector<unsigned char>* png_representation,
-                      const gfx::Rect& snapshot_bounds) {
+                      const gfx::Rect& snapshot_bounds,
+                      gfx::Image* image) {
   // TODO(bajones): Implement iOS snapshot functionality
   return false;
 }
 
 bool GrabWindowSnapshot(gfx::NativeWindow window,
-                        std::vector<unsigned char>* png_representation,
-                        const gfx::Rect& snapshot_bounds) {
+                        const gfx::Rect& snapshot_bounds,
+                        gfx::Image* image) {
   // TODO(bajones): Implement iOS snapshot functionality
   return false;
 }
@@ -33,20 +33,16 @@
   callback.Run(gfx::Image());
 }
 
-void GrabViewSnapshotAsync(
-    gfx::NativeView view,
-    const gfx::Rect& source_rect,
-    scoped_refptr<base::TaskRunner> background_task_runner,
-    const GrabWindowSnapshotAsyncPNGCallback& callback) {
-  callback.Run(scoped_refptr<base::RefCountedBytes>());
+void GrabViewSnapshotAsync(gfx::NativeView view,
+                           const gfx::Rect& source_rect,
+                           const GrabWindowSnapshotAsyncCallback& callback) {
+  callback.Run(gfx::Image());
 }
 
-void GrabWindowSnapshotAsync(
-    gfx::NativeWindow window,
-    const gfx::Rect& source_rect,
-    scoped_refptr<base::TaskRunner> background_task_runner,
-    const GrabWindowSnapshotAsyncPNGCallback& callback) {
-  callback.Run(scoped_refptr<base::RefCountedBytes>());
+void GrabWindowSnapshotAsync(gfx::NativeWindow window,
+                             const gfx::Rect& source_rect,
+                             const GrabWindowSnapshotAsyncCallback& callback) {
+  callback.Run(gfx::Image());
 }
 
 }  // namespace ui
diff --git a/ui/snapshot/snapshot_mac.mm b/ui/snapshot/snapshot_mac.mm
index 9761cb7..40cfaaf 100644
--- a/ui/snapshot/snapshot_mac.mm
+++ b/ui/snapshot/snapshot_mac.mm
@@ -9,7 +9,6 @@
 #include "base/callback.h"
 #include "base/logging.h"
 #include "base/mac/scoped_cftyperef.h"
-#include "base/mac/scoped_nsobject.h"
 #include "base/mac/sdk_forward_declarations.h"
 #include "base/task_runner.h"
 #include "ui/gfx/geometry/rect.h"
@@ -18,8 +17,8 @@
 namespace ui {
 
 bool GrabViewSnapshot(gfx::NativeView view,
-                      std::vector<unsigned char>* png_representation,
-                      const gfx::Rect& snapshot_bounds) {
+                      const gfx::Rect& snapshot_bounds,
+                      gfx::Image* image) {
   NSWindow* window = [view window];
   NSScreen* screen = [[NSScreen screens] firstObject];
   gfx::Rect screen_bounds = gfx::Rect(NSRectToCGRect([screen frame]));
@@ -43,8 +42,6 @@
   DCHECK_LE(screen_snapshot_bounds.right(), view_bounds.right());
   DCHECK_LE(screen_snapshot_bounds.bottom(), view_bounds.bottom());
 
-  png_representation->clear();
-
   base::ScopedCFTypeRef<CGImageRef> windowSnapshot(
       CGWindowListCreateImage(screen_snapshot_bounds.ToCGRect(),
                               kCGWindowListOptionIncludingWindow,
@@ -53,27 +50,19 @@
   if (CGImageGetWidth(windowSnapshot) <= 0)
     return false;
 
-  base::scoped_nsobject<NSBitmapImageRep> rep(
-      [[NSBitmapImageRep alloc] initWithCGImage:windowSnapshot]);
-  NSData* data = [rep representationUsingType:NSPNGFileType properties:@{}];
-  const unsigned char* buf = static_cast<const unsigned char*>([data bytes]);
-  NSUInteger length = [data length];
-  if (buf == NULL || length == 0)
-    return false;
-
-  png_representation->assign(buf, buf + length);
-  DCHECK(!png_representation->empty());
-
+  NSImage* nsImage =
+      [[NSImage alloc] initWithCGImage:windowSnapshot size:NSZeroSize];
+  *image = gfx::Image(nsImage);
   return true;
 }
 
 bool GrabWindowSnapshot(gfx::NativeWindow window,
-                        std::vector<unsigned char>* png_representation,
-                        const gfx::Rect& snapshot_bounds) {
+                        const gfx::Rect& snapshot_bounds,
+                        gfx::Image* image) {
   // Make sure to grab the "window frame" view so we get current tab +
   // tabstrip.
-  return GrabViewSnapshot([[window contentView] superview], png_representation,
-      snapshot_bounds);
+  return GrabViewSnapshot([[window contentView] superview], snapshot_bounds,
+                          image);
 }
 
 void GrabWindowSnapshotAndScaleAsync(
@@ -85,21 +74,17 @@
   callback.Run(gfx::Image());
 }
 
-void GrabViewSnapshotAsync(
-    gfx::NativeView view,
-    const gfx::Rect& source_rect,
-    scoped_refptr<base::TaskRunner> background_task_runner,
-    const GrabWindowSnapshotAsyncPNGCallback& callback) {
-  callback.Run(scoped_refptr<base::RefCountedBytes>());
+void GrabViewSnapshotAsync(gfx::NativeView view,
+                           const gfx::Rect& source_rect,
+                           const GrabWindowSnapshotAsyncCallback& callback) {
+  callback.Run(gfx::Image());
 }
 
-void GrabWindowSnapshotAsync(
-    gfx::NativeWindow window,
-    const gfx::Rect& source_rect,
-    scoped_refptr<base::TaskRunner> background_task_runner,
-    const GrabWindowSnapshotAsyncPNGCallback& callback) {
+void GrabWindowSnapshotAsync(gfx::NativeWindow window,
+                             const gfx::Rect& source_rect,
+                             const GrabWindowSnapshotAsyncCallback& callback) {
   return GrabViewSnapshotAsync([[window contentView] superview], source_rect,
-      background_task_runner, callback);
+                               callback);
 }
 
 }  // namespace ui
diff --git a/ui/snapshot/snapshot_mac_unittest.mm b/ui/snapshot/snapshot_mac_unittest.mm
index d1d9250..860b692f 100644
--- a/ui/snapshot/snapshot_mac_unittest.mm
+++ b/ui/snapshot/snapshot_mac_unittest.mm
@@ -8,38 +8,41 @@
 
 #include <memory>
 
+#include "base/mac/mac_util.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/mac/sdk_forward_declarations.h"
 #include "testing/platform_test.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/image/image.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
 
 namespace ui {
 namespace {
 
-typedef PlatformTest GrabWindowSnapshotTest;
+typedef CocoaTest GrabWindowSnapshotTest;
 
 TEST_F(GrabWindowSnapshotTest, TestGrabWindowSnapshot) {
+  // TODO(https://crbug.com/685088): This test fails on MacOS 10.11 and above.
+  if (base::mac::IsAtLeastOS10_11())
+    return;
+
   // Launch a test window so we can take a snapshot.
   NSRect frame = NSMakeRect(0, 0, 400, 400);
-  base::scoped_nsobject<NSWindow> window(
-      [[NSWindow alloc] initWithContentRect:frame
-                                  styleMask:NSBorderlessWindowMask
-                                    backing:NSBackingStoreBuffered
-                                      defer:NO]);
+  NSWindow* window = test_window();
+  [window setFrame:frame display:false];
   [window setBackgroundColor:[NSColor whiteColor]];
   [window makeKeyAndOrderFront:NSApp];
+  [window display];
 
-  std::unique_ptr<std::vector<unsigned char>> png_representation(
-      new std::vector<unsigned char>);
+  gfx::Image image;
   gfx::Rect bounds = gfx::Rect(0, 0, frame.size.width, frame.size.height);
-  EXPECT_TRUE(ui::GrabWindowSnapshot(window, png_representation.get(),
-                                           bounds));
+  EXPECT_TRUE(ui::GrabWindowSnapshot(window, bounds, &image));
 
-  // Copy png back into NSData object so we can make sure we grabbed a png.
-  base::scoped_nsobject<NSData> image_data(
-      [[NSData alloc] initWithBytes:&(*png_representation)[0]
-                             length:png_representation->size()]);
-  NSBitmapImageRep* rep = [NSBitmapImageRep imageRepWithData:image_data.get()];
+  NSImage* nsImage = image.ToNSImage();
+  CGImageRef cgImage =
+      [nsImage CGImageForProposedRect:nil context:nil hints:nil];
+  base::scoped_nsobject<NSBitmapImageRep> rep(
+      [[NSBitmapImageRep alloc] initWithCGImage:cgImage]);
   EXPECT_TRUE([rep isKindOfClass:[NSBitmapImageRep class]]);
   CGFloat scaleFactor = 1.0f;
   if ([window respondsToSelector:@selector(backingScaleFactor)])