diff --git a/DEPS b/DEPS index 19ed5de1..33ca458 100644 --- a/DEPS +++ b/DEPS
@@ -40,7 +40,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '08541e8d7f28d875f5a6238aea1bae871e4aa276', + 'skia_revision': '5395c598dbc3fc85b45a18752867aea65643f147', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -88,7 +88,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': '42ae93a39e49116f69e1a5b2056c55564a6309f0', + 'nacl_revision': '62bfd122aee87d4eb4a7876950e18c793c626cd0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other.
diff --git a/ash/host/ash_window_tree_host_platform.cc b/ash/host/ash_window_tree_host_platform.cc index a268db38..e5281456 100644 --- a/ash/host/ash_window_tree_host_platform.cc +++ b/ash/host/ash_window_tree_host_platform.cc
@@ -75,6 +75,10 @@ // coordinates. window()->SetEventTargeter( std::unique_ptr<ui::EventTargeter>(new ui::NullEventTargeter)); + + // Do anything platform specific necessary before shutdown (eg. stop + // listening for configuration XEvents). + platform_window()->PrepareForShutdown(); } void AshWindowTreeHostPlatform::SetRootTransform(
diff --git a/base/metrics/OWNERS b/base/metrics/OWNERS index e42c313..e637387 100644 --- a/base/metrics/OWNERS +++ b/base/metrics/OWNERS
@@ -2,3 +2,5 @@ isherman@chromium.org mpearson@chromium.org rkaplow@chromium.org + +# COMPONENT: Internals>Metrics
diff --git a/build/OWNERS b/build/OWNERS index e132538..c57052cb 100644 --- a/build/OWNERS +++ b/build/OWNERS
@@ -11,3 +11,5 @@ per-file package_mac_toolchain.py=erikchen@chromium.org per-file package_mac_toolchain.py=justincohen@chromium.org per-file whitespace_file.txt=* + +# COMPONENT: Build
diff --git a/build/android/gradle/OWNERS b/build/android/gradle/OWNERS index a0e0826..d1f9484 100644 --- a/build/android/gradle/OWNERS +++ b/build/android/gradle/OWNERS
@@ -1,2 +1,4 @@ agrieve@chromium.org wnwen@chromium.org + +# COMPONENT: Build
diff --git a/build/android/java_assertion_enabler/OWNERS b/build/android/java_assertion_enabler/OWNERS index e96e054..ea2bde4 100644 --- a/build/android/java_assertion_enabler/OWNERS +++ b/build/android/java_assertion_enabler/OWNERS
@@ -1,2 +1,4 @@ agrieve@chromium.org zpeng@chromium.org + +# COMPONENT: Build
diff --git a/build/config/android/OWNERS b/build/config/android/OWNERS index 39f58e9..2dd8a673 100644 --- a/build/config/android/OWNERS +++ b/build/config/android/OWNERS
@@ -1 +1,3 @@ agrieve@chromium.org + +# COMPONENT: Build
diff --git a/build/get_landmines.py b/build/get_landmines.py index c8d501b..0216b1c 100755 --- a/build/get_landmines.py +++ b/build/get_landmines.py
@@ -44,7 +44,7 @@ if platform() in ('win', 'mac'): print ('Improper dependency for create_nmf.py broke in r240802, ' 'fixed in r240860.') - if (platform() == 'win' and gyp_msvs_version().startswith('2015')): + if platform() == 'win': print 'Switch to VS2015 Update 3, 14393 SDK' print 'Need to clobber everything due to an IDL change in r154579 (blink)' print 'Need to clobber everything due to gen file moves in r175513 (Blink)'
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index ec6b12dc..d6a6523 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -181,6 +181,7 @@ "//components/minidump_uploader:minidump_uploader_java", "//components/navigation_interception/android:navigation_interception_java", "//components/ntp_tiles/android:ntp_tiles_java", + "//components/offline_items_collection/core:core_java", "//components/payments/content:payment_request_java", "//components/policy/android:policy_java", "//components/precache/android:precache_java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/NativePageHost.java b/chrome/android/java/src/org/chromium/chrome/browser/NativePageHost.java index ffb479d..9f67fa97 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/NativePageHost.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/NativePageHost.java
@@ -41,4 +41,7 @@ * @return The active tab. */ Tab getActiveTab(); + + /** @return whether the hosted native page is currently visible. */ + boolean isVisible(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java index 50542ab..3c4c3cb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java
@@ -18,6 +18,7 @@ import org.chromium.chrome.browser.compositor.overlays.SceneOverlay; import org.chromium.chrome.browser.device.DeviceClassManager; import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; +import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.widget.ClipDrawableProgressBar.DrawingInfo; import org.chromium.chrome.browser.widget.ControlContainer; import org.chromium.ui.base.DeviceFormFactor; @@ -164,8 +165,12 @@ } @Override - public void onSizeChanged(float width, float height, float visibleViewportOffsetY, - int orientation) {} + public void onSizeChanged( + float width, float height, float visibleViewportOffsetY, int orientation) { + // If Chrome Home is enabled, a size change means the toolbar is now in a different + // location so a render is needed. + if (FeatureUtilities.isChromeHomeEnabled()) mRenderHost.requestRender(); + } @Override public void getVirtualViews(List<VirtualView> views) {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NativePageFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NativePageFactory.java index 05ef6fe5..148bfae7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NativePageFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NativePageFactory.java
@@ -219,5 +219,10 @@ public Tab getActiveTab() { return mTab; } + + @Override + public boolean isVisible() { + return mTab == mTab.getTabModelSelector().getCurrentTab(); + } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java index 6317e6e0..c833e89 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -44,6 +44,7 @@ import org.chromium.chrome.browser.suggestions.Tile; import org.chromium.chrome.browser.suggestions.TileGridLayout; import org.chromium.chrome.browser.suggestions.TileGroup; +import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.util.MathUtils; @@ -235,6 +236,12 @@ mNewTabPageLayout.addOnLayoutChangeListener(this); setSearchProviderHasLogo(searchProviderHasLogo); + tab.addObserver(new EmptyTabObserver() { + @Override + public void onShown(Tab tab) { + mTileGroup.onSwitchToForeground(); + } + }); mTileGroup.startObserving(getMaxTileRows(searchProviderHasLogo) * getMaxTileColumns()); // Set up snippets @@ -417,6 +424,11 @@ return mTileGridPlaceholder; } + @VisibleForTesting + public TileGroup getTileGroup() { + return mTileGroup; + } + /** * Adds listeners to scrolling to take care of snap scrolling and updating the search box on * scroll.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java index 7bb207b..6ef26eb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -47,6 +47,8 @@ @Nullable private final AboveTheFoldItem mAboveTheFold; + @Nullable + private final TileGrid mTileGrid; private final SectionList mSections; private final SignInPromo mSigninPromo; private final AllDismissedItem mAllDismissed; @@ -85,9 +87,12 @@ mAboveTheFold = new AboveTheFoldItem(); mRoot.addChild(mAboveTheFold); } - if (tileGroupDelegate != null) { - mRoot.addChild(new TileGrid( - uiDelegate, mContextMenuManager, tileGroupDelegate, offlinePageBridge)); + if (tileGroupDelegate == null) { + mTileGrid = null; + } else { + mTileGrid = new TileGrid( + uiDelegate, mContextMenuManager, tileGroupDelegate, offlinePageBridge); + mRoot.addChild(mTileGrid); } mRoot.addChildren(mSections, mSigninPromo, mAllDismissed, mFooter); if (mAboveTheFoldView == null @@ -181,6 +186,7 @@ // The NTP Tiles already update when changes occurs, they don't need to be explicitly reset, // unlike the cards. mSections.refreshSuggestions(); + if (mTileGrid != null) mTileGrid.getTileGroup().onSwitchToForeground(); } public int getAboveTheFoldPosition() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java index 0d6fbccd..8e523383 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java
@@ -61,4 +61,7 @@ * Registers a {@link DestructionObserver}, notified when the New Tab Page goes away. */ void addDestructionObserver(DestructionObserver destructionObserver); + + /** @return whether the suggestions UI is currently visible. */ + boolean isVisible(); } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java index 02741c7..ff96290 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java
@@ -94,6 +94,11 @@ mDestructionObservers.add(destructionObserver); } + @Override + public boolean isVisible() { + return mHost.isVisible(); + } + /** Invalidates the delegate and calls the registered destruction observers. */ public void onDestroy() { assert !mIsDestroyed;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java index 5a2563f..170b98c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
@@ -85,6 +85,10 @@ @Override public void onLoadTaskCompleted() {} + public TileGroup getTileGroup() { + return mTileGroup; + } + private static int getMaxTileRows() { int defaultValue = 1; return ChromeFeatureList.getFieldTrialParamByFeatureAsInt(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java index 672f2d35..9735834 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
@@ -141,6 +141,18 @@ * @see #getTile(String) */ private Tile[] mTiles = new Tile[0]; + + /** Most recently received tile data that has not been displayed yet. */ + @Nullable + private Tile[] mPendingTileData; + + /** + * URL of the most recently removed tile. Used to identify when a tile removal is confirmed by + * the tile backend. + */ + @Nullable + private String mPendingRemovalUrl; + private boolean mHasReceivedData; /** @@ -183,13 +195,9 @@ @Override public void onMostVisitedURLsAvailable(final String[] titles, final String[] urls, final String[] whitelistIconPaths, final int[] sources) { - boolean isInitialLoad = !mHasReceivedData; - mHasReceivedData = true; - - Tile[] newTiles = new Tile[titles.length]; + boolean removalCompleted = mPendingRemovalUrl != null; Set<String> addedUrls = new HashSet<>(); - boolean countChanged = isInitialLoad || mTiles.length != titles.length; - boolean dataChanged = countChanged; + mPendingTileData = new Tile[titles.length]; for (int i = 0; i < titles.length; i++) { assert urls[i] != null; // We assume everywhere that the url is not null. @@ -200,22 +208,15 @@ continue; } - newTiles[i] = new Tile(titles[i], urls[i], whitelistIconPaths[i], i, sources[i]); - if (newTiles[i].importData(getTile(urls[i]))) dataChanged = true; + mPendingTileData[i] = + new Tile(titles[i], urls[i], whitelistIconPaths[i], i, sources[i]); addedUrls.add(urls[i]); + + if (urls[i].equals(mPendingRemovalUrl)) removalCompleted = false; } - if (!dataChanged) return; - - mTiles = newTiles; - - if (mOfflineModelObserver != null) { - mOfflineModelObserver.updateOfflinableSuggestionsAvailability(); - } - - if (countChanged) mObserver.onTileCountChanged(); - if (isInitialLoad) mObserver.onLoadTaskCompleted(); - mObserver.onTileDataChanged(); + if (removalCompleted) mPendingRemovalUrl = null; + if (!mHasReceivedData || !mUiDelegate.isVisible() || removalCompleted) loadTiles(); } @Override @@ -278,6 +279,11 @@ return mHasReceivedData; } + /** To be called when the view displaying the tile group becomes visible. */ + public void onSwitchToForeground() { + if (mPendingTileData != null) loadTiles(); + } + /** * Inflates a new tile view, initializes it, and loads an icon for it. * @param tile The tile that holds the data to populate the new tile view. @@ -321,6 +327,33 @@ return true; } + /** Loads tile data from {@link #mPendingTileData} and clears it afterwards. */ + private void loadTiles() { + assert mPendingTileData != null; + + boolean isInitialLoad = !mHasReceivedData; + mHasReceivedData = true; + + boolean countChanged = isInitialLoad || mTiles.length != mPendingTileData.length; + boolean dataChanged = countChanged; + for (Tile newTile : mPendingTileData) { + if (newTile.importData(getTile(newTile.getUrl()))) dataChanged = true; + } + + mTiles = mPendingTileData; + mPendingTileData = null; + + if (!dataChanged) return; + + if (mOfflineModelObserver != null) { + mOfflineModelObserver.updateOfflinableSuggestionsAvailability(); + } + + if (countChanged) mObserver.onTileCountChanged(); + if (isInitialLoad) mObserver.onLoadTaskCompleted(); + mObserver.onTileDataChanged(); + } + /** @return A tile matching the provided URL, or {@code null} if none is found. */ @Nullable private Tile getTile(String url) { @@ -400,6 +433,9 @@ Tile tile = getTile(mUrl); if (tile == null) return; + // Note: This does not track all the removals, but will track the most recent one. If + // that removal is committed, it's good enough for change detection. + mPendingRemovalUrl = mUrl; mTileGroupDelegate.removeMostVisitedItem(tile); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java index 2c36264..47a98fe3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -115,6 +115,10 @@ * Called when the native library is first available. */ public static void onNativeLibraryAvailable() { + // Check if VR classes are available before trying to use them. Note that the native + // vr_shell_delegate.cc is compiled out of unsupported platforms (like x86). + VrClassesWrapper wrapper = getVrClassesWrapper(); + if (wrapper == null) return; nativeOnLibraryAvailable(); } @@ -234,7 +238,9 @@ if (!LibraryLoader.isInitialized()) return null; // Note that we only support ChromeTabbedActivity for now. if (activity == null || !(activity instanceof ChromeTabbedActivity)) return null; - sInstance = new VrShellDelegate((ChromeActivity) activity); + VrClassesWrapper wrapper = getVrClassesWrapper(); + if (wrapper == null) return null; + sInstance = new VrShellDelegate((ChromeActivity) activity, wrapper); return sInstance; } @@ -308,9 +314,9 @@ return ChromeFeatureList.isEnabled(ChromeFeatureList.VR_SHELL); } - private VrShellDelegate(ChromeActivity activity) { + private VrShellDelegate(ChromeActivity activity, VrClassesWrapper wrapper) { mActivity = activity; - mVrClassesWrapper = createVrClassesWrapper(); + mVrClassesWrapper = wrapper; updateVrSupportLevel(); mNativeVrShellDelegate = nativeInit(); Choreographer choreographer = Choreographer.getInstance();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java index c84d09a..1bf6755 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java
@@ -440,6 +440,11 @@ return mTabModelSelector.getCurrentTab(); } + @Override + public boolean isVisible() { + return mCurrentState != SHEET_STATE_PEEK; + } + /** * Determines if a touch event is inside the toolbar. This assumes the toolbar is the full * width of the screen and that the toolbar is at the top of the bottom sheet.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java index a53220b..4b7da81 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -431,6 +431,12 @@ }); mMostVisitedSites.setTileSuggestions( new String[] {}, new String[] {}, new String[] {}, new int[] {}); + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + ntpView.getTileGroup().onSwitchToForeground(); // Force the tiles to be refreshed. + } + }); CriteriaHelper.pollUiThread(new Criteria("The tile grid was not updated.") { @Override public boolean isSatisfied() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java index 4523fbdc..ca48343 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
@@ -233,6 +233,11 @@ public void addDestructionObserver(DestructionObserver destructionObserver) {} @Override + public boolean isVisible() { + return true; + } + + @Override public SuggestionsMetricsReporter getMetricsReporter() { return mSuggestionsMetricsReporter; }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupTest.java index 67685d9..998386f 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupTest.java
@@ -171,6 +171,44 @@ } @Test + public void testTileLoadingWhenVisibleNotBlockedForInit() { + SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class); + when(uiDelegate.isVisible()).thenReturn(true); + TileGroup tileGroup = new TileGroup(RuntimeEnvironment.application, uiDelegate, + mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver, + mock(OfflinePageBridge.class), TILE_TITLE_LINES); + tileGroup.startObserving(MAX_TILES_TO_FETCH); + + notifyTileUrlsAvailable(URLS); + + // Because it's the first load, we accept the incoming tiles and refresh the view. + verify(mTileGroupObserver).onTileDataChanged(); + } + + @Test + public void testTileLoadingWhenVisibleBlocked() { + SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class); + when(uiDelegate.isVisible()).thenReturn(true); + TileGroup tileGroup = new TileGroup(RuntimeEnvironment.application, uiDelegate, + mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver, + mock(OfflinePageBridge.class), TILE_TITLE_LINES); + tileGroup.startObserving(MAX_TILES_TO_FETCH); + + notifyTileUrlsAvailable(URLS); + reset(mTileGroupObserver); + notifyTileUrlsAvailable(URLS[0]); + + // Even though the data changed, the notification should not happen because we want to not + // show changes to UI elements currently visible + verify(mTileGroupObserver, never()).onTileDataChanged(); + + // Simulating a switch from background to foreground should force the tilegrid to load the + // new data. + tileGroup.onSwitchToForeground(); + verify(mTileGroupObserver).onTileDataChanged(); + } + + @Test public void testRenderTileView() { TileGroup tileGroup = new TileGroup(RuntimeEnvironment.application, mock(SuggestionsUiDelegate.class),
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 12e6eb4..2517037b 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1483,6 +1483,7 @@ "//components/policy:generated", "//components/policy/core/browser", "//components/policy/proto", + "//components/precache/core:proto", "//components/prefs:prefs", "//components/previews/core", "//components/profile_metrics",
diff --git a/chrome/browser/extensions/api/metrics_private/OWNERS b/chrome/browser/extensions/api/metrics_private/OWNERS index feb8271..816cc8b5 100644 --- a/chrome/browser/extensions/api/metrics_private/OWNERS +++ b/chrome/browser/extensions/api/metrics_private/OWNERS
@@ -1,2 +1,4 @@ asvitkine@chromium.org isherman@chromium.org + +# COMPONENT: Internals>Metrics
diff --git a/chrome/browser/importer/OWNERS b/chrome/browser/importer/OWNERS index 91abb3b3..559bfd3b 100644 --- a/chrome/browser/importer/OWNERS +++ b/chrome/browser/importer/OWNERS
@@ -1,2 +1,4 @@ gab@chromium.org isherman@chromium.org + +# COMPONENT: UI>Browser>Import
diff --git a/chrome/browser/net/chrome_network_delegate_unittest.cc b/chrome/browser/net/chrome_network_delegate_unittest.cc index edecbe6a..8a08c72 100644 --- a/chrome/browser/net/chrome_network_delegate_unittest.cc +++ b/chrome/browser/net/chrome_network_delegate_unittest.cc
@@ -235,6 +235,55 @@ fake_aggregator.off_the_record_rx_bytes()); } +TEST_F(ChromeNetworkDelegateTest, HttpRequestCompletionErrorCodes) { + Initialize(); + + const struct { + const GURL url; + int net_error; + bool is_main_frame; + int expected_sample_bucket; + int expected_request_completion_count; + int expected_request_completion_main_frame_count; + } kTests[] = { + {GURL("http://example.com"), net::OK, true, std::abs(net::OK), 1, 1}, + {GURL("http://example.com"), net::ERR_ABORTED, true, + std::abs(net::ERR_ABORTED), 1, 1}, + {GURL("http://example.com"), net::OK, false, std::abs(net::OK), 1, 0}, + {GURL("https://example.com"), net::OK, true, std::abs(net::OK), 0, 0}, + }; + + const char kHttpRequestCompletionErrorCode[] = + "Net.HttpRequestCompletionErrorCodes"; + const char kHttpRequestCompletionErrorCodeMainFrame[] = + "Net.HttpRequestCompletionErrorCodes.MainFrame"; + + for (const auto& test : kTests) { + base::HistogramTester histograms; + + net::TestDelegate test_delegate; + std::unique_ptr<net::URLRequest> request(context()->CreateRequest( + test.url, net::DEFAULT_PRIORITY, &test_delegate)); + if (test.is_main_frame) { + request->SetLoadFlags(request->load_flags() | + net::LOAD_MAIN_FRAME_DEPRECATED); + } + network_delegate()->NotifyCompleted(request.get(), false, test.net_error); + + histograms.ExpectTotalCount(kHttpRequestCompletionErrorCode, + test.expected_request_completion_count); + histograms.ExpectUniqueSample(kHttpRequestCompletionErrorCode, + test.expected_sample_bucket, + test.expected_request_completion_count); + histograms.ExpectTotalCount( + kHttpRequestCompletionErrorCodeMainFrame, + test.expected_request_completion_main_frame_count); + histograms.ExpectUniqueSample( + kHttpRequestCompletionErrorCodeMainFrame, test.expected_sample_bucket, + test.expected_request_completion_main_frame_count); + } +} + class ChromeNetworkDelegatePolicyTest : public testing::Test { public: ChromeNetworkDelegatePolicyTest()
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc index f25f57d7..b3e5453 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -21,6 +21,7 @@ #include "chrome/browser/profiles/profile.h" #include "components/history/core/browser/history_database.h" #include "components/history/core/browser/history_service.h" +#include "components/history/core/browser/url_utils.h" #include "components/mime_util/mime_util.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/resource_request_info.h" @@ -503,6 +504,7 @@ auto host_data_map = base::MakeUnique<PrefetchDataMap>(); auto url_redirect_data_map = base::MakeUnique<RedirectDataMap>(); auto host_redirect_data_map = base::MakeUnique<RedirectDataMap>(); + auto manifest_data_map = base::MakeUnique<ManifestDataMap>(); // Get raw pointers to pass to the first task. Ownership of the unique_ptrs // will be passed to the reply task. @@ -510,16 +512,18 @@ auto* host_data_map_ptr = host_data_map.get(); auto* url_redirect_data_map_ptr = url_redirect_data_map.get(); auto* host_redirect_data_map_ptr = host_redirect_data_map.get(); + auto* manifest_data_map_ptr = manifest_data_map.get(); BrowserThread::PostTaskAndReply( BrowserThread::DB, FROM_HERE, base::Bind(&ResourcePrefetchPredictorTables::GetAllData, tables_, url_data_map_ptr, host_data_map_ptr, url_redirect_data_map_ptr, - host_redirect_data_map_ptr), + host_redirect_data_map_ptr, manifest_data_map_ptr), base::Bind(&ResourcePrefetchPredictor::CreateCaches, AsWeakPtr(), base::Passed(&url_data_map), base::Passed(&host_data_map), base::Passed(&url_redirect_data_map), - base::Passed(&host_redirect_data_map))); + base::Passed(&host_redirect_data_map), + base::Passed(&manifest_data_map))); } void ResourcePrefetchPredictor::RecordURLRequest( @@ -860,7 +864,8 @@ std::unique_ptr<PrefetchDataMap> url_data_map, std::unique_ptr<PrefetchDataMap> host_data_map, std::unique_ptr<RedirectDataMap> url_redirect_data_map, - std::unique_ptr<RedirectDataMap> host_redirect_data_map) { + std::unique_ptr<RedirectDataMap> host_redirect_data_map, + std::unique_ptr<ManifestDataMap> manifest_data_map) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_EQ(INITIALIZING, initialization_state_); @@ -868,12 +873,14 @@ DCHECK(!host_table_cache_); DCHECK(!url_redirect_table_cache_); DCHECK(!host_redirect_table_cache_); + DCHECK(!manifest_table_cache_); DCHECK(inflight_navigations_.empty()); url_table_cache_ = std::move(url_data_map); host_table_cache_ = std::move(host_data_map); url_redirect_table_cache_ = std::move(url_redirect_data_map); host_redirect_table_cache_ = std::move(host_redirect_data_map); + manifest_table_cache_ = std::move(manifest_data_map); ConnectToHistoryService(); } @@ -943,6 +950,7 @@ host_table_cache_->clear(); url_redirect_table_cache_->clear(); host_redirect_table_cache_->clear(); + manifest_table_cache_->clear(); BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, base::Bind(&ResourcePrefetchPredictorTables::DeleteAllData, tables_)); @@ -953,6 +961,7 @@ // in the cache. std::vector<std::string> urls_to_delete, hosts_to_delete; std::vector<std::string> url_redirects_to_delete, host_redirects_to_delete; + std::vector<std::string> manifest_hosts_to_delete; for (const auto& it : urls) { const std::string& url_spec = it.url().spec(); @@ -978,6 +987,13 @@ host_redirects_to_delete.push_back(host); host_redirect_table_cache_->erase(host); } + + std::string manifest_host = history::HostForTopHosts(it.url()); + if (manifest_table_cache_->find(manifest_host) != + manifest_table_cache_->end()) { + manifest_hosts_to_delete.push_back(manifest_host); + manifest_table_cache_->erase(manifest_host); + } } if (!urls_to_delete.empty() || !hosts_to_delete.empty()) { @@ -993,6 +1009,13 @@ base::Bind(&ResourcePrefetchPredictorTables::DeleteRedirectData, tables_, url_redirects_to_delete, host_redirects_to_delete)); } + + if (!manifest_hosts_to_delete.empty()) { + BrowserThread::PostTask( + BrowserThread::DB, FROM_HERE, + base::Bind(&ResourcePrefetchPredictorTables::DeleteManifestData, + tables_, manifest_hosts_to_delete)); + } } void ResourcePrefetchPredictor::RemoveOldestEntryInPrefetchDataMap(
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h index 1bfdf871..291da28 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor.h +++ b/chrome/browser/predictors/resource_prefetch_predictor.h
@@ -265,6 +265,7 @@ }; typedef ResourcePrefetchPredictorTables::PrefetchDataMap PrefetchDataMap; typedef ResourcePrefetchPredictorTables::RedirectDataMap RedirectDataMap; + typedef ResourcePrefetchPredictorTables::ManifestDataMap ManifestDataMap; typedef std::map<NavigationID, std::unique_ptr<PageRequestSummary>> NavigationMap; @@ -323,7 +324,8 @@ void CreateCaches(std::unique_ptr<PrefetchDataMap> url_data_map, std::unique_ptr<PrefetchDataMap> host_data_map, std::unique_ptr<RedirectDataMap> url_redirect_data_map, - std::unique_ptr<RedirectDataMap> host_redirect_data_map); + std::unique_ptr<RedirectDataMap> host_redirect_data_map, + std::unique_ptr<ManifestDataMap> manifest_data_map); // Called during initialization when history is read and the predictor // database has been read. @@ -409,6 +411,7 @@ std::unique_ptr<PrefetchDataMap> host_table_cache_; std::unique_ptr<RedirectDataMap> url_redirect_table_cache_; std::unique_ptr<RedirectDataMap> host_redirect_table_cache_; + std::unique_ptr<ManifestDataMap> manifest_table_cache_; std::map<GURL, base::TimeTicks> inflight_prefetches_; NavigationMap inflight_navigations_;
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables.cc b/chrome/browser/predictors/resource_prefetch_predictor_tables.cc index 7d5515e..ae83334 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor_tables.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor_tables.cc
@@ -24,6 +24,7 @@ const char kHostResourceTableName[] = "resource_prefetch_predictor_host"; const char kHostRedirectTableName[] = "resource_prefetch_predictor_host_redirect"; +const char kManifestTableName[] = "resource_prefetch_predictor_manifest"; const char kCreateGlobalMetadataStatementTemplate[] = "CREATE TABLE %s ( " @@ -112,7 +113,8 @@ PrefetchDataMap* url_data_map, PrefetchDataMap* host_data_map, RedirectDataMap* url_redirect_data_map, - RedirectDataMap* host_redirect_data_map) { + RedirectDataMap* host_redirect_data_map, + ManifestDataMap* manifest_map) { TRACE_EVENT0("browser", "ResourcePrefetchPredictor::GetAllData"); DCHECK_CURRENTLY_ON(BrowserThread::DB); if (CantAccessDatabase()) @@ -126,11 +128,13 @@ host_data_map->clear(); url_redirect_data_map->clear(); host_redirect_data_map->clear(); + manifest_map->clear(); GetAllResourceDataHelper(PREFETCH_KEY_TYPE_URL, url_data_map); GetAllResourceDataHelper(PREFETCH_KEY_TYPE_HOST, host_data_map); GetAllRedirectDataHelper(PREFETCH_KEY_TYPE_URL, url_redirect_data_map); GetAllRedirectDataHelper(PREFETCH_KEY_TYPE_HOST, host_redirect_data_map); + GetAllManifestDataHelper(manifest_map); } void ResourcePrefetchPredictorTables::UpdateData( @@ -168,6 +172,23 @@ DB()->CommitTransaction(); } +void ResourcePrefetchPredictorTables::UpdateManifestData( + const std::string& host, + const precache::PrecacheManifest& manifest_data) { + DCHECK_CURRENTLY_ON(BrowserThread::DB); + if (CantAccessDatabase()) + return; + + DB()->BeginTransaction(); + bool success = UpdateDataHelper( + PREFETCH_KEY_TYPE_HOST, PrefetchDataType::MANIFEST, host, manifest_data); + + if (!success) + DB()->RollbackTransaction(); + else + DB()->CommitTransaction(); +} + void ResourcePrefetchPredictorTables::DeleteResourceData( const std::vector<std::string>& urls, const std::vector<std::string>& hosts) { @@ -218,6 +239,15 @@ DeleteDataHelper(key_type, PrefetchDataType::REDIRECT, {key}); } +void ResourcePrefetchPredictorTables::DeleteManifestData( + const std::vector<std::string>& hosts) { + DCHECK_CURRENTLY_ON(BrowserThread::DB); + if (CantAccessDatabase()) + return; + + DeleteDataHelper(PREFETCH_KEY_TYPE_HOST, PrefetchDataType::MANIFEST, hosts); +} + void ResourcePrefetchPredictorTables::DeleteAllData() { DCHECK_CURRENTLY_ON(BrowserThread::DB); if (CantAccessDatabase()) @@ -226,7 +256,7 @@ sql::Statement deleter; for (const char* table_name : {kUrlResourceTableName, kUrlRedirectTableName, kHostResourceTableName, - kHostRedirectTableName}) { + kHostRedirectTableName, kManifestTableName}) { deleter.Assign(DB()->GetUniqueStatement( base::StringPrintf("DELETE FROM %s", table_name).c_str())); deleter.Run(); @@ -274,6 +304,18 @@ } } +void ResourcePrefetchPredictorTables::GetAllManifestDataHelper( + ManifestDataMap* manifest_map) { + sql::Statement manifest_reader(DB()->GetUniqueStatement( + base::StringPrintf("SELECT * FROM %s", kManifestTableName).c_str())); + + precache::PrecacheManifest data; + std::string key; + while (StepAndInitializeProtoData(&manifest_reader, &key, &data)) { + manifest_map->insert(std::make_pair(key, data)); + } +} + bool ResourcePrefetchPredictorTables::UpdateDataHelper( PrefetchKeyType key_type, PrefetchDataType data_type, @@ -367,8 +409,8 @@ if (incompatible_version) { for (const char* table_name : {kMetadataTableName, kUrlResourceTableName, kHostResourceTableName, - kUrlRedirectTableName, kHostRedirectTableName, kUrlMetadataTableName, - kHostMetadataTableName}) { + kUrlRedirectTableName, kHostRedirectTableName, kManifestTableName, + kUrlMetadataTableName, kHostMetadataTableName}) { success = success && db->Execute(base::StringPrintf("DROP TABLE IF EXISTS %s", table_name) @@ -425,7 +467,7 @@ for (const char* table_name : {kUrlResourceTableName, kHostResourceTableName, kUrlRedirectTableName, - kHostRedirectTableName}) { + kHostRedirectTableName, kManifestTableName}) { success = success && (db->DoesTableExist(table_name) || db->Execute(base::StringPrintf( @@ -468,7 +510,7 @@ PrefetchDataType data_type, TableOperationType op_type) { sql::StatementID id(__FILE__, key_type | (static_cast<int>(data_type) << 1) | - (static_cast<int>(op_type) << 2)); + (static_cast<int>(op_type) << 3)); const char* statement_template = (op_type == TableOperationType::REMOVE ? kDeleteProtoTableStatementTemplate : kInsertProtoTableStatementTemplate); @@ -487,6 +529,8 @@ return is_host ? kHostResourceTableName : kUrlResourceTableName; case PrefetchDataType::REDIRECT: return is_host ? kHostRedirectTableName : kUrlRedirectTableName; + case PrefetchDataType::MANIFEST: + return kManifestTableName; } NOTREACHED();
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables.h b/chrome/browser/predictors/resource_prefetch_predictor_tables.h index 7d95b1f..ff9c5ea 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor_tables.h +++ b/chrome/browser/predictors/resource_prefetch_predictor_tables.h
@@ -16,6 +16,7 @@ #include "chrome/browser/predictors/predictor_table_base.h" #include "chrome/browser/predictors/resource_prefetch_common.h" #include "chrome/browser/predictors/resource_prefetch_predictor.pb.h" +#include "components/precache/core/proto/precache.pb.h" namespace sql { class Statement; @@ -37,17 +38,16 @@ // - HostRedirectTable - redirects per host. class ResourcePrefetchPredictorTables : public PredictorTableBase { public: - // Map from primary key to PrefetchData for the key. typedef std::map<std::string, PrefetchData> PrefetchDataMap; - - // Map from primary key to RedirectData for the key. typedef std::map<std::string, RedirectData> RedirectDataMap; + typedef std::map<std::string, precache::PrecacheManifest> ManifestDataMap; // Returns data for all Urls and Hosts. virtual void GetAllData(PrefetchDataMap* url_data_map, PrefetchDataMap* host_data_map, RedirectDataMap* url_redirect_data_map, - RedirectDataMap* host_redirect_data_map); + RedirectDataMap* host_redirect_data_map, + ManifestDataMap* manifest_map); // Updates data for a Url and a host. If either of the |url_data| or // |host_data| or |url_redirect_data| or |host_redirect_data| has an empty @@ -60,6 +60,11 @@ const RedirectData& url_redirect_data, const RedirectData& host_redirect_data); + // Updates manifest data for the input |host|. + virtual void UpdateManifestData( + const std::string& host, + const precache::PrecacheManifest& manifest_data); + // Delete data for the input |urls| and |hosts|. virtual void DeleteResourceData(const std::vector<std::string>& urls, const std::vector<std::string>& hosts); @@ -76,6 +81,9 @@ virtual void DeleteSingleRedirectDataPoint(const std::string& key, PrefetchKeyType key_type); + // Delete data for the input |hosts|. + virtual void DeleteManifestData(const std::vector<std::string>& hosts); + // Deletes all data in all the tables. virtual void DeleteAllData(); @@ -104,7 +112,7 @@ private: // Represents the type of information that is stored in prefetch database. - enum class PrefetchDataType { RESOURCE, REDIRECT }; + enum class PrefetchDataType { RESOURCE, REDIRECT, MANIFEST }; enum class TableOperationType { INSERT, REMOVE }; @@ -116,7 +124,7 @@ // Database version. Always increment it when any change is made to the data // schema (including the .proto). - static constexpr int kDatabaseVersion = 5; + static constexpr int kDatabaseVersion = 6; // Helper functions below help perform functions on the Url and host table // using the same code. @@ -124,6 +132,8 @@ PrefetchDataMap* data_map); void GetAllRedirectDataHelper(PrefetchKeyType key_type, RedirectDataMap* redirect_map); + void GetAllManifestDataHelper(ManifestDataMap* manifest_map); + bool UpdateDataHelper(PrefetchKeyType key_type, PrefetchDataType data_type, const std::string& key,
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc index ed8db8c9..7f26eb4 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc
@@ -43,9 +43,12 @@ using PrefetchDataMap = ResourcePrefetchPredictorTables::PrefetchDataMap; using RedirectDataMap = ResourcePrefetchPredictorTables::RedirectDataMap; + using ManifestDataMap = ResourcePrefetchPredictorTables::ManifestDataMap; private: - // Initializes the tables, |test_url_data_| and |test_host_data_|. + // Initializes the tables, |test_url_data_|, |test_host_data_|, + // |test_url_redirect_data_|, |test_host_redirect_data_| and + // |test_manifest_data_|. void InitializeSampleData(); // Checks that the input PrefetchData are the same, although the resources @@ -62,13 +65,23 @@ void TestRedirectsAreEqual(const std::vector<RedirectStat>& lhs, const std::vector<RedirectStat>& rhs) const; + // Checks that the input ManifestData are the same, although the resources + // can be in different order. + void TestManifestDataAreEqual(const ManifestDataMap& lhs, + const ManifestDataMap& rhs) const; + void TestManifestResourcesAreEqual( + const std::vector<precache::PrecacheResource>& lhs, + const std::vector<precache::PrecacheResource>& rhs) const; + void AddKey(PrefetchDataMap* m, const std::string& key) const; void AddKey(RedirectDataMap* m, const std::string& key) const; + void AddKey(ManifestDataMap* m, const std::string& key) const; PrefetchDataMap test_url_data_; PrefetchDataMap test_host_data_; RedirectDataMap test_url_redirect_data_; RedirectDataMap test_host_redirect_data_; + ManifestDataMap test_manifest_data_; }; class ResourcePrefetchPredictorTablesReopenTest @@ -106,38 +119,46 @@ void ResourcePrefetchPredictorTablesTest::TestGetAllData() { PrefetchDataMap actual_url_data, actual_host_data; RedirectDataMap actual_url_redirect_data, actual_host_redirect_data; + ManifestDataMap actual_manifest_data; tables_->GetAllData(&actual_url_data, &actual_host_data, - &actual_url_redirect_data, &actual_host_redirect_data); + &actual_url_redirect_data, &actual_host_redirect_data, + &actual_manifest_data); TestPrefetchDataAreEqual(test_url_data_, actual_url_data); TestPrefetchDataAreEqual(test_host_data_, actual_host_data); TestRedirectDataAreEqual(test_url_redirect_data_, actual_url_redirect_data); TestRedirectDataAreEqual(test_host_redirect_data_, actual_host_redirect_data); + TestManifestDataAreEqual(test_manifest_data_, actual_manifest_data); } void ResourcePrefetchPredictorTablesTest::TestDeleteData() { std::vector<std::string> urls_to_delete = {"http://www.google.com", "http://www.yahoo.com"}; std::vector<std::string> hosts_to_delete = {"www.yahoo.com"}; - tables_->DeleteResourceData(urls_to_delete, hosts_to_delete); urls_to_delete = {"http://fb.com/google", "http://google.com"}; hosts_to_delete = {"microsoft.com"}; - tables_->DeleteRedirectData(urls_to_delete, hosts_to_delete); + hosts_to_delete = {"en.wikipedia.org"}; + tables_->DeleteManifestData(hosts_to_delete); + PrefetchDataMap actual_url_data, actual_host_data; RedirectDataMap actual_url_redirect_data, actual_host_redirect_data; + ManifestDataMap actual_manifest_data; tables_->GetAllData(&actual_url_data, &actual_host_data, - &actual_url_redirect_data, &actual_host_redirect_data); + &actual_url_redirect_data, &actual_host_redirect_data, + &actual_manifest_data); PrefetchDataMap expected_url_data, expected_host_data; RedirectDataMap expected_url_redirect_data, expected_host_redirect_data; + ManifestDataMap expected_manifest_data; AddKey(&expected_url_data, "http://www.reddit.com"); AddKey(&expected_host_data, "www.facebook.com"); AddKey(&expected_url_redirect_data, "http://nyt.com"); AddKey(&expected_host_redirect_data, "bbc.com"); + AddKey(&expected_manifest_data, "youtube.com"); TestPrefetchDataAreEqual(expected_url_data, actual_url_data); TestPrefetchDataAreEqual(expected_host_data, actual_host_data); @@ -145,6 +166,7 @@ actual_url_redirect_data); TestRedirectDataAreEqual(expected_host_redirect_data, actual_host_redirect_data); + TestManifestDataAreEqual(expected_manifest_data, actual_manifest_data); } void ResourcePrefetchPredictorTablesTest::TestDeleteSingleDataPoint() { @@ -154,8 +176,10 @@ PrefetchDataMap actual_url_data, actual_host_data; RedirectDataMap actual_url_redirect_data, actual_host_redirect_data; + ManifestDataMap actual_manifest_data; tables_->GetAllData(&actual_url_data, &actual_host_data, - &actual_url_redirect_data, &actual_host_redirect_data); + &actual_url_redirect_data, &actual_host_redirect_data, + &actual_manifest_data); PrefetchDataMap expected_url_data; AddKey(&expected_url_data, "http://www.google.com"); @@ -173,8 +197,10 @@ actual_host_data.clear(); actual_url_redirect_data.clear(); actual_host_redirect_data.clear(); + actual_manifest_data.clear(); tables_->GetAllData(&actual_url_data, &actual_host_data, - &actual_url_redirect_data, &actual_host_redirect_data); + &actual_url_redirect_data, &actual_host_redirect_data, + &actual_manifest_data); PrefetchDataMap expected_host_data; AddKey(&expected_host_data, "www.yahoo.com"); @@ -191,8 +217,10 @@ actual_host_data.clear(); actual_url_redirect_data.clear(); actual_host_redirect_data.clear(); + actual_manifest_data.clear(); tables_->GetAllData(&actual_url_data, &actual_host_data, - &actual_url_redirect_data, &actual_host_redirect_data); + &actual_url_redirect_data, &actual_host_redirect_data, + &actual_manifest_data); RedirectDataMap expected_url_redirect_data; AddKey(&expected_url_redirect_data, "http://fb.com/google"); @@ -210,8 +238,10 @@ actual_host_data.clear(); actual_url_redirect_data.clear(); actual_host_redirect_data.clear(); + actual_manifest_data.clear(); tables_->GetAllData(&actual_url_data, &actual_host_data, - &actual_url_redirect_data, &actual_host_redirect_data); + &actual_url_redirect_data, &actual_host_redirect_data, + &actual_manifest_data); RedirectDataMap expected_host_redirect_data; AddKey(&expected_host_redirect_data, "microsoft.com"); @@ -257,13 +287,22 @@ tables_->UpdateData(google, yahoo, facebook, microsoft); + precache::PrecacheManifest theverge; + InitializePrecacheResource(theverge.add_resource(), + "https://www.theverge.com/main.js", 0.7); + + tables_->UpdateManifestData("theverge.com", theverge); + PrefetchDataMap actual_url_data, actual_host_data; RedirectDataMap actual_url_redirect_data, actual_host_redirect_data; + ManifestDataMap actual_manifest_data; tables_->GetAllData(&actual_url_data, &actual_host_data, - &actual_url_redirect_data, &actual_host_redirect_data); + &actual_url_redirect_data, &actual_host_redirect_data, + &actual_manifest_data); PrefetchDataMap expected_url_data, expected_host_data; RedirectDataMap expected_url_redirect_data, expected_host_redirect_data; + ManifestDataMap expected_manifest_data; AddKey(&expected_url_data, "http://www.reddit.com"); AddKey(&expected_url_data, "http://www.yahoo.com"); expected_url_data.insert(std::make_pair("http://www.google.com", google)); @@ -280,12 +319,17 @@ expected_host_redirect_data.insert( std::make_pair("microsoft.com", microsoft)); + AddKey(&expected_manifest_data, "youtube.com"); + AddKey(&expected_manifest_data, "en.wikipedia.org"); + expected_manifest_data.insert(std::make_pair("theverge.com", theverge)); + TestPrefetchDataAreEqual(expected_url_data, actual_url_data); TestPrefetchDataAreEqual(expected_host_data, actual_host_data); TestRedirectDataAreEqual(expected_url_redirect_data, actual_url_redirect_data); TestRedirectDataAreEqual(expected_host_redirect_data, actual_host_redirect_data); + TestManifestDataAreEqual(expected_manifest_data, actual_manifest_data); } void ResourcePrefetchPredictorTablesTest::TestDeleteAllData() { @@ -293,12 +337,15 @@ PrefetchDataMap actual_url_data, actual_host_data; RedirectDataMap actual_url_redirect_data, actual_host_redirect_data; + ManifestDataMap actual_manifest_data; tables_->GetAllData(&actual_url_data, &actual_host_data, - &actual_url_redirect_data, &actual_host_redirect_data); + &actual_url_redirect_data, &actual_host_redirect_data, + &actual_manifest_data); EXPECT_TRUE(actual_url_data.empty()); EXPECT_TRUE(actual_host_data.empty()); EXPECT_TRUE(actual_url_redirect_data.empty()); EXPECT_TRUE(actual_host_redirect_data.empty()); + EXPECT_TRUE(actual_manifest_data.empty()); } void ResourcePrefetchPredictorTablesTest::TestPrefetchDataAreEqual( @@ -389,6 +436,48 @@ EXPECT_TRUE(lhs_index.empty()); } +void ResourcePrefetchPredictorTablesTest::TestManifestDataAreEqual( + const ManifestDataMap& lhs, + const ManifestDataMap& rhs) const { + EXPECT_EQ(lhs.size(), rhs.size()); + + for (const auto& m : rhs) { + const auto lhs_it = lhs.find(m.first); + ASSERT_TRUE(lhs_it != lhs.end()) << m.first; + EXPECT_EQ(lhs_it->second.id().id(), m.second.id().id()); + + std::vector<precache::PrecacheResource> lhs_resources( + lhs_it->second.resource().begin(), lhs_it->second.resource().end()); + std::vector<precache::PrecacheResource> rhs_resources( + m.second.resource().begin(), m.second.resource().end()); + + TestManifestResourcesAreEqual(lhs_resources, rhs_resources); + } +} + +void ResourcePrefetchPredictorTablesTest::TestManifestResourcesAreEqual( + const std::vector<precache::PrecacheResource>& lhs, + const std::vector<precache::PrecacheResource>& rhs) const { + EXPECT_EQ(lhs.size(), rhs.size()); + + std::map<std::string, precache::PrecacheResource> lhs_index; + // Repeated resources are not allowed. + for (const auto& r : lhs) + EXPECT_TRUE(lhs_index.insert(std::make_pair(r.url(), r)).second); + + for (const auto& r : rhs) { + auto lhs_it = lhs_index.find(r.url()); + if (lhs_it != lhs_index.end()) { + EXPECT_EQ(r, lhs_it->second); + lhs_index.erase(lhs_it); + } else { + ADD_FAILURE() << r.url(); + } + } + + EXPECT_TRUE(lhs_index.empty()); +} + void ResourcePrefetchPredictorTablesTest::AddKey(PrefetchDataMap* m, const std::string& key) const { PrefetchDataMap::const_iterator it = test_url_data_.find(key); @@ -413,6 +502,13 @@ m->insert(*it); } +void ResourcePrefetchPredictorTablesTest::AddKey(ManifestDataMap* m, + const std::string& key) const { + auto it = test_manifest_data_.find(key); + ASSERT_TRUE(it != test_manifest_data_.end()); + m->insert(*it); +} + void ResourcePrefetchPredictorTablesTest::InitializeSampleData() { PrefetchData empty_resource_data; RedirectData empty_redirect_data; @@ -553,6 +649,26 @@ tables_->UpdateData(empty_resource_data, empty_resource_data, empty_redirect_data, microsoft); } + + { // Manifest data. + precache::PrecacheManifest wikipedia; + InitializePrecacheResource(wikipedia.add_resource(), + "https://en.wikipedia.org/script.js", 0.7); + InitializePrecacheResource(wikipedia.add_resource(), + "https://en.wikipedia.org/image.png", 0.3); + + precache::PrecacheManifest youtube; + InitializePrecacheResource(youtube.add_resource(), + "https://youtube.com/photo.jpg", 0.5); + InitializePrecacheResource(youtube.add_resource(), + "https://youtube.com/base.js", 0.2); + + test_manifest_data_.clear(); + test_manifest_data_.insert(std::make_pair("en.wikipedia.org", wikipedia)); + test_manifest_data_.insert(std::make_pair("youtube.com", youtube)); + tables_->UpdateManifestData("en.wikipedia.org", wikipedia); + tables_->UpdateManifestData("youtube.com", youtube); + } } void ResourcePrefetchPredictorTablesTest::ReopenDatabase() { @@ -649,12 +765,14 @@ PrefetchDataMap url_data, host_data; RedirectDataMap url_redirect_data, host_redirect_data; + ManifestDataMap manifest_data; tables_->GetAllData(&url_data, &host_data, &url_redirect_data, - &host_redirect_data); + &host_redirect_data, &manifest_data); EXPECT_TRUE(url_data.empty()); EXPECT_TRUE(host_data.empty()); EXPECT_TRUE(url_redirect_data.empty()); EXPECT_TRUE(host_redirect_data.empty()); + EXPECT_TRUE(manifest_data.empty()); } TEST_F(ResourcePrefetchPredictorTablesReopenTest, GetAllData) {
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc b/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc index 805d04b..9a47e0c 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/predictors/resource_prefetch_predictor_test_util.h" +#include <limits> + #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h" namespace predictors { @@ -44,6 +46,13 @@ redirect->set_consecutive_misses(consecutive_misses); } +void InitializePrecacheResource(precache::PrecacheResource* resource, + const std::string& url, + double weight_ratio) { + resource->set_url(url); + resource->set_weight_ratio(weight_ratio); +} + PrefetchData CreatePrefetchData(const std::string& primary_key, uint64_t last_visit_time) { PrefetchData data; @@ -220,3 +229,38 @@ } } // namespace predictors + +namespace precache { + +std::ostream& operator<<(std::ostream& os, const PrecacheManifest& manifest) { + os << "[" << manifest.id().id() << "]" << std::endl; + for (const PrecacheResource& resource : manifest.resource()) + os << "\t\t" << resource << std::endl; + return os; +} + +std::ostream& operator<<(std::ostream& os, const PrecacheResource& resource) { + return os << "[" << resource.url() << "," << resource.top_host_name() << "," + << resource.weight_ratio() << "," << resource.weight() << "]"; +} + +bool operator==(const PrecacheManifest& lhs, const PrecacheManifest& rhs) { + bool equal = lhs.id().id() == rhs.id().id() && + lhs.resource_size() == rhs.resource_size(); + + if (!equal) + return false; + + for (int i = 0; i < lhs.resource_size(); ++i) + equal = equal && lhs.resource(i) == rhs.resource(i); + + return equal; +} + +bool operator==(const PrecacheResource& lhs, const PrecacheResource& rhs) { + return lhs.url() == rhs.url() && + std::fabs(lhs.weight_ratio() - rhs.weight_ratio()) < + std::numeric_limits<double>::epsilon(); +} + +} // namespace precache
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_test_util.h b/chrome/browser/predictors/resource_prefetch_predictor_test_util.h index 4f12990..eacc669 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor_test_util.h +++ b/chrome/browser/predictors/resource_prefetch_predictor_test_util.h
@@ -30,6 +30,10 @@ int number_of_misses, int consecutive_misses); +void InitializePrecacheResource(precache::PrecacheResource* resource, + const std::string& url, + double weight_ratio); + PrefetchData CreatePrefetchData(const std::string& primary_key, uint64_t last_visit_time = 0); RedirectData CreateRedirectData(const std::string& primary_key, @@ -80,4 +84,16 @@ } // namespace predictors +namespace precache { + +std::ostream& operator<<(std::ostream& stream, + const PrecacheManifest& manifest); +std::ostream& operator<<(std::ostream& stream, + const PrecacheResource& resource); + +bool operator==(const PrecacheManifest& lhs, const PrecacheManifest& rhs); +bool operator==(const PrecacheResource& lhs, const PrecacheResource& rhs); + +} // namespace precache + #endif // CHROME_BROWSER_PREDICTORS_RESOURCE_PREFETCH_PREDICTOR_TEST_UTIL_H_
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc index 0da9081..1e4e487 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
@@ -41,6 +41,7 @@ using PageRequestSummary = ResourcePrefetchPredictor::PageRequestSummary; using PrefetchDataMap = ResourcePrefetchPredictorTables::PrefetchDataMap; using RedirectDataMap = ResourcePrefetchPredictorTables::RedirectDataMap; +using ManifestDataMap = ResourcePrefetchPredictorTables::ManifestDataMap; scoped_refptr<net::HttpResponseHeaders> MakeResponseHeaders( const char* headers) { @@ -130,11 +131,12 @@ public: MockResourcePrefetchPredictorTables() { } - MOCK_METHOD4(GetAllData, + MOCK_METHOD5(GetAllData, void(PrefetchDataMap* url_data_map, PrefetchDataMap* host_data_map, RedirectDataMap* url_redirect_data_map, - RedirectDataMap* host_redirect_data_map)); + RedirectDataMap* host_redirect_data_map, + ManifestDataMap* manifest_data_map)); MOCK_METHOD4(UpdateData, void(const PrefetchData& url_data, const PrefetchData& host_data, @@ -257,6 +259,7 @@ PrefetchDataMap test_host_data_; RedirectDataMap test_url_redirect_data_; RedirectDataMap test_host_redirect_data_; + ManifestDataMap test_manifest_data_; PrefetchData empty_resource_data_; RedirectData empty_redirect_data_; @@ -293,7 +296,8 @@ GetAllData(Pointee(ContainerEq(PrefetchDataMap())), Pointee(ContainerEq(PrefetchDataMap())), Pointee(ContainerEq(RedirectDataMap())), - Pointee(ContainerEq(RedirectDataMap())))); + Pointee(ContainerEq(RedirectDataMap())), + Pointee(ContainerEq(ManifestDataMap())))); InitializePredictor(); EXPECT_TRUE(predictor_->inflight_navigations_.empty()); EXPECT_EQ(predictor_->initialization_state_, @@ -501,11 +505,13 @@ GetAllData(Pointee(ContainerEq(PrefetchDataMap())), Pointee(ContainerEq(PrefetchDataMap())), Pointee(ContainerEq(RedirectDataMap())), - Pointee(ContainerEq(RedirectDataMap())))) + Pointee(ContainerEq(RedirectDataMap())), + Pointee(ContainerEq(ManifestDataMap())))) .WillOnce(DoAll(SetArgPointee<0>(test_url_data_), SetArgPointee<1>(test_host_data_), SetArgPointee<2>(test_url_redirect_data_), - SetArgPointee<3>(test_host_redirect_data_))); + SetArgPointee<3>(test_host_redirect_data_), + SetArgPointee<4>(test_manifest_data_))); ResetPredictor(); InitializePredictor(); @@ -519,6 +525,7 @@ EXPECT_EQ(test_host_data_, *predictor_->host_table_cache_); EXPECT_EQ(test_url_redirect_data_, *predictor_->url_redirect_table_cache_); EXPECT_EQ(test_host_redirect_data_, *predictor_->host_redirect_table_cache_); + EXPECT_EQ(test_manifest_data_, *predictor_->manifest_table_cache_); } // Single navigation but history count is low, so should not record. @@ -667,7 +674,8 @@ GetAllData(Pointee(ContainerEq(PrefetchDataMap())), Pointee(ContainerEq(PrefetchDataMap())), Pointee(ContainerEq(RedirectDataMap())), - Pointee(ContainerEq(RedirectDataMap())))) + Pointee(ContainerEq(RedirectDataMap())), + Pointee(ContainerEq(ManifestDataMap())))) .WillOnce(DoAll(SetArgPointee<0>(test_url_data_), SetArgPointee<1>(test_host_data_))); ResetPredictor(); @@ -772,7 +780,8 @@ GetAllData(Pointee(ContainerEq(PrefetchDataMap())), Pointee(ContainerEq(PrefetchDataMap())), Pointee(ContainerEq(RedirectDataMap())), - Pointee(ContainerEq(RedirectDataMap())))) + Pointee(ContainerEq(RedirectDataMap())), + Pointee(ContainerEq(ManifestDataMap())))) .WillOnce(DoAll(SetArgPointee<0>(test_url_data_), SetArgPointee<1>(test_host_data_))); ResetPredictor(); @@ -892,7 +901,8 @@ GetAllData(Pointee(ContainerEq(PrefetchDataMap())), Pointee(ContainerEq(PrefetchDataMap())), Pointee(ContainerEq(RedirectDataMap())), - Pointee(ContainerEq(RedirectDataMap())))) + Pointee(ContainerEq(RedirectDataMap())), + Pointee(ContainerEq(ManifestDataMap())))) .WillOnce(DoAll(SetArgPointee<2>(test_url_redirect_data_), SetArgPointee<3>(test_host_redirect_data_))); ResetPredictor();
diff --git a/chrome/browser/resources/print_preview/previewarea/preview_area.js b/chrome/browser/resources/print_preview/previewarea/preview_area.js index ca553a7c..522995c 100644 --- a/chrome/browser/resources/print_preview/previewarea/preview_area.js +++ b/chrome/browser/resources/print_preview/previewarea/preview_area.js
@@ -602,14 +602,21 @@ }, /** - * Called when the generation of a preview fails. Shows an error message. - * @private + * Cancels the timeout so that an error message can be shown. */ - onPreviewGenerationFail_: function() { + cancelTimeout: function() { if (this.loadingTimeout_) { clearTimeout(this.loadingTimeout_); this.loadingTimeout_ = null; } + }, + + /** + * Called when the generation of a preview fails. Shows an error message. + * @private + */ + onPreviewGenerationFail_: function() { + this.cancelTimeout(); this.showMessage_(PreviewArea.MessageId_.PREVIEW_FAILED); cr.dispatchSimpleEvent( this, PreviewArea.EventType.PREVIEW_GENERATION_FAIL); @@ -622,11 +629,7 @@ * @private */ onPluginLoad_: function() { - if (this.loadingTimeout_) { - clearTimeout(this.loadingTimeout_); - this.loadingTimeout_ = null; - } - + this.cancelTimeout(); this.setOverlayVisible_(false); this.isPluginReloaded_ = true; this.dispatchPreviewGenerationDoneIfReady_();
diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js index 04fdd1d..7c0afb0 100644 --- a/chrome/browser/resources/print_preview/print_preview.js +++ b/chrome/browser/resources/print_preview/print_preview.js
@@ -957,7 +957,10 @@ */ onSettingsInvalid_: function() { this.uiState_ = PrintPreview.UiState_.ERROR; + this.isPreviewGenerationInProgress_ = false; + this.printHeader_.isPrintButtonEnabled = false; console.error('Invalid settings error reported from native layer'); + this.previewArea_.cancelTimeout(); this.previewArea_.showCustomMessage( loadTimeData.getString('invalidPrinterSettings')); },
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc index e993024..36c278ed 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -335,9 +335,8 @@ } void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitchASCII( - "enable-features", - "FillDOMInThreatDetails,ThreatDomDetailsTagAttributes<SBDomStudy"); + command_line->AppendSwitchASCII("enable-features", + "ThreatDomDetailsTagAttributes<SBDomStudy"); command_line->AppendSwitchASCII("force-fieldtrials", "SBDomStudy/SBDomGroup"); command_line->AppendSwitchASCII(
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.h b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.h index 7162a01e..39fe982 100644 --- a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.h +++ b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.h
@@ -65,6 +65,10 @@ std::unordered_map<SHA256Hash, int, SHA256HashHasher> domain_hashes_; // Other feature parameters. + // + // If you add any required feature parameters, make sure to update the field + // trial testing configuration for the "SettingsResetPrompt" feature in + // src/testing/variations/fieldtrial_testing_config.json base::TimeDelta delay_before_prompt_; int prompt_wave_ = 0; base::TimeDelta time_between_prompts_;
diff --git a/chrome/browser/safe_browsing/threat_details.cc b/chrome/browser/safe_browsing/threat_details.cc index 6549a63..50a818c 100644 --- a/chrome/browser/safe_browsing/threat_details.cc +++ b/chrome/browser/safe_browsing/threat_details.cc
@@ -39,9 +39,6 @@ // static ThreatDetailsFactory* ThreatDetails::factory_ = NULL; -const base::Feature kFillDOMInThreatDetails{"FillDOMInThreatDetails", - base::FEATURE_DISABLED_BY_DEFAULT}; - namespace { typedef std::unordered_set<std::string> StringSet; @@ -286,10 +283,6 @@ const int parent_element_node_id, const std::vector<AttributeNameValue>& attributes, const ClientSafeBrowsingReportRequest::Resource* resource) { - if (!base::FeatureList::IsEnabled(kFillDOMInThreatDetails)) { - return; - } - // Create the element. It should not exist already since this function should // only be called once for each element. const std::string element_key =
diff --git a/chrome/browser/safe_browsing/threat_details.h b/chrome/browser/safe_browsing/threat_details.h index 55a501e7..d1a8aec7 100644 --- a/chrome/browser/safe_browsing/threat_details.h +++ b/chrome/browser/safe_browsing/threat_details.h
@@ -17,7 +17,6 @@ #include <vector> #include "base/containers/hash_tables.h" -#include "base/feature_list.h" #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/ref_counted.h" @@ -37,8 +36,6 @@ namespace safe_browsing { -extern const base::Feature kFillDOMInThreatDetails; - // Maps a URL to its Resource. class ThreatDetailsCacheCollector; class ThreatDetailsRedirectsCollector;
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc index 1122c129..ceea2128 100644 --- a/chrome/browser/safe_browsing/threat_details_unittest.cc +++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -11,7 +11,6 @@ #include "base/pickle.h" #include "base/run_loop.h" #include "base/test/histogram_tester.h" -#include "base/test/scoped_feature_list.h" #include "base/time/time.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/profiles/profile.h" @@ -213,9 +212,6 @@ ChromeRenderViewHostTestHarness::SetUp(); ASSERT_TRUE(profile()->CreateHistoryService(true /* delete_file */, false /* no_db */)); - - feature_list_.reset(new base::test::ScopedFeatureList); - feature_list_->InitAndEnableFeature(kFillDOMInThreatDetails); } std::string WaitForSerializedReport(ThreatDetails* report, @@ -371,7 +367,6 @@ } scoped_refptr<MockSafeBrowsingUIManager> ui_manager_; - std::unique_ptr<base::test::ScopedFeatureList> feature_list_; }; // Tests creating a simple threat report of a malware URL.
diff --git a/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc b/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc index 483c495..9ad194b 100644 --- a/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc +++ b/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc
@@ -33,8 +33,8 @@ ~TwoClientSessionsSyncTest() override {} void WaitForWindowsInForeignSession(int index, ScopedWindowMap windows) { - std::vector<ScopedWindowMap> expected_windows; - expected_windows.push_back(std::move(windows)); + std::vector<ScopedWindowMap> expected_windows(1); + expected_windows[0] = std::move(windows); EXPECT_TRUE(ForeignSessionsMatchChecker(index, expected_windows).Wait()); }
diff --git a/chrome/browser/themes/OWNERS b/chrome/browser/themes/OWNERS index 998f514..328894a 100644 --- a/chrome/browser/themes/OWNERS +++ b/chrome/browser/themes/OWNERS
@@ -1,2 +1,4 @@ estade@chromium.org pkotwicz@chromium.org + +# COMPONENT: UI>Browser>Themes
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 8080d56..83d5e5e 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1184,6 +1184,7 @@ "//components/proximity_auth/webui", "//components/web_modal", "//device/bluetooth", + "//extensions/common:mojo", "//mash/public/interfaces", "//ui/vector_icons", ]
diff --git a/chrome/browser/ui/apps/chrome_app_delegate.cc b/chrome/browser/ui/apps/chrome_app_delegate.cc index 5b90605..2b69637 100644 --- a/chrome/browser/ui/apps/chrome_app_delegate.cc +++ b/chrome/browser/ui/apps/chrome_app_delegate.cc
@@ -34,11 +34,14 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/host_zoom_map.h" #include "content/public/browser/notification_service.h" -#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h" #include "extensions/common/constants.h" +#include "extensions/common/mojo/app_window.mojom.h" #include "printing/features/features.h" +#include "services/service_manager/public/cpp/interface_provider.h" #if defined(USE_ASH) #include "ash/common/shelf/shelf_constants.h" // nogncheck @@ -305,10 +308,11 @@ if (!blocked) web_contents->Focus(); // RenderViewHost may be NULL during shutdown. - content::RenderViewHost* host = web_contents->GetRenderViewHost(); + content::RenderFrameHost* host = web_contents->GetMainFrame(); if (host) { - host->Send(new ChromeViewMsg_SetVisuallyDeemphasized(host->GetRoutingID(), - blocked)); + extensions::mojom::AppWindowPtr app_window; + host->GetProcess()->GetRemoteInterfaces()->GetInterface(&app_window); + app_window->SetVisuallyDeemphasized(blocked); } }
diff --git a/chrome/browser/ui/libgtkui/OWNERS b/chrome/browser/ui/libgtkui/OWNERS index b556369..c18ff55 100644 --- a/chrome/browser/ui/libgtkui/OWNERS +++ b/chrome/browser/ui/libgtkui/OWNERS
@@ -1,3 +1,5 @@ # You can only be a GTK owner if your name starts with "e". erg@chromium.org estade@chromium.org + +# COMPONENT: UI>Browser>Themes
diff --git a/chrome/browser/ui/views/autofill/OWNERS b/chrome/browser/ui/views/autofill/OWNERS index 658a9f5..f930a56 100644 --- a/chrome/browser/ui/views/autofill/OWNERS +++ b/chrome/browser/ui/views/autofill/OWNERS
@@ -1 +1,3 @@ estade@chromium.org + +# COMPONENT: UI>Browser>Autofill
diff --git a/chrome/browser/ui/views/hung_renderer_view.cc b/chrome/browser/ui/views/hung_renderer_view.cc index 156fa21..0a5c803 100644 --- a/chrome/browser/ui/views/hung_renderer_view.cc +++ b/chrome/browser/ui/views/hung_renderer_view.cc
@@ -352,9 +352,6 @@ crash_keys.push_back( std::make_pair(crash_keys::kHungRendererLastEventType, base::IntToString(unresponsive_state_.last_event_type))); - crash_keys.push_back( - std::make_pair(crash_keys::kHungRendererReason, - base::IntToString(unresponsive_state_.reason))); // Try to generate a crash report for the hung process. CrashDumpAndTerminateHungChildProcess(rph->GetHandle(), crash_keys);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index 2324255..30898dde 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -570,11 +570,16 @@ void OmniboxViewViews::UpdateSchemeStyle(const gfx::Range& range) { DCHECK(range.IsValid()); - const SkColor security_color = - location_bar_view_->GetSecureTextColor(security_level_); - const bool strike = security_level_ == security_state::DANGEROUS; - ApplyColor(security_color, range); - ApplyStyle(gfx::DIAGONAL_STRIKE, strike, range); + // Only SECURE and DANGEROUS levels (pages served over HTTPS or flagged by + // SafeBrowsing) get a special scheme color treatment. If the security level + // is NONE or HTTP_SHOW_WARNING, we do not override the text style previously + // applied to the scheme text range by SetEmphasis(). + if (security_level_ == security_state::NONE || + security_level_ == security_state::HTTP_SHOW_WARNING) + return; + ApplyColor(location_bar_view_->GetSecureTextColor(security_level_), range); + if (security_level_ == security_state::DANGEROUS) + ApplyStyle(gfx::DIAGONAL_STRIKE, true, range); } void OmniboxViewViews::EmphasizeURLComponents() {
diff --git a/chrome/browser/ui/webui/uber/OWNERS b/chrome/browser/ui/webui/uber/OWNERS deleted file mode 100644 index 658a9f5..0000000 --- a/chrome/browser/ui/webui/uber/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -estade@chromium.org
diff --git a/chrome/common/extensions/chrome_extension_messages.h b/chrome/common/extensions/chrome_extension_messages.h index c47d50c..5d7bdf0a 100644 --- a/chrome/common/extensions/chrome_extension_messages.h +++ b/chrome/common/extensions/chrome_extension_messages.h
@@ -36,11 +36,6 @@ // Messages sent from the browser to the renderer. -// Toggles visual muting of the render view area. This is on when a constrained -// window is showing. -IPC_MESSAGE_ROUTED1(ChromeViewMsg_SetVisuallyDeemphasized, - bool /* deemphazied */) - // Sent to the renderer if install stage updates were requested for an inline // install. IPC_MESSAGE_ROUTED1(ExtensionMsg_InlineInstallStageChanged,
diff --git a/chrome/installer/linux/BUILD.gn b/chrome/installer/linux/BUILD.gn index 95a1d9d..406a8a2 100644 --- a/chrome/installer/linux/BUILD.gn +++ b/chrome/installer/linux/BUILD.gn
@@ -85,15 +85,9 @@ ] if (is_chrome_branded) { - sources += [ - "common/google-chrome/google-chrome.appdata.xml.template", - "common/google-chrome/google-chrome.info", - ] + sources += [ "common/google-chrome/google-chrome.info" ] } else { - sources += [ - "common/chromium-browser/chromium-browser.appdata.xml", - "common/chromium-browser/chromium-browser.info", - ] + sources += [ "common/chromium-browser/chromium-browser.info" ] } if (current_cpu == "x86") {
diff --git a/chrome/installer/linux/common/chromium-browser/chromium-browser.appdata.xml b/chrome/installer/linux/common/chromium-browser/chromium-browser.appdata.xml deleted file mode 100644 index 1f4e463..0000000 --- a/chrome/installer/linux/common/chromium-browser/chromium-browser.appdata.xml +++ /dev/null
@@ -1,36 +0,0 @@ -<!-- Copyright 2017 The Chromium Authors --> -<?xml version="1.0" encoding="UTF-8"?> -<component type="desktop"> - <id>chromium-browser.desktop</id> - <update_contact>chromium-dev@chromium.org</update_contact> - <metadata_license>CC0-1.0</metadata_license> - <project_license>BSD-3-Clause and LGPL-2.1+ and Apache-2.0 and IJG and MIT and GPL-2.0+ and ISC and OpenSSL and (MPL-1.1 or GPL-2.0 or LGPL-2.0)</project_license> - <name>Chromium Web Browser</name> - <summary>The web browser from Chromium project</summary> - <description> - <p> - Chromium is an open-source browser project that aims to build a safer, faster, - and more stable way to experience the web. - </p> - <p> - We invite you to join our effort to build a powerful platform for developing a - new generation of web applications. - </p> - <p> - Chromium supports Vorbis, Theora, WebM and HTML5 audio and video standards, but - does not include the non-free AAC, H.264, MP3 or Adobe Flash code that is found - in Chrome. - </p> - </description> - <url type="homepage">https://www.chromium.org/Home</url> - <screenshots> - <screenshot type="default"> - <image>https://www.gstatic.com/chrome/appstream/chrome-1.png</image> - <caption/> - </screenshot> - </screenshots> - <translation/> - <developer_name>The Chromium Authors</developer_name> - <url type="bugtracker">https://www.chromium.org/for-testers/bug-reporting-guidelines</url> - <url type="help">https://chromium.googlesource.com/chromium/src/+/master/docs/linux_debugging.md</url> -</component>
diff --git a/chrome/installer/linux/common/google-chrome/google-chrome.appdata.xml.template b/chrome/installer/linux/common/google-chrome/google-chrome.appdata.xml.template deleted file mode 100644 index 1f03817f..0000000 --- a/chrome/installer/linux/common/google-chrome/google-chrome.appdata.xml.template +++ /dev/null
@@ -1,26 +0,0 @@ -<!-- Copyright 2017 The Chromium Authors --> -<?xml version="1.0" encoding="UTF-8"?> -<component type="desktop"> - <id>@@PACKAGE@@.desktop</id> - <update_contact>chromium-dev@chromium.org</update_contact> - <metadata_license>CC0-1.0</metadata_license> - <project_license>Freeware under Google Chrome Terms of Service</project_license> - <name>@@MENUNAME@@</name> - <summary>The web browser from Google</summary> - <description> - <p> - @@FULLDESC@@ - </p> - </description> - <url type="homepage">@@PRODUCTURL@@</url> - <screenshots> - <screenshot type="default"> - <image>https://www.gstatic.com/chrome/appstream/chrome-1.png</image> - <caption/> - </screenshot> - </screenshots> - <translation/> - <developer_name>Google</developer_name> - <url type="bugtracker">https://support.google.com/chrome/?p=feedback</url> - <url type="help">https://support.google.com/chrome</url> -</component>
diff --git a/chrome/installer/linux/common/installer.include b/chrome/installer/linux/common/installer.include index a39eb1d2c..a8666514 100644 --- a/chrome/installer/linux/common/installer.include +++ b/chrome/installer/linux/common/installer.include
@@ -244,14 +244,6 @@ # desktop integration install -m 755 "${BUILDDIR}/xdg-mime" "${STAGEDIR}${INSTALLDIR}/" install -m 755 "${BUILDDIR}/xdg-settings" "${STAGEDIR}${INSTALLDIR}/" - if [ ${PACKAGE:0:6} = google ]; then - process_template "${BUILDDIR}/installer/common/google-chrome.appdata.xml.template" \ - "${STAGEDIR}/usr/share/appdata/${PACKAGE}.appdata.xml" - chmod 644 "${STAGEDIR}/usr/share/appdata/${PACKAGE}.appdata.xml" - else - install -m 644 "${BUILDDIR}/installer/common/chromium-browser.appdata.xml" \ - "${STAGEDIR}/usr/share/appdata/${PACKAGE}.appdata.xml" - fi process_template "${BUILDDIR}/installer/common/desktop.template" \ "${STAGEDIR}/usr/share/applications/${PACKAGE}.desktop" chmod 644 "${STAGEDIR}/usr/share/applications/${PACKAGE}.desktop"
diff --git a/chrome/installer/linux/rpm/chrome.spec.template b/chrome/installer/linux/rpm/chrome.spec.template index e878a85..08c402c 100644 --- a/chrome/installer/linux/rpm/chrome.spec.template +++ b/chrome/installer/linux/rpm/chrome.spec.template
@@ -89,7 +89,6 @@ /etc/cron.daily/@@PACKAGE@@ %ghost %attr(755,root,root) /usr/bin/google-chrome /usr/bin/@@USR_BIN_SYMLINK_NAME@@ -/usr/share/appdata/@@PACKAGE@@.appdata.xml /usr/share/applications/@@PACKAGE@@.desktop /usr/share/gnome-control-center/default-apps/@@PACKAGE@@.xml %docdir /usr/share/man/man1
diff --git a/chrome/renderer/chrome_render_view_observer.cc b/chrome/renderer/chrome_render_view_observer.cc index 5e3c48f..48126223 100644 --- a/chrome/renderer/chrome_render_view_observer.cc +++ b/chrome/renderer/chrome_render_view_observer.cc
@@ -46,8 +46,7 @@ content::RenderView* render_view, web_cache::WebCacheImpl* web_cache_impl) : content::RenderViewObserver(render_view), - web_cache_impl_(web_cache_impl), - webview_visually_deemphasized_(false) {} + web_cache_impl_(web_cache_impl) {} ChromeRenderViewObserver::~ChromeRenderViewObserver() { } @@ -58,10 +57,6 @@ #if !defined(OS_ANDROID) IPC_MESSAGE_HANDLER(ChromeViewMsg_WebUIJavaScript, OnWebUIJavaScript) #endif -#if BUILDFLAG(ENABLE_EXTENSIONS) - IPC_MESSAGE_HANDLER(ChromeViewMsg_SetVisuallyDeemphasized, - OnSetVisuallyDeemphasized) -#endif #if defined(OS_ANDROID) IPC_MESSAGE_HANDLER(ChromeViewMsg_UpdateBrowserControlsState, OnUpdateBrowserControlsState) @@ -148,23 +143,6 @@ web_cache_impl_->ExecutePendingClearCache(); } -#if BUILDFLAG(ENABLE_EXTENSIONS) -void ChromeRenderViewObserver::OnSetVisuallyDeemphasized(bool deemphasized) { - if (webview_visually_deemphasized_ == deemphasized) - return; - - webview_visually_deemphasized_ = deemphasized; - - if (deemphasized) { - // 70% opaque grey. - SkColor greyish = SkColorSetARGB(178, 0, 0, 0); - render_view()->GetWebView()->setPageOverlayColor(greyish); - } else { - render_view()->GetWebView()->setPageOverlayColor(SK_ColorTRANSPARENT); - } -} -#endif - void ChromeRenderViewObserver::DidCommitProvisionalLoad( blink::WebLocalFrame* frame, bool is_new_navigation) {
diff --git a/chrome/renderer/chrome_render_view_observer.h b/chrome/renderer/chrome_render_view_observer.h index f6473b0..ea76e9d 100644 --- a/chrome/renderer/chrome_render_view_observer.h +++ b/chrome/renderer/chrome_render_view_observer.h
@@ -43,9 +43,6 @@ #if !defined(OS_ANDROID) void OnWebUIJavaScript(const base::string16& javascript); #endif -#if BUILDFLAG(ENABLE_EXTENSIONS) - void OnSetVisuallyDeemphasized(bool deemphasized); -#endif #if defined(OS_ANDROID) void OnUpdateBrowserControlsState(content::BrowserControlsState constraints, content::BrowserControlsState current, @@ -63,9 +60,6 @@ // Owned by ChromeContentRendererClient and outlive us. web_cache::WebCacheImpl* web_cache_impl_; - // true if webview is overlayed with grey color. - bool webview_visually_deemphasized_; - DISALLOW_COPY_AND_ASSIGN(ChromeRenderViewObserver); };
diff --git a/chromecast/browser/metrics/OWNERS b/chromecast/browser/metrics/OWNERS index 20f63bf3..73e387e 100644 --- a/chromecast/browser/metrics/OWNERS +++ b/chromecast/browser/metrics/OWNERS
@@ -2,3 +2,5 @@ asvitkine@chromium.org mpearson@chromium.org isherman@chromium.org + +# COMPONENT: Internals>Metrics
diff --git a/components/metrics/OWNERS b/components/metrics/OWNERS index 236892ba..3b1e068 100644 --- a/components/metrics/OWNERS +++ b/components/metrics/OWNERS
@@ -3,3 +3,5 @@ isherman@chromium.org mpearson@chromium.org rkaplow@chromium.org + +# COMPONENT: Internals>Metrics
diff --git a/components/metrics_services_manager/OWNERS b/components/metrics_services_manager/OWNERS index 236892ba..3b1e068 100644 --- a/components/metrics_services_manager/OWNERS +++ b/components/metrics_services_manager/OWNERS
@@ -3,3 +3,5 @@ isherman@chromium.org mpearson@chromium.org rkaplow@chromium.org + +# COMPONENT: Internals>Metrics
diff --git a/components/minidump_uploader/OWNERS b/components/minidump_uploader/OWNERS index 79f0e9b..af66982 100644 --- a/components/minidump_uploader/OWNERS +++ b/components/minidump_uploader/OWNERS
@@ -3,3 +3,5 @@ # Crash uploading mechanism isherman@chromium.org + +# COMPONENT: Internals>CrashReporting
diff --git a/components/offline_items_collection/core/BUILD.gn b/components/offline_items_collection/core/BUILD.gn index 1a76124..501adb8 100644 --- a/components/offline_items_collection/core/BUILD.gn +++ b/components/offline_items_collection/core/BUILD.gn
@@ -2,6 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +if (is_android) { + import("//build/config/android/config.gni") + import("//build/config/android/rules.gni") +} + static_library("core") { sources = [ "offline_content_aggregator.cc", @@ -16,10 +21,23 @@ "offline_item_state.h", ] - deps = [ + public_deps = [ "//base", "//url", ] + + deps = [] + + if (is_android) { + sources += [ + "android/offline_content_aggregator_bridge.cc", + "android/offline_content_aggregator_bridge.h", + "android/offline_item_bridge.cc", + "android/offline_item_bridge.h", + ] + + deps += [ ":jni_headers" ] + } } source_set("unit_tests") { @@ -35,3 +53,42 @@ "//components/offline_items_collection/core/test_support", ] } + +if (is_android) { + android_library("core_java") { + java_files = [ + "android/java/src/org/chromium/components/offline_items_collection/ContentId.java", + "android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java", + "android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java", + "android/java/src/org/chromium/components/offline_items_collection/OfflineItem.java", + "android/java/src/org/chromium/components/offline_items_collection/OfflineItemBridge.java", + ] + + srcjar_deps = [ ":jni_enums" ] + + deps = [ + "//base:base_java", + "//third_party/android_tools:android_support_annotations_java", + ] + } + + generate_jni("jni_headers") { + visibility = [ ":*" ] + + sources = [ + "android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java", + "android/java/src/org/chromium/components/offline_items_collection/OfflineItemBridge.java", + ] + + jni_package = "components/offline_items_collection/core/android" + } + + java_cpp_enum("jni_enums") { + visibility = [ ":*" ] + + sources = [ + "offline_item_filter.h", + "offline_item_state.h", + ] + } +}
diff --git a/components/offline_items_collection/core/DEPS b/components/offline_items_collection/core/DEPS index c539f2f..af6de73 100644 --- a/components/offline_items_collection/core/DEPS +++ b/components/offline_items_collection/core/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+base", "+components/offline_pages", + "+jni", "+testing", "+url", -] \ No newline at end of file +]
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/ContentId.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/ContentId.java new file mode 100644 index 0000000..045618b --- /dev/null +++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/ContentId.java
@@ -0,0 +1,23 @@ +// 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. + +package org.chromium.components.offline_items_collection; + +/** + * This class is a Java counterpart to the C++ ContentId + * (components/offline_items_collection/core/offline_item.h) class. + * + * For all member variable descriptions see the C++ class. + * TODO(dtrainor): Investigate making all class members for this and the C++ counterpart const. + */ +public class ContentId { + public String namespace; + public String id; + + public ContentId() {} + public ContentId(String namespace, String id) { + this.namespace = namespace; + this.id = id; + } +} \ No newline at end of file
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java new file mode 100644 index 0000000..f14368f8 --- /dev/null +++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java
@@ -0,0 +1,166 @@ +// 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. + +package org.chromium.components.offline_items_collection; + +import org.chromium.base.ObserverList; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +import java.util.ArrayList; + +/** + * A helper class responsible for exposing the C++ OfflineContentAggregator + * (components/offline_items_collection/core/offline_content_aggregator.h) class to Java. This + * class is created and owned by it's C++ counterpart OfflineContentAggregatorBridge + * (components/offline_items_collection/core/android/offline_content_aggregator_bridge.h). + */ +@JNINamespace("offline_items_collection::android") +public class OfflineContentAggregatorBridge implements OfflineContentProvider { + private long mNativeOfflineContentAggregatorBridge; + private ObserverList<OfflineContentProvider.Observer> mObservers; + private boolean mItemsAvailable; + + /** + * A private constructor meant to be called by the C++ OfflineContentAggregatorBridge. + * @param nativeOfflineContentAggregatorBridge A C++ pointer to the + * OfflineContentAggregatorBridge. + */ + private OfflineContentAggregatorBridge(long nativeOfflineContentAggregatorBridge) { + mNativeOfflineContentAggregatorBridge = nativeOfflineContentAggregatorBridge; + mItemsAvailable = false; + mObservers = new ObserverList<OfflineContentProvider.Observer>(); + } + + // OfflineContentProvider implementation. + @Override + public boolean areItemsAvailable() { + return mItemsAvailable; + } + + @Override + public void openItem(ContentId id) { + if (mNativeOfflineContentAggregatorBridge == 0) return; + nativeOpenItem(mNativeOfflineContentAggregatorBridge, id.namespace, id.id); + } + + @Override + public void removeItem(ContentId id) { + if (mNativeOfflineContentAggregatorBridge == 0) return; + nativeRemoveItem(mNativeOfflineContentAggregatorBridge, id.namespace, id.id); + } + + @Override + public void cancelDownload(ContentId id) { + if (mNativeOfflineContentAggregatorBridge == 0) return; + nativeCancelDownload(mNativeOfflineContentAggregatorBridge, id.namespace, id.id); + } + + @Override + public void pauseDownload(ContentId id) { + if (mNativeOfflineContentAggregatorBridge == 0) return; + nativePauseDownload(mNativeOfflineContentAggregatorBridge, id.namespace, id.id); + } + + @Override + public void resumeDownload(ContentId id) { + if (mNativeOfflineContentAggregatorBridge == 0) return; + nativeResumeDownload(mNativeOfflineContentAggregatorBridge, id.namespace, id.id); + } + + @Override + public OfflineItem getItemById(ContentId id) { + if (mNativeOfflineContentAggregatorBridge == 0) return null; + return nativeGetItemById(mNativeOfflineContentAggregatorBridge, id.namespace, id.id); + } + + @Override + public ArrayList<OfflineItem> getAllItems() { + if (mNativeOfflineContentAggregatorBridge == 0) return null; + return nativeGetAllItems(mNativeOfflineContentAggregatorBridge); + } + + @Override + public void addObserver(OfflineContentProvider.Observer observer) { + mObservers.addObserver(observer); + } + + @Override + public void removeObserver(OfflineContentProvider.Observer observer) { + mObservers.removeObserver(observer); + } + + // Methods called from C++ via JNI. + @CalledByNative + private void onItemsAvailable() { + mItemsAvailable = true; + + for (Observer observer : mObservers) { + observer.onItemsAvailable(); + } + } + + @CalledByNative + private void onItemsAdded(ArrayList<OfflineItem> items) { + if (items.size() == 0) return; + + for (Observer observer : mObservers) { + observer.onItemsAdded(items); + } + } + + @CalledByNative + private void onItemRemoved(String nameSpace, String id) { + ContentId contentId = new ContentId(nameSpace, id); + + for (Observer observer : mObservers) { + observer.onItemRemoved(contentId); + } + } + + @CalledByNative + private void onItemUpdated(OfflineItem item) { + for (Observer observer : mObservers) { + observer.onItemUpdated(item); + } + } + + /** + * Called when the C++ OfflineContentAggregatorBridge is destroyed. This tears down the Java + * component of the JNI bridge so that this class, which may live due to other references, no + * longer attempts to access the C++ side of the bridge. + */ + @CalledByNative + private void onNativeDestroyed() { + mNativeOfflineContentAggregatorBridge = 0; + } + + /** + * A private static factory method meant to be called by the C++ OfflineContentAggregatorBridge. + * @param nativeOfflineContentAggregatorBridge A C++ pointer to the + * OfflineContentAggregatorBridge. + * @return A new instance of this OfflineContentAggregatorBridge. + */ + @CalledByNative + private static OfflineContentAggregatorBridge create( + long nativeOfflineContentAggregatorBridge) { + return new OfflineContentAggregatorBridge(nativeOfflineContentAggregatorBridge); + } + + // Methods called to C++ via JNI. + private native void nativeOpenItem( + long nativeOfflineContentAggregatorBridge, String nameSpace, String id); + private native void nativeRemoveItem( + long nativeOfflineContentAggregatorBridge, String nameSpace, String id); + private native void nativeCancelDownload( + long nativeOfflineContentAggregatorBridge, String nameSpace, String id); + private native void nativePauseDownload( + long nativeOfflineContentAggregatorBridge, String nameSpace, String id); + private native void nativeResumeDownload( + long nativeOfflineContentAggregatorBridge, String nameSpace, String id); + private native OfflineItem nativeGetItemById( + long nativeOfflineContentAggregatorBridge, String nameSpace, String id); + private native ArrayList<OfflineItem> nativeGetAllItems( + long nativeOfflineContentAggregatorBridge); +} \ No newline at end of file
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java new file mode 100644 index 0000000..7c177a7 --- /dev/null +++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java
@@ -0,0 +1,60 @@ +// 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. + +package org.chromium.components.offline_items_collection; + +import java.util.ArrayList; + +/** + * This interface is a Java counterpart to the C++ OfflineContentProvider + * (components/offline_items_collection/core/offline_content_provider.h) class. + */ +public interface OfflineContentProvider { + /** This interface is a Java counterpart to the C++ OfflineContentProvider::Observer + * (components/offline_items_collection/core/offline_content_provider.h) class. + */ + interface Observer { + /** See OfflineContentProvider::Observer::OnItemsAvailable(...). */ + void onItemsAvailable(); + + /** See OfflineContentProvider::Observer::OnItemsAdded(...). */ + void onItemsAdded(ArrayList<OfflineItem> items); + + /** See OfflineContentProvider::Observer::OnItemRemoved(...). */ + void onItemRemoved(ContentId id); + + /** See OfflineContentProvider::Observer::OnItemUpdated(...). */ + void onItemUpdated(OfflineItem item); + } + + /** See OfflineContentProvider::AreItemsAvailable(). */ + boolean areItemsAvailable(); + + /** See OfflineContentProvider::OpenItem(...). */ + void openItem(ContentId id); + + /** See OfflineContentProvider::RemoveItem(...). */ + void removeItem(ContentId id); + + /** See OfflineContentProvider::CancelDownload(...). */ + void cancelDownload(ContentId id); + + /** See OfflineContentProvider::PauseDownload(...). */ + void pauseDownload(ContentId id); + + /** See OfflineContentProvider::ResumeDownload(...). */ + void resumeDownload(ContentId id); + + /** See OfflineContentProvider::GetItemById(...). */ + OfflineItem getItemById(ContentId id); + + /** See OfflineContentProvider::GetAllItems(). */ + ArrayList<OfflineItem> getAllItems(); + + /** See OfflineContentProvider::AddObserver(...). */ + void addObserver(Observer observer); + + /** See OfflineContentProvider::RemoveObserver(...). */ + void removeObserver(Observer observer); +} \ No newline at end of file
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineItem.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineItem.java new file mode 100644 index 0000000..c4a9fee --- /dev/null +++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineItem.java
@@ -0,0 +1,52 @@ +// 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. + +package org.chromium.components.offline_items_collection; + +import org.chromium.base.annotations.SuppressFBWarnings; +import org.chromium.components.offline_items_collection.OfflineItemFilter.OfflineItemFilterEnum; +import org.chromium.components.offline_items_collection.OfflineItemState.OfflineItemStateEnum; + +/** + * This class is the Java counterpart to the C++ OfflineItem + * (components/offline_items_collection/core/offline_item.h) class. + * + * For all member variable descriptions see the C++ class. + * TODO(dtrainor): Investigate making all class members for this and the C++ counterpart const. + */ +@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") +public class OfflineItem { + public ContentId id; + + // Display metadata. + public String title; + public String description; + @OfflineItemFilterEnum + public int filter; + + // Content Metadata. + public long totalSizeBytes; + public boolean externallyRemoved; + public long creationTimeMs; + public long lastAccessedTimeMs; + + // Request Metadata. + public String pageUrl; + public String originalUrl; + public boolean isOffTheRecord; + + // In Progress Metadata. + @OfflineItemStateEnum + public int state; + public boolean isResumable; + public long receivedBytes; + public int percentCompleted; + public long timeRemainingMs; + + OfflineItem() { + id = new ContentId(); + filter = OfflineItemFilter.FILTER_OTHER; + state = OfflineItemState.COMPLETE; + } +} \ No newline at end of file
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineItemBridge.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineItemBridge.java new file mode 100644 index 0000000..6817870 --- /dev/null +++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineItemBridge.java
@@ -0,0 +1,70 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.components.offline_items_collection; + +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; +import org.chromium.components.offline_items_collection.OfflineItemFilter.OfflineItemFilterEnum; +import org.chromium.components.offline_items_collection.OfflineItemState.OfflineItemStateEnum; + +import java.util.ArrayList; + +/** + * The Java counterpart to the C++ class OfflineItemBridge + * (components/offline_items_collection/core/android/offline_item_bridge.h). This class has no + * public members or methods and is meant as a private factory to build {@link OfflineItem} + * instances. + */ +@JNINamespace("offline_items_collection::android") +public class OfflineItemBridge { + private OfflineItemBridge() {} + + /** + * This is a helper method to allow C++ to create an {@link ArrayList} to add + * {@link OfflineItem}s to. + * @return An {@link ArrayList} for {@link OfflineItem}s. + */ + @CalledByNative + private static ArrayList<OfflineItem> createArrayList() { + return new ArrayList<OfflineItem>(); + } + + /** + * Creates an {@link OfflineItem} from the passed in parameters. See {@link OfflineItem} for a + * list of the members that will be populated. If {@code list} isn't {@code null}, the newly + * created {@link OfflineItem} will be added to it. + * @param list An {@link ArrayList} to optionally add the newly created {@link OfflineItem} to. + * @return The newly created {@link OfflineItem} based on the passed in parameters. + */ + @CalledByNative + private static OfflineItem createOfflineItemAndMaybeAddToList(ArrayList<OfflineItem> list, + String nameSpace, String id, String title, String description, + @OfflineItemFilterEnum int filter, long totalSizeBytes, boolean externallyRemoved, + long creationTimeMs, long lastAccessedTimeMs, String pageUrl, String originalUrl, + boolean isOffTheRecord, @OfflineItemStateEnum int state, boolean isResumable, + long receivedBytes, int percentCompleted, long timeRemainingMs) { + OfflineItem item = new OfflineItem(); + item.id.namespace = nameSpace; + item.id.id = id; + item.title = title; + item.description = description; + item.filter = filter; + item.totalSizeBytes = totalSizeBytes; + item.externallyRemoved = externallyRemoved; + item.creationTimeMs = creationTimeMs; + item.lastAccessedTimeMs = lastAccessedTimeMs; + item.pageUrl = pageUrl; + item.originalUrl = originalUrl; + item.isOffTheRecord = isOffTheRecord; + item.state = state; + item.isResumable = isResumable; + item.receivedBytes = receivedBytes; + item.percentCompleted = percentCompleted; + item.timeRemainingMs = timeRemainingMs; + + if (list != null) list.add(item); + return item; + } +} \ No newline at end of file
diff --git a/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc b/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc new file mode 100644 index 0000000..52cca187 --- /dev/null +++ b/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc
@@ -0,0 +1,174 @@ +// 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 "components/offline_items_collection/core/android/offline_content_aggregator_bridge.h" + +#include "base/android/jni_string.h" +#include "components/offline_items_collection/core/android/offline_item_bridge.h" +#include "components/offline_items_collection/core/offline_item.h" +#include "jni/OfflineContentAggregatorBridge_jni.h" + +using base::android::AttachCurrentThread; +using base::android::ConvertJavaStringToUTF8; +using base::android::ConvertUTF8ToJavaString; +using base::android::JavaParamRef; +using base::android::ScopedJavaLocalRef; + +namespace offline_items_collection { +namespace android { + +namespace { +const char kOfflineContentAggregatorBridgeUserDataKey[] = "aggregator_bridge"; + +ContentId CreateContentId(JNIEnv* env, + const JavaParamRef<jstring>& j_namespace, + const JavaParamRef<jstring>& j_id) { + return ContentId(ConvertJavaStringToUTF8(env, j_namespace), + ConvertJavaStringToUTF8(env, j_id)); +} + +} // namespace + +// static. +bool OfflineContentAggregatorBridge::Register(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +// static +OfflineContentAggregatorBridge* +OfflineContentAggregatorBridge::GetForOfflineContentAggregator( + OfflineContentAggregator* aggregator) { + if (!aggregator->GetUserData(kOfflineContentAggregatorBridgeUserDataKey)) { + aggregator->SetUserData(kOfflineContentAggregatorBridgeUserDataKey, + new OfflineContentAggregatorBridge(aggregator)); + } + + return static_cast<OfflineContentAggregatorBridge*>( + aggregator->GetUserData(kOfflineContentAggregatorBridgeUserDataKey)); +} + +OfflineContentAggregatorBridge::OfflineContentAggregatorBridge( + OfflineContentAggregator* aggregator) + : aggregator_(aggregator) { + JNIEnv* env = AttachCurrentThread(); + java_ref_.Reset(Java_OfflineContentAggregatorBridge_create( + env, reinterpret_cast<intptr_t>(this))); + + aggregator_->AddObserver(this); +} + +OfflineContentAggregatorBridge::~OfflineContentAggregatorBridge() { + // TODO(dtrainor): Do not need to unregister because in the destructor of the + // base class of OfflineContentAggregator. Is |observers_| already dead? + aggregator_->RemoveObserver(this); + + Java_OfflineContentAggregatorBridge_onNativeDestroyed(AttachCurrentThread(), + java_ref_.obj()); +} + +jboolean OfflineContentAggregatorBridge::AreItemsAvailable( + JNIEnv* env, + const JavaParamRef<jobject>& jobj) { + return aggregator_->AreItemsAvailable(); +} + +void OfflineContentAggregatorBridge::OpenItem( + JNIEnv* env, + const JavaParamRef<jobject>& jobj, + const JavaParamRef<jstring>& j_namespace, + const JavaParamRef<jstring>& j_id) { + aggregator_->OpenItem(CreateContentId(env, j_namespace, j_id)); +} + +void OfflineContentAggregatorBridge::RemoveItem( + JNIEnv* env, + const JavaParamRef<jobject>& jobj, + const JavaParamRef<jstring>& j_namespace, + const JavaParamRef<jstring>& j_id) { + aggregator_->RemoveItem(CreateContentId(env, j_namespace, j_id)); +} + +void OfflineContentAggregatorBridge::CancelDownload( + JNIEnv* env, + const JavaParamRef<jobject>& jobj, + const JavaParamRef<jstring>& j_namespace, + const JavaParamRef<jstring>& j_id) { + aggregator_->CancelDownload(CreateContentId(env, j_namespace, j_id)); +} + +void OfflineContentAggregatorBridge::PauseDownload( + JNIEnv* env, + const JavaParamRef<jobject>& jobj, + const JavaParamRef<jstring>& j_namespace, + const JavaParamRef<jstring>& j_guid) { + aggregator_->PauseDownload(CreateContentId(env, j_namespace, j_guid)); +} + +void OfflineContentAggregatorBridge::ResumeDownload( + JNIEnv* env, + const JavaParamRef<jobject>& jobj, + const JavaParamRef<jstring>& j_namespace, + const JavaParamRef<jstring>& j_id) { + aggregator_->ResumeDownload(CreateContentId(env, j_namespace, j_id)); +} + +ScopedJavaLocalRef<jobject> OfflineContentAggregatorBridge::GetItemById( + JNIEnv* env, + const JavaParamRef<jobject>& jobj, + const JavaParamRef<jstring>& j_namespace, + const JavaParamRef<jstring>& j_id) { + const OfflineItem* item = + aggregator_->GetItemById(CreateContentId(env, j_namespace, j_id)); + + return OfflineItemBridge::CreateOfflineItem(env, item); +} + +ScopedJavaLocalRef<jobject> OfflineContentAggregatorBridge::GetAllItems( + JNIEnv* env, + const JavaParamRef<jobject>& jobj) { + return OfflineItemBridge::CreateOfflineItemList(env, + aggregator_->GetAllItems()); +} + +void OfflineContentAggregatorBridge::OnItemsAvailable( + OfflineContentProvider* provider) { + if (java_ref_.is_null()) + return; + + JNIEnv* env = AttachCurrentThread(); + Java_OfflineContentAggregatorBridge_onItemsAvailable(env, java_ref_.obj()); +} + +void OfflineContentAggregatorBridge::OnItemsAdded( + const OfflineContentProvider::OfflineItemList& items) { + if (java_ref_.is_null()) + return; + + JNIEnv* env = AttachCurrentThread(); + Java_OfflineContentAggregatorBridge_onItemsAdded( + env, java_ref_.obj(), + OfflineItemBridge::CreateOfflineItemList(env, items)); +} + +void OfflineContentAggregatorBridge::OnItemRemoved(const ContentId& id) { + if (java_ref_.is_null()) + return; + + JNIEnv* env = AttachCurrentThread(); + Java_OfflineContentAggregatorBridge_onItemRemoved( + env, java_ref_.obj(), ConvertUTF8ToJavaString(env, id.name_space), + ConvertUTF8ToJavaString(env, id.id)); +} + +void OfflineContentAggregatorBridge::OnItemUpdated(const OfflineItem& item) { + if (java_ref_.is_null()) + return; + + JNIEnv* env = AttachCurrentThread(); + Java_OfflineContentAggregatorBridge_onItemUpdated( + env, java_ref_.obj(), OfflineItemBridge::CreateOfflineItem(env, &item)); +} + +} // namespace android +} // namespace offline_items_collection
diff --git a/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h b/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h new file mode 100644 index 0000000..89dc2a96 --- /dev/null +++ b/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h
@@ -0,0 +1,95 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_CONTENT_AGGREGATOR_BRIDGE_H_ +#define COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_CONTENT_AGGREGATOR_BRIDGE_H_ + +#include "base/android/jni_android.h" +#include "base/android/scoped_java_ref.h" +#include "base/supports_user_data.h" +#include "components/offline_items_collection/core/offline_content_aggregator.h" +#include "components/offline_items_collection/core/offline_content_provider.h" + +namespace offline_items_collection { + +struct ContentId; +struct OfflineItem; + +namespace android { + +// A helper class responsible for bridging an OfflineContentAggregator from C++ +// to Java. This class attaches as a piece of SupportsUserData::Data to the +// OfflineContentAggregator and can only be created through the +// GetForOfflineContentAggregator() method. +// This class creates and contains a strong reference to it's Java counterpart, +// so the Java bridge will live as long as this class lives. For more +// information on the Java counterpart see OfflineContentAggregatorBridge.java. +class OfflineContentAggregatorBridge : public OfflineContentProvider::Observer, + public base::SupportsUserData::Data { + public: + // Helper method to initialize the JNI hooks between Java and C++. + static bool Register(JNIEnv* env); + + // Returns an OfflineContentAggregatorBridge for |aggregator|. There will be + // only one bridge per OfflineContentAggregator. + static OfflineContentAggregatorBridge* GetForOfflineContentAggregator( + OfflineContentAggregator* aggregator); + + ~OfflineContentAggregatorBridge() override; + + // Methods called from Java via JNI. + jboolean AreItemsAvailable(JNIEnv* env, + const base::android::JavaParamRef<jobject>& jobj); + void OpenItem(JNIEnv* env, + const base::android::JavaParamRef<jobject>& jobj, + const base::android::JavaParamRef<jstring>& j_namespace, + const base::android::JavaParamRef<jstring>& j_id); + void RemoveItem(JNIEnv* env, + const base::android::JavaParamRef<jobject>& jobj, + const base::android::JavaParamRef<jstring>& j_namespace, + const base::android::JavaParamRef<jstring>& j_id); + void CancelDownload(JNIEnv* env, + const base::android::JavaParamRef<jobject>& jobj, + const base::android::JavaParamRef<jstring>& j_namespace, + const base::android::JavaParamRef<jstring>& j_id); + void PauseDownload(JNIEnv* env, + const base::android::JavaParamRef<jobject>& jobj, + const base::android::JavaParamRef<jstring>& j_namespace, + const base::android::JavaParamRef<jstring>& j_id); + void ResumeDownload(JNIEnv* env, + const base::android::JavaParamRef<jobject>& jobj, + const base::android::JavaParamRef<jstring>& j_namespace, + const base::android::JavaParamRef<jstring>& j_id); + base::android::ScopedJavaLocalRef<jobject> GetItemById( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& jobj, + const base::android::JavaParamRef<jstring>& j_namespace, + const base::android::JavaParamRef<jstring>& j_id); + base::android::ScopedJavaLocalRef<jobject> GetAllItems( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& jobj); + + private: + OfflineContentAggregatorBridge(OfflineContentAggregator* aggregator); + + // OfflineContentProvider::Observer implementation. + void OnItemsAvailable(OfflineContentProvider* provider) override; + void OnItemsAdded( + const OfflineContentProvider::OfflineItemList& items) override; + void OnItemRemoved(const ContentId& id) override; + void OnItemUpdated(const OfflineItem& item) override; + + // A reference to the Java counterpart of this class. See + // OfflineContentAggregatorBridge.java. + base::android::ScopedJavaGlobalRef<jobject> java_ref_; + + OfflineContentAggregator* const aggregator_; + + DISALLOW_COPY_AND_ASSIGN(OfflineContentAggregatorBridge); +}; + +} // namespace android +} // namespace offline_items_collection + +#endif // COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_CONTENT_AGGREGATOR_BRIDGE_H_
diff --git a/components/offline_items_collection/core/android/offline_item_bridge.cc b/components/offline_items_collection/core/android/offline_item_bridge.cc new file mode 100644 index 0000000..477bf7b07 --- /dev/null +++ b/components/offline_items_collection/core/android/offline_item_bridge.cc
@@ -0,0 +1,69 @@ +// 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 "components/offline_items_collection/core/android/offline_item_bridge.h" + +#include "base/android/jni_string.h" +#include "jni/OfflineItemBridge_jni.h" + +using base::android::ConvertUTF8ToJavaString; +using base::android::ScopedJavaLocalRef; + +namespace offline_items_collection { +namespace android { + +namespace { + +// Helper method to unify the OfflineItem conversion argument list to a single +// place. This is meant to reduce code churn from OfflineItem member +// modification. The behavior is as follows: +// - The method always returns the new Java OfflineItem instance. +// - If |jlist| is specified (an ArrayList<OfflineItem>), the item is added to +// that list. |jlist| can also be null, in which case the item isn't added to +// anything. +ScopedJavaLocalRef<jobject> createOfflineItemAndMaybeAddToList( + JNIEnv* env, + ScopedJavaLocalRef<jobject> jlist, + const OfflineItem& item) { + return Java_OfflineItemBridge_createOfflineItemAndMaybeAddToList( + env, jlist, ConvertUTF8ToJavaString(env, item.id.name_space), + ConvertUTF8ToJavaString(env, item.id.id), + ConvertUTF8ToJavaString(env, item.title), + ConvertUTF8ToJavaString(env, item.description), + static_cast<jint>(item.filter), item.total_size_bytes, + item.externally_removed, item.creation_time.ToJavaTime(), + item.last_accessed_time.ToJavaTime(), + ConvertUTF8ToJavaString(env, item.page_url.spec()), + ConvertUTF8ToJavaString(env, item.original_url.spec()), + item.is_off_the_record, static_cast<jint>(item.state), item.is_resumable, + item.received_bytes, item.percent_completed, item.time_remaining_ms); +} + +} // namespace + +// static +ScopedJavaLocalRef<jobject> OfflineItemBridge::CreateOfflineItem( + JNIEnv* env, + const OfflineItem* const item) { + return item ? createOfflineItemAndMaybeAddToList(env, nullptr, *item) + : nullptr; +} + +// static +ScopedJavaLocalRef<jobject> OfflineItemBridge::CreateOfflineItemList( + JNIEnv* env, + const std::vector<OfflineItem>& items) { + ScopedJavaLocalRef<jobject> jlist = + Java_OfflineItemBridge_createArrayList(env); + + for (const auto& item : items) + createOfflineItemAndMaybeAddToList(env, jlist, item); + + return jlist; +} + +OfflineItemBridge::OfflineItemBridge() = default; + +} // namespace android +} // namespace offline_items_collection
diff --git a/components/offline_items_collection/core/android/offline_item_bridge.h b/components/offline_items_collection/core/android/offline_item_bridge.h new file mode 100644 index 0000000..76d1513 --- /dev/null +++ b/components/offline_items_collection/core/android/offline_item_bridge.h
@@ -0,0 +1,38 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_ITEM_BRIDGE_H_ +#define COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_ITEM_BRIDGE_H_ + +#include <vector> + +#include "base/android/jni_android.h" +#include "base/android/scoped_java_ref.h" +#include "components/offline_items_collection/core/offline_item.h" + +namespace offline_items_collection { +namespace android { + +// A helper class for creating Java OfflineItem instances from the C++ +// OfflineItem counterpart. +class OfflineItemBridge { + public: + // Creates a Java OfflineItem from |item|. + static base::android::ScopedJavaLocalRef<jobject> CreateOfflineItem( + JNIEnv* env, + const OfflineItem* const item); + + // Creates an Java ArrayList<OfflineItem> from |items|. + static base::android::ScopedJavaLocalRef<jobject> CreateOfflineItemList( + JNIEnv* env, + const std::vector<OfflineItem>& items); + + private: + OfflineItemBridge(); +}; + +} // namespace android +} // namespace offline_items_collection + +#endif // COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_ITEM_BRIDGE_H_
diff --git a/components/offline_items_collection/core/offline_item_filter.h b/components/offline_items_collection/core/offline_item_filter.h index a1d20ab..3bdb64b2 100644 --- a/components/offline_items_collection/core/offline_item_filter.h +++ b/components/offline_items_collection/core/offline_item_filter.h
@@ -8,7 +8,7 @@ namespace offline_items_collection { // A Java counterpart will be generated for this enum. -// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.offline_items_collection.core.item +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.offline_items_collection enum OfflineItemFilter { FILTER_ALL = 0, FILTER_PAGE,
diff --git a/components/offline_items_collection/core/offline_item_state.h b/components/offline_items_collection/core/offline_item_state.h index 1f7ec12..2ddb5fb 100644 --- a/components/offline_items_collection/core/offline_item_state.h +++ b/components/offline_items_collection/core/offline_item_state.h
@@ -8,7 +8,7 @@ namespace offline_items_collection { // A Java counterpart will be generated for this enum. -// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.offline_items_collection.core.item +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.offline_items_collection enum OfflineItemState { IN_PROGRESS = 0, COMPLETE,
diff --git a/components/precache/core/proto/precache.proto b/components/precache/core/proto/precache.proto index 5b987e2a..2e9aec2 100644 --- a/components/precache/core/proto/precache.proto +++ b/components/precache/core/proto/precache.proto
@@ -33,6 +33,8 @@ }; // A manifest of cacheable resources to be precached for a specific host. +// CAUTION: When any change is done here, bump kDatabaseVersion in +// chrome/browser/predictors/resource_prefetch_predictor_tables.h message PrecacheManifest { // List of resources that we predict that the user will need if they are // likely to fetch the host.
diff --git a/content/browser/devtools/devtools_manager_unittest.cc b/content/browser/devtools/devtools_manager_unittest.cc index 09c7c11..9a8649e 100644 --- a/content/browser/devtools/devtools_manager_unittest.cc +++ b/content/browser/devtools/devtools_manager_unittest.cc
@@ -148,8 +148,7 @@ // Start with a short timeout. inspected_rvh->GetWidget()->StartHangMonitorTimeout( - TimeDelta::FromMilliseconds(10), blink::WebInputEvent::Undefined, - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_UNKNOWN); + TimeDelta::FromMilliseconds(10), blink::WebInputEvent::Undefined); // Wait long enough for first timeout and see if it fired. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(), @@ -161,8 +160,7 @@ client_host.Close(); // Start with a short timeout. inspected_rvh->GetWidget()->StartHangMonitorTimeout( - TimeDelta::FromMilliseconds(10), blink::WebInputEvent::Undefined, - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_UNKNOWN); + TimeDelta::FromMilliseconds(10), blink::WebInputEvent::Undefined); // Wait long enough for first timeout and see if it fired. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
diff --git a/content/browser/download/download_resource_handler.cc b/content/browser/download/download_resource_handler.cc index e52984a..c7ba502 100644 --- a/content/browser/download/download_resource_handler.cc +++ b/content/browser/download/download_resource_handler.cc
@@ -171,9 +171,16 @@ // Create a new buffer, which will be handed to the download thread for file // writing and deletion. -bool DownloadResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) { - return core_.OnWillRead(buf, buf_size); +void DownloadResourceHandler::OnWillRead( + scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) { + if (!core_.OnWillRead(buf, buf_size)) { + controller->Cancel(); + return; + } + + controller->Resume(); } // Pass the buffer to the download file writer.
diff --git a/content/browser/download/download_resource_handler.h b/content/browser/download/download_resource_handler.h index 0847f75..ad2b38e 100644 --- a/content/browser/download/download_resource_handler.h +++ b/content/browser/download/download_resource_handler.h
@@ -66,8 +66,9 @@ // Create a new buffer, which will be handed to the download thread for file // writing and deletion. - bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) override; + void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) override; void OnReadCompleted(int bytes_read, std::unique_ptr<ResourceController> controller) override;
diff --git a/content/browser/download/save_file_resource_handler.cc b/content/browser/download/save_file_resource_handler.cc index efea74f..98b332d 100644 --- a/content/browser/download/save_file_resource_handler.cc +++ b/content/browser/download/save_file_resource_handler.cc
@@ -70,8 +70,10 @@ } } -bool SaveFileResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) { +void SaveFileResourceHandler::OnWillRead( + scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) { DCHECK_EQ(AuthorizationState::AUTHORIZED, authorization_state_); DCHECK(buf && buf_size); if (!read_buffer_.get()) { @@ -79,7 +81,7 @@ read_buffer_ = new net::IOBuffer(*buf_size); } *buf = read_buffer_.get(); - return true; + controller->Resume(); } void SaveFileResourceHandler::OnReadCompleted(
diff --git a/content/browser/download/save_file_resource_handler.h b/content/browser/download/save_file_resource_handler.h index 63f061d..334837bc 100644 --- a/content/browser/download/save_file_resource_handler.h +++ b/content/browser/download/save_file_resource_handler.h
@@ -67,8 +67,9 @@ // Creates a new buffer, which will be handed to the download thread for file // writing and deletion. - bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) override; + void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) override; // Passes the buffer to the download file writer. void OnReadCompleted(int bytes_read,
diff --git a/content/browser/frame_host/OWNERS b/content/browser/frame_host/OWNERS index cb3028c3..6f288e7 100644 --- a/content/browser/frame_host/OWNERS +++ b/content/browser/frame_host/OWNERS
@@ -1,2 +1 @@ -alexmos@chromium.org -clamy@chromium.org +# COMPONENT: Internals>Sandbox>SiteIsolation
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 26fb404..b6086a0 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2549,8 +2549,7 @@ render_view_host_->GetWidget()->increment_in_flight_event_count(); render_view_host_->GetWidget()->StartHangMonitorTimeout( TimeDelta::FromMilliseconds(RenderViewHostImpl::kUnloadTimeoutMS), - blink::WebInputEvent::Undefined, - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_BEFORE_UNLOAD); + blink::WebInputEvent::Undefined); send_before_unload_start_time_ = base::TimeTicks::Now(); Send(new FrameMsg_BeforeUnload(routing_id_, is_reload)); } @@ -2624,14 +2623,11 @@ // leave the current page. In this case, use the regular timeout value used // during the beforeunload handling. if (is_before_unload_dialog) { - RendererUnresponsiveType type = - success ? RendererUnresponsiveType::RENDERER_UNRESPONSIVE_BEFORE_UNLOAD - : RendererUnresponsiveType::RENDERER_UNRESPONSIVE_DIALOG_CLOSED; render_view_host_->GetWidget()->StartHangMonitorTimeout( success ? TimeDelta::FromMilliseconds(RenderViewHostImpl::kUnloadTimeoutMS) : render_view_host_->GetWidget()->hung_renderer_delay(), - blink::WebInputEvent::Undefined, type); + blink::WebInputEvent::Undefined); } SendJavaScriptDialogReply(reply_msg, success, user_input); @@ -2644,8 +2640,7 @@ // a response. if (is_before_unload_dialog && dialog_was_suppressed) { render_view_host_->GetWidget()->delegate()->RendererUnresponsive( - render_view_host_->GetWidget(), - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_DIALOG_SUPPRESSED); + render_view_host_->GetWidget()); } }
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index 0141d86e..fb510b8 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -891,28 +891,28 @@ // we have a RenderViewHost for each RenderFrameHost. // TODO(creis): RenderViewHost will eventually go away and be replaced with // some form of page context. - RenderViewHostImpl* render_view_host_; + RenderViewHostImpl* const render_view_host_; - RenderFrameHostDelegate* delegate_; + RenderFrameHostDelegate* const delegate_; // The SiteInstance associated with this RenderFrameHost. All content drawn // in this RenderFrameHost is part of this SiteInstance. Cannot change over // time. - scoped_refptr<SiteInstanceImpl> site_instance_; + const scoped_refptr<SiteInstanceImpl> site_instance_; // The renderer process this RenderFrameHost is associated with. It is // equivalent to the result of site_instance_->GetProcess(), but that // method has the side effect of creating the process if it doesn't exist. // Cache a pointer to avoid unnecessary process creation. - RenderProcessHost* process_; + RenderProcessHost* const process_; // Reference to the whole frame tree that this RenderFrameHost belongs to. // Allows this RenderFrameHost to add and remove nodes in response to // messages from the renderer requesting DOM manipulation. - FrameTree* frame_tree_; + FrameTree* const frame_tree_; // The FrameTreeNode which this RenderFrameHostImpl is hosted in. - FrameTreeNode* frame_tree_node_; + FrameTreeNode* const frame_tree_node_; // The active parent RenderFrameHost for this frame, if it is a subframe. // Null for the main frame. This is cached because the parent FrameTreeNode
diff --git a/content/browser/loader/async_resource_handler.cc b/content/browser/loader/async_resource_handler.cc index 38433ab7..7d146f31 100644 --- a/content/browser/loader/async_resource_handler.cc +++ b/content/browser/loader/async_resource_handler.cc
@@ -361,21 +361,28 @@ controller->Resume(); } -bool AsyncResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) { +void AsyncResourceHandler::OnWillRead( + scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) { DCHECK(!has_controller()); - // TODO(mmenke): Should fail with ERR_INSUFFICIENT_RESOURCES here. - if (!CheckForSufficientResource()) - return false; + if (!CheckForSufficientResource()) { + controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); + return; + } // Return early if InliningHelper allocates the buffer, so that we should // inline the data into the IPC message without allocating SharedMemory. - if (inlining_helper_->PrepareInlineBufferIfApplicable(buf, buf_size)) - return true; + if (inlining_helper_->PrepareInlineBufferIfApplicable(buf, buf_size)) { + controller->Resume(); + return; + } - if (!EnsureResourceBufferIsInitialized()) - return false; + if (!EnsureResourceBufferIsInitialized()) { + controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); + return; + } DCHECK(buffer_->CanAllocate()); char* memory = buffer_->Allocate(&allocation_size_); @@ -384,7 +391,7 @@ *buf = new DependentIOBuffer(buffer_.get(), memory); *buf_size = allocation_size_; - return true; + controller->Resume(); } void AsyncResourceHandler::OnReadCompleted(
diff --git a/content/browser/loader/async_resource_handler.h b/content/browser/loader/async_resource_handler.h index dff9e67..85d98d41 100644 --- a/content/browser/loader/async_resource_handler.h +++ b/content/browser/loader/async_resource_handler.h
@@ -50,8 +50,9 @@ std::unique_ptr<ResourceController> controller) override; void OnWillStart(const GURL& url, std::unique_ptr<ResourceController> controller) override; - bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) override; + void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) override; void OnReadCompleted(int bytes_read, std::unique_ptr<ResourceController> controller) override; void OnResponseCompleted(
diff --git a/content/browser/loader/detachable_resource_handler.cc b/content/browser/loader/detachable_resource_handler.cc index c534a25..aa1f7bd 100644 --- a/content/browser/loader/detachable_resource_handler.cc +++ b/content/browser/loader/detachable_resource_handler.cc
@@ -36,7 +36,7 @@ // ResourceController implementation: void Resume() override { MarkAsUsed(); - detachable_handler_->Resume(); + detachable_handler_->ResumeInternal(); } void Cancel() override { @@ -78,6 +78,8 @@ : ResourceHandler(request), next_handler_(std::move(next_handler)), cancel_delay_(cancel_delay), + parent_read_buffer_(nullptr), + parent_read_buffer_size_(nullptr), is_finished_(false) { GetRequestInfo()->set_detachable_handler(this); } @@ -134,6 +136,23 @@ // The nested ResourceHandler may have logged that it's blocking the // request. Log it as no longer doing so, to avoid a DCHECK on resume. request()->LogUnblocked(); + + // If in the middle of an OnWillRead call, need to allocate the read buffer + // before resuming. + if (parent_read_buffer_) { + DCHECK(parent_read_buffer_size_); + + scoped_refptr<net::IOBuffer>* parent_read_buffer = parent_read_buffer_; + int* parent_read_buffer_size = parent_read_buffer_size_; + parent_read_buffer_ = nullptr; + parent_read_buffer_size_ = nullptr; + + // Will allocate the buffer and resume the request. + OnWillRead(parent_read_buffer, parent_read_buffer_size, + ReleaseController()); + return; + } + Resume(); } } @@ -183,17 +202,24 @@ next_handler_->OnWillStart(url, base::MakeUnique<Controller>(this)); } -bool DetachableResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) { +void DetachableResourceHandler::OnWillRead( + scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) { if (!next_handler_) { if (!read_buffer_.get()) read_buffer_ = new net::IOBuffer(kReadBufSize); *buf = read_buffer_; *buf_size = kReadBufSize; - return true; + controller->Resume(); + return; } - return next_handler_->OnWillRead(buf, buf_size); + parent_read_buffer_ = buf; + parent_read_buffer_size_ = buf_size; + + HoldController(std::move(controller)); + next_handler_->OnWillRead(buf, buf_size, base::MakeUnique<Controller>(this)); } void DetachableResourceHandler::OnReadCompleted( @@ -236,6 +262,12 @@ next_handler_->OnDataDownloaded(bytes_downloaded); } +void DetachableResourceHandler::ResumeInternal() { + parent_read_buffer_ = nullptr; + parent_read_buffer_size_ = nullptr; + Resume(); +} + void DetachableResourceHandler::OnTimedOut() { // Requests are only timed out after being detached, and shouldn't be deferred // once detached.
diff --git a/content/browser/loader/detachable_resource_handler.h b/content/browser/loader/detachable_resource_handler.h index c9599a24..3e7075a1 100644 --- a/content/browser/loader/detachable_resource_handler.h +++ b/content/browser/loader/detachable_resource_handler.h
@@ -14,6 +14,7 @@ #include "base/timer/timer.h" #include "content/browser/loader/resource_controller.h" #include "content/browser/loader/resource_handler.h" +#include "content/common/content_export.h" namespace net { class IOBuffer; @@ -34,7 +35,7 @@ // // Note that, once detached, the request continues without the original next // handler, so any policy decisions in that handler are skipped. -class DetachableResourceHandler : public ResourceHandler { +class CONTENT_EXPORT DetachableResourceHandler : public ResourceHandler { public: DetachableResourceHandler(net::URLRequest* request, base::TimeDelta cancel_delay, @@ -60,8 +61,9 @@ std::unique_ptr<ResourceController> controller) override; void OnWillStart(const GURL& url, std::unique_ptr<ResourceController> controller) override; - bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) override; + void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) override; void OnReadCompleted(int bytes_read, std::unique_ptr<ResourceController> controller) override; void OnResponseCompleted( @@ -72,6 +74,7 @@ private: class Controller; + void ResumeInternal(); void OnTimedOut(); std::unique_ptr<ResourceHandler> next_handler_; @@ -80,6 +83,12 @@ std::unique_ptr<base::OneShotTimer> detached_timer_; base::TimeDelta cancel_delay_; + // Only non-NULL between a call to |next_handler_|'s OnWillRead and it + // resuming the request. Needed so that if detached during that time, can + // complete the call. + scoped_refptr<net::IOBuffer>* parent_read_buffer_; + int* parent_read_buffer_size_; + bool is_finished_; DISALLOW_COPY_AND_ASSIGN(DetachableResourceHandler);
diff --git a/content/browser/loader/detachable_resource_handler_unittest.cc b/content/browser/loader/detachable_resource_handler_unittest.cc new file mode 100644 index 0000000..2905662a --- /dev/null +++ b/content/browser/loader/detachable_resource_handler_unittest.cc
@@ -0,0 +1,354 @@ +// 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 "content/browser/loader/detachable_resource_handler.h" + +#include <string> + +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" +#include "content/browser/loader/mock_resource_loader.h" +#include "content/browser/loader/resource_controller.h" +#include "content/browser/loader/test_resource_handler.h" +#include "content/public/browser/resource_request_info.h" +#include "content/public/common/resource_response.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "net/base/net_errors.h" +#include "net/url_request/redirect_info.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_status.h" +#include "net/url_request/url_request_test_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace content { + +namespace { + +// Full response body. +const char kResponseBody[] = "Nifty response body."; +// Two separate reads allow for testing cancellation in the middle of one read, +// and between reads. +const char kFirstBodyRead[] = "Nifty"; +const char kSecondBodyRead[] = " response body."; + +enum class DetachPhase { + DETACHED_FROM_CREATION, + ON_WILL_START, + REQUEST_REDIRECTED, + ON_RESPONSE_STARTED, + FIRST_ON_WILL_READ, + FIRST_ON_READ_COMPLETED, + SECOND_ON_WILL_READ, + SECOND_ON_READ_COMPLETED, + ON_READ_EOF, + ON_RESPONSE_COMPLETED, + NEVER_DETACH, +}; + +class DetachableResourceHandlerTest + : public testing::TestWithParam<DetachPhase> { + public: + DetachableResourceHandlerTest() + : request_(context_.CreateRequest(GURL("http://foo/"), + net::DEFAULT_PRIORITY, + nullptr)) { + ResourceRequestInfo::AllocateForTesting(request_.get(), + RESOURCE_TYPE_MAIN_FRAME, + nullptr, // context + 0, // render_process_id + 0, // render_view_id + 0, // render_frame_id + true, // is_main_frame + false, // parent_is_main_frame + true, // allow_download + true, // is_async + PREVIEWS_OFF); // previews_state + + std::unique_ptr<TestResourceHandler> test_handler; + if (GetParam() != DetachPhase::DETACHED_FROM_CREATION) { + test_handler = base::MakeUnique<TestResourceHandler>(); + test_handler_ = test_handler->GetWeakPtr(); + } + // TODO(mmenke): This file currently has no timeout tests. Should it? + detachable_handler_ = base::MakeUnique<DetachableResourceHandler>( + request_.get(), base::TimeDelta::FromMinutes(30), + std::move(test_handler)); + mock_loader_ = + base::MakeUnique<MockResourceLoader>(detachable_handler_.get()); + } + + // If the DetachableResourceHandler is supposed to detach the next handler at + // |phase|, attempts to detach the request. + void MaybeSyncDetachAtPhase(DetachPhase phase) { + if (GetParam() == phase) { + detachable_handler_->Detach(); + EXPECT_FALSE(test_handler_); + } + } + + // Returns true if the DetachableResourceHandler should have detached the next + // handler at or before the specified phase. Also checks that |test_handler_| + // is nullptr iff the request should have been detached by the specified + // phase. + bool WasDetachedBy(DetachPhase phase) { + if (GetParam() <= phase) { + EXPECT_FALSE(test_handler_); + return true; + } + EXPECT_TRUE(test_handler_); + return false; + } + + // If the DetachableResourceHandler is supposed to detach the next handler at + // |phase|, attempts to detach the request. Expected to be called in sync + // tests after the specified phase has started. Performs additional sanity + // checks based on that assumption. + void MaybeAsyncDetachAt(DetachPhase phase) { + if (GetParam() < phase) { + EXPECT_FALSE(test_handler_); + EXPECT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status()); + return; + } + + EXPECT_EQ(MockResourceLoader::Status::CALLBACK_PENDING, + mock_loader_->status()); + + if (GetParam() == phase) { + detachable_handler_->Detach(); + EXPECT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status()); + EXPECT_FALSE(test_handler_); + return; + } + + test_handler_->Resume(); + } + + protected: + TestBrowserThreadBundle thread_bundle_; + net::TestURLRequestContext context_; + std::unique_ptr<net::URLRequest> request_; + + base::WeakPtr<TestResourceHandler> test_handler_; + + std::unique_ptr<DetachableResourceHandler> detachable_handler_; + std::unique_ptr<MockResourceLoader> mock_loader_; +}; + +// Tests where ResourceHandler completes synchronously. Handler is detached +// just before the phase indicated by the DetachPhase parameter. +TEST_P(DetachableResourceHandlerTest, Sync) { + MaybeSyncDetachAtPhase(DetachPhase::ON_WILL_START); + ASSERT_EQ(MockResourceLoader::Status::IDLE, + mock_loader_->OnWillStart(request_->url())); + if (!WasDetachedBy(DetachPhase::ON_WILL_START)) { + EXPECT_EQ(1, test_handler_->on_will_start_called()); + EXPECT_EQ(0, test_handler_->on_request_redirected_called()); + } + + MaybeSyncDetachAtPhase(DetachPhase::REQUEST_REDIRECTED); + ASSERT_EQ( + MockResourceLoader::Status::IDLE, + mock_loader_->OnRequestRedirected( + net::RedirectInfo(), make_scoped_refptr(new ResourceResponse()))); + if (!WasDetachedBy(DetachPhase::REQUEST_REDIRECTED)) { + EXPECT_EQ(1, test_handler_->on_request_redirected_called()); + EXPECT_EQ(0, test_handler_->on_response_started_called()); + } + + MaybeSyncDetachAtPhase(DetachPhase::ON_RESPONSE_STARTED); + ASSERT_EQ(MockResourceLoader::Status::IDLE, + mock_loader_->OnResponseStarted( + make_scoped_refptr(new ResourceResponse()))); + if (!WasDetachedBy(DetachPhase::ON_RESPONSE_STARTED)) { + EXPECT_EQ(1, test_handler_->on_request_redirected_called()); + EXPECT_EQ(1, test_handler_->on_response_started_called()); + EXPECT_EQ(0, test_handler_->on_will_read_called()); + } + + MaybeSyncDetachAtPhase(DetachPhase::FIRST_ON_WILL_READ); + ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnWillRead()); + if (!WasDetachedBy(DetachPhase::FIRST_ON_WILL_READ)) { + EXPECT_EQ(1, test_handler_->on_will_read_called()); + EXPECT_EQ(0, test_handler_->on_read_completed_called()); + } + + MaybeSyncDetachAtPhase(DetachPhase::FIRST_ON_READ_COMPLETED); + ASSERT_EQ(MockResourceLoader::Status::IDLE, + mock_loader_->OnReadCompleted(kFirstBodyRead)); + if (!WasDetachedBy(DetachPhase::FIRST_ON_READ_COMPLETED)) { + EXPECT_EQ(1, test_handler_->on_read_completed_called()); + EXPECT_EQ(kFirstBodyRead, test_handler_->body()); + } + + MaybeSyncDetachAtPhase(DetachPhase::SECOND_ON_WILL_READ); + ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnWillRead()); + if (!WasDetachedBy(DetachPhase::SECOND_ON_WILL_READ)) { + EXPECT_EQ(2, test_handler_->on_will_read_called()); + EXPECT_EQ(1, test_handler_->on_read_completed_called()); + } + + MaybeSyncDetachAtPhase(DetachPhase::SECOND_ON_READ_COMPLETED); + ASSERT_EQ(MockResourceLoader::Status::IDLE, + mock_loader_->OnReadCompleted(kSecondBodyRead)); + if (!WasDetachedBy(DetachPhase::SECOND_ON_READ_COMPLETED)) { + EXPECT_EQ(2, test_handler_->on_will_read_called()); + EXPECT_EQ(2, test_handler_->on_read_completed_called()); + EXPECT_EQ(kResponseBody, test_handler_->body()); + } + + ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnWillRead()); + if (!WasDetachedBy(DetachPhase::SECOND_ON_READ_COMPLETED)) { + EXPECT_EQ(3, test_handler_->on_will_read_called()); + EXPECT_EQ(2, test_handler_->on_read_completed_called()); + EXPECT_EQ(0, test_handler_->on_response_completed_called()); + } + + MaybeSyncDetachAtPhase(DetachPhase::ON_READ_EOF); + ASSERT_EQ(MockResourceLoader::Status::IDLE, + mock_loader_->OnReadCompleted("")); + if (!WasDetachedBy(DetachPhase::ON_READ_EOF)) { + EXPECT_EQ(3, test_handler_->on_read_completed_called()); + EXPECT_EQ(1, test_handler_->on_read_eof_called()); + EXPECT_EQ(0, test_handler_->on_response_completed_called()); + } + + MaybeSyncDetachAtPhase(DetachPhase::ON_RESPONSE_COMPLETED); + ASSERT_EQ(MockResourceLoader::Status::IDLE, + mock_loader_->OnResponseCompleted( + net::URLRequestStatus::FromError(net::OK))); + if (!WasDetachedBy(DetachPhase::ON_RESPONSE_COMPLETED)) { + EXPECT_EQ(1, test_handler_->on_response_completed_called()); + EXPECT_EQ(kResponseBody, test_handler_->body()); + } +} + +// Tests where ResourceHandler completes asynchronously. Handler is detached +// during the phase indicated by the DetachPhase parameter. Async cases where +// the handler is detached between phases are similar enough to the sync tests +// that they wouldn't provide meaningfully better test coverage. +// +// Before the handler is detached, all calls complete asynchronously. +// Afterwards, they all complete synchronously. +TEST_P(DetachableResourceHandlerTest, Async) { + if (GetParam() != DetachPhase::DETACHED_FROM_CREATION) { + test_handler_->set_defer_on_will_start(true); + test_handler_->set_defer_on_request_redirected(true); + test_handler_->set_defer_on_response_started(true); + test_handler_->set_defer_on_will_read(true); + test_handler_->set_defer_on_read_completed(true); + test_handler_->set_defer_on_read_eof(true); + // Note: Can't set |defer_on_response_completed|, since the + // DetachableResourceHandler DCHECKs when the next handler tries to defer + // the ERR_ABORTED message it sends downstream. + } + + mock_loader_->OnWillStart(request_->url()); + if (test_handler_) { + EXPECT_EQ(1, test_handler_->on_will_start_called()); + EXPECT_EQ(0, test_handler_->on_request_redirected_called()); + } + MaybeAsyncDetachAt(DetachPhase::ON_WILL_START); + + mock_loader_->OnRequestRedirected(net::RedirectInfo(), + make_scoped_refptr(new ResourceResponse())); + if (test_handler_) { + EXPECT_EQ(1, test_handler_->on_request_redirected_called()); + EXPECT_EQ(0, test_handler_->on_response_started_called()); + } + MaybeAsyncDetachAt(DetachPhase::REQUEST_REDIRECTED); + + mock_loader_->OnResponseStarted(make_scoped_refptr(new ResourceResponse())); + if (test_handler_) { + EXPECT_EQ(1, test_handler_->on_request_redirected_called()); + EXPECT_EQ(1, test_handler_->on_response_started_called()); + EXPECT_EQ(0, test_handler_->on_will_read_called()); + } + MaybeAsyncDetachAt(DetachPhase::ON_RESPONSE_STARTED); + + mock_loader_->OnWillRead(); + if (test_handler_) { + EXPECT_EQ(1, test_handler_->on_will_read_called()); + EXPECT_EQ(0, test_handler_->on_read_completed_called()); + } + MaybeAsyncDetachAt(DetachPhase::FIRST_ON_WILL_READ); + + mock_loader_->OnReadCompleted(kFirstBodyRead); + if (test_handler_) { + EXPECT_EQ(1, test_handler_->on_read_completed_called()); + EXPECT_EQ(kFirstBodyRead, test_handler_->body()); + } + MaybeAsyncDetachAt(DetachPhase::FIRST_ON_READ_COMPLETED); + + if (test_handler_) + test_handler_->set_defer_on_will_read(true); + mock_loader_->OnWillRead(); + if (test_handler_) { + EXPECT_EQ(2, test_handler_->on_will_read_called()); + EXPECT_EQ(1, test_handler_->on_read_completed_called()); + } + MaybeAsyncDetachAt(DetachPhase::SECOND_ON_WILL_READ); + + if (test_handler_) + test_handler_->set_defer_on_read_completed(true); + mock_loader_->OnReadCompleted(kSecondBodyRead); + if (test_handler_) { + EXPECT_EQ(2, test_handler_->on_will_read_called()); + EXPECT_EQ(2, test_handler_->on_read_completed_called()); + EXPECT_EQ(kResponseBody, test_handler_->body()); + } + MaybeAsyncDetachAt(DetachPhase::SECOND_ON_READ_COMPLETED); + + // Test doesn't check detaching on the third OnWillRead call. + ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnWillRead()); + if (GetParam() > DetachPhase::SECOND_ON_READ_COMPLETED) { + EXPECT_EQ(3, test_handler_->on_will_read_called()); + EXPECT_EQ(2, test_handler_->on_read_completed_called()); + EXPECT_EQ(0, test_handler_->on_response_completed_called()); + } else { + EXPECT_FALSE(test_handler_); + } + + if (test_handler_) + test_handler_->set_defer_on_read_completed(true); + mock_loader_->OnReadCompleted(""); + if (test_handler_) { + EXPECT_EQ(3, test_handler_->on_read_completed_called()); + EXPECT_EQ(1, test_handler_->on_read_eof_called()); + EXPECT_EQ(0, test_handler_->on_response_completed_called()); + } + MaybeAsyncDetachAt(DetachPhase::ON_READ_EOF); + + if (test_handler_) + test_handler_->set_defer_on_response_completed(true); + mock_loader_->OnResponseCompleted(net::URLRequestStatus::FromError(net::OK)); + if (test_handler_) { + EXPECT_EQ(1, test_handler_->on_response_completed_called()); + EXPECT_EQ(kResponseBody, test_handler_->body()); + } + MaybeAsyncDetachAt(DetachPhase::ON_RESPONSE_COMPLETED); +} + +INSTANTIATE_TEST_CASE_P(/* No prefix needed*/, + DetachableResourceHandlerTest, + testing::Values(DetachPhase::DETACHED_FROM_CREATION, + DetachPhase::ON_WILL_START, + DetachPhase::REQUEST_REDIRECTED, + DetachPhase::ON_RESPONSE_STARTED, + DetachPhase::FIRST_ON_WILL_READ, + DetachPhase::FIRST_ON_READ_COMPLETED, + DetachPhase::SECOND_ON_WILL_READ, + DetachPhase::SECOND_ON_READ_COMPLETED, + DetachPhase::ON_READ_EOF, + DetachPhase::ON_RESPONSE_COMPLETED, + DetachPhase::NEVER_DETACH)); + +} // namespace + +} // namespace content
diff --git a/content/browser/loader/intercepting_resource_handler.cc b/content/browser/loader/intercepting_resource_handler.cc index 902ba30..77b28b4 100644 --- a/content/browser/loader/intercepting_resource_handler.cc +++ b/content/browser/loader/intercepting_resource_handler.cc
@@ -21,7 +21,9 @@ class InterceptingResourceHandler::Controller : public ResourceController { public: explicit Controller(InterceptingResourceHandler* mime_handler) - : intercepting_handler_(mime_handler) {} + : intercepting_handler_(mime_handler) { + DCHECK(intercepting_handler_->has_controller()); + } void Resume() override { MarkAsUsed(); @@ -92,21 +94,27 @@ DoLoop(); } -bool InterceptingResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) { - if (state_ == State::PASS_THROUGH) - return next_handler_->OnWillRead(buf, buf_size); +void InterceptingResourceHandler::OnWillRead( + scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) { + if (state_ == State::PASS_THROUGH) { + next_handler_->OnWillRead(buf, buf_size, std::move(controller)); + return; + } DCHECK_EQ(State::STARTING, state_); + DCHECK(!first_read_buffer_); + DCHECK_EQ(0, first_read_buffer_size_); + DCHECK(!parent_read_buffer_); + DCHECK(!parent_read_buffer_size_); - if (!next_handler_->OnWillRead(buf, buf_size)) - return false; + parent_read_buffer_ = buf; + parent_read_buffer_size_ = buf_size; - first_read_buffer_ = *buf; - first_read_buffer_size_ = *buf_size; - first_read_buffer_double_ = new net::IOBuffer(static_cast<size_t>(*buf_size)); - *buf = first_read_buffer_double_; - return true; + state_ = State::SENDING_ON_WILL_READ_TO_OLD_HANDLER; + HoldController(std::move(controller)); + DoLoop(); } void InterceptingResourceHandler::OnReadCompleted( @@ -191,6 +199,12 @@ case State::PASS_THROUGH: NOTREACHED(); break; + case State::SENDING_ON_WILL_READ_TO_OLD_HANDLER: + SendOnWillReadToOldHandler(); + break; + case State::WAITING_FOR_OLD_HANDLERS_BUFFER: + OnBufferReceived(); + break; case State::SENDING_ON_WILL_START_TO_NEW_HANDLER: SendOnResponseStartedToNewHandler(); break; @@ -213,9 +227,15 @@ case State::SENDING_PAYLOAD_TO_OLD_HANDLER: SendPayloadToOldHandler(); break; + case State::RECEIVING_BUFFER_FROM_OLD_HANDLER: + ReceivedBufferFromOldHandler(); + break; case State::SENDING_BUFFER_TO_NEW_HANDLER: SendFirstReadBufferToNewHandler(); break; + case State::SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER: + ReceivedBufferFromNewHandler(); + break; } } } @@ -245,6 +265,36 @@ weak_ptr_factory_.GetWeakPtr())); } +void InterceptingResourceHandler::SendOnWillReadToOldHandler() { + DCHECK_EQ(State::SENDING_ON_WILL_READ_TO_OLD_HANDLER, state_); + + state_ = State::WAITING_FOR_OLD_HANDLERS_BUFFER; + next_handler_->OnWillRead(&first_read_buffer_, &first_read_buffer_size_, + base::MakeUnique<Controller>(this)); +} + +void InterceptingResourceHandler::OnBufferReceived() { + DCHECK_EQ(State::WAITING_FOR_OLD_HANDLERS_BUFFER, state_); + + // TODO(mmenke): If this method is just going to allocate a double buffer + // anyways, can the call to the old handler's OnWillRead be removed? That + // would mean handling replaying data in the case that |next_handler_|'s + // buffer is smaller than the double buffer, but SendPayloadToOldHandler + // already handles that case, anyways, so could share that code with the + // no-swap path as well. Or better, just have MimeSniffingResourceHandler + // create and manage the buffer itself. + first_read_buffer_double_ = + new net::IOBuffer(static_cast<size_t>(first_read_buffer_size_)); + *parent_read_buffer_ = first_read_buffer_double_; + *parent_read_buffer_size_ = first_read_buffer_size_; + + parent_read_buffer_ = nullptr; + parent_read_buffer_size_ = nullptr; + + state_ = State::STARTING; + Resume(); +} + void InterceptingResourceHandler::SendOnResponseStartedToOldHandler() { state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER; next_handler_->OnResponseStarted(response_.get(), @@ -253,7 +303,10 @@ void InterceptingResourceHandler::SendPayloadToOldHandler() { DCHECK_EQ(State::SENDING_PAYLOAD_TO_OLD_HANDLER, state_); - if (payload_bytes_written_ == payload_for_old_handler_.size()) { + DCHECK(has_controller()); + + if (static_cast<size_t>(payload_bytes_written_) == + payload_for_old_handler_.size()) { net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0); if (payload_for_old_handler_.empty()) { // If there is no payload, just finalize the request on the old handler. @@ -273,29 +326,43 @@ return; } - scoped_refptr<net::IOBuffer> buffer; - int size = 0; - if (first_read_buffer_) { - // |first_read_buffer_| is a buffer gotten from |next_handler_| via - // OnWillRead. Use the buffer. - buffer = first_read_buffer_; - size = first_read_buffer_size_; + state_ = State::RECEIVING_BUFFER_FROM_OLD_HANDLER; - first_read_buffer_ = nullptr; - first_read_buffer_size_ = 0; - } else { - if (!next_handler_->OnWillRead(&buffer, &size)) { - Cancel(); - return; - } + scoped_refptr<net::IOBuffer> buffer; + // If |first_read_buffer_| is non-NULL, it was already received from + // |next_handler_| via OnWillRead. Can just use the buffer. + if (first_read_buffer_) { + DCHECK_GT(first_read_buffer_size_, 0); + + ResumeInternal(); + return; } - size = std::min(size, static_cast<int>(payload_for_old_handler_.size() - - payload_bytes_written_)); - memcpy(buffer->data(), - payload_for_old_handler_.data() + payload_bytes_written_, size); - payload_bytes_written_ += size; - next_handler_->OnReadCompleted(size, base::MakeUnique<Controller>(this)); + DCHECK(!first_read_buffer_size_); + next_handler_->OnWillRead(&first_read_buffer_, &first_read_buffer_size_, + base::MakeUnique<Controller>(this)); +} + +void InterceptingResourceHandler::ReceivedBufferFromOldHandler() { + DCHECK_EQ(State::RECEIVING_BUFFER_FROM_OLD_HANDLER, state_); + DCHECK(first_read_buffer_); + DCHECK_GT(first_read_buffer_size_, 0); + + int bytes_to_copy = + std::min(first_read_buffer_size_, + static_cast<int>(payload_for_old_handler_.size() - + payload_bytes_written_)); + memcpy(first_read_buffer_->data(), + payload_for_old_handler_.data() + payload_bytes_written_, + bytes_to_copy); + payload_bytes_written_ += bytes_to_copy; + + first_read_buffer_ = nullptr; + first_read_buffer_size_ = 0; + + state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER; + next_handler_->OnReadCompleted(bytes_to_copy, + base::MakeUnique<Controller>(this)); } void InterceptingResourceHandler::SendOnResponseStartedToNewHandler() { @@ -306,6 +373,8 @@ void InterceptingResourceHandler::SendFirstReadBufferToNewHandler() { DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER); + DCHECK(!new_handler_read_buffer_); + DCHECK(!new_handler_read_buffer_size_); if (first_read_buffer_bytes_written_ == first_read_buffer_bytes_read_) { state_ = State::PASS_THROUGH; @@ -314,19 +383,32 @@ return; } - scoped_refptr<net::IOBuffer> buf; - int size = 0; - if (!next_handler_->OnWillRead(&buf, &size)) { - Cancel(); - return; - } - size = std::min(size, static_cast<int>(first_read_buffer_bytes_read_ - - first_read_buffer_bytes_written_)); - memcpy(buf->data(), + state_ = State::SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER; + next_handler_->OnWillRead(&new_handler_read_buffer_, + &new_handler_read_buffer_size_, + base::MakeUnique<Controller>(this)); +} + +void InterceptingResourceHandler::ReceivedBufferFromNewHandler() { + DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER); + DCHECK(new_handler_read_buffer_); + DCHECK(new_handler_read_buffer_size_); + + int bytes_to_copy = + std::min(new_handler_read_buffer_size_, + static_cast<int>(first_read_buffer_bytes_read_ - + first_read_buffer_bytes_written_)); + memcpy(new_handler_read_buffer_->data(), first_read_buffer_double_->data() + first_read_buffer_bytes_written_, - size); - first_read_buffer_bytes_written_ += size; - next_handler_->OnReadCompleted(size, base::MakeUnique<Controller>(this)); + bytes_to_copy); + first_read_buffer_bytes_written_ += bytes_to_copy; + + new_handler_read_buffer_ = nullptr; + new_handler_read_buffer_size_ = 0; + + state_ = State::SENDING_BUFFER_TO_NEW_HANDLER; + next_handler_->OnReadCompleted(bytes_to_copy, + base::MakeUnique<Controller>(this)); } } // namespace content
diff --git a/content/browser/loader/intercepting_resource_handler.h b/content/browser/loader/intercepting_resource_handler.h index 56e6e0a..cbfbba4 100644 --- a/content/browser/loader/intercepting_resource_handler.h +++ b/content/browser/loader/intercepting_resource_handler.h
@@ -45,8 +45,9 @@ void OnResponseStarted( ResourceResponse* response, std::unique_ptr<ResourceController> controller) override; - bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) override; + void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) override; void OnReadCompleted(int bytes_read, std::unique_ptr<ResourceController> controller) override; void OnResponseCompleted( @@ -81,10 +82,18 @@ // handlers. SWAPPING_HANDLERS, + // States where the InterceptingResourceHandler passes the initial + // OnWillRead call to the old handler, and then waits for the resulting + // buffer read buffer. + SENDING_ON_WILL_READ_TO_OLD_HANDLER, + WAITING_FOR_OLD_HANDLERS_BUFFER, + // The InterceptingResourceHandler is sending the payload given via - // UseNewHandler to the old handler and waiting for its completion via - // Resume(). + // UseNewHandler to the old handler. The first state starts retrieving a + // buffer from the old handler, the second state copies as much of the data + // as possible to the received buffer and passes it to the old handler. SENDING_PAYLOAD_TO_OLD_HANDLER, + RECEIVING_BUFFER_FROM_OLD_HANDLER, // The InterceptingResourcHandler is calling the new handler's // OnResponseStarted method and waiting for its completion via Resume(). @@ -102,9 +111,12 @@ // called. WAITING_FOR_ON_READ_COMPLETED, - // The InterceptingResourceHandler is sending the old handler's contents to - // the new handler and waiting for its completion via Resume(). + // The two phases of uploading previously received data stored in + // |first_read_buffer_double_| to the new handler, which is now stored in + // |next_handler_|. The first state gets a buffer to write to, and the next + // copies all the data it can to that buffer. SENDING_BUFFER_TO_NEW_HANDLER, + SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER, // The InterceptingResourceHandler has replaced its next ResourceHandler if // needed, and has ensured the buffered read data was properly transmitted @@ -118,10 +130,14 @@ void ResumeInternal(); + void SendOnWillReadToOldHandler(); + void OnBufferReceived(); void SendOnResponseStartedToOldHandler(); void SendPayloadToOldHandler(); + void ReceivedBufferFromOldHandler(); void SendFirstReadBufferToNewHandler(); void SendOnResponseStartedToNewHandler(); + void ReceivedBufferFromNewHandler(); State state_ = State::STARTING; @@ -135,9 +151,21 @@ // Instead of |first_read_buffer_|, this handler creates a new IOBuffer with // the same size and return it to the client. scoped_refptr<net::IOBuffer> first_read_buffer_double_; - size_t first_read_buffer_size_ = 0; - size_t first_read_buffer_bytes_read_ = 0; - size_t first_read_buffer_bytes_written_ = 0; + int first_read_buffer_size_ = 0; + int first_read_buffer_bytes_read_ = 0; + int first_read_buffer_bytes_written_ = 0; + + // Information about the new handler's buffer while copying data from + // |first_read_buffer_double_| to the new handler's buffer. + // Note that when these are used, the old handler has been destroyed, and + // |next_handler_| is now the new one. + scoped_refptr<net::IOBuffer> new_handler_read_buffer_; + int new_handler_read_buffer_size_ = 0; + + // Pointers to parent-owned read buffer and its size. Only used for first + // OnWillRead call. + scoped_refptr<net::IOBuffer>* parent_read_buffer_ = nullptr; + int* parent_read_buffer_size_ = nullptr; scoped_refptr<ResourceResponse> response_;
diff --git a/content/browser/loader/intercepting_resource_handler_unittest.cc b/content/browser/loader/intercepting_resource_handler_unittest.cc index 5e41a48f..8d8dee1e 100644 --- a/content/browser/loader/intercepting_resource_handler_unittest.cc +++ b/content/browser/loader/intercepting_resource_handler_unittest.cc
@@ -36,22 +36,6 @@ namespace { -class TestResourceController : public ResourceController { - public: - TestResourceController() = default; - void Cancel() override {} - void CancelAndIgnore() override {} - void CancelWithError(int error_code) override {} - void Resume() override { ++resume_calls_; } - - int resume_calls() const { return resume_calls_; } - - private: - int resume_calls_ = 0; - - DISALLOW_COPY_AND_ASSIGN(TestResourceController); -}; - class InterceptingResourceHandlerTest : public testing::Test { public: InterceptingResourceHandlerTest() @@ -383,8 +367,10 @@ // OnResponseStarted and OnReadCompleted. TEST_F(InterceptingResourceHandlerTest, DeferredOperations) { const char kData[] = "The data"; - const std::string kPayload = "The long long long long long payload"; - const int kOldHandlerBufferSize = 10; + const char kPayload[] = "The long long long long long payload"; + // This should be less than half the size of the payload, so it needs at least + // 3 reads to receive. + const int kOldHandlerBufferSize = arraysize(kPayload) / 3; // When sending a payload to the old ResourceHandler, the // InterceptingResourceHandler doesn't send a final EOF read. @@ -392,13 +378,35 @@ // entirely? old_handler_->set_expect_eof_read(false); old_handler_->SetBufferSize(kOldHandlerBufferSize); + old_handler_->set_defer_on_will_read(true); old_handler_->set_defer_on_read_completed(true); scoped_refptr<net::IOBuffer> old_buffer = old_handler_->buffer(); // Simulate the MimeSniffingResourceHandler buffering the data. + ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnWillStart(request_->url())); - ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnWillRead()); + // The old handler defers the read. + ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING, + mock_loader_->OnWillRead()); + old_handler_->WaitUntilDeferred(); + + EXPECT_EQ(net::URLRequestStatus::IO_PENDING, old_handler_status_.status()); + EXPECT_EQ(1, old_handler_->on_will_read_called()); + EXPECT_EQ(0, old_handler_->on_read_completed_called()); + EXPECT_EQ(0, old_handler_->on_response_completed_called()); + + // Defer the next OnWillRead, too. This is needed to test the case where + // OnWillRead completes asynchronously when passing the payload to the old + // handler. + old_handler_->set_defer_on_will_read(true); + + // The old handle resumes the request. + old_handler_->Resume(); + + // Resume() call may do work asynchronously. Wait until that's done. + mock_loader_->WaitUntilIdleOrCanceled(); + ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status()); ASSERT_NE(mock_loader_->io_buffer(), old_buffer.get()); @@ -415,6 +423,7 @@ scoped_new_handler->SetBufferSize(1); scoped_new_handler->set_defer_on_will_start(true); scoped_new_handler->set_defer_on_response_started(true); + scoped_new_handler->set_defer_on_will_read(true); scoped_new_handler->set_defer_on_read_completed(true); scoped_new_handler->set_defer_on_response_completed(true); intercepting_handler_->UseNewHandler(std::move(scoped_new_handler), kPayload); @@ -424,6 +433,11 @@ ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING, mock_loader_->OnResponseStarted( make_scoped_refptr(new ResourceResponse()))); + old_handler_->WaitUntilDeferred(); + + EXPECT_EQ(1, old_handler_->on_read_completed_called()); + EXPECT_EQ(0, old_handler_->on_response_completed_called()); + EXPECT_EQ(0, new_handler->on_response_started_called()); // The old handler has received the first N bytes of the payload synchronously // where N is the size of the buffer exposed via OnWillRead. @@ -432,10 +446,24 @@ EXPECT_EQ(net::URLRequestStatus::IO_PENDING, old_handler_status_.status()); EXPECT_EQ(net::URLRequestStatus::IO_PENDING, new_handler_status.status()); + // Run until the old handler's OnWillRead method defers the request while + // replaying the payload. + old_handler_->Resume(); + old_handler_->WaitUntilDeferred(); + EXPECT_EQ(2, old_handler_->on_will_read_called()); + EXPECT_EQ(1, old_handler_->on_read_completed_called()); + EXPECT_EQ(0, old_handler_->on_response_completed_called()); + EXPECT_EQ(std::string(kPayload, 0, kOldHandlerBufferSize), old_handler_body_); + EXPECT_EQ(std::string(), new_handler_body); + EXPECT_EQ(net::URLRequestStatus::IO_PENDING, old_handler_status_.status()); + EXPECT_EQ(net::URLRequestStatus::IO_PENDING, new_handler_status.status()); + // Run until the new handler's OnWillStart method defers the request. old_handler_->Resume(); - // Resume() call may do work asynchronously. Wait until that's done. - base::RunLoop().RunUntilIdle(); + new_handler->WaitUntilDeferred(); + + EXPECT_EQ(1, new_handler->on_will_start_called()); + EXPECT_EQ(0, new_handler->on_response_started_called()); ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING, mock_loader_->status()); EXPECT_EQ(kPayload, old_handler_body_); @@ -447,7 +475,10 @@ // Run until the new handler's OnResponseStarted method defers the request. new_handler->Resume(); // Resume() call may do work asynchronously. Wait until that's done. - base::RunLoop().RunUntilIdle(); + new_handler->WaitUntilDeferred(); + + EXPECT_EQ(1, new_handler->on_response_started_called()); + EXPECT_EQ(0, new_handler->on_will_read_called()); ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING, mock_loader_->status()); EXPECT_EQ(std::string(), new_handler_body); @@ -458,27 +489,44 @@ mock_loader_->WaitUntilIdleOrCanceled(); ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status()); - // Data is read, the new handler defers completion of the read. + // Data is read, the new handler defers OnWillRead. ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING, mock_loader_->OnReadCompleted(kData)); + new_handler->WaitUntilDeferred(); + EXPECT_EQ(1, new_handler->on_will_read_called()); + EXPECT_EQ(0, new_handler->on_read_completed_called()); + + // The new ResourceHandler resumes, and then defers again in OnReadCompleted. + new_handler->Resume(); + new_handler->WaitUntilDeferred(); + EXPECT_EQ(1, new_handler->on_will_read_called()); + EXPECT_EQ(1, new_handler->on_read_completed_called()); + EXPECT_EQ(0, new_handler->on_response_completed_called()); EXPECT_EQ("T", new_handler_body); + // New handler resumes again, everything continues synchronously until all + // written data is consumed. new_handler->Resume(); mock_loader_->WaitUntilIdleOrCanceled(); ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status()); EXPECT_EQ(kData, new_handler_body); EXPECT_EQ(net::URLRequestStatus::IO_PENDING, new_handler_status.status()); + EXPECT_EQ(0, new_handler->on_read_eof_called()); + EXPECT_EQ(0, new_handler->on_response_completed_called()); // Final EOF byte is read. ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnWillRead()); ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnReadCompleted("")); + EXPECT_EQ(1, new_handler->on_read_eof_called()); + EXPECT_EQ(0, new_handler->on_response_completed_called()); ASSERT_EQ( MockResourceLoader::Status::CALLBACK_PENDING, mock_loader_->OnResponseCompleted({net::URLRequestStatus::SUCCESS, 0})); EXPECT_EQ(net::URLRequestStatus::SUCCESS, new_handler_status.status()); + EXPECT_EQ(1, new_handler->on_response_completed_called()); } // Test cancellation where there is only the old handler in an
diff --git a/content/browser/loader/layered_resource_handler.cc b/content/browser/loader/layered_resource_handler.cc index d1cf3a4..91d1787 100644 --- a/content/browser/loader/layered_resource_handler.cc +++ b/content/browser/loader/layered_resource_handler.cc
@@ -47,10 +47,12 @@ next_handler_->OnWillStart(url, std::move(controller)); } -bool LayeredResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) { +void LayeredResourceHandler::OnWillRead( + scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) { DCHECK(next_handler_.get()); - return next_handler_->OnWillRead(buf, buf_size); + return next_handler_->OnWillRead(buf, buf_size, std::move(controller)); } void LayeredResourceHandler::OnReadCompleted(
diff --git a/content/browser/loader/layered_resource_handler.h b/content/browser/loader/layered_resource_handler.h index 0a3846c1..2a714e3 100644 --- a/content/browser/loader/layered_resource_handler.h +++ b/content/browser/loader/layered_resource_handler.h
@@ -37,8 +37,9 @@ std::unique_ptr<ResourceController> controller) override; void OnWillStart(const GURL& url, std::unique_ptr<ResourceController> controller) override; - bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) override; + void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) override; void OnReadCompleted(int bytes_read, std::unique_ptr<ResourceController> controller) override; void OnResponseCompleted(
diff --git a/content/browser/loader/mime_sniffing_resource_handler.cc b/content/browser/loader/mime_sniffing_resource_handler.cc index e90fa81..29d9b12 100644 --- a/content/browser/loader/mime_sniffing_resource_handler.cc +++ b/content/browser/loader/mime_sniffing_resource_handler.cc
@@ -125,6 +125,8 @@ must_download_is_set_(false), read_buffer_size_(0), bytes_read_(0), + parent_read_buffer_(nullptr), + parent_read_buffer_size_(nullptr), intercepting_handler_(intercepting_handler), request_context_type_(request_context_type), in_state_loop_(false), @@ -215,24 +217,41 @@ AdvanceState(); } -bool MimeSniffingResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) { - if (state_ == STATE_STREAMING) - return next_handler_->OnWillRead(buf, buf_size); +void MimeSniffingResourceHandler::OnWillRead( + scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) { + DCHECK(buf); + DCHECK(buf_size); + DCHECK(!parent_read_buffer_); + DCHECK(!parent_read_buffer_size_); + + if (state_ == STATE_STREAMING) { + next_handler_->OnWillRead(buf, buf_size, std::move(controller)); + return; + } + + DCHECK_EQ(State::STATE_BUFFERING, state_); if (read_buffer_.get()) { CHECK_LT(bytes_read_, read_buffer_size_); *buf = new DependentIOBuffer(read_buffer_.get(), bytes_read_); *buf_size = read_buffer_size_ - bytes_read_; - } else { - if (!next_handler_->OnWillRead(buf, buf_size)) - return false; - - read_buffer_ = *buf; - read_buffer_size_ = *buf_size; - DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2); + controller->Resume(); + return; } - return true; + + DCHECK(!read_buffer_size_); + + parent_read_buffer_ = buf; + parent_read_buffer_size_ = buf_size; + + HoldController(std::move(controller)); + + // Have to go through AdvanceState here so that if OnWillRead completes + // synchronously, won't post a task. + state_ = State::STATE_CALLING_ON_WILL_READ; + AdvanceState(); } void MimeSniffingResourceHandler::OnReadCompleted( @@ -316,6 +335,12 @@ case STATE_BUFFERING: MaybeIntercept(); break; + case STATE_CALLING_ON_WILL_READ: + CallOnWillRead(); + break; + case STATE_WAITING_FOR_BUFFER: + BufferReceived(); + break; case STATE_INTERCEPTION_CHECK_DONE: ReplayResponseReceived(); break; @@ -324,7 +349,6 @@ break; case STATE_STARTING: case STATE_STREAMING: - in_state_loop_ = false; Resume(); return; default: @@ -348,6 +372,32 @@ ResumeInternal(); } +void MimeSniffingResourceHandler::CallOnWillRead() { + DCHECK_EQ(STATE_CALLING_ON_WILL_READ, state_); + + state_ = STATE_WAITING_FOR_BUFFER; + next_handler_->OnWillRead(&read_buffer_, &read_buffer_size_, + base::MakeUnique<Controller>(this)); +} + +void MimeSniffingResourceHandler::BufferReceived() { + DCHECK_EQ(STATE_WAITING_FOR_BUFFER, state_); + + DCHECK(read_buffer_); + DCHECK(parent_read_buffer_); + DCHECK(parent_read_buffer_size_); + DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2); + + *parent_read_buffer_ = read_buffer_; + *parent_read_buffer_size_ = read_buffer_size_; + + parent_read_buffer_ = nullptr; + parent_read_buffer_size_ = nullptr; + + state_ = State::STATE_BUFFERING; + Resume(); +} + void MimeSniffingResourceHandler::ReplayResponseReceived() { DCHECK_EQ(STATE_INTERCEPTION_CHECK_DONE, state_); state_ = STATE_REPLAYING_RESPONSE_RECEIVED;
diff --git a/content/browser/loader/mime_sniffing_resource_handler.h b/content/browser/loader/mime_sniffing_resource_handler.h index 47a9dff9..2120093 100644 --- a/content/browser/loader/mime_sniffing_resource_handler.h +++ b/content/browser/loader/mime_sniffing_resource_handler.h
@@ -66,6 +66,11 @@ // about request interception. STATE_BUFFERING, + // In these states, the MimeSniffingResourceHandler is calling OnWillRead on + // the downstream ResourceHandler and then waiting for the response. + STATE_CALLING_ON_WILL_READ, + STATE_WAITING_FOR_BUFFER, + // In this state, the MimeSniffingResourceHandler has identified the mime // type and made a decision on whether the request should be intercepted or // not. It is nows attempting to replay the response to downstream @@ -88,8 +93,9 @@ void OnResponseStarted( ResourceResponse* response, std::unique_ptr<ResourceController> controller) override; - bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) override; + void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) override; void OnReadCompleted(int bytes_read, std::unique_ptr<ResourceController> controller) override; void OnResponseCompleted( @@ -110,6 +116,12 @@ // Intercepts the request as a stream/download if needed. void MaybeIntercept(); + // Calls OnWillRead on the downstream handlers. + void CallOnWillRead(); + + // Copies received buffer to parent. + void BufferReceived(); + // Replays OnResponseStarted on the downstream handlers. void ReplayResponseReceived(); @@ -167,6 +179,11 @@ int read_buffer_size_; int bytes_read_; + // Pointers to parent-owned read buffer and its size. Only used for first + // OnWillRead call. + scoped_refptr<net::IOBuffer>* parent_read_buffer_; + int* parent_read_buffer_size_; + // The InterceptingResourceHandler that will perform ResourceHandler swap if // needed. InterceptingResourceHandler* intercepting_handler_;
diff --git a/content/browser/loader/mime_sniffing_resource_handler_unittest.cc b/content/browser/loader/mime_sniffing_resource_handler_unittest.cc index 0cc90f6..ae18ed3b 100644 --- a/content/browser/loader/mime_sniffing_resource_handler_unittest.cc +++ b/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
@@ -189,6 +189,7 @@ void TestHandlerSniffing(bool response_started, bool defer_response_started, bool will_read, + bool defer_will_read, bool read_completed, bool defer_read_completed); @@ -197,6 +198,7 @@ void TestHandlerNoSniffing(bool response_started, bool defer_response_started, bool will_read, + bool defer_will_read, bool read_completed, bool defer_read_completed); @@ -312,6 +314,7 @@ bool response_started, bool defer_response_started, bool will_read, + bool defer_will_read, bool read_completed, bool defer_read_completed) { net::URLRequestContext context; @@ -343,6 +346,7 @@ scoped_test_handler->set_on_response_started_result(response_started); scoped_test_handler->set_defer_on_response_started(defer_response_started); scoped_test_handler->set_on_will_read_result(will_read); + scoped_test_handler->set_defer_on_will_read(defer_will_read); scoped_test_handler->set_on_read_completed_result(read_completed); scoped_test_handler->set_defer_on_read_completed(defer_read_completed); TestResourceHandler* test_handler = scoped_test_handler.get(); @@ -384,6 +388,16 @@ return; } + if (defer_will_read) { + ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING, + mock_loader.status()); + EXPECT_EQ(MimeSniffingResourceHandler::STATE_WAITING_FOR_BUFFER, + mime_sniffing_handler.state_); + test_handler->Resume(); + // MimeSniffingResourceHandler may not synchronously resume the request. + base::RunLoop().RunUntilIdle(); + } + ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader.status()); // Simulate an HTML page. The mime sniffer will identify the MimeType and @@ -462,6 +476,7 @@ bool response_started, bool defer_response_started, bool will_read, + bool defer_will_read, bool read_completed, bool defer_read_completed) { net::URLRequestContext context; @@ -493,6 +508,7 @@ scoped_test_handler->set_on_response_started_result(response_started); scoped_test_handler->set_defer_on_response_started(defer_response_started); scoped_test_handler->set_on_will_read_result(will_read); + scoped_test_handler->set_defer_on_will_read(defer_will_read); scoped_test_handler->set_on_read_completed_result(read_completed); scoped_test_handler->set_defer_on_read_completed(defer_read_completed); TestResourceHandler* test_handler = scoped_test_handler.get(); @@ -560,6 +576,16 @@ return; } + if (defer_will_read) { + ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING, + mock_loader.status()); + EXPECT_EQ(MimeSniffingResourceHandler::STATE_STREAMING, + mime_sniffing_handler.state_); + test_handler->Resume(); + // MimeSniffingResourceHandler may not synchronously resume the request. + base::RunLoop().RunUntilIdle(); + } + ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader.status()); mock_loader.OnReadCompleted(std::string(2000, 'a')); @@ -722,136 +748,110 @@ // Test that the MimeSniffingHandler operates properly when it doesn't sniff // resources. +// TODO(mmenke): None of these test async cancellation. Should they? TEST_F(MimeSniffingResourceHandlerTest, NoSniffing) { // Test simple case. TestHandlerNoSniffing( - true /* response_started_succeeds */, - false /* defer_response_started */, - true /* will_read_succeeds */, - true /* read_completed_succeeds */, - false /* defer_read_completed */); + true /* response_started_succeeds */, false /* defer_response_started */, + true /* will_read_succeeds */, false /* defer_will_read */, + true /* read_completed_succeeds */, false /* defer_read_completed */); - // Test deferral in OnResponseStarted and/or in OnReadCompleted. + // Test deferral. TestHandlerNoSniffing( - true /* response_started_succeeds */, - true /* defer_response_started */, - true /* will_read_succeeds */, - true /* read_completed_succeeds */, - false /* defer_read_completed */); + true /* response_started_succeeds */, true /* defer_response_started */, + true /* will_read_succeeds */, false /* defer_will_read */, + true /* read_completed_succeeds */, false /* defer_read_completed */); TestHandlerNoSniffing( - true /* response_started_succeeds */, - false /* defer_response_started */, - true /* will_read_succeeds */, - true /* read_completed_succeeds */, - true /* defer_read_completed */); + true /* response_started_succeeds */, false /* defer_response_started */, + true /* will_read_succeeds */, true /* defer_will_read */, + true /* read_completed_succeeds */, false /* defer_read_completed */); TestHandlerNoSniffing( - true /* response_started_succeeds */, - true /* defer_response_started */, - true /* will_read_succeeds */, - true /* read_completed_succeeds */, - true /* defer_read_completed */); + true /* response_started_succeeds */, false /* defer_response_started */, + true /* will_read_succeeds */, false /* defer_will_read */, + true /* read_completed_succeeds */, true /* defer_read_completed */); + TestHandlerNoSniffing( + true /* response_started_succeeds */, true /* defer_response_started */, + true /* will_read_succeeds */, true /* defer_will_read */, + true /* read_completed_succeeds */, true /* defer_read_completed */); // Test cancel in OnResponseStarted, OnWillRead, OnReadCompleted. TestHandlerNoSniffing( - false /* response_started_succeeds */, - false /* defer_response_started */, - false /* will_read_succeeds */, - false /* read_completed_succeeds */, - false /* defer_read_completed */); + false /* response_started_succeeds */, false /* defer_response_started */, + false /* will_read_succeeds */, false /* defer_will_read */, + false /* read_completed_succeeds */, false /* defer_read_completed */); TestHandlerNoSniffing( - true /* response_started_succeeds */, - false /* defer_response_started */, - false /* will_read_succeeds */, - false /* read_completed_succeeds */, - false /* defer_read_completed */); + true /* response_started_succeeds */, false /* defer_response_started */, + false /* will_read_succeeds */, false /* defer_will_read */, + false /* read_completed_succeeds */, false /* defer_read_completed */); TestHandlerNoSniffing( - true /* response_started_succeeds */, - false /* defer_response_started */, - true /* will_read_succeeds */, - false /* read_completed_succeeds */, - false /* defer_read_completed */); + true /* response_started_succeeds */, false /* defer_response_started */, + true /* will_read_succeeds */, false /* defer_will_read */, + false /* read_completed_succeeds */, false /* defer_read_completed */); - // Test cancel after OnResponseStarted deferral. + // Test cancel after deferral. TestHandlerNoSniffing( - true /* response_started_succeeds */, - true /* defer_response_started */, - false /* will_read_succeeds */, - false /* read_completed_succeeds */, - false /* defer_read_completed */); + true /* response_started_succeeds */, true /* defer_response_started */, + false /* will_read_succeeds */, false /* defer_will_read */, + false /* read_completed_succeeds */, false /* defer_read_completed */); TestHandlerNoSniffing( - true /* response_started_succeeds */, - true /* defer_response_started */, - true /* will_read_succeeds */, - false /* read_completed_succeeds */, - false /* defer_read_completed */); + true /* response_started_succeeds */, true /* defer_response_started */, + true /* defer_will_read */, true /* will_read_succeeds */, + false /* read_completed_succeeds */, false /* defer_read_completed */); content::RunAllPendingInMessageLoop(); } // Test that the MimeSniffingHandler operates properly when it sniffs // resources. +// TODO(mmenke): None of these test async cancellation. Should they? TEST_F(MimeSniffingResourceHandlerTest, Sniffing) { // Test simple case. TestHandlerSniffing( - true /* response_started_succeeds */, - false /* defer_response_started */, - true /* will_read_succeeds */, - true /* read_completed_succeeds */, - false /* defer_read_completed */); + true /* response_started_succeeds */, false /* defer_response_started */, + true /* will_read_succeeds */, false /* defer_will_read */, + true /* read_completed_succeeds */, false /* defer_read_completed */); - // Test deferral in OnResponseStarted and/or in OnReadCompleted. + // Test deferral. TestHandlerSniffing( - true /* response_started_succeeds */, - true /* defer_response_started */, - true /* will_read_succeeds */, - true /* read_completed_succeeds */, - false /* defer_read_completed */); + true /* response_started_succeeds */, true /* defer_response_started */, + true /* will_read_succeeds */, false /* defer_will_read */, + true /* read_completed_succeeds */, false /* defer_read_completed */); TestHandlerSniffing( - true /* response_started_succeeds */, - false /* defer_response_started */, - true /* will_read_succeeds */, - true /* read_completed_succeeds */, - true /* defer_read_completed */); + true /* response_started_succeeds */, false /* defer_response_started */, + true /* will_read_succeeds */, true /* defer_will_read */, + true /* read_completed_succeeds */, false /* defer_read_completed */); TestHandlerSniffing( - true /* response_started_succeeds */, - true /* defer_response_started */, - true /* will_read_succeeds */, - true /* read_completed_succeeds */, - true /* defer_read_completed */); + true /* response_started_succeeds */, false /* defer_response_started */, + true /* will_read_succeeds */, false /* defer_will_read */, + true /* read_completed_succeeds */, true /* defer_read_completed */); + TestHandlerSniffing( + true /* response_started_succeeds */, true /* defer_response_started */, + true /* will_read_succeeds */, true /* defer_will_read */, + true /* read_completed_succeeds */, true /* defer_read_completed */); // Test cancel in OnResponseStarted, OnWillRead, OnReadCompleted. TestHandlerSniffing( - false /* response_started_succeeds */, - false /* defer_response_started */, - false /* will_read_succeeds */, - false /* read_completed_succeeds */, - false /* defer_read_completed */); + false /* response_started_succeeds */, false /* defer_response_started */, + false /* will_read_succeeds */, false /* defer_will_read */, + false /* read_completed_succeeds */, false /* defer_read_completed */); TestHandlerSniffing( - true /* response_started_succeeds */, - false /* defer_response_started */, - false /* will_read_succeeds */, - false /* read_completed_succeeds */, - false /* defer_read_completed */); + true /* response_started_succeeds */, false /* defer_response_started */, + false /* will_read_succeeds */, false /* defer_will_read */, + false /* read_completed_succeeds */, false /* defer_read_completed */); TestHandlerSniffing( - true /* response_started_succeeds */, - false /* defer_response_started */, - true /* will_read_succeeds */, - false /* read_completed_succeeds */, - false /* defer_read_completed */); + true /* response_started_succeeds */, false /* defer_response_started */, + true /* will_read_succeeds */, false /* defer_will_read */, + false /* read_completed_succeeds */, false /* defer_read_completed */); - // Test cancel after OnResponseStarted deferral. + // Test cancel after deferral. TestHandlerSniffing( - true /* response_started_succeeds */, - true /* defer_response_started */, - false /* will_read_succeeds */, - false /* read_completed_succeeds */, - false /* defer_read_completed */); + true /* response_started_succeeds */, true /* defer_response_started */, + false /* will_read_succeeds */, false /* defer_will_read */, + false /* read_completed_succeeds */, false /* defer_read_completed */); TestHandlerSniffing( - true /* response_started_succeeds */, - true /* defer_response_started */, - true /* will_read_succeeds */, - false /* read_completed_succeeds */, - false /* defer_read_completed */); + true /* response_started_succeeds */, true /* defer_response_started */, + true /* will_read_succeeds */, true /* defer_will_read */, + false /* read_completed_succeeds */, false /* defer_read_completed */); content::RunAllPendingInMessageLoop(); }
diff --git a/content/browser/loader/mock_resource_loader.cc b/content/browser/loader/mock_resource_loader.cc index 56ed554c..391782b 100644 --- a/content/browser/loader/mock_resource_loader.cc +++ b/content/browser/loader/mock_resource_loader.cc
@@ -98,25 +98,19 @@ EXPECT_EQ(Status::IDLE, status_); status_ = Status::CALLING_HANDLER; - bool result = - resource_handler_->OnWillRead(&io_buffer_, &io_buffer_size_); - - // The second case isn't really allowed, but a number of classes do it - // anyways. - EXPECT_TRUE(status_ == Status::CALLING_HANDLER || - (result == false && status_ == Status::CANCELED)); - if (!result) { - // In the case of double-cancels, keep the old error code. - if (status_ != Status::CANCELED) - error_code_ = net::ERR_ABORTED; - EXPECT_EQ(0, io_buffer_size_); + waiting_on_buffer_ = true; + resource_handler_->OnWillRead( + &io_buffer_, &io_buffer_size_, + base::MakeUnique<TestResourceController>(weak_factory_.GetWeakPtr())); + if (status_ == Status::CALLING_HANDLER) { + // Shouldn't update |io_buffer_| or |io_buffer_size_| yet if Resume() + // hasn't yet been called. EXPECT_FALSE(io_buffer_); - status_ = Status::CANCELED; - } else { - EXPECT_LT(0, io_buffer_size_); - EXPECT_TRUE(io_buffer_); - status_ = Status::IDLE; + EXPECT_EQ(0, io_buffer_size_); + + status_ = Status::CALLBACK_PENDING; } + return status_; }; @@ -196,6 +190,9 @@ status_ = Status::CANCELED; canceled_out_of_band_ = true; + // If OnWillRead was deferred, no longer waiting on a buffer. + waiting_on_buffer_ = false; + // To mimic real behavior, keep old error, in the case of double-cancel. if (error_code_ == net::OK) error_code_ = error_code; @@ -211,6 +208,13 @@ if (canceled_out_of_band_ && status_ == Status::CANCELED) return; + // Shouldn't update |io_buffer_| or |io_buffer_size_| on cancel. + if (waiting_on_buffer_) { + EXPECT_FALSE(io_buffer_); + EXPECT_EQ(0, io_buffer_size_); + waiting_on_buffer_ = false; + } + EXPECT_LT(error_code, 0); EXPECT_TRUE(status_ == Status::CALLBACK_PENDING || status_ == Status::CALLING_HANDLER); @@ -222,6 +226,14 @@ } void MockResourceLoader::OnResume() { + if (waiting_on_buffer_) { + EXPECT_TRUE(io_buffer_); + EXPECT_LT(0, io_buffer_size_); + + waiting_on_buffer_ = false; + } + + // Shouldn't update |io_buffer_| or |io_buffer_size_| on cancel. EXPECT_TRUE(status_ == Status::CALLBACK_PENDING || status_ == Status::CALLING_HANDLER);
diff --git a/content/browser/loader/mock_resource_loader.h b/content/browser/loader/mock_resource_loader.h index 23ad76f..5922ade 100644 --- a/content/browser/loader/mock_resource_loader.h +++ b/content/browser/loader/mock_resource_loader.h
@@ -103,6 +103,10 @@ scoped_refptr<net::IOBuffer> io_buffer_; int io_buffer_size_ = 0; + // True if waiting to receive a buffer due to an OnWillRead call. This does + // not affect behavior; it's only used for DCHECKing. + bool waiting_on_buffer_ = false; + std::unique_ptr<base::RunLoop> canceled_or_idle_run_loop_; base::WeakPtrFactory<MockResourceLoader> weak_factory_;
diff --git a/content/browser/loader/mojo_async_resource_handler.cc b/content/browser/loader/mojo_async_resource_handler.cc index 246133d..20a9bf1 100644 --- a/content/browser/loader/mojo_async_resource_handler.cc +++ b/content/browser/loader/mojo_async_resource_handler.cc
@@ -223,11 +223,14 @@ controller->Resume(); } -bool MojoAsyncResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) { - // TODO(mmenke): Cancel with net::ERR_INSUFFICIENT_RESOURCES instead. - if (!CheckForSufficientResource()) - return false; +void MojoAsyncResourceHandler::OnWillRead( + scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) { + if (!CheckForSufficientResource()) { + controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); + return; + } if (!shared_writer_) { MojoCreateDataPipeOptions options; @@ -248,18 +251,23 @@ bool defer = false; scoped_refptr<net::IOBufferWithSize> buffer; - if (!AllocateWriterIOBuffer(&buffer, &defer)) - return false; + if (!AllocateWriterIOBuffer(&buffer, &defer)) { + controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); + return; + } if (!defer) { if (static_cast<size_t>(buffer->size()) >= kMinAllocationSize) { *buf = buffer_ = buffer; *buf_size = buffer_->size(); - return true; + controller->Resume(); + return; } // The allocated buffer is too small. - if (EndWrite(0) != MOJO_RESULT_OK) - return false; + if (EndWrite(0) != MOJO_RESULT_OK) { + controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); + return; + } } DCHECK(!is_using_io_buffer_not_from_writer_); is_using_io_buffer_not_from_writer_ = true; @@ -269,7 +277,7 @@ DCHECK_EQ(0u, buffer_offset_); *buf = buffer_; *buf_size = buffer_->size(); - return true; + controller->Resume(); } void MojoAsyncResourceHandler::OnReadCompleted(
diff --git a/content/browser/loader/mojo_async_resource_handler.h b/content/browser/loader/mojo_async_resource_handler.h index 9639460..b8cd1e5 100644 --- a/content/browser/loader/mojo_async_resource_handler.h +++ b/content/browser/loader/mojo_async_resource_handler.h
@@ -69,8 +69,9 @@ std::unique_ptr<ResourceController> controller) override; void OnWillStart(const GURL& url, std::unique_ptr<ResourceController> controller) override; - bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) override; + void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) override; void OnReadCompleted(int bytes_read, std::unique_ptr<ResourceController> controller) override; void OnResponseCompleted(
diff --git a/content/browser/loader/mojo_async_resource_handler_unittest.cc b/content/browser/loader/mojo_async_resource_handler_unittest.cc index 1e6ed74c..2a29d61 100644 --- a/content/browser/loader/mojo_async_resource_handler_unittest.cc +++ b/content/browser/loader/mojo_async_resource_handler_unittest.cc
@@ -518,8 +518,7 @@ ASSERT_TRUE(CallOnWillStartAndOnResponseStarted()); ASSERT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->OnWillRead()); - // TODO(mmenke): Make this fail with net::ERR_INSUFFICIENT_RESOURCES. - EXPECT_EQ(net::ERR_ABORTED, mock_loader_->error_code()); + EXPECT_EQ(net::ERR_INSUFFICIENT_RESOURCES, mock_loader_->error_code()); EXPECT_EQ(1, rdh_.num_in_flight_requests_for_testing()); handler_ = nullptr; EXPECT_EQ(0, rdh_.num_in_flight_requests_for_testing());
diff --git a/content/browser/loader/navigation_resource_handler.cc b/content/browser/loader/navigation_resource_handler.cc index 0c35c8e..5e6dd69 100644 --- a/content/browser/loader/navigation_resource_handler.cc +++ b/content/browser/loader/navigation_resource_handler.cc
@@ -154,11 +154,13 @@ controller->Resume(); } -bool NavigationResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) { +void NavigationResourceHandler::OnWillRead( + scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) { DCHECK(!has_controller()); writer_.OnWillRead(buf, buf_size, -1); - return true; + controller->Resume(); } void NavigationResourceHandler::OnReadCompleted(
diff --git a/content/browser/loader/navigation_resource_handler.h b/content/browser/loader/navigation_resource_handler.h index 935b203..c605e62 100644 --- a/content/browser/loader/navigation_resource_handler.h +++ b/content/browser/loader/navigation_resource_handler.h
@@ -54,8 +54,9 @@ std::unique_ptr<ResourceController> controller) override; void OnWillStart(const GURL& url, std::unique_ptr<ResourceController> controller) override; - bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) override; + void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) override; void OnReadCompleted(int bytes_read, std::unique_ptr<ResourceController> controller) override; void OnResponseCompleted(
diff --git a/content/browser/loader/redirect_to_file_resource_handler.cc b/content/browser/loader/redirect_to_file_resource_handler.cc index b9784b06..3bddfd7 100644 --- a/content/browser/loader/redirect_to_file_resource_handler.cc +++ b/content/browser/loader/redirect_to_file_resource_handler.cc
@@ -185,9 +185,10 @@ } } -bool RedirectToFileResourceHandler::OnWillRead( +void RedirectToFileResourceHandler::OnWillRead( scoped_refptr<net::IOBuffer>* buf, - int* buf_size) { + int* buf_size, + std::unique_ptr<ResourceController> controller) { if (buf_->capacity() < next_buffer_size_) buf_->SetCapacity(next_buffer_size_); @@ -198,7 +199,7 @@ *buf_size = buf_->RemainingCapacity(); buf_write_pending_ = true; - return true; + controller->Resume(); } void RedirectToFileResourceHandler::OnReadCompleted(
diff --git a/content/browser/loader/redirect_to_file_resource_handler.h b/content/browser/loader/redirect_to_file_resource_handler.h index 7c91cac..9f642e7 100644 --- a/content/browser/loader/redirect_to_file_resource_handler.h +++ b/content/browser/loader/redirect_to_file_resource_handler.h
@@ -68,8 +68,9 @@ std::unique_ptr<ResourceController> controller) override; void OnWillStart(const GURL& url, std::unique_ptr<ResourceController> controller) override; - bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) override; + void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) override; void OnReadCompleted(int bytes_read, std::unique_ptr<ResourceController> controller) override; void OnResponseCompleted(
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc index b1a2e012..aa7b57b8 100644 --- a/content/browser/loader/resource_dispatcher_host_unittest.cc +++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -2429,15 +2429,14 @@ for (size_t i = 0; i < kMaxRequestsPerProcess; ++i) CheckSuccessfulRequest(msgs[i], net::URLRequestTestJob::test_data_2()); - // TODO(mmenke): These should be failing with ERR_INSUFFICIENT_RESOURCES. - // Update OnWillRead to use a ResourceController so it can fail with different - // error codes. CheckFailedRequest(msgs[kMaxRequestsPerProcess + 0], - net::URLRequestTestJob::test_data_2(), net::ERR_ABORTED); + net::URLRequestTestJob::test_data_2(), + net::ERR_INSUFFICIENT_RESOURCES); CheckSuccessfulRequest(msgs[kMaxRequestsPerProcess + 1], net::URLRequestTestJob::test_data_2()); CheckFailedRequest(msgs[kMaxRequestsPerProcess + 2], - net::URLRequestTestJob::test_data_2(), net::ERR_ABORTED); + net::URLRequestTestJob::test_data_2(), + net::ERR_INSUFFICIENT_RESOURCES); second_filter->OnChannelClosing(); third_filter->OnChannelClosing();
diff --git a/content/browser/loader/resource_handler.h b/content/browser/loader/resource_handler.h index cf4a5a0..c292cab2 100644 --- a/content/browser/loader/resource_handler.h +++ b/content/browser/loader/resource_handler.h
@@ -106,12 +106,11 @@ // Unlike other methods, may be called synchronously on Resume, for // performance reasons. // - // If the handler returns false, then the request is cancelled. Otherwise, - // once data is available, OnReadCompleted will be called. - // TODO(mmenke): Make this method use a ResourceController, and allow it to - // succeed asynchronously. - virtual bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) = 0; + // The request will not continue until one of |controller|'s resume or + // cancellation methods is invoked. + virtual void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) = 0; // Data (*bytes_read bytes) was written into the buffer provided by // OnWillRead. The request will not continue until one of |controller|'s
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc index 6e9610b..eafe829 100644 --- a/content/browser/loader/resource_loader.cc +++ b/content/browser/loader/resource_loader.cc
@@ -512,10 +512,20 @@ // was called from Resume(). FollowDeferredRedirectInternal(); break; + case DEFERRED_ON_WILL_READ: + // Always post a task, as synchronous resumes don't go through this + // method. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&ResourceLoader::ReadMore, weak_ptr_factory_.GetWeakPtr(), + false /* handle_result_asynchronously */)); + break; case DEFERRED_READ: if (called_from_resource_controller) { - // TODO(mmenke): Call ReadMore instead? Strange that this is the only - // path which calls different methods, depending on the path. + // TODO(mmenke): Call PrepareToReadMore instead? Strange that this is + // the only case which calls different methods, depending on the path. + // ResumeReading does check for cancellation. Should other paths do that + // as well? base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&ResourceLoader::ResumeReading, weak_ptr_factory_.GetWeakPtr())); @@ -523,7 +533,7 @@ // If this was called as a result of a handler succeeding synchronously, // force the result of the next read to be handled asynchronously, to // avoid blocking the IO thread. - ReadMore(true /* handle_result_asynchronously */); + PrepareToReadMore(true /* handle_result_asynchronously */); } break; case DEFERRED_RESPONSE_COMPLETE: @@ -638,40 +648,45 @@ read_deferral_start_time_ = base::TimeTicks::Now(); // Using a ScopedDeferral here would result in calling ReadMore(true) on sync - // success. Calling ReadMore(false) here instead allows small responses to be - // handled completely synchronously, if no ResourceHandler defers handling of - // the response. + // success. Calling PrepareToReadMore(false) here instead allows small + // responses to be handled completely synchronously, if no ResourceHandler + // defers handling of the response. deferred_stage_ = DEFERRED_SYNC; handler_->OnResponseStarted(response.get(), base::MakeUnique<Controller>(this)); if (is_deferred()) { deferred_stage_ = DEFERRED_READ; } else { - ReadMore(false); + PrepareToReadMore(false); + } +} + +void ResourceLoader::PrepareToReadMore(bool handle_result_async) { + TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::PrepareToReadMore", this, + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); + DCHECK(!is_deferred()); + + deferred_stage_ = DEFERRED_SYNC; + + handler_->OnWillRead(&read_buffer_, &read_buffer_size_, + base::MakeUnique<Controller>(this)); + + if (is_deferred()) { + deferred_stage_ = DEFERRED_ON_WILL_READ; + } else { + ReadMore(handle_result_async); } } void ResourceLoader::ReadMore(bool handle_result_async) { - TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::ReadMore", this, - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - DCHECK(!is_deferred()); + DCHECK(read_buffer_.get()); + DCHECK_GT(read_buffer_size_, 0); - // Make sure we track the buffer in at least one place. This ensures it gets - // deleted even in the case the request has already finished its job and - // doesn't use the buffer. - scoped_refptr<net::IOBuffer> buf; - int buf_size; - if (!handler_->OnWillRead(&buf, &buf_size)) { - // Cancel the request, which will then call back into |this| to inform it of - // a "read error". - Cancel(); - return; - } - - DCHECK(buf.get()); - DCHECK(buf_size > 0); - - int result = request_->Read(buf.get(), buf_size); + int result = request_->Read(read_buffer_.get(), read_buffer_size_); + // Have to do this after the Read call, to ensure it still has an outstanding + // reference. + read_buffer_ = nullptr; + read_buffer_size_ = 0; if (result == net::ERR_IO_PENDING) return; @@ -697,7 +712,7 @@ read_deferral_start_time_ = base::TimeTicks(); } if (request_->status().is_success()) { - ReadMore(false /* handle_result_asynchronously */); + PrepareToReadMore(false /* handle_result_asynchronously */); } else { ResponseCompleted(); }
diff --git a/content/browser/loader/resource_loader.h b/content/browser/loader/resource_loader.h index e7da4b7c..ce610e0 100644 --- a/content/browser/loader/resource_loader.h +++ b/content/browser/loader/resource_loader.h
@@ -99,8 +99,11 @@ void CancelRequestInternal(int error, bool from_renderer); void FollowDeferredRedirectInternal(); void CompleteResponseStarted(); - // If |handle_result_async| is true, the result of a read that completed - // synchronously will be handled asynchronously, except on EOF or error. + // If |handle_result_async| is true, the result of the following read will be + // handled asynchronously if it completes synchronously, unless it's EOF or an + // error. This is to prevent a single request from blocking the thread for too + // long. + void PrepareToReadMore(bool handle_result_async); void ReadMore(bool handle_result_async); void ResumeReading(); // Passes a read result to the handler. @@ -133,6 +136,7 @@ DEFERRED_SYNC, DEFERRED_START, DEFERRED_REDIRECT, + DEFERRED_ON_WILL_READ, DEFERRED_READ, DEFERRED_RESPONSE_COMPLETE, DEFERRED_FINISH @@ -167,6 +171,11 @@ // Stores the URL from a deferred redirect. GURL deferred_redirect_url_; + // Read buffer and its size. Class members as OnWillRead can complete + // asynchronously. + scoped_refptr<net::IOBuffer> read_buffer_; + int read_buffer_size_; + base::WeakPtrFactory<ResourceLoader> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ResourceLoader);
diff --git a/content/browser/loader/resource_loader_unittest.cc b/content/browser/loader/resource_loader_unittest.cc index 6ebcb72..e9000119 100644 --- a/content/browser/loader/resource_loader_unittest.cc +++ b/content/browser/loader/resource_loader_unittest.cc
@@ -799,6 +799,7 @@ raw_ptr_resource_handler_->set_defer_on_will_start(true); raw_ptr_resource_handler_->set_defer_on_request_redirected(true); raw_ptr_resource_handler_->set_defer_on_response_started(true); + raw_ptr_resource_handler_->set_defer_on_will_read(true); raw_ptr_resource_handler_->set_defer_on_read_completed(true); raw_ptr_resource_handler_->set_defer_on_read_eof(true); raw_ptr_resource_handler_->set_defer_on_response_completed(true); @@ -845,6 +846,18 @@ EXPECT_EQ(0, raw_ptr_resource_handler_->on_will_read_called()); EXPECT_EQ(0, raw_ptr_resource_handler_->on_response_completed_called()); + // Resume and run until OnWillRead. + raw_ptr_resource_handler_->Resume(); + raw_ptr_resource_handler_->WaitUntilDeferred(); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_will_read_called()); + + // Spinning the message loop should not advance the state further. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_will_read_called()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_completed_called()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof_called()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_response_completed_called()); + // Resume and run until OnReadCompleted. raw_ptr_resource_handler_->Resume(); raw_ptr_resource_handler_->WaitUntilDeferred(); @@ -854,17 +867,32 @@ base::RunLoop().RunUntilIdle(); EXPECT_EQ(1, raw_ptr_resource_handler_->on_will_read_called()); EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_completed_called()); - EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof_called()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_response_completed_called()); + + // Defer on the next OnWillRead call, for the EOF. + raw_ptr_resource_handler_->set_defer_on_will_read(true); + + // Resume and run until the next OnWillRead call. + raw_ptr_resource_handler_->Resume(); + raw_ptr_resource_handler_->WaitUntilDeferred(); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_completed_called()); + + // Spinning the message loop should not advance the state further. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(2, raw_ptr_resource_handler_->on_will_read_called()); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_completed_called()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof_called()); EXPECT_EQ(0, raw_ptr_resource_handler_->on_response_completed_called()); // Resume and run until the final 0-byte read, signaling EOF. raw_ptr_resource_handler_->Resume(); raw_ptr_resource_handler_->WaitUntilDeferred(); - EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof_called()); // Spinning the message loop should not advance the state further. base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof_called()); EXPECT_EQ(0, raw_ptr_resource_handler_->on_response_completed_called()); EXPECT_EQ(test_data(), raw_ptr_resource_handler_->body()); @@ -896,6 +924,7 @@ raw_ptr_resource_handler_->set_defer_on_will_start(true); raw_ptr_resource_handler_->set_defer_on_response_started(true); + raw_ptr_resource_handler_->set_defer_on_will_read(true); raw_ptr_resource_handler_->set_defer_on_read_completed(true); raw_ptr_resource_handler_->set_defer_on_read_eof(true); raw_ptr_resource_handler_->set_defer_on_response_completed(true); @@ -927,6 +956,18 @@ EXPECT_EQ(0, raw_ptr_resource_handler_->on_will_read_called()); EXPECT_EQ(0, raw_ptr_resource_handler_->on_response_completed_called()); + // Resume and run until OnWillRead. + raw_ptr_resource_handler_->Resume(); + raw_ptr_resource_handler_->WaitUntilDeferred(); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_will_read_called()); + + // Spinning the message loop should not advance the state further. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_will_read_called()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_completed_called()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof_called()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_response_completed_called()); + // Resume and run until OnReadCompleted. raw_ptr_resource_handler_->Resume(); raw_ptr_resource_handler_->WaitUntilDeferred(); @@ -936,17 +977,32 @@ base::RunLoop().RunUntilIdle(); EXPECT_EQ(1, raw_ptr_resource_handler_->on_will_read_called()); EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_completed_called()); - EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof_called()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_response_completed_called()); + + // Defer on the next OnWillRead call, for the EOF. + raw_ptr_resource_handler_->set_defer_on_will_read(true); + + // Resume and run until the next OnWillRead. + raw_ptr_resource_handler_->Resume(); + raw_ptr_resource_handler_->WaitUntilDeferred(); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_completed_called()); + + // Spinning the message loop should not advance the state further. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(2, raw_ptr_resource_handler_->on_will_read_called()); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_completed_called()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof_called()); EXPECT_EQ(0, raw_ptr_resource_handler_->on_response_completed_called()); // Resume and run until the final 0-byte read, signalling EOF. raw_ptr_resource_handler_->Resume(); raw_ptr_resource_handler_->WaitUntilDeferred(); - EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof_called()); // Spinning the message loop should not advance the state further. base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof_called()); EXPECT_EQ(0, raw_ptr_resource_handler_->on_response_completed_called()); EXPECT_EQ(test_data(), raw_ptr_resource_handler_->body()); @@ -1055,7 +1111,7 @@ EXPECT_EQ(1, did_receive_response_); EXPECT_EQ(1, did_finish_loading_); EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_completed_called()); - EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof_called()); EXPECT_EQ(1, raw_ptr_resource_handler_->on_response_completed_called()); EXPECT_EQ(net::ERR_ABORTED, @@ -1071,7 +1127,7 @@ base::RunLoop().RunUntilIdle(); EXPECT_EQ(1, did_receive_response_); EXPECT_EQ(1, did_finish_loading_); - EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof_called()); EXPECT_EQ(1, raw_ptr_resource_handler_->on_response_completed_called()); EXPECT_EQ(net::ERR_ABORTED, @@ -1089,7 +1145,7 @@ EXPECT_EQ(1, did_receive_response_); EXPECT_EQ(1, did_finish_loading_); EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_completed_called()); - EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof_called()); EXPECT_EQ(1, raw_ptr_resource_handler_->on_response_completed_called()); EXPECT_EQ(net::ERR_ABORTED, @@ -1106,7 +1162,7 @@ base::RunLoop().RunUntilIdle(); EXPECT_EQ(1, did_receive_response_); EXPECT_EQ(1, did_finish_loading_); - EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof_called()); EXPECT_EQ(1, raw_ptr_resource_handler_->on_response_completed_called()); EXPECT_EQ(net::ERR_ABORTED, @@ -1171,6 +1227,23 @@ EXPECT_EQ("", raw_ptr_resource_handler_->body()); } +TEST_F(ResourceLoaderTest, AsyncCancelOnWillRead) { + raw_ptr_resource_handler_->set_defer_on_will_read(true); + + loader_->StartRequest(); + raw_ptr_resource_handler_->WaitUntilDeferred(); + raw_ptr_resource_handler_->CancelWithError(net::ERR_FAILED); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1, did_receive_response_); + EXPECT_EQ(1, did_finish_loading_); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_will_read_called()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_completed_called()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof_called()); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_response_completed_called()); + + EXPECT_EQ(net::ERR_FAILED, raw_ptr_resource_handler_->final_status().error()); +} + TEST_F(ResourceLoaderTest, AsyncCancelOnReadCompleted) { raw_ptr_resource_handler_->set_defer_on_read_completed(true); @@ -1181,7 +1254,7 @@ EXPECT_EQ(1, did_receive_response_); EXPECT_EQ(1, did_finish_loading_); EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_completed_called()); - EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof_called()); EXPECT_EQ(1, raw_ptr_resource_handler_->on_response_completed_called()); EXPECT_EQ(net::ERR_FAILED, raw_ptr_resource_handler_->final_status().error()); @@ -1197,7 +1270,7 @@ base::RunLoop().RunUntilIdle(); EXPECT_EQ(1, did_receive_response_); EXPECT_EQ(1, did_finish_loading_); - EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof_called()); EXPECT_EQ(1, raw_ptr_resource_handler_->on_response_completed_called()); EXPECT_EQ(net::ERR_FAILED, raw_ptr_resource_handler_->final_status().error()); @@ -1215,7 +1288,7 @@ EXPECT_EQ(1, did_receive_response_); EXPECT_EQ(1, did_finish_loading_); EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_completed_called()); - EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(0, raw_ptr_resource_handler_->on_read_eof_called()); EXPECT_EQ(1, raw_ptr_resource_handler_->on_response_completed_called()); EXPECT_EQ(net::ERR_FAILED, raw_ptr_resource_handler_->final_status().error()); @@ -1232,7 +1305,7 @@ base::RunLoop().RunUntilIdle(); EXPECT_EQ(1, did_receive_response_); EXPECT_EQ(1, did_finish_loading_); - EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof()); + EXPECT_EQ(1, raw_ptr_resource_handler_->on_read_eof_called()); EXPECT_EQ(1, raw_ptr_resource_handler_->on_response_completed_called()); EXPECT_EQ(net::ERR_FAILED, raw_ptr_resource_handler_->final_status().error());
diff --git a/content/browser/loader/stream_resource_handler.cc b/content/browser/loader/stream_resource_handler.cc index 17e232a..c8ac918 100644 --- a/content/browser/loader/stream_resource_handler.cc +++ b/content/browser/loader/stream_resource_handler.cc
@@ -43,10 +43,12 @@ controller->Resume(); } -bool StreamResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) { +void StreamResourceHandler::OnWillRead( + scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) { writer_.OnWillRead(buf, buf_size, -1); - return true; + controller->Resume(); } void StreamResourceHandler::OnReadCompleted(
diff --git a/content/browser/loader/stream_resource_handler.h b/content/browser/loader/stream_resource_handler.h index 9f69994..7c678fc4 100644 --- a/content/browser/loader/stream_resource_handler.h +++ b/content/browser/loader/stream_resource_handler.h
@@ -46,8 +46,9 @@ std::unique_ptr<ResourceController> controller) override; // Create a new buffer to store received data. - bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) override; + void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) override; // A read was completed, forward the data to the Stream. void OnReadCompleted(int bytes_read,
diff --git a/content/browser/loader/sync_resource_handler.cc b/content/browser/loader/sync_resource_handler.cc index 3124302..596fbc93 100644 --- a/content/browser/loader/sync_resource_handler.cc +++ b/content/browser/loader/sync_resource_handler.cc
@@ -96,11 +96,13 @@ controller->Resume(); } -bool SyncResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) { +void SyncResourceHandler::OnWillRead( + scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) { *buf = read_buffer_.get(); *buf_size = kReadBufSize; - return true; + controller->Resume(); } void SyncResourceHandler::OnReadCompleted(
diff --git a/content/browser/loader/sync_resource_handler.h b/content/browser/loader/sync_resource_handler.h index 38fa416..881be7f 100644 --- a/content/browser/loader/sync_resource_handler.h +++ b/content/browser/loader/sync_resource_handler.h
@@ -42,8 +42,9 @@ std::unique_ptr<ResourceController> controller) override; void OnWillStart(const GURL& url, std::unique_ptr<ResourceController> controller) override; - bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) override; + void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) override; void OnReadCompleted(int bytes_read, std::unique_ptr<ResourceController> controller) override; void OnResponseCompleted(
diff --git a/content/browser/loader/test_resource_handler.cc b/content/browser/loader/test_resource_handler.cc index 1f8c970..4bcf6e29 100644 --- a/content/browser/loader/test_resource_handler.cc +++ b/content/browser/loader/test_resource_handler.cc
@@ -141,8 +141,10 @@ controller->Resume(); } -bool TestResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) { +void TestResourceHandler::OnWillRead( + scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) { EXPECT_FALSE(canceled_); EXPECT_FALSE(expect_on_data_downloaded_); EXPECT_EQ(0, on_response_completed_called_); @@ -157,13 +159,22 @@ if (!on_will_read_result_) { canceled_ = true; - } else { - *buf = buffer_; - *buf_size = buffer_size_; - memset(buffer_->data(), '\0', buffer_size_); + controller->Cancel(); + return; } - return on_will_read_result_; + if (defer_on_will_read_) { + parent_read_buffer_ = buf; + parent_read_buffer_size_ = buf_size; + defer_on_will_read_ = false; + HoldController(std::move(controller)); + deferred_run_loop_->Quit(); + return; + } + + *buf = buffer_; + *buf_size = buffer_size_; + controller->Resume(); } void TestResourceHandler::OnReadCompleted( @@ -174,12 +185,12 @@ EXPECT_EQ(1, on_will_start_called_); EXPECT_EQ(1, on_response_started_called_); EXPECT_EQ(0, on_response_completed_called_); - EXPECT_EQ(0, on_read_eof_); + EXPECT_EQ(0, on_read_eof_called_); ScopedCallDepthTracker call_depth_tracker(&call_depth_); ++on_read_completed_called_; if (bytes_read == 0) - ++on_read_eof_; + ++on_read_eof_called_; EXPECT_LE(static_cast<size_t>(bytes_read), buffer_size_); if (body_ptr_) @@ -207,9 +218,13 @@ std::unique_ptr<ResourceController> controller) { ScopedCallDepthTracker call_depth_tracker(&call_depth_); + // These may be non-NULL if there was an out-of-band cancel. + parent_read_buffer_ = nullptr; + parent_read_buffer_size_ = nullptr; + EXPECT_EQ(0, on_response_completed_called_); if (status.is_success() && !expect_on_data_downloaded_ && expect_eof_read_) - EXPECT_EQ(1, on_read_eof_); + EXPECT_EQ(1, on_read_eof_called_); ++on_response_completed_called_; @@ -242,12 +257,26 @@ void TestResourceHandler::Resume() { ScopedCallDepthTracker call_depth_tracker(&call_depth_); + + if (parent_read_buffer_) { + *parent_read_buffer_ = buffer_; + *parent_read_buffer_size_ = buffer_size_; + parent_read_buffer_ = nullptr; + parent_read_buffer_size_ = nullptr; + memset(buffer_->data(), '\0', buffer_size_); + } + ResourceHandler::Resume(); } void TestResourceHandler::CancelWithError(net::Error net_error) { ScopedCallDepthTracker call_depth_tracker(&call_depth_); canceled_ = true; + + // Don't want to populate these after a cancel. + parent_read_buffer_ = nullptr; + parent_read_buffer_size_ = nullptr; + ResourceHandler::CancelWithError(net_error); }
diff --git a/content/browser/loader/test_resource_handler.h b/content/browser/loader/test_resource_handler.h index 911300e..f31488b 100644 --- a/content/browser/loader/test_resource_handler.h +++ b/content/browser/loader/test_resource_handler.h
@@ -52,8 +52,9 @@ std::unique_ptr<ResourceController> controller) override; void OnWillStart(const GURL& url, std::unique_ptr<ResourceController> controller) override; - bool OnWillRead(scoped_refptr<net::IOBuffer>* buf, - int* buf_size) override; + void OnWillRead(scoped_refptr<net::IOBuffer>* buf, + int* buf_size, + std::unique_ptr<ResourceController> controller) override; void OnReadCompleted(int bytes_read, std::unique_ptr<ResourceController> controller) override; void OnResponseCompleted( @@ -102,6 +103,10 @@ void set_defer_on_response_started(bool defer_on_response_started) { defer_on_response_started_ = defer_on_response_started; } + // Only the next OnWillRead call will set |defer| to true. + void set_defer_on_will_read(bool defer_on_will_read) { + defer_on_will_read_ = defer_on_will_read; + } // Only the next OnReadCompleted call will set |defer| to true. void set_defer_on_read_completed(bool defer_on_read_completed) { defer_on_read_completed_ = defer_on_read_completed; @@ -134,7 +139,7 @@ int on_response_started_called() const { return on_response_started_called_; } int on_will_read_called() const { return on_will_read_called_; } int on_read_completed_called() const { return on_read_completed_called_; } - int on_read_eof() const { return on_read_eof_; } + int on_read_eof_called() const { return on_read_eof_called_; } int on_response_completed_called() const { return on_response_completed_called_; } @@ -181,6 +186,7 @@ bool defer_on_will_start_ = false; bool defer_on_request_redirected_ = false; bool defer_on_response_started_ = false; + bool defer_on_will_read_ = false; bool defer_on_read_completed_ = false; bool defer_on_read_eof_ = false; bool defer_on_response_completed_ = false; @@ -194,7 +200,7 @@ int on_response_started_called_ = 0; int on_will_read_called_ = 0; int on_read_completed_called_ = 0; - int on_read_eof_ = 0; + int on_read_eof_called_ = 0; int on_response_completed_called_ = 0; GURL start_url_; @@ -205,6 +211,11 @@ net::URLRequestStatus::FromError(net::ERR_UNEXPECTED); bool canceled_ = false; + // Pointers to the parent's read buffer and size. Only non-NULL during + // OnWillRead call, until cancellation or resumption. + scoped_refptr<net::IOBuffer>* parent_read_buffer_ = nullptr; + int* parent_read_buffer_size_ = nullptr; + // Tracks recursive calls, which aren't allowed. int call_depth_ = 0;
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index 1eac862..cef2679 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -505,7 +505,7 @@ // called. int instance_id_ = 1; - BrowserContext* browser_context_; + BrowserContext* const browser_context_; // Owned by |browser_context_|. StoragePartitionImpl* storage_partition_impl_;
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index e45cab8f..503ca52 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -959,11 +959,6 @@ if (delegate_->ShouldIgnoreUnresponsiveRenderer()) return; - UMA_HISTOGRAM_ENUMERATION( - "ChildProcess.HangRendererType", - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_CLOSE_PAGE, - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_MAX); - ClosePageIgnoringUnloadEvents(); }
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h index 32bb92d42..ef61faf 100644 --- a/content/browser/renderer_host/render_widget_host_delegate.h +++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -12,7 +12,6 @@ #include "build/build_config.h" #include "content/common/content_export.h" #include "content/common/drag_event_source_info.h" -#include "content/public/browser/renderer_unresponsive_type.h" #include "content/public/common/drop_data.h" #include "third_party/WebKit/public/platform/WebDisplayMode.h" #include "third_party/WebKit/public/platform/WebDragOperation.h" @@ -151,8 +150,7 @@ // Notification that the renderer has become unresponsive. The // delegate can use this notification to show a warning to the user. - virtual void RendererUnresponsive(RenderWidgetHostImpl* render_widget_host, - RendererUnresponsiveType type) {} + virtual void RendererUnresponsive(RenderWidgetHostImpl* render_widget_host) {} // Notification that a previously unresponsive renderer has become // responsive again. The delegate can use this notification to end the
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index eaff97c..beb9649 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -288,8 +288,6 @@ is_focused_(false), hung_renderer_delay_( base::TimeDelta::FromMilliseconds(kHungRendererDelayMs)), - hang_monitor_reason_( - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_UNKNOWN), hang_monitor_event_type_(blink::WebInputEvent::Undefined), last_event_type_(blink::WebInputEvent::Undefined), new_content_rendering_delay_( @@ -948,28 +946,20 @@ void RenderWidgetHostImpl::StartHangMonitorTimeout( base::TimeDelta delay, - blink::WebInputEvent::Type event_type, - RendererUnresponsiveType hang_monitor_reason) { + blink::WebInputEvent::Type event_type) { if (!hang_monitor_timeout_) return; if (!hang_monitor_timeout_->IsRunning()) hang_monitor_event_type_ = event_type; last_event_type_ = event_type; hang_monitor_timeout_->Start(delay); - hang_monitor_reason_ = hang_monitor_reason; } void RenderWidgetHostImpl::RestartHangMonitorTimeoutIfNecessary() { if (!hang_monitor_timeout_) return; - if (in_flight_event_count_ > 0 && !is_hidden_) { - if (hang_monitor_reason_ == - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_UNKNOWN) { - hang_monitor_reason_ = - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_IN_FLIGHT_EVENTS; - } + if (in_flight_event_count_ > 0 && !is_hidden_) hang_monitor_timeout_->Restart(hung_renderer_delay_); - } } void RenderWidgetHostImpl::DisableHangMonitorForTesting() { @@ -978,11 +968,8 @@ } void RenderWidgetHostImpl::StopHangMonitorTimeout() { - if (hang_monitor_timeout_) { + if (hang_monitor_timeout_) hang_monitor_timeout_->Stop(); - hang_monitor_reason_ = - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_UNKNOWN; - } RendererIsResponsive(); } @@ -1706,12 +1693,9 @@ Source<RenderWidgetHost>(this), NotificationService::NoDetails()); is_unresponsive_ = true; - RendererUnresponsiveType reason = hang_monitor_reason_; - hang_monitor_reason_ = - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_UNKNOWN; if (delegate_) - delegate_->RendererUnresponsive(this, reason); + delegate_->RendererUnresponsive(this); // Do not add code after this since the Delegate may delete this // RenderWidgetHostImpl in RendererUnresponsive. @@ -2114,11 +2098,8 @@ void RenderWidgetHostImpl::IncrementInFlightEventCount( blink::WebInputEvent::Type event_type) { increment_in_flight_event_count(); - if (!is_hidden_) { - StartHangMonitorTimeout( - hung_renderer_delay_, event_type, - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_IN_FLIGHT_EVENTS); - } + if (!is_hidden_) + StartHangMonitorTimeout(hung_renderer_delay_, event_type); } void RenderWidgetHostImpl::DecrementInFlightEventCount(
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 11dddf1..c60dc620 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -317,8 +317,7 @@ // the new one will only fire if it has a shorter delay than the time // left on the existing timeouts. void StartHangMonitorTimeout(base::TimeDelta delay, - blink::WebInputEvent::Type event_type, - RendererUnresponsiveType hang_monitor_reason); + blink::WebInputEvent::Type event_type); // Stops all existing hang monitor timeouts and assumes the renderer is // responsive. @@ -877,10 +876,6 @@ // This value indicates how long to wait before we consider a renderer hung. base::TimeDelta hung_renderer_delay_; - // Stores the reason the hang_monitor_timeout_ has been started. Used to - // report histograms if the renderer is hung. - RendererUnresponsiveType hang_monitor_reason_; - // Type of the last blocking event that started the hang monitor. blink::WebInputEvent::Type hang_monitor_event_type_;
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index 425709a..5faee12a 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -413,8 +413,7 @@ return handle_wheel_event_; } - void RendererUnresponsive(RenderWidgetHostImpl* render_widget_host, - RendererUnresponsiveType type) override { + void RendererUnresponsive(RenderWidgetHostImpl* render_widget_host) override { unresponsive_timer_fired_ = true; } @@ -1120,15 +1119,13 @@ // while one is in progress (see crbug.com/11007). TEST_F(RenderWidgetHostTest, DontPostponeHangMonitorTimeout) { // Start with a short timeout. - host_->StartHangMonitorTimeout( - TimeDelta::FromMilliseconds(10), WebInputEvent::Undefined, - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_UNKNOWN); + host_->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10), + WebInputEvent::Undefined); // Immediately try to add a long 30 second timeout. EXPECT_FALSE(delegate_->unresponsive_timer_fired()); - host_->StartHangMonitorTimeout( - TimeDelta::FromSeconds(30), WebInputEvent::Undefined, - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_UNKNOWN); + host_->StartHangMonitorTimeout(TimeDelta::FromSeconds(30), + WebInputEvent::Undefined); // Wait long enough for first timeout and see if it fired. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( @@ -1142,16 +1139,14 @@ // and then started again. TEST_F(RenderWidgetHostTest, StopAndStartHangMonitorTimeout) { // Start with a short timeout, then stop it. - host_->StartHangMonitorTimeout( - TimeDelta::FromMilliseconds(10), WebInputEvent::Undefined, - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_UNKNOWN); + host_->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10), + WebInputEvent::Undefined); host_->StopHangMonitorTimeout(); // Start it again to ensure it still works. EXPECT_FALSE(delegate_->unresponsive_timer_fired()); - host_->StartHangMonitorTimeout( - TimeDelta::FromMilliseconds(10), WebInputEvent::Undefined, - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_UNKNOWN); + host_->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10), + WebInputEvent::Undefined); // Wait long enough for first timeout and see if it fired. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( @@ -1165,15 +1160,13 @@ // updated to a shorter duration. TEST_F(RenderWidgetHostTest, ShorterDelayHangMonitorTimeout) { // Start with a timeout. - host_->StartHangMonitorTimeout( - TimeDelta::FromMilliseconds(100), WebInputEvent::Undefined, - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_UNKNOWN); + host_->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(100), + WebInputEvent::Undefined); // Start it again with shorter delay. EXPECT_FALSE(delegate_->unresponsive_timer_fired()); - host_->StartHangMonitorTimeout( - TimeDelta::FromMilliseconds(20), WebInputEvent::Undefined, - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_UNKNOWN); + host_->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(20), + WebInputEvent::Undefined); // Wait long enough for the second timeout and see if it fired. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
diff --git a/content/browser/resources/media/tab_view.js b/content/browser/resources/media/tab_view.js index ca205091..84897f5 100644 --- a/content/browser/resources/media/tab_view.js +++ b/content/browser/resources/media/tab_view.js
@@ -85,17 +85,6 @@ } }, - makeTabRemovable: function(id) { - if (!this.tabElements_[id]) - return; - var close = document.createElement('a'); - close.textContent = '[x]'; - close.addEventListener('click', function() { - this.removeTab(id); - }.bind(this)); - this.tabElements_[id].head.appendChild(close); - }, - /** * Switches the specified tab into view. *
diff --git a/content/browser/resources/media/webrtc_internals.js b/content/browser/resources/media/webrtc_internals.js index 86e415082..8ada8ad 100644 --- a/content/browser/resources/media/webrtc_internals.js +++ b/content/browser/resources/media/webrtc_internals.js
@@ -181,8 +181,7 @@ var element = $(getPeerConnectionId(data)); if (element) { delete peerConnectionDataStore[element.id]; - // add a [x] button to close this tab instead of removing it immediately. - tabView.makeTabRemovable(element.id); + tabView.removeTab(element.id); } }
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index dadfadfe..d7fad7d 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -994,7 +994,15 @@ // Test that the view bounds for an out-of-process iframe are set and updated // correctly, including accounting for local frame offsets in the parent and // scroll positions. -IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ViewBoundsInNestedFrameTest) { +#if defined(OS_ANDROID) +// Test failing on some Android builders, due to inaccurate coordinates on +// some devices. See: https://crbug.com/700007. +#define MAYBE_ViewBoundsInNestedFrameTest DISABLED_ViewBoundsInNestedFrameTest +#else +#define MAYBE_ViewBoundsInNestedFrameTest ViewBoundsInNestedFrameTest +#endif +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, + MAYBE_ViewBoundsInNestedFrameTest) { GURL main_url(embedded_test_server()->GetURL( "a.com", "/cross_site_iframe_factory.html?a(a)")); EXPECT_TRUE(NavigateToURL(shell(), main_url)); @@ -1302,9 +1310,11 @@ // Test that mouse events are being routed to the correct RenderWidgetHostView // based on coordinates. -#if defined(THREAD_SANITIZER) +#if defined(THREAD_SANITIZER) || defined(OS_ANDROID) // The test times out often on TSAN bot. // https://crbug.com/591170. +// Test failing on some Android builders, due to inaccurate coordinates on +// some devices. See: https://crbug.com/700007. #define MAYBE_SurfaceHitTestTest DISABLED_SurfaceHitTestTest #else #define MAYBE_SurfaceHitTestTest SurfaceHitTestTest @@ -1329,7 +1339,15 @@ // Test that mouse events are being routed to the correct RenderWidgetHostView // when there are nested out-of-process iframes. -IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NestedSurfaceHitTestTest) { +#if defined(OS_ANDROID) +// Test failing on some Android builders, due to inaccurate coordinates on +// some devices. See: https://crbug.com/700007. +#define MAYBE_NestedSurfaceHitTestTest DISABLED_NestedSurfaceHitTestTest +#else +#define MAYBE_NestedSurfaceHitTestTest NestedSurfaceHitTestTest +#endif +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, + MAYBE_NestedSurfaceHitTestTest) { GURL main_url(embedded_test_server()->GetURL( "/frame_tree/page_with_positioned_nested_frames.html")); EXPECT_TRUE(NavigateToURL(shell(), main_url)); @@ -1468,8 +1486,17 @@ // This test verifies that MouseEnter and MouseLeave events fire correctly // when the mouse cursor moves between processes. +#if defined(OS_ANDROID) +// Test failing on some Android builders, due to inaccurate coordinates on +// some devices. See: https://crbug.com/700007. +#define MAYBE_CrossProcessMouseEnterAndLeaveTest \ + DISABLED_CrossProcessMouseEnterAndLeaveTest +#else +#define MAYBE_CrossProcessMouseEnterAndLeaveTest \ + CrossProcessMouseEnterAndLeaveTest +#endif IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, - CrossProcessMouseEnterAndLeaveTest) { + MAYBE_CrossProcessMouseEnterAndLeaveTest) { GURL main_url(embedded_test_server()->GetURL( "a.com", "/cross_site_iframe_factory.html?a(b,c(d))")); EXPECT_TRUE(NavigateToURL(shell(), main_url)); @@ -1588,7 +1615,15 @@ // Verify that mouse capture works on a RenderWidgetHostView level, so that // dragging scroll bars and selecting text continues even when the mouse // cursor crosses over cross-process frame boundaries. -IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossProcessMouseCapture) { +#if defined(OS_ANDROID) +// Test failing on some Android builders, due to inaccurate coordinates on +// some devices. See: https://crbug.com/700007. +#define MAYBE_CrossProcessMouseCapture DISABLED_CrossProcessMouseCapture +#else +#define MAYBE_CrossProcessMouseCapture CrossProcessMouseCapture +#endif +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, + MAYBE_CrossProcessMouseCapture) { GURL main_url(embedded_test_server()->GetURL( "/frame_tree/page_with_positioned_frame.html")); EXPECT_TRUE(NavigateToURL(shell(), main_url));
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 569e113..6d8fc2d 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4833,8 +4833,7 @@ } void WebContentsImpl::RendererUnresponsive( - RenderWidgetHostImpl* render_widget_host, - RendererUnresponsiveType type) { + RenderWidgetHostImpl* render_widget_host) { for (auto& observer : observers_) observer.OnRendererUnresponsive(render_widget_host); @@ -4845,11 +4844,6 @@ if (ShouldIgnoreUnresponsiveRenderer()) return; - // Record histograms about the type of renderer hang. - UMA_HISTOGRAM_ENUMERATION( - "ChildProcess.HangRendererType", type, - RendererUnresponsiveType::RENDERER_UNRESPONSIVE_MAX); - RenderFrameHostImpl* rfhi = static_cast<RenderFrameHostImpl*>(GetRenderViewHost()->GetMainFrame()); if (rfhi->is_waiting_for_beforeunload_ack()) { @@ -4865,7 +4859,6 @@ if (delegate_) { WebContentsUnresponsiveState unresponsive_state; - unresponsive_state.reason = type; unresponsive_state.outstanding_ack_count = render_widget_host->in_flight_event_count(); unresponsive_state.outstanding_event_type =
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index d8c4d1f..3cb1046 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -652,8 +652,7 @@ RenderWidgetHostImpl* GetRenderWidgetHostWithPageFocus() override; void FocusOwningWebContents( RenderWidgetHostImpl* render_widget_host) override; - void RendererUnresponsive(RenderWidgetHostImpl* render_widget_host, - RendererUnresponsiveType type) override; + void RendererUnresponsive(RenderWidgetHostImpl* render_widget_host) override; void RendererResponsive(RenderWidgetHostImpl* render_widget_host) override; void RequestToLockMouse(RenderWidgetHostImpl* render_widget_host, bool user_gesture,
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index c37f2dc..e30d28c 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -385,8 +385,10 @@ "//mojo/public/java:system_java", "//net/android:net_java", "//net/android:net_java_test_support", + "//third_party/android_support_test_runner:rules_java", "//third_party/android_support_test_runner:runner_java", "//third_party/android_tools:legacy_http_javalib", + "//third_party/junit", "//ui/android:ui_java", ] @@ -398,6 +400,8 @@ "javatests/src/org/chromium/content/browser/ClipboardTest.java", "javatests/src/org/chromium/content/browser/ContentCommandLineTest.java", "javatests/src/org/chromium/content/browser/ContentDetectionTestBase.java", + "javatests/src/org/chromium/content/browser/ContentDetectionActivityTestRule.java", + "javatests/src/org/chromium/content/browser/ContentDetectionTestCommon.java", "javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java", "javatests/src/org/chromium/content/browser/ContentViewLocationTest.java", "javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java", @@ -408,6 +412,7 @@ "javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java", "javatests/src/org/chromium/content/browser/ImportantFileWriterAndroidTest.java", "javatests/src/org/chromium/content/browser/InterstitialPageTest.java", + "javatests/src/org/chromium/content/browser/JavaBridgeActivityTestRule.java", "javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java", "javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java", "javatests/src/org/chromium/content/browser/JavaBridgeBareboneTest.java", @@ -417,6 +422,7 @@ "javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java", "javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java", "javatests/src/org/chromium/content/browser/JavaBridgeTestBase.java", + "javatests/src/org/chromium/content/browser/JavaBridgeTestCommon.java", "javatests/src/org/chromium/content/browser/LocationProviderTest.java", "javatests/src/org/chromium/content/browser/MediaResourceGetterTest.java", "javatests/src/org/chromium/content/browser/MediaSessionTest.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java index 60547ae..aa7b94b 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -135,12 +135,12 @@ @Override public void didFinishNavigation(String url, boolean isInMainFrame, boolean isErrorPage, - boolean hasCommitted, boolean isSamePage, boolean isFragmentNavigation, + boolean hasCommitted, boolean isSameDocument, boolean isFragmentNavigation, Integer pageTransition, int errorCode, String errorDescription, int httpStatusCode) { determinedProcessVisibility(); - if (hasCommitted && isInMainFrame && !isSamePage) { + if (hasCommitted && isInMainFrame && !isSameDocument) { resetPopupsAndInput(); } }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionActivityTestRule.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionActivityTestRule.java new file mode 100644 index 0000000..53dc306 --- /dev/null +++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionActivityTestRule.java
@@ -0,0 +1,75 @@ +// 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. + +package org.chromium.content.browser; + +import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; + +import org.chromium.content.browser.test.util.TestCallbackHelperContainer; +import org.chromium.content_shell_apk.ContentShellActivityTestRule; + +/** + * ActivityTestRule for content detection test suites. + */ +public class ContentDetectionActivityTestRule extends ContentShellActivityTestRule { + private static final long WAIT_TIMEOUT_SECONDS = scaleTimeout(10); + + private final ContentDetectionTestCommon mTestCommon = new ContentDetectionTestCommon(this); + + /** + * Returns the TestCallbackHelperContainer associated with this ContentView, + * or creates it lazily. + */ + public TestCallbackHelperContainer getTestCallbackHelperContainer() { + return mTestCommon.getTestCallbackHelperContainer(); + } + + @Override + protected void beforeActivityLaunched() { + super.beforeActivityLaunched(); + mTestCommon.createTestContentIntentHandler(); + } + + @Override + protected void afterActivityLaunched() { + super.afterActivityLaunched(); + mTestCommon.setContentHandler(); + } + + /** + * Encodes the provided content string into an escaped url as intents do. + * @param content Content to escape into a url. + * @return Escaped url. + */ + public static String urlForContent(String content) { + return ContentDetectionTestCommon.urlForContent(content); + } + + /** + * Checks if the provided test url is the current url in the content view. + * @param testUrl Test url to check. + * @return true if the test url is the current one, false otherwise. + */ + public boolean isCurrentTestUrl(String testUrl) { + return mTestCommon.isCurrentTestUrl(testUrl); + } + + /** + * Scrolls to the node with the provided id, taps on it and waits for an intent to come. + * @param id Id of the node to scroll and tap. + * @return The content url of the received intent or null if none. + */ + public String scrollAndTapExpectingIntent(String id) throws Throwable { + return mTestCommon.scrollAndTapExpectingIntent(id); + } + + /** + * Scrolls to the node with the provided id, taps on it and waits for a new page load to finish. + * Useful when tapping on links that take to other pages. + * @param id Id of the node to scroll and tap. + */ + public void scrollAndTapNavigatingOut(String id) throws Throwable { + mTestCommon.scrollAndTapNavigatingOut(id); + } +}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionTestBase.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionTestBase.java index 0c2fac8..bc234ef 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionTestBase.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionTestBase.java
@@ -4,99 +4,39 @@ package org.chromium.content.browser; -import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; - import android.app.Activity; -import android.net.Uri; -import org.chromium.base.test.util.CallbackHelper; -import org.chromium.base.test.util.UrlUtils; -import org.chromium.content.browser.test.util.DOMUtils; import org.chromium.content.browser.test.util.TestCallbackHelperContainer; -import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper; -import org.chromium.content_shell.ShellViewAndroidDelegate.ContentIntentHandler; +import org.chromium.content_shell_apk.ContentShellActivity; import org.chromium.content_shell_apk.ContentShellTestBase; - -import java.util.concurrent.TimeUnit; +import org.chromium.content_shell_apk.ContentShellTestCommon.TestCommonCallback; /** * Base class for content detection test suites. */ -public class ContentDetectionTestBase extends ContentShellTestBase { - - private static final long WAIT_TIMEOUT_SECONDS = scaleTimeout(10); - - private TestCallbackHelperContainer mCallbackHelper; - private TestContentIntentHandler mContentIntentHandler; - - /** - * CallbackHelper for OnStartContentIntent. - */ - private static class OnStartContentIntentHelper extends CallbackHelper { - private String mIntentUrl; - public void notifyCalled(String intentUrl) { - mIntentUrl = intentUrl; - notifyCalled(); - } - public String getIntentUrl() { - assert getCallCount() > 0; - return mIntentUrl; - } - } - - /** - * ContentIntentHandler impl to test content detection. - */ - private static class TestContentIntentHandler implements ContentIntentHandler { - private OnStartContentIntentHelper mOnStartContentIntentHelper; - - public OnStartContentIntentHelper getOnStartContentIntentHelper() { - if (mOnStartContentIntentHelper == null) { - mOnStartContentIntentHelper = new OnStartContentIntentHelper(); - } - return mOnStartContentIntentHelper; - } - - @Override - public void onIntentUrlReceived(String intentUrl) { - mOnStartContentIntentHelper.notifyCalled(intentUrl); - } - } +public class ContentDetectionTestBase + extends ContentShellTestBase implements TestCommonCallback<ContentShellActivity> { + private final ContentDetectionTestCommon mTestCommon = new ContentDetectionTestCommon(this); /** * Returns the TestCallbackHelperContainer associated with this ContentView, * or creates it lazily. */ protected TestCallbackHelperContainer getTestCallbackHelperContainer() { - if (mCallbackHelper == null) { - mCallbackHelper = new TestCallbackHelperContainer(getContentViewCore()); - } - return mCallbackHelper; + return mTestCommon.getTestCallbackHelperContainer(); } @Override protected void setUp() throws Exception { super.setUp(); - mContentIntentHandler = new TestContentIntentHandler(); + mTestCommon.createTestContentIntentHandler(); } + @SuppressWarnings("deprecation") @Override protected void setActivity(Activity activity) { super.setActivity(activity); - getActivity() - .getShellManager() - .getActiveShell() - .getViewAndroidDelegate() - .setContentIntentHandler(mContentIntentHandler); - } - - /** - * Encodes the provided content string into an escaped url as intents do. - * @param content Content to escape into a url. - * @return Escaped url. - */ - protected static String urlForContent(String content) { - return Uri.encode(content).replaceAll("%20", "+"); + mTestCommon.setContentHandler(); } /** @@ -105,8 +45,16 @@ * @return true if the test url is the current one, false otherwise. */ protected boolean isCurrentTestUrl(String testUrl) { - return UrlUtils.getIsolatedTestFileUrl(testUrl).equals(getContentViewCore() - .getWebContents().getUrl()); + return mTestCommon.isCurrentTestUrl(testUrl); + } + + /** + * Encodes the provided content string into an escaped url as intents do. + * @param content Content to escape into a url. + * @return Escaped url. + */ + public static String urlForContent(String content) { + return ContentDetectionTestCommon.urlForContent(content); } /** @@ -115,34 +63,15 @@ * @return The content url of the received intent or null if none. */ protected String scrollAndTapExpectingIntent(String id) throws Throwable { - OnStartContentIntentHelper onStartContentIntentHelper = - mContentIntentHandler.getOnStartContentIntentHelper(); - int currentCallCount = onStartContentIntentHelper.getCallCount(); - - DOMUtils.clickNode(getContentViewCore(), id); - - onStartContentIntentHelper.waitForCallback(currentCallCount, 1, WAIT_TIMEOUT_SECONDS, - TimeUnit.SECONDS); - getInstrumentation().waitForIdleSync(); - return onStartContentIntentHelper.getIntentUrl(); + return mTestCommon.scrollAndTapExpectingIntent(id); } /** * Scrolls to the node with the provided id, taps on it and waits for a new page load to finish. * Useful when tapping on links that take to other pages. * @param id Id of the node to scroll and tap. - * @return The content url of the received intent or null if none. */ protected void scrollAndTapNavigatingOut(String id) throws Throwable { - TestCallbackHelperContainer callbackHelperContainer = getTestCallbackHelperContainer(); - OnPageFinishedHelper onPageFinishedHelper = - callbackHelperContainer.getOnPageFinishedHelper(); - int currentCallCount = onPageFinishedHelper.getCallCount(); - - DOMUtils.clickNode(getContentViewCore(), id); - - onPageFinishedHelper.waitForCallback(currentCallCount, 1, WAIT_TIMEOUT_SECONDS, - TimeUnit.SECONDS); - getInstrumentation().waitForIdleSync(); + mTestCommon.scrollAndTapNavigatingOut(id); } } \ No newline at end of file
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionTestCommon.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionTestCommon.java new file mode 100644 index 0000000..0d8d96b --- /dev/null +++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionTestCommon.java
@@ -0,0 +1,123 @@ +// 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. + +package org.chromium.content.browser; + +import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; + +import android.net.Uri; + +import org.chromium.base.test.util.CallbackHelper; +import org.chromium.base.test.util.UrlUtils; +import org.chromium.content.browser.test.util.DOMUtils; +import org.chromium.content.browser.test.util.TestCallbackHelperContainer; +import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper; +import org.chromium.content_shell.ShellViewAndroidDelegate.ContentIntentHandler; +import org.chromium.content_shell_apk.ContentShellActivity; +import org.chromium.content_shell_apk.ContentShellTestCommon.TestCommonCallback; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ContentDetectionTestCommon { + private static final long WAIT_TIMEOUT_SECONDS = scaleTimeout(10); + + private final TestCommonCallback<ContentShellActivity> mCallback; + + private TestCallbackHelperContainer mCallbackHelper; + private TestContentIntentHandler mContentIntentHandler; + + public ContentDetectionTestCommon(TestCommonCallback<ContentShellActivity> callback) { + mCallback = callback; + } + + /** + * CallbackHelper for OnStartContentIntent. + */ + private static class OnStartContentIntentHelper extends CallbackHelper { + private String mIntentUrl; + public void notifyCalled(String intentUrl) { + mIntentUrl = intentUrl; + notifyCalled(); + } + public String getIntentUrl() { + assert getCallCount() > 0; + return mIntentUrl; + } + } + + /** + * ContentIntentHandler impl to test content detection. + */ + public static class TestContentIntentHandler implements ContentIntentHandler { + private OnStartContentIntentHelper mOnStartContentIntentHelper; + + public OnStartContentIntentHelper getOnStartContentIntentHelper() { + if (mOnStartContentIntentHelper == null) { + mOnStartContentIntentHelper = new OnStartContentIntentHelper(); + } + return mOnStartContentIntentHelper; + } + + @Override + public void onIntentUrlReceived(String intentUrl) { + mOnStartContentIntentHelper.notifyCalled(intentUrl); + } + } + + static String urlForContent(String content) { + return Uri.encode(content).replaceAll("%20", "+"); + } + + TestCallbackHelperContainer getTestCallbackHelperContainer() { + if (mCallbackHelper == null) { + mCallbackHelper = + new TestCallbackHelperContainer(mCallback.getContentViewCoreForTestCommon()); + } + return mCallbackHelper; + } + + void createTestContentIntentHandler() { + mContentIntentHandler = new TestContentIntentHandler(); + } + + void setContentHandler() { + mCallback.getActivityForTestCommon() + .getShellManager() + .getActiveShell() + .getViewAndroidDelegate() + .setContentIntentHandler(mContentIntentHandler); + } + + boolean isCurrentTestUrl(String testUrl) { + return UrlUtils.getIsolatedTestFileUrl(testUrl).equals( + mCallback.getContentViewCoreForTestCommon().getWebContents().getUrl()); + } + + String scrollAndTapExpectingIntent(String id) throws InterruptedException, TimeoutException { + OnStartContentIntentHelper onStartContentIntentHelper = + mContentIntentHandler.getOnStartContentIntentHelper(); + int currentCallCount = onStartContentIntentHelper.getCallCount(); + + DOMUtils.clickNode(mCallback.getContentViewCoreForTestCommon(), id); + + onStartContentIntentHelper.waitForCallback( + currentCallCount, 1, WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS); + mCallback.getInstrumentationForTestCommon().waitForIdleSync(); + return onStartContentIntentHelper.getIntentUrl(); + } + + void scrollAndTapNavigatingOut(String id) throws InterruptedException, TimeoutException { + TestCallbackHelperContainer callbackHelperContainer = getTestCallbackHelperContainer(); + OnPageFinishedHelper onPageFinishedHelper = + callbackHelperContainer.getOnPageFinishedHelper(); + int currentCallCount = onPageFinishedHelper.getCallCount(); + + DOMUtils.clickNode(mCallback.getContentViewCoreForTestCommon(), id); + + onPageFinishedHelper.waitForCallback( + currentCallCount, 1, WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS); + mCallback.getInstrumentationForTestCommon().waitForIdleSync(); + } +}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeActivityTestRule.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeActivityTestRule.java new file mode 100644 index 0000000..ba3d5cf --- /dev/null +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeActivityTestRule.java
@@ -0,0 +1,73 @@ +// 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. + +package org.chromium.content.browser; + +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import org.chromium.content.browser.test.util.TestCallbackHelperContainer; +import org.chromium.content_shell_apk.ContentShellActivity; +import org.chromium.content_shell_apk.ContentShellActivityTestRule; +import org.chromium.content_shell_apk.ContentShellTestCommon.TestCommonCallback; + +import java.lang.annotation.Annotation; + +/** + * ActivityTestRule with common functionality for testing the Java Bridge. + */ +public class JavaBridgeActivityTestRule + extends ContentShellActivityTestRule implements TestCommonCallback<ContentShellActivity> { + private JavaBridgeTestCommon mTestCommon; + + public JavaBridgeActivityTestRule() { + super(); + mTestCommon = new JavaBridgeTestCommon(this); + } + + /** + * Sets up the ContentView. Intended to be called from setUp(). + */ + private void setUpContentView() { + mTestCommon.setUpContentView(); + } + + public TestCallbackHelperContainer getTestCallBackHelperContainer() { + return mTestCommon.getTestCallBackHelperContainer(); + } + + public void executeJavaScript(String script) throws Throwable { + mTestCommon.executeJavaScript(script); + } + + public void injectObjectAndReload(Object object, String name) throws Exception { + injectObjectAndReload(object, name, null); + } + + public void injectObjectAndReload(Object object, String name, + Class<? extends Annotation> requiredAnnotation) throws Exception { + mTestCommon.injectObjectsAndReload(object, name, null, null, requiredAnnotation); + } + + public void injectObjectsAndReload(final Object object1, final String name1, + final Object object2, final String name2, + final Class<? extends Annotation> requiredAnnotation) throws Exception { + mTestCommon.injectObjectsAndReload(object1, name1, object2, name2, requiredAnnotation); + } + + public void synchronousPageReload() throws Throwable { + mTestCommon.synchronousPageReload(); + } + + @Override + public Statement apply(final Statement base, Description desc) { + return super.apply(new Statement() { + @Override + public void evaluate() throws Throwable { + setUpContentView(); + base.evaluate(); + } + }, desc); + } +}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java index a6f891e..fdf3b1d 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java
@@ -8,6 +8,7 @@ import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.base.test.util.Feature; +import org.chromium.content.browser.JavaBridgeTestCommon.Controller; /** * Part of the test suite for the Java Bridge. This class tests that we correctly convert
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java index 8006b98d..2be60b5 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java
@@ -8,6 +8,7 @@ import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.base.test.util.Feature; +import org.chromium.content.browser.JavaBridgeTestCommon.Controller; /** * Part of the test suite for the Java Bridge. This class tests the general use of arrays.
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java index a26160a..1ea2e88 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java
@@ -13,6 +13,7 @@ import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; +import org.chromium.content.browser.JavaBridgeTestCommon.Controller; import org.chromium.content.browser.test.util.TestCallbackHelperContainer; import org.chromium.content_public.browser.LoadUrlParams; @@ -179,7 +180,7 @@ @Feature({"AndroidWebView", "Android-JavaBridge"}) public void testRemoveObjectNotAdded() throws Throwable { TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = - mTestCallbackHelperContainer.getOnPageFinishedHelper(); + getTestCallBackHelperContainer().getOnPageFinishedHelper(); int currentCallCount = onPageFinishedHelper.getCallCount(); runTestOnUiThread(new Runnable() { @Override @@ -863,7 +864,7 @@ // Manually inject the Test object, making sure to use the // ContentViewCore#addJavascriptInterface, not the possibly unsafe version. TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = - mTestCallbackHelperContainer.getOnPageFinishedHelper(); + getTestCallBackHelperContainer().getOnPageFinishedHelper(); int currentCallCount = onPageFinishedHelper.getCallCount(); runTestOnUiThread(new Runnable() { @Override
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java index 766120b7..cbad6a1d42 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java
@@ -11,6 +11,7 @@ import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.RetryOnFailure; +import org.chromium.content.browser.JavaBridgeTestCommon.Controller; import org.chromium.content_public.browser.JavaScriptCallback; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.NavigationController; @@ -253,8 +254,7 @@ private String executeJavaScriptAndGetResult(final WebContents webContents, final String script) throws Throwable { final String[] result = new String[1]; - class ResultCallback extends JavaBridgeTestBase.Controller - implements JavaScriptCallback { + class ResultCallback extends Controller implements JavaScriptCallback { @Override public void handleJavaScriptResult(String jsonResult) { result[0] = jsonResult; @@ -277,7 +277,7 @@ */ private void loadDataSync(final NavigationController navigationController, final String data, final String mimeType, final boolean isBase64Encoded) throws Throwable { - loadUrl(navigationController, mTestCallbackHelperContainer, + loadUrl(navigationController, getTestCallBackHelperContainer(), LoadUrlParams.createLoadDataParams(data, mimeType, isBase64Encoded)); } }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java index 089b7f34..075eb59 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java
@@ -11,6 +11,7 @@ import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.UrlUtils; +import org.chromium.content.browser.JavaBridgeTestCommon.Controller; import java.io.File;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java index b90022d..e1cb4b21 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java
@@ -8,6 +8,7 @@ import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.base.test.util.Feature; +import org.chromium.content.browser.JavaBridgeTestCommon.Controller; /** * Part of the test suite for the Java Bridge. This test tests the
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java index 84b9c688..3b46841 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java
@@ -8,6 +8,7 @@ import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.base.test.util.Feature; +import org.chromium.content.browser.JavaBridgeTestCommon.Controller; /** * Part of the test suite for the Java Bridge. This test checks that we correctly convert Java
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeTestBase.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeTestBase.java index 592e6f9..d7907c6 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeTestBase.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeTestBase.java
@@ -4,92 +4,39 @@ package org.chromium.content.browser; -import android.util.Log; - -import junit.framework.Assert; - -import org.chromium.base.annotations.SuppressFBWarnings; -import org.chromium.base.test.util.UrlUtils; import org.chromium.content.browser.test.util.TestCallbackHelperContainer; -import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_shell_apk.ContentShellActivity; import org.chromium.content_shell_apk.ContentShellTestBase; +import org.chromium.content_shell_apk.ContentShellTestCommon.TestCommonCallback; import java.lang.annotation.Annotation; /** * Common functionality for testing the Java Bridge. */ -public class JavaBridgeTestBase extends ContentShellTestBase { - - protected TestCallbackHelperContainer mTestCallbackHelperContainer; +public class JavaBridgeTestBase + extends ContentShellTestBase implements TestCommonCallback<ContentShellActivity> { + private final JavaBridgeTestCommon mTestCommon = new JavaBridgeTestCommon(this); /** * Sets up the ContentView. Intended to be called from setUp(). */ private void setUpContentView() throws Exception { - // This starts the activity, so must be called on the test thread. - final ContentShellActivity activity = launchContentShellWithUrl( - UrlUtils.encodeHtmlDataUri("<html><head></head><body>test</body></html>")); - - waitForActiveShellToBeDoneLoading(); - - try { - runTestOnUiThread(new Runnable() { - @Override - public void run() { - mTestCallbackHelperContainer = new TestCallbackHelperContainer( - activity.getActiveContentViewCore()); - } - }); - } catch (Throwable e) { - throw new RuntimeException( - "Failed to set up ContentView: " + Log.getStackTraceString(e)); - } + mTestCommon.setUpContentView(); } @Override protected void setUp() throws Exception { super.setUp(); - setUpContentView(); + mTestCommon.setUpContentView(); } - @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") - protected static class Controller { - private boolean mIsResultReady; - - protected synchronized void notifyResultIsReady() { - mIsResultReady = true; - notify(); - } - protected synchronized void waitForResult() { - while (!mIsResultReady) { - try { - wait(5000); - } catch (Exception e) { - continue; - } - if (!mIsResultReady) { - Assert.fail("Wait timed out"); - } - } - mIsResultReady = false; - } + public TestCallbackHelperContainer getTestCallBackHelperContainer() { + return mTestCommon.getTestCallBackHelperContainer(); } protected void executeJavaScript(final String script) throws Throwable { - runTestOnUiThread(new Runnable() { - @Override - public void run() { - // When a JavaScript URL is executed, if the value of the last - // expression evaluated is not 'undefined', this value is - // converted to a string and used as the new document for the - // frame. We don't want this behaviour, so wrap the script in - // an anonymous function. - getWebContents().getNavigationController().loadUrl( - new LoadUrlParams("javascript:(function() { " + script + " })()")); - } - }); + mTestCommon.executeJavaScript(script); } protected void injectObjectAndReload(final Object object, final String name) throws Exception { @@ -104,39 +51,10 @@ protected void injectObjectsAndReload(final Object object1, final String name1, final Object object2, final String name2, final Class<? extends Annotation> requiredAnnotation) throws Exception { - TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = - mTestCallbackHelperContainer.getOnPageFinishedHelper(); - int currentCallCount = onPageFinishedHelper.getCallCount(); - try { - runTestOnUiThread(new Runnable() { - @Override - public void run() { - getContentViewCore().addPossiblyUnsafeJavascriptInterface(object1, - name1, requiredAnnotation); - if (object2 != null && name2 != null) { - getContentViewCore().addPossiblyUnsafeJavascriptInterface(object2, - name2, requiredAnnotation); - } - getContentViewCore().getWebContents().getNavigationController().reload(true); - } - }); - onPageFinishedHelper.waitForCallback(currentCallCount); - } catch (Throwable e) { - throw new RuntimeException( - "Failed to injectObjectsAndReload: " + Log.getStackTraceString(e)); - } + mTestCommon.injectObjectsAndReload(object1, name1, object2, name2, requiredAnnotation); } protected void synchronousPageReload() throws Throwable { - TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = - mTestCallbackHelperContainer.getOnPageFinishedHelper(); - int currentCallCount = onPageFinishedHelper.getCallCount(); - runTestOnUiThread(new Runnable() { - @Override - public void run() { - getContentViewCore().getWebContents().getNavigationController().reload(true); - } - }); - onPageFinishedHelper.waitForCallback(currentCallCount); + mTestCommon.synchronousPageReload(); } }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeTestCommon.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeTestCommon.java new file mode 100644 index 0000000..83f21bfd --- /dev/null +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeTestCommon.java
@@ -0,0 +1,146 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.content.browser; + +import android.util.Log; + +import org.junit.Assert; + +import org.chromium.base.annotations.SuppressFBWarnings; +import org.chromium.base.test.util.UrlUtils; +import org.chromium.content.browser.test.util.TestCallbackHelperContainer; +import org.chromium.content_public.browser.LoadUrlParams; +import org.chromium.content_shell_apk.ContentShellActivity; +import org.chromium.content_shell_apk.ContentShellTestCommon.TestCommonCallback; + +import java.lang.annotation.Annotation; + +/** + * Common functionality implementation for testing the Java Bridge. + */ +public final class JavaBridgeTestCommon { + protected TestCallbackHelperContainer mTestCallbackHelperContainer; + + private final TestCommonCallback<ContentShellActivity> mCallback; + + public JavaBridgeTestCommon(TestCommonCallback<ContentShellActivity> callback) { + mCallback = callback; + } + + @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") + public static class Controller { + private static final int RESULT_WAIT_TIME = 5000; + + private boolean mIsResultReady; + + protected synchronized void notifyResultIsReady() { + mIsResultReady = true; + notify(); + } + + protected synchronized void waitForResult() { + while (!mIsResultReady) { + try { + wait(RESULT_WAIT_TIME); + } catch (Exception e) { + continue; + } + if (!mIsResultReady) { + Assert.fail("Wait timed out"); + } + } + mIsResultReady = false; + } + } + + TestCallbackHelperContainer getTestCallBackHelperContainer() { + return mTestCallbackHelperContainer; + } + + void setUpContentView() { + // This starts the activity, so must be called on the test thread. + final ContentShellActivity activity = mCallback.launchContentShellWithUrlForTestCommon( + UrlUtils.encodeHtmlDataUri("<html><head></head><body>test</body></html>")); + mCallback.waitForActiveShellToBeDoneLoadingForTestCommon(); + + try { + mCallback.runOnUiThreadForTestCommon(new Runnable() { + @Override + public void run() { + mTestCallbackHelperContainer = + new TestCallbackHelperContainer(activity.getActiveContentViewCore()); + } + }); + } catch (Throwable e) { + throw new RuntimeException( + "Failed to set up ContentView: " + Log.getStackTraceString(e)); + } + } + + void executeJavaScript(final String script) throws Throwable { + mCallback.runOnUiThreadForTestCommon(new Runnable() { + @Override + public void run() { + // When a JavaScript URL is executed, if the value of the last + // expression evaluated is not 'undefined', this value is + // converted to a string and used as the new document for the + // frame. We don't want this behaviour, so wrap the script in + // an anonymous function. + mCallback.getActivityForTestCommon() + .getActiveShell() + .getWebContents() + .getNavigationController() + .loadUrl(new LoadUrlParams("javascript:(function() { " + script + " })()")); + } + }); + } + + void injectObjectsAndReload(final Object object1, final String name1, final Object object2, + final String name2, final Class<? extends Annotation> requiredAnnotation) + throws Exception { + TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = + mTestCallbackHelperContainer.getOnPageFinishedHelper(); + int currentCallCount = onPageFinishedHelper.getCallCount(); + try { + mCallback.runOnUiThreadForTestCommon(new Runnable() { + @Override + public void run() { + mCallback.getContentViewCoreForTestCommon() + .addPossiblyUnsafeJavascriptInterface( + object1, name1, requiredAnnotation); + if (object2 != null && name2 != null) { + mCallback.getContentViewCoreForTestCommon() + .addPossiblyUnsafeJavascriptInterface( + object2, name2, requiredAnnotation); + } + mCallback.getContentViewCoreForTestCommon() + .getWebContents() + .getNavigationController() + .reload(true); + } + }); + onPageFinishedHelper.waitForCallback(currentCallCount); + } catch (Throwable e) { + throw new RuntimeException( + "Failed to injectObjectsAndReload: " + Log.getStackTraceString(e)); + } + } + + void synchronousPageReload() throws Throwable { + TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = + mTestCallbackHelperContainer.getOnPageFinishedHelper(); + int currentCallCount = onPageFinishedHelper.getCallCount(); + mCallback.runOnUiThreadForTestCommon(new Runnable() { + @Override + public void run() { + mCallback.getContentViewCoreForTestCommon() + .getWebContents() + .getNavigationController() + .reload(true); + } + }); + onPageFinishedHelper.waitForCallback(currentCallCount); + } +}
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn index 92660a8..4eb1281 100644 --- a/content/public/browser/BUILD.gn +++ b/content/public/browser/BUILD.gn
@@ -202,7 +202,6 @@ "render_widget_host.h", "render_widget_host_view.h", "render_widget_host_view_mac_delegate.h", - "renderer_unresponsive_type.h", "resource_context.h", "resource_dispatcher_host.cc", "resource_dispatcher_host.h",
diff --git a/content/public/browser/renderer_unresponsive_type.h b/content/public/browser/renderer_unresponsive_type.h deleted file mode 100644 index e2190f7d..0000000 --- a/content/public/browser/renderer_unresponsive_type.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_PUBLIC_BROWSER_RENDERER_UNRESPONSIVE_TYPE_H_ -#define CONTENT_PUBLIC_BROWSER_RENDERER_UNRESPONSIVE_TYPE_H_ - -#include "content/common/content_export.h" - -namespace content { - -// Used in histograms to differentiate between the different types of -// renderer hang. Only add values at the end, do not delete values. -enum RendererUnresponsiveType { - RENDERER_UNRESPONSIVE_UNKNOWN = 0, - RENDERER_UNRESPONSIVE_IN_FLIGHT_EVENTS = 1, - RENDERER_UNRESPONSIVE_DIALOG_CLOSED = 2, - RENDERER_UNRESPONSIVE_DIALOG_SUPPRESSED = 3, - RENDERER_UNRESPONSIVE_BEFORE_UNLOAD = 4, - - // Used when a page hangs after a JavaScript dialog is fired inside of unload. - // This is no longer allowed to happen so this value is no longer used. - RENDERER_UNRESPONSIVE_UNLOAD_OBSOLETE = 5, - RENDERER_UNRESPONSIVE_CLOSE_PAGE = 6, - RENDERER_UNRESPONSIVE_MAX = RENDERER_UNRESPONSIVE_CLOSE_PAGE, -}; - -} // namespace content - -#endif // CONTENT_PUBLIC_BROWSER_RENDERER_UNRESPONSIVE_TYPE_H_
diff --git a/content/public/browser/web_contents_unresponsive_state.cc b/content/public/browser/web_contents_unresponsive_state.cc index 8a97780..e78be6f 100644 --- a/content/public/browser/web_contents_unresponsive_state.cc +++ b/content/public/browser/web_contents_unresponsive_state.cc
@@ -7,8 +7,7 @@ namespace content { WebContentsUnresponsiveState::WebContentsUnresponsiveState() - : reason(RendererUnresponsiveType::RENDERER_UNRESPONSIVE_UNKNOWN), - outstanding_ack_count(0), + : outstanding_ack_count(0), last_event_type(blink::WebInputEvent::Undefined) {} } // namespace content
diff --git a/content/public/browser/web_contents_unresponsive_state.h b/content/public/browser/web_contents_unresponsive_state.h index 8231d095..838625a 100644 --- a/content/public/browser/web_contents_unresponsive_state.h +++ b/content/public/browser/web_contents_unresponsive_state.h
@@ -6,7 +6,6 @@ #define CONTENT_PUBLIC_BROWSER_WEB_CONTENTS_UNRESPONSIVE_STATE_H_ #include "content/common/content_export.h" -#include "content/public/browser/renderer_unresponsive_type.h" #include "third_party/WebKit/public/platform/WebInputEvent.h" namespace content { @@ -17,9 +16,6 @@ struct CONTENT_EXPORT WebContentsUnresponsiveState { WebContentsUnresponsiveState(); - // The reason why the renderer was unresponsive. - RendererUnresponsiveType reason; - // TODO(dtapuska): Remove these fields once crbug.com/615090 is fixed. // The number of outstanding blocking input events sent to the renderer // that have not be acknowledged.
diff --git a/content/public/test/android/BUILD.gn b/content/public/test/android/BUILD.gn index 91d05b2..a3ed8d68 100644 --- a/content/public/test/android/BUILD.gn +++ b/content/public/test/android/BUILD.gn
@@ -24,10 +24,14 @@ "//base:base_java_test_support", "//content/public/android:content_java", "//device/geolocation:geolocation_java_test_support", + "//third_party/android_support_test_runner:runner_java", + "//third_party/junit:junit", "//ui/android:ui_java", ] java_files = [ "javatests/src/org/chromium/content/browser/test/NativeLibraryTestBase.java", + "javatests/src/org/chromium/content/browser/test/NativeLibraryTestCommon.java", + "javatests/src/org/chromium/content/browser/test/NativeLibraryTestRule.java", "javatests/src/org/chromium/content/browser/test/util/ApplicationUtils.java", "javatests/src/org/chromium/content/browser/test/util/ClickUtils.java", "javatests/src/org/chromium/content/browser/test/util/Criteria.java",
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestBase.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestBase.java index 4bfd1cf..daa3795 100644 --- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestBase.java +++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestBase.java
@@ -6,67 +6,26 @@ import android.test.InstrumentationTestCase; -import org.chromium.base.PathUtils; -import org.chromium.base.ThreadUtils; -import org.chromium.base.library_loader.LibraryLoader; -import org.chromium.base.library_loader.LibraryProcessType; -import org.chromium.base.library_loader.ProcessInitException; -import org.chromium.content.browser.BrowserStartupController; -import org.chromium.content.browser.test.util.ApplicationUtils; - /** * Test extension that adds support for loading and dealing with native libraries. */ public class NativeLibraryTestBase extends InstrumentationTestCase { - private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "content"; + private final NativeLibraryTestCommon mTestCommon = new NativeLibraryTestCommon(); /** * Loads the native library on the activity UI thread (must not be called from the UI thread). */ + @SuppressWarnings("deprecation") public void loadNativeLibraryNoBrowserProcess() { - handleNativeInitialization(false); + mTestCommon.handleNativeInitialization(false, getInstrumentation()); } /** * Loads the native library on the activity UI thread (must not be called from the UI thread). * After loading the library, this will initialize the browser process. */ + @SuppressWarnings("deprecation") public void loadNativeLibraryAndInitBrowserProcess() { - handleNativeInitialization(true); - } - - private void handleNativeInitialization(final boolean initBrowserProcess) { - assertFalse(ThreadUtils.runningOnUiThread()); - - PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX); - - ApplicationUtils.waitForLibraryDependencies(getInstrumentation()); - - // LibraryLoader is not in general multithreaded; as other InstrumentationTestCase code - // (specifically, ChromeBrowserProvider) uses it from the main thread we must do - // likewise. - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - nativeInitialization(initBrowserProcess); - } - }); - } - - private void nativeInitialization(boolean initBrowserProcess) { - if (initBrowserProcess) { - try { - BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER) - .startBrowserProcessesSync(false); - } catch (ProcessInitException e) { - throw new Error(e); - } - } else { - try { - LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized(); - } catch (ProcessInitException e) { - throw new Error(e); - } - } + mTestCommon.handleNativeInitialization(true, getInstrumentation()); } }
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestCommon.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestCommon.java new file mode 100644 index 0000000..72edea94 --- /dev/null +++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestCommon.java
@@ -0,0 +1,57 @@ +// 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. + +package org.chromium.content.browser.test; + +import android.app.Instrumentation; + +import org.junit.Assert; + +import org.chromium.base.PathUtils; +import org.chromium.base.ThreadUtils; +import org.chromium.base.library_loader.LibraryLoader; +import org.chromium.base.library_loader.LibraryProcessType; +import org.chromium.base.library_loader.ProcessInitException; +import org.chromium.content.browser.BrowserStartupController; +import org.chromium.content.browser.test.util.ApplicationUtils; + +class NativeLibraryTestCommon { + private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "content"; + + void handleNativeInitialization( + final boolean initBrowserProcess, Instrumentation instrumentation) { + Assert.assertFalse(ThreadUtils.runningOnUiThread()); + + PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX); + + ApplicationUtils.waitForLibraryDependencies(instrumentation); + + // LibraryLoader is not in general multithreaded; as other InstrumentationTestCase code + // (specifically, ChromeBrowserProvider) uses it from the main thread we must do + // likewise. + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + nativeInitialization(initBrowserProcess); + } + }); + } + + void nativeInitialization(boolean initBrowserProcess) { + if (initBrowserProcess) { + try { + BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER) + .startBrowserProcessesSync(false); + } catch (ProcessInitException e) { + throw new Error(e); + } + } else { + try { + LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized(); + } catch (ProcessInitException e) { + throw new Error(e); + } + } + } +}
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestRule.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestRule.java new file mode 100644 index 0000000..a673f12 --- /dev/null +++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestRule.java
@@ -0,0 +1,40 @@ +// 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. + +package org.chromium.content.browser.test; + +import android.support.test.InstrumentationRegistry; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * TestRule that adds support for loading and dealing with native libraries. + * + * NativeLibraryTestRule does not interact with any Activity. + */ +public class NativeLibraryTestRule implements TestRule { + private final NativeLibraryTestCommon mTestCommon = new NativeLibraryTestCommon(); + + /** + * Loads the native library on the activity UI thread (must not be called from the UI thread). + */ + public void loadNativeLibraryNoBrowserProcess() { + mTestCommon.handleNativeInitialization(false, InstrumentationRegistry.getInstrumentation()); + } + + /** + * Loads the native library on the activity UI thread (must not be called from the UI thread). + * After loading the library, this will initialize the browser process. + */ + public void loadNativeLibraryAndInitBrowserProcess() { + mTestCommon.handleNativeInitialization(true, InstrumentationRegistry.getInstrumentation()); + } + + @Override + public Statement apply(Statement base, Description description) { + return base; + } +}
diff --git a/content/renderer/mus/OWNERS b/content/renderer/mus/OWNERS index 105357c..7def73e6 100644 --- a/content/renderer/mus/OWNERS +++ b/content/renderer/mus/OWNERS
@@ -2,3 +2,5 @@ sadrul@chromium.org fsamuel@chromium.org rjkroege@chromium.org + +# COMPONENT: Internals>MUS
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellActivityTestRule.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellActivityTestRule.java index df1fcdf9b..c1ca6228 100644 --- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellActivityTestRule.java +++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellActivityTestRule.java
@@ -52,26 +52,6 @@ } @Override - public ContentShellActivity getActivityForTestCommon() { - return getActivity(); - } - - @Override - public Instrumentation getInstrumentationForTestCommon() { - return InstrumentationRegistry.getInstrumentation(); - } - - @Override - public ContentShellActivity launchActivityWithIntentForTestCommon(Intent t) { - return launchActivity(t); - } - - @Override - public void runOnUiThreadForTestCommon(Runnable runnable) throws Throwable { - runOnUiThread(runnable); - } - - @Override protected void beforeActivityLaunched() { mDelegate.assertScreenIsOn(); } @@ -181,4 +161,44 @@ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RerunWithUpdatedContainerView {} + + @Override + public ContentShellActivity getActivityForTestCommon() { + return getActivity(); + } + + @Override + public Instrumentation getInstrumentationForTestCommon() { + return InstrumentationRegistry.getInstrumentation(); + } + + @Override + public ContentShellActivity launchActivityWithIntentForTestCommon(Intent t) { + return launchActivity(t); + } + + @Override + public void runOnUiThreadForTestCommon(Runnable runnable) throws Throwable { + runOnUiThread(runnable); + } + + @Override + public ContentViewCore getContentViewCoreForTestCommon() { + return getContentViewCore(); + } + + @Override + public WebContents getWebContentsForTestCommon() { + return getWebContents(); + } + + @Override + public void waitForActiveShellToBeDoneLoadingForTestCommon() { + waitForActiveShellToBeDoneLoading(); + } + + @Override + public ContentShellActivity launchContentShellWithUrlForTestCommon(String url) { + return launchContentShellWithUrl(url); + } }
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java index 8d1d7386..ae8b821 100644 --- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java +++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java
@@ -40,31 +40,6 @@ mDelegate = new ContentShellTestCommon(this); } - @SuppressWarnings("deprecation") - @Override - public ContentShellActivity getActivityForTestCommon() { - return getActivity(); - } - - @Override - @SuppressWarnings("deprecation") - public Instrumentation getInstrumentationForTestCommon() { - return getInstrumentation(); - } - - @SuppressWarnings("deprecation") - @Override - public ContentShellActivity launchActivityWithIntentForTestCommon(Intent intent) { - setActivityIntent(intent); - return getActivity(); - } - - @SuppressWarnings("deprecation") - @Override - public void runOnUiThreadForTestCommon(Runnable runnable) throws Throwable { - runTestOnUiThread(runnable); - } - @Override @SuppressWarnings("deprecation") protected void setUp() throws Exception { @@ -185,4 +160,49 @@ + " See ContentShellTestBase#runTest.", e); } } + + @SuppressWarnings("deprecation") + @Override + public ContentShellActivity getActivityForTestCommon() { + return getActivity(); + } + + @Override + @SuppressWarnings("deprecation") + public Instrumentation getInstrumentationForTestCommon() { + return getInstrumentation(); + } + + @SuppressWarnings("deprecation") + @Override + public ContentShellActivity launchActivityWithIntentForTestCommon(Intent intent) { + setActivityIntent(intent); + return getActivity(); + } + + @SuppressWarnings("deprecation") + @Override + public void runOnUiThreadForTestCommon(Runnable runnable) throws Throwable { + runTestOnUiThread(runnable); + } + + @Override + public ContentViewCore getContentViewCoreForTestCommon() { + return getContentViewCore(); + } + + @Override + public WebContents getWebContentsForTestCommon() { + return getWebContents(); + } + + @Override + public void waitForActiveShellToBeDoneLoadingForTestCommon() { + waitForActiveShellToBeDoneLoading(); + } + + @Override + public ContentShellActivity launchContentShellWithUrlForTestCommon(String url) { + return launchContentShellWithUrl(url); + } }
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestCommon.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestCommon.java index 263723f..1259221 100644 --- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestCommon.java +++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestCommon.java
@@ -191,5 +191,9 @@ T launchActivityWithIntentForTestCommon(Intent t); T getActivityForTestCommon(); void runOnUiThreadForTestCommon(Runnable runnable) throws Throwable; + ContentViewCore getContentViewCoreForTestCommon(); + ContentShellActivity launchContentShellWithUrlForTestCommon(String url); + WebContents getWebContentsForTestCommon(); + void waitForActiveShellToBeDoneLoadingForTestCommon(); } }
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 8bdc92e9..c948785 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1139,6 +1139,7 @@ "../browser/loader/async_resource_handler_unittest.cc", "../browser/loader/async_revalidation_driver_unittest.cc", "../browser/loader/async_revalidation_manager_unittest.cc", + "../browser/loader/detachable_resource_handler_unittest.cc", "../browser/loader/intercepting_resource_handler_unittest.cc", "../browser/loader/mime_sniffing_resource_handler_unittest.cc", "../browser/loader/mock_resource_loader.cc",
diff --git a/device/sensors/data_fetcher_shared_memory_base.cc b/device/sensors/data_fetcher_shared_memory_base.cc index 21a72f1f..160bddb 100644 --- a/device/sensors/data_fetcher_shared_memory_base.cc +++ b/device/sensors/data_fetcher_shared_memory_base.cc
@@ -112,9 +112,10 @@ DataFetcherSharedMemoryBase::~DataFetcherSharedMemoryBase() { DCHECK_EQ(0u, started_consumers_); - // make sure polling thread stops asap. - if (polling_thread_) - polling_thread_->Stop(); + // By this point the polling thread should have already been stopped (it's not + // safe for it to be running in this class's destructor as tasks are posted to + // it that call virtual methods of this class). + DCHECK(!polling_thread_ || !polling_thread_->IsRunning()); } bool DataFetcherSharedMemoryBase::StartFetchingDeviceData( @@ -174,6 +175,13 @@ StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION); StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION_ABSOLUTE); StopFetchingDeviceData(CONSUMER_TYPE_LIGHT); + + // Ensure that the polling thread stops before entering the destructor of the + // subclass, as the stopping of the polling thread causes tasks to execute + // that call virtual methods of this class, which can cause crashes if they + // execute while (or after) the subclass is being torn down. + if (polling_thread_) + polling_thread_->Stop(); } mojo::ScopedSharedBufferHandle
diff --git a/device/sensors/data_fetcher_shared_memory_base_unittest.cc b/device/sensors/data_fetcher_shared_memory_base_unittest.cc index 910f8bab..2f01f70 100644 --- a/device/sensors/data_fetcher_shared_memory_base_unittest.cc +++ b/device/sensors/data_fetcher_shared_memory_base_unittest.cc
@@ -53,7 +53,7 @@ motion_buffer_(nullptr), orientation_buffer_(nullptr), orientation_absolute_buffer_(nullptr) {} - ~FakeDataFetcher() override {} + ~FakeDataFetcher() override { Shutdown(); } bool Init(ConsumerType consumer_type, void* buffer) { EXPECT_TRUE(buffer);
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn index edbf276e..97f392b9 100644 --- a/extensions/common/BUILD.gn +++ b/extensions/common/BUILD.gn
@@ -19,6 +19,7 @@ if (enable_extensions) { mojom("mojo") { sources = [ + "mojo/app_window.mojom", "mojo/keep_alive.mojom", ] if (proprietary_codecs && enable_wifi_display) {
diff --git a/extensions/common/mojo/app_window.mojom b/extensions/common/mojo/app_window.mojom new file mode 100644 index 0000000..ffa6a4d --- /dev/null +++ b/extensions/common/mojo/app_window.mojom
@@ -0,0 +1,9 @@ +// 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. + +module extensions.mojom; + +interface AppWindow { + SetVisuallyDeemphasized(bool deemphasized); +};
diff --git a/extensions/renderer/DEPS b/extensions/renderer/DEPS index 2eae9acd..5633eba 100644 --- a/extensions/renderer/DEPS +++ b/extensions/renderer/DEPS
@@ -20,5 +20,7 @@ "+v8/include", "+storage/common/fileapi", + + "+services/service_manager/public/cpp", ]
diff --git a/extensions/renderer/extensions_render_frame_observer.cc b/extensions/renderer/extensions_render_frame_observer.cc index be6dbcc..a96c45f 100644 --- a/extensions/renderer/extensions_render_frame_observer.cc +++ b/extensions/renderer/extensions_render_frame_observer.cc
@@ -9,9 +9,12 @@ #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" #include "content/public/renderer/render_frame.h" +#include "content/public/renderer/render_view.h" #include "extensions/common/extension_messages.h" #include "extensions/common/stack_frame.h" +#include "services/service_manager/public/cpp/interface_registry.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebView.h" namespace extensions { @@ -76,12 +79,32 @@ ExtensionsRenderFrameObserver::ExtensionsRenderFrameObserver( content::RenderFrame* render_frame) - : content::RenderFrameObserver(render_frame) { + : content::RenderFrameObserver(render_frame), + webview_visually_deemphasized_(false) { + render_frame->GetInterfaceRegistry()->AddInterface( + base::Bind(&ExtensionsRenderFrameObserver::BindAppWindowRequest, + base::Unretained(this))); } ExtensionsRenderFrameObserver::~ExtensionsRenderFrameObserver() { } +void ExtensionsRenderFrameObserver::BindAppWindowRequest( + mojom::AppWindowRequest request) { + bindings_.AddBinding(this, std::move(request)); +} + +void ExtensionsRenderFrameObserver::SetVisuallyDeemphasized(bool deemphasized) { + if (webview_visually_deemphasized_ == deemphasized) + return; + + webview_visually_deemphasized_ = deemphasized; + + SkColor color = + deemphasized ? SkColorSetARGB(178, 0, 0, 0) : SK_ColorTRANSPARENT; + render_frame()->GetRenderView()->GetWebView()->setPageOverlayColor(color); +} + void ExtensionsRenderFrameObserver::DetailedConsoleMessageAdded( const base::string16& message, const base::string16& source,
diff --git a/extensions/renderer/extensions_render_frame_observer.h b/extensions/renderer/extensions_render_frame_observer.h index 35f03a90..bfa910f 100644 --- a/extensions/renderer/extensions_render_frame_observer.h +++ b/extensions/renderer/extensions_render_frame_observer.h
@@ -9,19 +9,27 @@ #include "base/macros.h" #include "content/public/renderer/render_frame_observer.h" +#include "extensions/common/mojo/app_window.mojom.h" +#include "mojo/public/cpp/bindings/binding_set.h" namespace extensions { // This class holds the extensions specific parts of RenderFrame, and has the // same lifetime. -class ExtensionsRenderFrameObserver - : public content::RenderFrameObserver { +class ExtensionsRenderFrameObserver : public content::RenderFrameObserver, + public mojom::AppWindow { public: explicit ExtensionsRenderFrameObserver( content::RenderFrame* render_frame); ~ExtensionsRenderFrameObserver() override; private: + void BindAppWindowRequest(mojom::AppWindowRequest request); + + // Toggles visual muting of the render view area. This is on when a + // constrained window is showing. + void SetVisuallyDeemphasized(bool deemphasized) override; + // RenderFrameObserver implementation. void DetailedConsoleMessageAdded(const base::string16& message, const base::string16& source, @@ -30,6 +38,11 @@ int32_t severity_level) override; void OnDestruct() override; + // true if webview is overlayed with grey color. + bool webview_visually_deemphasized_; + + mojo::BindingSet<mojom::AppWindow> bindings_; + DISALLOW_COPY_AND_ASSIGN(ExtensionsRenderFrameObserver); };
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index 4c2c50ea..3eaf1adc7 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc
@@ -913,7 +913,6 @@ (gl_version_info_->IsAtLeastGLES(3, 1) || (gl_version_info_->IsAtLeastGL(3, 0) && extensions.Contains("GL_ARB_shading_language_420pack") && - extensions.Contains("GL_ARB_texture_storage") && extensions.Contains("GL_ARB_texture_gather") && extensions.Contains("GL_ARB_explicit_uniform_location") && extensions.Contains("GL_ARB_explicit_attrib_location") &&
diff --git a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc index ab7965a..4b9d7e43 100644 --- a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc +++ b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc
@@ -25,6 +25,7 @@ is_in_gamma_correct_mode_(false), supports_usampler_(true), supports_r8_image_(true), + supports_r8_read_format_(true), is_gles31_compatible_(false), frame_id_(0), width_(0), @@ -58,55 +59,67 @@ is_gles31_compatible_ = decoder->GetGLContext()->GetVersionInfo()->IsAtLeastGLES(3, 1); - if (is_gles31_compatible_) { - supports_r8_image_ = - decoder->GetGLContext()->HasExtension("GL_NV_image_formats"); + // Check if RGBA8UI is supported as an FBO colour target with depth. + // If not supported, GLSL needs to convert the data to/from float so there is + // a small extra cost. + { + GLuint rgba8ui_texture = 0, depth_texture = 0; + glGenTextures(1, &rgba8ui_texture); + glBindTexture(GL_TEXTURE_2D, rgba8ui_texture); + glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8UI, 4, 4); - // ES 3.0 requires GL_RGBA8UI is color renderable. - supports_usampler_ = true; - } else { - // CMAA requires GL_ARB_shader_image_load_store for GL, and it requires r8 - // image texture. - DCHECK(decoder->GetGLContext()->HasExtension( - "GL_ARB_shader_image_load_store")); - supports_r8_image_ = true; + glGenTextures(1, &depth_texture); + glBindTexture(GL_TEXTURE_2D, depth_texture); + glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, 4, 4); - // Check if RGBA8UI is supported as an FBO colour target with depth. - // If not supported, GLSL needs to convert the data to/from float so there - // is a small extra cost. - { - glActiveTexture(GL_TEXTURE0); + // Create the FBO + GLuint rgba8ui_framebuffer = 0; + glGenFramebuffersEXT(1, &rgba8ui_framebuffer); + glBindFramebufferEXT(GL_FRAMEBUFFER, rgba8ui_framebuffer); - GLuint rgba8ui_texture = 0, depth_texture = 0; - glGenTextures(1, &rgba8ui_texture); - glBindTexture(GL_TEXTURE_2D, rgba8ui_texture); - glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8UI, 4, 4); + // Bind to the FBO to test support + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, rgba8ui_texture, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, depth_texture, 0); + GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); - glGenTextures(1, &depth_texture); - glBindTexture(GL_TEXTURE_2D, depth_texture); - glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, 4, 4); + supports_usampler_ = (status == GL_FRAMEBUFFER_COMPLETE); - // Create the FBO - GLuint rgba8ui_framebuffer = 0; - glGenFramebuffersEXT(1, &rgba8ui_framebuffer); - glBindFramebufferEXT(GL_FRAMEBUFFER, rgba8ui_framebuffer); + glDeleteFramebuffersEXT(1, &rgba8ui_framebuffer); + glDeleteTextures(1, &rgba8ui_texture); + glDeleteTextures(1, &depth_texture); + } - // Bind to the FBO to test support - glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, rgba8ui_texture, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, depth_texture, 0); - GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); + // Check to see if R8 images are supported + // If not supported, images are bound as R32F for write targets, not R8. + { + GLuint r8_texture = 0; + glGenTextures(1, &r8_texture); + glBindTexture(GL_TEXTURE_2D, r8_texture); + glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_R8, 4, 4); - supports_usampler_ = (status == GL_FRAMEBUFFER_COMPLETE); + glGetError(); // reset all previous errors + glBindImageTextureEXT(0, r8_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R8); + if (glGetError() != GL_NO_ERROR) + supports_r8_image_ = false; - glDeleteFramebuffersEXT(1, &rgba8ui_framebuffer); - glDeleteTextures(1, &rgba8ui_texture); - glDeleteTextures(1, &depth_texture); + glDeleteTextures(1, &r8_texture); + } - decoder->RestoreTextureUnitBindings(0); - decoder->RestoreActiveTexture(); - decoder->RestoreFramebufferBindings(); + // Check if R8 GLSL read formats are supported. + // If not supported, r32f is used instead. + { + const char shader_source[] = + SHADER(layout(r8) restrict writeonly uniform highp image2D g_r8Image; + void main() { + imageStore(g_r8Image, ivec2(0, 0), vec4(1.0, 0.0, 0.0, 0.0)); + }); + + GLuint shader = CreateShader(GL_FRAGMENT_SHADER, "", shader_source); + supports_r8_read_format_ = (shader != 0); + if (shader != 0) { + glDeleteShader(shader); } } @@ -115,6 +128,9 @@ VLOG(1) << "ApplyFramebufferAttachmentCMAAINTEL: " << "Supports R8 Images is " << (supports_r8_image_ ? "true" : "false"); + VLOG(1) << "ApplyFramebufferAttachmentCMAAINTEL: " + << "Supports R8 Read Format is " + << (supports_r8_read_format_ ? "true" : "false"); // Create the shaders std::ostringstream defines, edge1, edge2, combineEdges, blur, displayEdges, @@ -132,7 +148,7 @@ defines << "#define IN_GAMMA_CORRECT_MODE\n"; } - if (supports_r8_image_) { + if (supports_r8_read_format_) { defines << "#define EDGE_READ_FORMAT r8\n"; } else { defines << "#define EDGE_READ_FORMAT r32f\n"; @@ -613,7 +629,7 @@ const char header_es31[] = "#version 310 es \n"; - const char header_gl130[] = + const char header_gl30[] = "#version 130 \n" "#extension GL_ARB_shading_language_420pack : require \n" "#extension GL_ARB_texture_gather : require \n" @@ -621,16 +637,14 @@ "#extension GL_ARB_explicit_attrib_location : require \n" "#extension GL_ARB_shader_image_load_store : require \n"; - std::ostringstream header; + const char* header = NULL; if (is_gles31_compatible_) { - header << header_es31; - if (supports_r8_image_) - header << "#extension GL_NV_image_formats : require\n"; + header = header_es31; } else { - header << header_gl130; + header = header_gl30; } - const char* source_array[4] = {header.str().c_str(), defines, "\n", source}; + const char* source_array[4] = {header, defines, "\n", source}; glShaderSource(shader, 4, source_array, NULL); glCompileShader(shader);
diff --git a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h index 9f2bd9ae..f9bad67 100644 --- a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h +++ b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h
@@ -57,6 +57,7 @@ bool is_in_gamma_correct_mode_; bool supports_usampler_; bool supports_r8_image_; + bool supports_r8_read_format_; bool is_gles31_compatible_; int frame_id_;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 7342032..90939e7 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -17502,6 +17502,7 @@ apply_framebuffer_attachment_cmaa_intel_.reset( new ApplyFramebufferAttachmentCMAAINTELResourceManager()); apply_framebuffer_attachment_cmaa_intel_->Initialize(this); + RestoreCurrentFramebufferBindings(); if (LOCAL_PEEK_GL_ERROR("glApplyFramebufferAttachmentCMAAINTEL") != GL_NO_ERROR) return;
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm index 9c99ee7..1a5ea66 100644 --- a/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm +++ b/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm
@@ -213,7 +213,7 @@ - (void)contentSuggestionsServiceFullRefreshRequired: (ntp_snippets::ContentSuggestionsService*)suggestionsService { - // Update dataSink. + [self.dataSink reloadAllData]; } - (void)contentSuggestionsServiceShutdown:
diff --git a/ios/chrome/browser/ui/collection_view/BUILD.gn b/ios/chrome/browser/ui/collection_view/BUILD.gn index da91a22..3a9b5d78 100644 --- a/ios/chrome/browser/ui/collection_view/BUILD.gn +++ b/ios/chrome/browser/ui/collection_view/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. source_set("collection_view") { + configs += [ "//build/config/compiler:enable_arc" ] sources = [ "collection_view_controller.h", "collection_view_controller.mm", @@ -20,6 +21,7 @@ } source_set("test_support") { + configs += [ "//build/config/compiler:enable_arc" ] testonly = true sources = [ "collection_view_controller_test.h",
diff --git a/ios/chrome/browser/ui/collection_view/cells/BUILD.gn b/ios/chrome/browser/ui/collection_view/cells/BUILD.gn index e6e8c32..16bf165 100644 --- a/ios/chrome/browser/ui/collection_view/cells/BUILD.gn +++ b/ios/chrome/browser/ui/collection_view/cells/BUILD.gn
@@ -41,6 +41,7 @@ } source_set("test_support") { + configs += [ "//build/config/compiler:enable_arc" ] testonly = true sources = [ "test_utils.h",
diff --git a/ios/chrome/browser/ui/collection_view/cells/test_utils.mm b/ios/chrome/browser/ui/collection_view/cells/test_utils.mm index a5c7e32..54cb5ae 100644 --- a/ios/chrome/browser/ui/collection_view/cells/test_utils.mm +++ b/ios/chrome/browser/ui/collection_view/cells/test_utils.mm
@@ -4,6 +4,10 @@ #import "ios/chrome/browser/ui/collection_view/cells/test_utils.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace ios_internal { UIImage* CollectionViewTestImage() {
diff --git a/ios/chrome/browser/ui/collection_view/collection_view_controller.h b/ios/chrome/browser/ui/collection_view/collection_view_controller.h index 4273f56..d777ca8 100644 --- a/ios/chrome/browser/ui/collection_view/collection_view_controller.h +++ b/ios/chrome/browser/ui/collection_view/collection_view_controller.h
@@ -25,7 +25,7 @@ : MDCCollectionViewController<AppBarPresenting> // The model of this controller. -@property(nonatomic, readonly) +@property(strong, nonatomic, readonly) CollectionViewModel<CollectionViewItem*>* collectionViewModel; // Initializer with the desired style.
diff --git a/ios/chrome/browser/ui/collection_view/collection_view_controller.mm b/ios/chrome/browser/ui/collection_view/collection_view_controller.mm index 050eb0e..cbdc9d8 100644 --- a/ios/chrome/browser/ui/collection_view/collection_view_controller.mm +++ b/ios/chrome/browser/ui/collection_view/collection_view_controller.mm
@@ -6,28 +6,29 @@ #include "base/logging.h" #include "base/mac/foundation_util.h" -#import "base/mac/scoped_nsobject.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" #import "ios/chrome/browser/ui/material_components/utils.h" #import "ios/third_party/material_components_ios/src/components/AppBar/src/MaterialAppBar.h" #import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h" -@implementation CollectionViewController { - // The implementation of this controller follows the guidelines from - // https://github.com/material-components/material-components-ios/tree/develop/components/AppBar - base::scoped_nsobject<MDCAppBar> _appBar; - base::scoped_nsobject<CollectionViewModel> _collectionViewModel; -} +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +// The implementation of this controller follows the guidelines from +// https://github.com/material-components/material-components-ios/tree/develop/components/AppBar +@implementation CollectionViewController +@synthesize appBar = _appBar; +@synthesize collectionViewModel = _collectionViewModel; - (instancetype)initWithStyle:(CollectionViewControllerStyle)style { - UICollectionViewLayout* layout = - [[[MDCCollectionViewFlowLayout alloc] init] autorelease]; + UICollectionViewLayout* layout = [[MDCCollectionViewFlowLayout alloc] init]; self = [super initWithCollectionViewLayout:layout]; if (self) { if (style == CollectionViewControllerStyleAppBar) { - _appBar.reset([[MDCAppBar alloc] init]); - [self addChildViewController:_appBar.get().headerViewController]; + _appBar = [[MDCAppBar alloc] init]; + [self addChildViewController:_appBar.headerViewController]; } } return self; @@ -56,16 +57,8 @@ return self.appBar.headerViewController; } -- (MDCAppBar*)appBar { - return _appBar.get(); -} - -- (CollectionViewModel*)collectionViewModel { - return _collectionViewModel.get(); -} - - (void)loadModel { - _collectionViewModel.reset([[CollectionViewModel alloc] init]); + _collectionViewModel = [[CollectionViewModel alloc] init]; } - (void)reconfigureCellsForItems:(NSArray*)items @@ -121,8 +114,8 @@ DCHECK(![MDCCollectionViewController instancesRespondToSelector:_cmd]); // Retain the item to be able to move it. - base::scoped_nsobject<CollectionViewItem> item( - [[self.collectionViewModel itemAtIndexPath:indexPath] retain]); + CollectionViewItem* item = + [self.collectionViewModel itemAtIndexPath:indexPath]; // Item coordinates. NSInteger sectionIdentifier =
diff --git a/ios/chrome/browser/ui/collection_view/collection_view_controller_test.mm b/ios/chrome/browser/ui/collection_view/collection_view_controller_test.mm index 33a4194..626866a 100644 --- a/ios/chrome/browser/ui/collection_view/collection_view_controller_test.mm +++ b/ios/chrome/browser/ui/collection_view/collection_view_controller_test.mm
@@ -4,10 +4,8 @@ #import "ios/chrome/browser/ui/collection_view/collection_view_controller_test.h" -#include "base/ios/weak_nsobject.h" #include "base/logging.h" #import "base/mac/foundation_util.h" -#include "base/mac/scoped_nsobject.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" @@ -19,6 +17,10 @@ #include "testing/gtest_mac.h" #include "ui/base/l10n/l10n_util.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + CollectionViewControllerTest::CollectionViewControllerTest() {} CollectionViewControllerTest::~CollectionViewControllerTest() {} @@ -183,10 +185,9 @@ ProceduralBlock completion_block) { NSIndexPath* index_path = [NSIndexPath indexPathForItem:item inSection:section]; - base::WeakNSObject<CollectionViewController> weak_controller(controller_); + __weak CollectionViewController* weak_controller = controller_; void (^batch_updates)() = ^{ - base::scoped_nsobject<CollectionViewController> strong_controller( - [weak_controller retain]); + CollectionViewController* strong_controller = weak_controller; if (!strong_controller) return; // Notify delegate to delete data. @@ -200,8 +201,7 @@ void (^completion)(BOOL finished) = ^(BOOL finished) { // Notify delegate of deletion. - base::scoped_nsobject<CollectionViewController> strong_controller( - [weak_controller retain]); + CollectionViewController* strong_controller = weak_controller; if (!strong_controller) return; [strong_controller collectionView:[strong_controller collectionView]
diff --git a/ios/chrome/browser/ui/collection_view/collection_view_model.mm b/ios/chrome/browser/ui/collection_view/collection_view_model.mm index d57b258c..0866b37 100644 --- a/ios/chrome/browser/ui/collection_view/collection_view_model.mm +++ b/ios/chrome/browser/ui/collection_view/collection_view_model.mm
@@ -5,33 +5,34 @@ #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" #include "base/logging.h" -#include "base/mac/scoped_nsobject.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace { typedef NSMutableArray<CollectionViewItem*> SectionItems; } @implementation CollectionViewModel { // Ordered list of section identifiers, one per section in the model. - base::scoped_nsobject<NSMutableArray<NSNumber*>> _sectionIdentifiers; + NSMutableArray<NSNumber*>* _sectionIdentifiers; // The lists of section items, one per section. - base::scoped_nsobject<NSMutableArray<SectionItems*>> _sections; + NSMutableArray<SectionItems*>* _sections; // Maps from section identifier to header and footer. - base::scoped_nsobject<NSMutableDictionary<NSNumber*, CollectionViewItem*>> - _headers; - base::scoped_nsobject<NSMutableDictionary<NSNumber*, CollectionViewItem*>> - _footers; + NSMutableDictionary<NSNumber*, CollectionViewItem*>* _headers; + NSMutableDictionary<NSNumber*, CollectionViewItem*>* _footers; } - (instancetype)init { if ((self = [super init])) { - _sectionIdentifiers.reset([[NSMutableArray alloc] init]); - _sections.reset([[NSMutableArray alloc] init]); - _headers.reset([[NSMutableDictionary alloc] init]); - _footers.reset([[NSMutableDictionary alloc] init]); + _sectionIdentifiers = [[NSMutableArray alloc] init]; + _sections = [[NSMutableArray alloc] init]; + _headers = [[NSMutableDictionary alloc] init]; + _footers = [[NSMutableDictionary alloc] init]; } return self; } @@ -44,7 +45,7 @@ [self internalSectionForIdentifier:sectionIdentifier]); [_sectionIdentifiers addObject:@(sectionIdentifier)]; - base::scoped_nsobject<SectionItems> section([[SectionItems alloc] init]); + SectionItems* section = [[SectionItems alloc] init]; [_sections addObject:section]; } @@ -57,7 +58,7 @@ [_sectionIdentifiers insertObject:@(sectionIdentifier) atIndex:index]; - base::scoped_nsobject<SectionItems> section([[SectionItems alloc] init]); + SectionItems* section = [[SectionItems alloc] init]; [_sections insertObject:section atIndex:index]; }
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm index d720459..273dc3f 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
@@ -87,8 +87,6 @@ NSMutableDictionary<NSNumber*, ContentSuggestionsSectionInformation*>* sectionInfoBySectionIdentifier; -// Reloads all the data from the data source, deleting all the current items. -- (void)reloadData; // Adds a new section if needed and returns the section identifier. - (NSInteger)addSectionIfNeeded: (ContentSuggestionsSectionInformation*)sectionInformation; @@ -120,13 +118,13 @@ (ContentSuggestionsViewController*)collectionViewController { _collectionViewController = collectionViewController; - [self reloadData]; + [self reloadAllData]; } #pragma mark - ContentSuggestionsDataSink - (void)dataAvailable { - [self reloadData]; + [self reloadAllData]; } - (void)clearSuggestion:(ContentSuggestionIdentifier*)suggestionIdentifier { @@ -159,6 +157,37 @@ [self.collectionViewController dismissEntryAtIndexPath:indexPath]; } +- (void)reloadAllData { + [self resetModels]; + CollectionViewModel* model = + self.collectionViewController.collectionViewModel; + + NSArray<ContentSuggestion*>* suggestions = [self.dataSource allSuggestions]; + + for (ContentSuggestion* suggestion in suggestions) { + NSInteger sectionIdentifier = + [self addSectionIfNeeded:suggestion.suggestionIdentifier.sectionInfo]; + ContentSuggestionsArticleItem* articleItem = + [[ContentSuggestionsArticleItem alloc] + initWithType:ItemTypeForContentSuggestionType(suggestion.type) + title:suggestion.title + subtitle:suggestion.text + delegate:self + url:suggestion.url]; + + articleItem.publisher = suggestion.publisher; + articleItem.publishDate = suggestion.publishDate; + + articleItem.suggestionIdentifier = suggestion.suggestionIdentifier; + + [model addItem:articleItem toSectionWithIdentifier:sectionIdentifier]; + } + + if ([self.collectionViewController isViewLoaded]) { + [self.collectionViewController.collectionView reloadData]; + } +} + #pragma mark - Public methods - (BOOL)shouldUseCustomStyleForSection:(NSInteger)section { @@ -206,37 +235,6 @@ #pragma mark - Private methods -- (void)reloadData { - [self resetModels]; - CollectionViewModel* model = - self.collectionViewController.collectionViewModel; - - NSArray<ContentSuggestion*>* suggestions = [self.dataSource allSuggestions]; - - for (ContentSuggestion* suggestion in suggestions) { - NSInteger sectionIdentifier = - [self addSectionIfNeeded:suggestion.suggestionIdentifier.sectionInfo]; - ContentSuggestionsArticleItem* articleItem = - [[ContentSuggestionsArticleItem alloc] - initWithType:ItemTypeForContentSuggestionType(suggestion.type) - title:suggestion.title - subtitle:suggestion.text - delegate:self - url:suggestion.url]; - - articleItem.publisher = suggestion.publisher; - articleItem.publishDate = suggestion.publishDate; - - articleItem.suggestionIdentifier = suggestion.suggestionIdentifier; - - [model addItem:articleItem toSectionWithIdentifier:sectionIdentifier]; - } - - if ([self.collectionViewController isViewLoaded]) { - [self.collectionViewController.collectionView reloadData]; - } -} - - (NSInteger)addSectionIfNeeded: (ContentSuggestionsSectionInformation*)sectionInformation { NSInteger sectionIdentifier = SectionIdentifierForInfo(sectionInformation);
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink.h index 5d2deef..43d7750 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink.h +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink.h
@@ -19,6 +19,10 @@ // about the data source pushing something to the data sink. - (void)clearSuggestion:(ContentSuggestionIdentifier*)suggestionIdentifier; +// Notifies the Data Sink that it must remove all current data and reload new +// ones. +- (void)reloadAllData; + @end #endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_DATA_SINK_H_
diff --git a/ios/chrome/browser/ui/reading_list/BUILD.gn b/ios/chrome/browser/ui/reading_list/BUILD.gn index 185dbe1..e513818 100644 --- a/ios/chrome/browser/ui/reading_list/BUILD.gn +++ b/ios/chrome/browser/ui/reading_list/BUILD.gn
@@ -133,10 +133,12 @@ "//components/reading_list/ios", "//ios/chrome/app/strings", "//ios/chrome/browser/reading_list", + "//ios/chrome/browser/ui:ui", "//ios/chrome/browser/ui/commands", "//ios/chrome/test/app:test_support", "//ios/chrome/test/earl_grey:test_support", "//ios/testing:ios_test_support", + "//ios/testing/earl_grey:earl_grey_support", "//ios/third_party/earl_grey", "//ios/third_party/material_components_ios", "//ios/web:test_support",
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm index e4c41d7..82e6ba61 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
@@ -12,6 +12,7 @@ #import "ios/chrome/browser/ui/commands/generic_chrome_command.h" #include "ios/chrome/browser/ui/commands/ios_command_ids.h" #import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h" +#include "ios/chrome/browser/ui/ui_util.h" #include "ios/chrome/grit/ios_strings.h" #import "ios/chrome/test/app/chrome_test_util.h" #import "ios/chrome/test/earl_grey/accessibility_util.h" @@ -19,6 +20,7 @@ #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" #import "ios/chrome/test/earl_grey/chrome_matchers.h" #import "ios/chrome/test/earl_grey/chrome_test_case.h" +#import "ios/testing/earl_grey/disabled_test_macros.h" #import "ios/testing/wait_util.h" #import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h" #import "ios/web/public/test/http_server.h" @@ -219,6 +221,11 @@ // Tests that sharing a web page to the Reading List results in a snackbar // appearing, and that the Reading List entry is present in the Reading List. - (void)testSavingToReadingList { + // TODO(crbug.com/700001): This test is failing on iPad. + if (IsIPadIdiom()) { + EARL_GREY_TEST_DISABLED(@"Disabled for iPad"); + } + // Setup a server serving a page at http://potato with the title "tomato". std::map<GURL, std::string> responses; const GURL regularPageURL = web::test::HttpServer::MakeUrl("http://potato");
diff --git a/ios/clean/chrome/app/steps/BUILD.gn b/ios/clean/chrome/app/steps/BUILD.gn index 0289f26..b2c05f8 100644 --- a/ios/clean/chrome/app/steps/BUILD.gn +++ b/ios/clean/chrome/app/steps/BUILD.gn
@@ -29,6 +29,7 @@ "//ios/chrome/browser/web:web_internal", "//ios/clean/chrome/app:application_state", "//ios/clean/chrome/browser", + "//ios/clean/chrome/browser/model", "//ios/clean/chrome/browser/ui/tab_grid", "//ios/net", "//ios/web:web_arc",
diff --git a/ios/clean/chrome/app/steps/tab_grid_coordinator+application_step.mm b/ios/clean/chrome/app/steps/tab_grid_coordinator+application_step.mm index b75efef..b592bf2 100644 --- a/ios/clean/chrome/app/steps/tab_grid_coordinator+application_step.mm +++ b/ios/clean/chrome/app/steps/tab_grid_coordinator+application_step.mm
@@ -11,6 +11,8 @@ #import "base/supports_user_data.h" #import "ios/clean/chrome/app/application_state.h" #import "ios/clean/chrome/browser/browser_coordinator+internal.h" +#import "ios/clean/chrome/browser/model/browser.h" +#import "ios/clean/chrome/browser/model/browser_list.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -43,7 +45,8 @@ } - (void)runInState:(ApplicationState*)state { - self.browserState = state.browserState; + self.browser = + BrowserList::FromBrowserState(state.browserState)->CreateNewBrowser(); [self start]; state.window.rootViewController = self.viewController;
diff --git a/ios/clean/chrome/browser/BUILD.gn b/ios/clean/chrome/browser/BUILD.gn index 621ee11..0cbf261e 100644 --- a/ios/clean/chrome/browser/BUILD.gn +++ b/ios/clean/chrome/browser/BUILD.gn
@@ -18,6 +18,7 @@ "//ios/chrome/browser", "//ios/chrome/browser/browser_state", "//ios/chrome/browser/tabs:tabs_internal", + "//ios/clean/chrome/browser/model", "//ios/shared/chrome/browser/coordinator_context", ] }
diff --git a/ios/clean/chrome/browser/browser_coordinator+internal.h b/ios/clean/chrome/browser/browser_coordinator+internal.h index 95197cc..0fdec93 100644 --- a/ios/clean/chrome/browser/browser_coordinator+internal.h +++ b/ios/clean/chrome/browser/browser_coordinator+internal.h
@@ -48,7 +48,7 @@ // Adds |coordinator| as a child, taking ownership of it, setting the receiver's // viewController (if any) as the child's baseViewController, and setting -// the receiver's browserState as the child's browserState. +// the receiver's |browser| as the child's |browser|. - (void)addChildCoordinator:(BrowserCoordinator*)coordinator; // Removes |coordinator| as a child, relinquishing ownership of it. If
diff --git a/ios/clean/chrome/browser/browser_coordinator.h b/ios/clean/chrome/browser/browser_coordinator.h index 550c4db..6b06543 100644 --- a/ios/clean/chrome/browser/browser_coordinator.h +++ b/ios/clean/chrome/browser/browser_coordinator.h
@@ -11,10 +11,8 @@ #import <UIKit/UIKit.h> +class Browser; @class CoordinatorContext; -namespace ios { -class ChromeBrowserState; -} // An object that manages a UI component via a view controller. // This is the public interface to this class; subclasses should also import @@ -26,10 +24,10 @@ // The context object for this coordinator. @property(nonatomic, strong, readonly) CoordinatorContext* context; -// The browser state used by this coordinator and passed into any child +// The browser object used by this coordinator and passed into any child // coordinators added to it. This is a weak pointer, and setting this property -// doesn't transfer ownership of the browser state. -@property(nonatomic, assign) ios::ChromeBrowserState* browserState; +// doesn't transfer ownership of the browser. +@property(nonatomic, assign) Browser* browser; // The basic lifecycle methods for coordinators are -start and -stop. These // are blank template methods; child classes are expected to implement them and
diff --git a/ios/clean/chrome/browser/browser_coordinator.mm b/ios/clean/chrome/browser/browser_coordinator.mm index dfe32a0..4c7af01 100644 --- a/ios/clean/chrome/browser/browser_coordinator.mm +++ b/ios/clean/chrome/browser/browser_coordinator.mm
@@ -27,7 +27,7 @@ @implementation BrowserCoordinator @synthesize context = _context; -@synthesize browserState = _browserState; +@synthesize browser = _browser; @synthesize childCoordinators = _childCoordinators; @synthesize parentCoordinator = _parentCoordinator; @synthesize overlaying = _overlaying; @@ -66,7 +66,7 @@ "property."; [self.childCoordinators addObject:coordinator]; coordinator.parentCoordinator = self; - coordinator.browserState = self.browserState; + coordinator.browser = self.browser; coordinator.context.baseViewController = self.viewController; }
diff --git a/ios/clean/chrome/browser/ui/settings/BUILD.gn b/ios/clean/chrome/browser/ui/settings/BUILD.gn index c10b381..e2ff2a46 100644 --- a/ios/clean/chrome/browser/ui/settings/BUILD.gn +++ b/ios/clean/chrome/browser/ui/settings/BUILD.gn
@@ -13,6 +13,7 @@ deps = [ "//ios/chrome/browser/ui/settings", "//ios/clean/chrome/browser", + "//ios/clean/chrome/browser/model", "//ios/clean/chrome/browser/ui/actions", "//ios/clean/chrome/browser/ui/commands", "//ios/shared/chrome/browser/coordinator_context",
diff --git a/ios/clean/chrome/browser/ui/settings/settings_coordinator.mm b/ios/clean/chrome/browser/ui/settings/settings_coordinator.mm index 5edbd3b..536bebce 100644 --- a/ios/clean/chrome/browser/ui/settings/settings_coordinator.mm +++ b/ios/clean/chrome/browser/ui/settings/settings_coordinator.mm
@@ -10,6 +10,7 @@ #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" #import "ios/clean/chrome/browser/browser_coordinator+internal.h" +#import "ios/clean/chrome/browser/model/browser.h" #import "ios/clean/chrome/browser/ui/commands/settings_commands.h" #import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h" @@ -29,8 +30,10 @@ - (void)start { self.viewController = [SettingsNavigationController - newSettingsMainControllerWithMainBrowserState:self.browserState - currentBrowserState:self.browserState + newSettingsMainControllerWithMainBrowserState:self.browser + ->browser_state() + currentBrowserState:self.browser + ->browser_state() delegate:self]; [self.context.baseViewController presentViewController:self.viewController animated:self.context.animated
diff --git a/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn b/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn index 6f12de1..a197d8f 100644 --- a/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn +++ b/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn
@@ -15,6 +15,7 @@ "//base", "//ios/chrome/browser/browser_state", "//ios/clean/chrome/browser", + "//ios/clean/chrome/browser/model", "//ios/clean/chrome/browser/ui/commands", "//ios/clean/chrome/browser/ui/settings", "//ios/clean/chrome/browser/ui/tab",
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm index 938f900..d36633a 100644 --- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm +++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
@@ -13,6 +13,7 @@ #include "base/strings/sys_string_conversions.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/clean/chrome/browser/browser_coordinator+internal.h" +#import "ios/clean/chrome/browser/model/browser.h" #import "ios/clean/chrome/browser/ui/commands/settings_commands.h" #import "ios/clean/chrome/browser/ui/commands/tab_commands.h" #import "ios/clean/chrome/browser/ui/commands/tab_grid_commands.h" @@ -47,11 +48,11 @@ #pragma mark - Properties -- (void)setBrowserState:(ios::ChromeBrowserState*)browserState { - [super setBrowserState:browserState]; +- (void)setBrowser:(Browser*)browser { + [super setBrowser:browser]; for (int i = 0; i < 7; i++) { - web::WebState::CreateParams webStateCreateParams(browserState); + web::WebState::CreateParams webStateCreateParams(browser->browser_state()); std::unique_ptr<web::WebState> webState = web::WebState::Create(webStateCreateParams); _webStates.push_back(std::move(webState)); @@ -118,7 +119,8 @@ } - (void)createNewTabAtIndexPath:(NSIndexPath*)indexPath { - web::WebState::CreateParams webStateCreateParams(self.browserState); + web::WebState::CreateParams webStateCreateParams( + self.browser->browser_state()); std::unique_ptr<web::WebState> webState = web::WebState::Create(webStateCreateParams); _webStates.push_back(std::move(webState));
diff --git a/net/cert/x509_certificate_openssl.cc b/net/cert/x509_certificate_openssl.cc index 30d9598..3644984 100644 --- a/net/cert/x509_certificate_openssl.cc +++ b/net/cert/x509_certificate_openssl.cc
@@ -15,6 +15,7 @@ #include "crypto/openssl_util.h" #include "net/base/ip_address.h" #include "net/base/net_errors.h" +#include "net/cert/x509_util.h" #include "net/cert/x509_util_openssl.h" #include "third_party/boringssl/src/include/openssl/asn1.h" #include "third_party/boringssl/src/include/openssl/bytestring.h" @@ -245,12 +246,9 @@ const char* data, size_t length) { crypto::EnsureOpenSSLInit(); - const unsigned char* d2i_data = - reinterpret_cast<const unsigned char*>(data); - // Don't cache this data for x509_util::GetDER as this wire format - // may be not be identical from the i2d_X509 roundtrip. - X509* cert = d2i_X509(NULL, &d2i_data, base::checked_cast<long>(length)); - return cert; + bssl::UniquePtr<CRYPTO_BUFFER> buffer = x509_util::CreateCryptoBuffer( + reinterpret_cast<const uint8_t*>(data), length); + return X509_parse_from_buffer(buffer.get()); } // static
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc index 1b08102d..bdbce02cc 100644 --- a/net/socket/ssl_client_socket_impl.cc +++ b/net/socket/ssl_client_socket_impl.cc
@@ -234,42 +234,36 @@ } #endif -scoped_refptr<X509Certificate> OSChainFromOpenSSL(STACK_OF(X509) * +scoped_refptr<X509Certificate> OSChainFromBuffers(STACK_OF(CRYPTO_BUFFER) * openssl_chain) { - if (sk_X509_num(openssl_chain) == 0) { + if (sk_CRYPTO_BUFFER_num(openssl_chain) == 0) { NOTREACHED(); return nullptr; } -#if defined(USE_OPENSSL_CERTS) - // When OSCertHandle is typedef'ed to X509, this implementation does a short - // cut to avoid converting back and forth between DER and the X509 struct. - X509Certificate::OSCertHandles intermediates; - for (size_t i = 1; i < sk_X509_num(openssl_chain); ++i) { - X509* cert = sk_X509_value(openssl_chain, i); - DCHECK(cert->buf); - intermediates.push_back(cert); - } - - X509* leaf = sk_X509_value(openssl_chain, 0); - DCHECK(leaf->buf); - return X509Certificate::CreateFromHandle(leaf, intermediates); -#else // Convert the certificate chains to a platform certificate handle. std::vector<base::StringPiece> der_chain; - der_chain.reserve(sk_X509_num(openssl_chain)); - for (size_t i = 0; i < sk_X509_num(openssl_chain); ++i) { - X509* cert = sk_X509_value(openssl_chain, i); - DCHECK(cert->buf); + der_chain.reserve(sk_CRYPTO_BUFFER_num(openssl_chain)); + for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(openssl_chain); ++i) { + const CRYPTO_BUFFER* cert = sk_CRYPTO_BUFFER_value(openssl_chain, i); base::StringPiece der; - if (!x509_util::GetDER(cert, &der)) - return nullptr; - der_chain.push_back(der); + der_chain.push_back(base::StringPiece( + reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert)), + CRYPTO_BUFFER_len(cert))); } return X509Certificate::CreateFromDERCertChain(der_chain); -#endif } +#if !defined(OS_IOS) +bssl::UniquePtr<CRYPTO_BUFFER> OSCertHandleToBuffer( + X509Certificate::OSCertHandle os_handle) { + std::string der_encoded; + if (!X509Certificate::GetDEREncoded(os_handle, &der_encoded)) + return nullptr; + return x509_util::CreateCryptoBuffer(der_encoded); +} +#endif + } // namespace class SSLClientSocketImpl::SSLContext { @@ -312,10 +306,11 @@ crypto::EnsureOpenSSLInit(); ssl_socket_data_index_ = SSL_get_ex_new_index(0, 0, 0, 0, 0); DCHECK_NE(ssl_socket_data_index_, -1); - ssl_ctx_.reset(SSL_CTX_new(SSLv23_client_method())); - SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), CertVerifyCallback, NULL); + ssl_ctx_.reset(SSL_CTX_new(TLS_with_buffers_method())); SSL_CTX_set_cert_cb(ssl_ctx_.get(), ClientCertRequestCallback, NULL); - SSL_CTX_set_verify(ssl_ctx_.get(), SSL_VERIFY_PEER, NULL); + + // The server certificate is verified after the handshake in DoVerifyCert. + SSL_CTX_i_promise_to_verify_certs_after_the_handshake(ssl_ctx_.get()); // Disable the internal session cache. Session caching is handled // externally (i.e. by SSLClientSessionCache). @@ -377,15 +372,6 @@ return socket->ClientCertRequestCallback(ssl); } - static int CertVerifyCallback(X509_STORE_CTX* store_ctx, void* arg) { - SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data( - store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx())); - SSLClientSocketImpl* socket = GetInstance()->GetClientSocketFromSSL(ssl); - CHECK(socket); - - return socket->CertVerifyCallback(store_ctx); - } - static int NewSessionCallback(SSL* ssl, SSL_SESSION* session) { SSLClientSocketImpl* socket = GetInstance()->GetClientSocketFromSSL(ssl); return socket->NewSessionCallback(session); @@ -523,18 +509,13 @@ cert_request_info->host_and_port = host_and_port_; cert_request_info->cert_authorities.clear(); - STACK_OF(X509_NAME)* authorities = SSL_get_client_CA_list(ssl_.get()); - for (size_t i = 0; i < sk_X509_NAME_num(authorities); i++) { - X509_NAME* ca_name = sk_X509_NAME_value(authorities, i); - uint8_t* str = nullptr; - int length = i2d_X509_NAME(ca_name, &str); - if (length > 0) { - cert_request_info->cert_authorities.push_back(std::string( - reinterpret_cast<const char*>(str), static_cast<size_t>(length))); - } else { - NOTREACHED(); // Error serializing |ca_name|. - } - OPENSSL_free(str); + const STACK_OF(CRYPTO_BUFFER)* authorities = + SSL_get0_server_requested_CAs(ssl_.get()); + for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(authorities); i++) { + const CRYPTO_BUFFER* ca_name = sk_CRYPTO_BUFFER_value(authorities, i); + cert_request_info->cert_authorities.push_back( + std::string(reinterpret_cast<const char*>(CRYPTO_BUFFER_data(ca_name)), + CRYPTO_BUFFER_len(ca_name))); } cert_request_info->cert_key_types.clear(); @@ -788,17 +769,14 @@ void SSLClientSocketImpl::DumpMemoryStats(SocketMemoryStats* stats) const { if (transport_adapter_) stats->buffer_size = transport_adapter_->GetAllocationSize(); - STACK_OF(X509)* server_cert_chain = SSL_get_peer_cert_chain(ssl_.get()); + const STACK_OF(CRYPTO_BUFFER)* server_cert_chain = + SSL_get0_peer_certificates(ssl_.get()); if (server_cert_chain) { - for (size_t i = 0; i < sk_X509_num(server_cert_chain); ++i) { - X509* cert = sk_X509_value(server_cert_chain, i); - // Estimate the size of the certificate before deduplication. - // The multiplier (4) is added to account for the difference between the - // serialized cert size and the actual cert allocation. - // TODO(xunjieli): Update this after crbug.com/671420 is done. - stats->cert_size += 4 * i2d_X509(cert, nullptr); + for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(server_cert_chain); ++i) { + const CRYPTO_BUFFER* cert = sk_CRYPTO_BUFFER_value(server_cert_chain, i); + stats->cert_size += CRYPTO_BUFFER_len(cert); } - stats->cert_count = sk_X509_num(server_cert_chain); + stats->cert_count = sk_CRYPTO_BUFFER_num(server_cert_chain); } stats->total_size = stats->buffer_size + stats->cert_size; } @@ -1194,7 +1172,7 @@ int SSLClientSocketImpl::DoVerifyCert(int result) { DCHECK(start_cert_verification_time_.is_null()); - server_cert_ = OSChainFromOpenSSL(SSL_get_peer_cert_chain(ssl_.get())); + server_cert_ = OSChainFromBuffers(SSL_get0_peer_certificates(ssl_.get())); // OpenSSL decoded the certificate, but the platform certificate // implementation could not. This is treated as a fatal SSL-level protocol @@ -1615,28 +1593,6 @@ // Second pass: a client certificate should have been selected. if (ssl_config_.client_cert.get()) { - bssl::UniquePtr<X509> leaf_x509 = - OSCertHandleToOpenSSL(ssl_config_.client_cert->os_cert_handle()); - if (!leaf_x509) { - LOG(WARNING) << "Failed to import certificate"; - OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT); - return -1; - } - - bssl::UniquePtr<STACK_OF(X509)> chain = OSCertHandlesToOpenSSL( - ssl_config_.client_cert->GetIntermediateCertificates()); - if (!chain) { - LOG(WARNING) << "Failed to import intermediate certificates"; - OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT); - return -1; - } - - if (!SSL_use_certificate(ssl_.get(), leaf_x509.get()) || - !SSL_set1_chain(ssl_.get(), chain.get())) { - LOG(WARNING) << "Failed to set client certificate"; - return -1; - } - if (!ssl_config_.client_private_key) { // The caller supplied a null private key. Fail the handshake and surface // an appropriate error to the caller. @@ -1645,7 +1601,35 @@ return -1; } - SSL_set_private_key_method(ssl_.get(), &SSLContext::kPrivateKeyMethod); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> chain; + std::vector<CRYPTO_BUFFER*> chain_raw; + bssl::UniquePtr<CRYPTO_BUFFER> buf = + OSCertHandleToBuffer(ssl_config_.client_cert->os_cert_handle()); + if (!buf) { + LOG(WARNING) << "Failed to import certificate"; + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT); + return -1; + } + chain_raw.push_back(buf.get()); + chain.push_back(std::move(buf)); + + for (X509Certificate::OSCertHandle cert : + ssl_config_.client_cert->GetIntermediateCertificates()) { + bssl::UniquePtr<CRYPTO_BUFFER> buf = OSCertHandleToBuffer(cert); + if (!buf) { + LOG(WARNING) << "Failed to import intermediate"; + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT); + return -1; + } + chain_raw.push_back(buf.get()); + chain.push_back(std::move(buf)); + } + + if (!SSL_set_chain_and_key(ssl_.get(), chain_raw.data(), chain_raw.size(), + nullptr, &SSLContext::kPrivateKeyMethod)) { + LOG(WARNING) << "Failed to set client certificate"; + return -1; + } std::vector<SSLPrivateKey::Hash> digest_prefs = ssl_config_.client_private_key->GetDigestPreferences(); @@ -1675,9 +1659,8 @@ SSL_set_private_key_digest_prefs(ssl_.get(), digests.data(), digests.size()); - int cert_count = 1 + sk_X509_num(chain.get()); net_log_.AddEvent(NetLogEventType::SSL_CLIENT_CERT_PROVIDED, - NetLog::IntCallback("cert_count", cert_count)); + NetLog::IntCallback("cert_count", chain.size())); return 1; } #endif // defined(OS_IOS) @@ -1688,11 +1671,6 @@ return 1; } -int SSLClientSocketImpl::CertVerifyCallback(X509_STORE_CTX* store_ctx) { - // The server certificate is verified later in DoVerifyCert. - return 1; -} - void SSLClientSocketImpl::MaybeCacheSession() { // Only cache the session once both a new session has been established and the // certificate has been verified. Due to False Start, these events may happen
diff --git a/net/socket/ssl_client_socket_impl.h b/net/socket/ssl_client_socket_impl.h index 1ca746ee..019c1c5 100644 --- a/net/socket/ssl_client_socket_impl.h +++ b/net/socket/ssl_client_socket_impl.h
@@ -175,11 +175,6 @@ // a certificate for this client. int ClientCertRequestCallback(SSL* ssl); - // CertVerifyCallback is called to verify the server's certificates. We do - // verification after the handshake so this function only enforces that the - // certificates don't change during renegotiation. - int CertVerifyCallback(X509_STORE_CTX* store_ctx); - // Called after the initial handshake completes and after the server // certificate has been verified. The order of handshake completion and // certificate verification depends on whether the connection was false
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc index f422a767..b335e46b 100644 --- a/net/socket/ssl_client_socket_pool.cc +++ b/net/socket/ssl_client_socket_pool.cc
@@ -346,6 +346,17 @@ return ERR_ALPN_NEGOTIATION_FAILED; } + const std::string& host = params_->host_and_port().host(); + bool is_google = + host == "google.com" || + (host.size() > 11 && host.rfind(".google.com") == host.size() - 11); + + // These are hosts that we intend to use in the initial TLS 1.3 deployment. + // TLS connections to them, whether or not this browser is in the experiment + // group, form the basis of our comparisons. + bool tls13_supported = + (host == "drive.google.com" || host == "mail.google.com"); + if (result == OK || ssl_socket_->IgnoreCertError(result, params_->load_flags())) { DCHECK(!connect_timing_.ssl_start.is_null()); @@ -396,10 +407,6 @@ 100); } - const std::string& host = params_->host_and_port().host(); - bool is_google = - host == "google.com" || - (host.size() > 11 && host.rfind(".google.com") == host.size() - 11); if (is_google) { UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_Google2", connect_duration, @@ -422,10 +429,27 @@ 100); } } + + if (tls13_supported) { + UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_TLS13Experiment", + connect_duration, + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMinutes(1), 100); + } } UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSL_Connection_Error", std::abs(result)); + if (is_google) { + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSL_Connection_Error_Google", + std::abs(result)); + } + + if (tls13_supported) { + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSL_Connection_Error_TLS13Experiment", + std::abs(result)); + } + if (result == OK || IsCertificateError(result)) { SetSocket(std::move(ssl_socket_)); } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index b6e4a693..2b47a81 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc
@@ -740,7 +740,6 @@ pool_(NULL), http_server_properties_(http_server_properties), transport_security_state_(transport_security_state), - read_buffer_(new IOBuffer(kReadBufferSize)), stream_hi_water_mark_(kFirstStreamId), last_accepted_push_stream_id_(0), unclaimed_pushed_streams_(this), @@ -1378,8 +1377,9 @@ connection_->DumpMemoryStats(stats); // |connection_| is estimated in stats->total_size. |read_buffer_| is - // estimated in kReadBufferSize. TODO(xunjieli): Make them use EMU(). - return stats->total_size + kReadBufferSize + + // estimated in |read_buffer_size|. TODO(xunjieli): Make them use EMU(). + size_t read_buffer_size = read_buffer_ ? kReadBufferSize : 0; + return stats->total_size + read_buffer_size + SpdyEstimateMemoryUsage(spdy_session_key_) + SpdyEstimateMemoryUsage(pooled_aliases_) + SpdyEstimateMemoryUsage(active_streams_) + @@ -1869,19 +1869,24 @@ } int SpdySession::DoRead() { + DCHECK(!read_buffer_); CHECK(in_io_loop_); CHECK(connection_); CHECK(connection_->socket()); read_state_ = READ_STATE_DO_READ_COMPLETE; int rv = ERR_READ_IF_READY_NOT_IMPLEMENTED; + read_buffer_ = new IOBuffer(kReadBufferSize); if (base::FeatureList::IsEnabled(Socket::kReadIfReadyExperiment)) { rv = connection_->socket()->ReadIfReady( read_buffer_.get(), kReadBufferSize, base::Bind(&SpdySession::PumpReadLoop, weak_factory_.GetWeakPtr(), READ_STATE_DO_READ)); - // TODO(xunjieli): Follow-up CL to release |read_buffer_|. - // https://crbug.com/690915. + if (rv == ERR_IO_PENDING) { + read_buffer_ = nullptr; + read_state_ = READ_STATE_DO_READ; + return rv; + } } if (rv == ERR_READ_IF_READY_NOT_IMPLEMENTED) { // Fallback to regular Read(). @@ -1890,12 +1895,11 @@ base::Bind(&SpdySession::PumpReadLoop, weak_factory_.GetWeakPtr(), READ_STATE_DO_READ_COMPLETE)); } - if (rv == ERR_IO_PENDING) - read_state_ = READ_STATE_DO_READ; return rv; } int SpdySession::DoReadComplete(int result) { + DCHECK(read_buffer_); CHECK(in_io_loop_); // Parse a frame. For now this code requires that the frame fit into our @@ -1933,6 +1937,7 @@ SpdyFramer::SPDY_NO_ERROR); } + read_buffer_ = nullptr; read_state_ = READ_STATE_DO_READ; return OK; }
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h index 0056482..9852e2d6 100644 --- a/net/spdy/spdy_session.h +++ b/net/spdy/spdy_session.h
@@ -1019,6 +1019,7 @@ std::unique_ptr<ClientSocketHandle> connection_; // The read buffer used to read data from the socket. + // Non-null if there is a Read() pending. scoped_refptr<IOBuffer> read_buffer_; SpdyStreamId stream_hi_water_mark_; // The next stream id to use.
diff --git a/net/ssl/ssl_client_session_cache.cc b/net/ssl/ssl_client_session_cache.cc index a21d680..e2c32c5 100644 --- a/net/ssl/ssl_client_session_cache.cc +++ b/net/ssl/ssl_client_session_cache.cc
@@ -142,15 +142,11 @@ size_t pair_cert_count = sk_CRYPTO_BUFFER_num(session->certs); for (size_t i = 0; i < pair_cert_count; ++i) { const CRYPTO_BUFFER* cert = sk_CRYPTO_BUFFER_value(session->certs, i); - // TODO(xunjieli): The multipler is added to account for the difference - // between the serialized form and real cert allocation. Remove after - // crbug.com/671420 is done. - size_t individual_cert_size = 4 * CRYPTO_BUFFER_len(cert); - undeduped_cert_size += individual_cert_size; + undeduped_cert_size += CRYPTO_BUFFER_len(cert); auto result = crypto_buffer_set.insert(cert); if (!result.second) continue; - cert_size += individual_cert_size; + cert_size += CRYPTO_BUFFER_len(cert); cert_count++; } }
diff --git a/printing/backend/win_helper.cc b/printing/backend/win_helper.cc index c96e123c..99d0e6f 100644 --- a/printing/backend/win_helper.cc +++ b/printing/backend/win_helper.cc
@@ -19,6 +19,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/win/scoped_comptr.h" +#include "base/win/windows_version.h" #include "printing/backend/print_backend.h" #include "printing/backend/print_backend_consts.h" #include "printing/backend/printing_info_win.h" @@ -470,6 +471,22 @@ return ticket; } +bool IsPrinterRPCSOnly(HANDLE printer) { + PrinterInfo5 info_5; + if (!info_5.Init(printer)) + return false; + const wchar_t* name = info_5.get()->pPrinterName; + const wchar_t* port = info_5.get()->pPortName; + int num_languages = + DeviceCapabilities(name, port, DC_PERSONALITY, NULL, NULL); + if (num_languages != 1) + return false; + std::vector<wchar_t> buf(33, 0); + DeviceCapabilities(name, port, DC_PERSONALITY, buf.data(), NULL); + static constexpr wchar_t kRPCSLanguage[] = L"RPCS"; + return wcscmp(buf.data(), kRPCSLanguage) == 0; +} + std::unique_ptr<DEVMODE, base::FreeDeleter> CreateDevMode(HANDLE printer, DEVMODE* in) { LONG buffer_size = DocumentProperties( @@ -484,6 +501,14 @@ std::unique_ptr<DEVMODE, base::FreeDeleter> out( reinterpret_cast<DEVMODE*>(calloc(buffer_size, 1))); DWORD flags = (in ? (DM_IN_BUFFER) : 0) | DM_OUT_BUFFER; + + // Check for RPCS drivers on Windows 8+ as DocumentProperties will crash if + // called on one of these printers. See crbug.com/679160 + if (base::win::GetVersion() >= base::win::VERSION_WIN8 && + IsPrinterRPCSOnly(printer)) { + return std::unique_ptr<DEVMODE, base::FreeDeleter>(); + } + if (DocumentProperties( NULL, printer, const_cast<wchar_t*>(L""), out.get(), in, flags) != IDOK) {
diff --git a/services/resource_coordinator/public/interfaces/BUILD.gn b/services/resource_coordinator/public/interfaces/BUILD.gn index 959f3ecd..1c735ef 100644 --- a/services/resource_coordinator/public/interfaces/BUILD.gn +++ b/services/resource_coordinator/public/interfaces/BUILD.gn
@@ -7,5 +7,10 @@ mojom("interfaces") { sources = [ "memory/memory_instrumentation.mojom", + "tracing/tracing.mojom", + ] + + public_deps = [ + "//mojo/common:common_custom_types", ] }
diff --git a/services/resource_coordinator/public/interfaces/tracing/OWNERS b/services/resource_coordinator/public/interfaces/tracing/OWNERS new file mode 100644 index 0000000..08850f4 --- /dev/null +++ b/services/resource_coordinator/public/interfaces/tracing/OWNERS
@@ -0,0 +1,2 @@ +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/services/resource_coordinator/public/interfaces/tracing/tracing.mojom b/services/resource_coordinator/public/interfaces/tracing/tracing.mojom new file mode 100644 index 0000000..fb8cd3c --- /dev/null +++ b/services/resource_coordinator/public/interfaces/tracing/tracing.mojom
@@ -0,0 +1,58 @@ +// 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. + +module resource_coordinator.tracing.mojom; + +import "mojo/common/time.mojom"; +import "mojo/common/values.mojom"; + +// The JSON type of data coming from a tracing agents. +// +// - All agents with the same label should have the same type. +// - There can be multiple agents with the same label, if their data type is +// ARRAY. Their data will be concatenated together and separated by commas. +// - There can be only one agent with data type STRING. +enum TraceDataType { + ARRAY, + STRING +}; + +// Tracing agents, like |chrome|, |etw|, |battor|, and |cros|, use this +// interface to register themselves to the tracing service. +interface Factory { + RegisterAgent(Agent agent, string name, string label, TraceDataType type, + bool supports_explicit_clock_sync_); +}; + +// There should be at most one implementation of this interface per process. +// When the tracing service calls |StopAndFlush| on an agent, the agent begins +// serializing data into the recorder that was given in the |StartTracing| call. +// When finished, the agent should close the recorder connection to signal the +// tracing service that no more data will be sent. +interface Agent { + StartTracing(string categories, Recorder recorder); + StopAndFlush(); + RequestClockSyncMarker() => (mojo.common.mojom.TimeTicks issue_ts, + mojo.common.mojom.TimeTicks issue_end_ts); + RequestBufferStatus() => (uint32 capacity, uint32 count); +}; + +// An agent can make several calls to |AddChunk|. Chunks will be concatenated +// with no separator (type STRING) or using comma as the separator (type ARRAY). +// There should be only one agent of type STRING per agent label; otherwise +// their trace data would be mixed up. +interface Recorder { + AddChunk(string chunk); + AddMetadata(mojo.common.mojom.DictionaryValue metadata); +}; + +// A tracing controller uses this interface to coordinate trace data collection +// from all registered agents. At any given time, there should be at most one +// connected controller. +interface Coordinator { + StartTracing(handle<data_pipe_producer> stream, string categories); + StopAndFlush(); + IsTracing() => (bool is_tracing); + RequestBufferUsage() => (float percent_full, uint32 approximate_count); +};
diff --git a/services/ui/demo/OWNERS b/services/ui/demo/OWNERS index 47351aa..d57048e 100644 --- a/services/ui/demo/OWNERS +++ b/services/ui/demo/OWNERS
@@ -1,2 +1,4 @@ kylechar@chromium.org rjkroege@chromium.org + +# COMPONENT: Internals>MUS
diff --git a/services/ui/display/OWNERS b/services/ui/display/OWNERS index 47351aa..d57048e 100644 --- a/services/ui/display/OWNERS +++ b/services/ui/display/OWNERS
@@ -1,2 +1,4 @@ kylechar@chromium.org rjkroege@chromium.org + +# COMPONENT: Internals>MUS
diff --git a/services/ui/gpu/OWNERS b/services/ui/gpu/OWNERS index afaf270..e62bb33a 100644 --- a/services/ui/gpu/OWNERS +++ b/services/ui/gpu/OWNERS
@@ -1,3 +1,5 @@ fsamuel@chromium.org rjkroege@chromium.org sadrul@chromium.org + +# COMPONENT: Internals>GPU
diff --git a/services/ui/surfaces/OWNERS b/services/ui/surfaces/OWNERS index 1f1af6b..2edcdb6 100644 --- a/services/ui/surfaces/OWNERS +++ b/services/ui/surfaces/OWNERS
@@ -1,2 +1,4 @@ fsamuel@chromium.org rjkroege@chromium.org + +# COMPONENT: Internals>Compositing
diff --git a/styleguide/java/OWNERS b/styleguide/java/OWNERS index 137bf18..131b31e 100644 --- a/styleguide/java/OWNERS +++ b/styleguide/java/OWNERS
@@ -3,3 +3,5 @@ nyquist@chromium.org tedchoc@chromium.org yfriedman@chromium.org + +# COMPONENT: Build
diff --git a/testing/buildbot/chromium.webkit.json b/testing/buildbot/chromium.webkit.json index d181eaa..fd0f827 100644 --- a/testing/buildbot/chromium.webkit.json +++ b/testing/buildbot/chromium.webkit.json
@@ -220,27 +220,15 @@ "WebKit Mac10.12": { "gtest_tests": [ { - "swarming": { - "can_use_on_swarming_builders": true - }, "test": "blink_heap_unittests" }, { - "swarming": { - "can_use_on_swarming_builders": true - }, "test": "blink_platform_unittests" }, { - "swarming": { - "can_use_on_swarming_builders": true - }, "test": "webkit_unit_tests" }, { - "swarming": { - "can_use_on_swarming_builders": true - }, "test": "wtf_unittests" } ],
diff --git a/testing/variations/OWNERS b/testing/variations/OWNERS index 4de6b9d..251709c 100644 --- a/testing/variations/OWNERS +++ b/testing/variations/OWNERS
@@ -3,3 +3,5 @@ isherman@chromium.org jwd@chromium.org rkaplow@chromium.org + +# COMPONENT: Internals>Metrics
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index ae2982e4..05682d52 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -2514,6 +2514,27 @@ ] } ], + "SettingsResetPrompt": [ + { + "platforms": [ + "win" + ], + "experiments": [ + { + "name": "Enabled", + "params": { + "delay_before_prompt_seconds": "1", + "domain_hashes": "{\"c027a731da03fee479b2ba00b3afe74b3fd9190f0622755db8ffa504efbde66e\":\"3\"}", + "prompt_wave": "20170101", + "time_between_prompts_seconds": "3600" + }, + "enable_features": [ + "SettingsResetPrompt" + ] + } + ] + } + ], "SignInPasswordPromo": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index aca777c6..0ccc45a 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -157,9 +157,6 @@ crbug.com/667045 paint/invalidation/table/composited-cell-collapsed-border-add-anonymous.html [ Crash Timeout ] crbug.com/667045 virtual/disable-spinvalidation/paint/invalidation/table/composited-cell-collapsed-border-add-anonymous.html [ Crash Timeout ] -crbug.com/699044 virtual/disable-spinvalidation/paint/invalidation/caret-subpixel.html [ NeedsRebaseline ] -crbug.com/699044 virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll.html [ NeedsRebaseline ] - # ====== Paint team owned tests to here ====== # ====== LayoutNG-only failures from here ====== @@ -1827,6 +1824,8 @@ crbug.com/695270 [ Linux ] external/csswg-test/css-writing-modes-3/overconstrained-rel-pos-rtl-top-bottom-vlr-007.xht [ Failure ] crbug.com/695270 [ Linux ] external/csswg-test/css-writing-modes-3/overconstrained-rel-pos-rtl-top-bottom-vrl-006.xht [ Failure ] +crbug.com/626703 external/wpt/domxpath/001.html [ Failure ] + # ====== New tests from w3c-test-autoroller added here ====== crbug.com/626703 [ Android Win10 ] external/wpt/fullscreen/api/document-exit-fullscreen-nested-in-iframe-manual.html [ Timeout ] crbug.com/626703 external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16be.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations index e7ea1fe..b164493 100644 --- a/third_party/WebKit/LayoutTests/W3CImportExpectations +++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -661,10 +661,6 @@ external/wpt/html/semantics/forms/form-submission-0/url-encoded.html [ Skip ] external/wpt/svg/linking/scripted [ Skip ] -# They have a wrong encoding, and test_parser.py throws UnicodeEncodeError. -external/wpt/domxpath/001.html [ Skip ] -external/wpt/domxpath/002.html [ Skip ] - # This test depends on a support file with non-LF new lines, which # causes a patch error in the bot_update step when importing this test. crbug.com/691107 external/wpt/webvtt/webvtt-file-format-parsing/webvtt-file-parsing/001.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/accessibility/readme.md b/third_party/WebKit/LayoutTests/accessibility/readme.md index 5dfce1d..a02d46f7 100644 --- a/third_party/WebKit/LayoutTests/accessibility/readme.md +++ b/third_party/WebKit/LayoutTests/accessibility/readme.md
@@ -3,7 +3,7 @@ ## General Info on LayoutTests: Building and Running the Tests See [Layout Tests](/docs/testing/layout_tests.md) for general -info on how to build and run layout tests. +info on how to build and run layout tests. ## Old vs. New @@ -20,7 +20,7 @@ The code that implements the bindings is here: -* ```components/test_runner/accessibility_controller.cc``` -* ```components/test_runner/web_ax_object_proxy.cc``` +* ```content/shell/test_runner/accessibility_controller.cc``` +* ```content/shell/test_runner/web_ax_object_proxy.cc``` You'll probably find bindings for the features you want to test already. If not, it's not hard to add new ones.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/domxpath/001.html b/third_party/WebKit/LayoutTests/external/wpt/domxpath/001.html new file mode 100644 index 0000000..c26795a --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/domxpath/001.html
@@ -0,0 +1,60 @@ +<!doctype html> +<meta charset="utf8"> +<title>XPath in text/html: elements</title> +<link rel="help" href="http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#Interfaces"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<div id="log"><span></span></div> +<div><span></span></div> +<dØdd></dØdd> +<svg> +<path /> +<path /> +</svg> + +<script> +function test_xpath_succeeds(path, expected, resolver) { + resolver = resolver ? resolver : null; + var res = document.evaluate(path, document, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + actual = []; + for (var i=0;;i++) { + var node = res.snapshotItem(i); + if (node === null) { + break; + } + actual.push(node); + } + assert_array_equals(actual, expected); +} + +function test_xpath_throws(path, error_code, resolver) { + resolver = resolver ? resolver : null; + assert_throws(error_code, function() {document.evaluate(path, document, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)}) +} + +function ns_resolver(x) { + map = {"html":"http://www.w3.org/1999/xhtml", + "svg":"http://www.w3.org/2000/svg", + "math":"http://www.w3.org/1998/Math/MathML"}; + var rv = map.hasOwnProperty(x) ? map[x] : null; + return rv; +} + +generate_tests(test_xpath_succeeds,[ + ["HTML elements no namespace prefix", "//div", document.getElementsByTagName("div")], + ["HTML elements namespace prefix", "//html:div", document.getElementsByTagName("div"), ns_resolver], + ["HTML elements mixed use of prefix", "//html:div/span", document.getElementsByTagName("span"), ns_resolver], + ["SVG elements no namespace prefix", "//path", []], + ["SVG elements namespace prefix", "//svg:path", document.getElementsByTagName("path"), ns_resolver], + ["HTML elements mixed case", "//DiV", document.getElementsByTagName("div")], + ["SVG elements mixed case selector", "//svg:PatH", [], ns_resolver], + ["Non-ascii HTML element", "//dØdd", document.getElementsByTagName("dØdd"), ns_resolver], + ["Non-ascii HTML element2", "//dødd", [], ns_resolver], + ["Non-ascii HTML element3", "//DØDD", document.getElementsByTagName("dØdd"), ns_resolver] +]) + +generate_tests(test_xpath_throws, [ + ["Throw with invalid prefix", "//invalid:path", "NAMESPACE_ERR"], +]) +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/domxpath/002-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/domxpath/002-expected.txt new file mode 100644 index 0000000..a10e1f4c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/domxpath/002-expected.txt
@@ -0,0 +1,18 @@ +This is a testharness.js-based test. +PASS Select html element based on attribute +FAIL Select html element based on attribute mixed case assert_array_equals: lengths differ, expected 1 got 0 +PASS Select both HTML and SVG elements based on attribute +PASS Select HTML element with non-ascii attribute 1 +PASS Select HTML element with non-ascii attribute 2 +FAIL Select HTML element with non-ascii attribute 3 assert_array_equals: lengths differ, expected 1 got 0 +PASS Select SVG element based on mixed case attribute +FAIL Select both HTML and SVG elements based on mixed case attribute assert_array_equals: lengths differ, expected 1 got 0 +PASS Select SVG elements with refX attribute +PASS Select SVG elements with refX attribute incorrect case +PASS Select SVG elements with refX attribute lowercase +PASS Select SVG element with non-ascii attribute 1 +PASS Select SVG element with non-ascii attribute 2 +PASS xmlns attribute +PASS svg element with XLink attribute +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/domxpath/002.html b/third_party/WebKit/LayoutTests/external/wpt/domxpath/002.html new file mode 100644 index 0000000..95b4afc --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/domxpath/002.html
@@ -0,0 +1,60 @@ +<!doctype html> +<meta charset="utf8"> +<title>XPath in text/html: attributes</title> +<link rel="help" href="http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#Interfaces"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<div id="log" nonÄsciiAttribute><span></span></div> +<svg xmlns="http://www.w3.org/2000/svg", xmlns:xlink="http://www.w3.org/1999/xlink"> +<path id="a" refx /> +<path id="b" nonÄscii xlink:href /> +</svg> + +<script> +function test_xpath_succeeds(path, expected, resolver) { + resolver = resolver ? resolver : null; + var res = document.evaluate(path, document, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + actual = []; + for (var i=0;;i++) { + var node = res.snapshotItem(i); + if (node === null) { + break; + } + actual.push(node); + } + assert_array_equals(actual, expected); +} + +function test_xpath_throws(path, error_code, resolver) { + resolver = resolver ? resolver : null; + assert_throws(error_code, function() {document.evaluate(path, document, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)}) +} + +function ns_resolver(x) { + map = {"html":"http://www.w3.org/1999/xhtml", + "svg":"http://www.w3.org/2000/svg", + "math":"http://www.w3.org/1998/Math/MathML", + "xlink":"http://www.w3.org/1999/xlink"}; + var rv = map.hasOwnProperty(x) ? map[x] : null; + return rv; +} + +generate_tests(test_xpath_succeeds,[ + ["Select html element based on attribute", "//div[@id='log']", [document.getElementById("log")]], + ["Select html element based on attribute mixed case", "//div[@Id='log']", [document.getElementById("log")]], + ["Select both HTML and SVG elements based on attribute", "//*[@id]", [document.getElementById("log")].concat(Array.prototype.slice.call(document.getElementsByTagName("path")))], + ["Select HTML element with non-ascii attribute 1", "//*[@nonÄsciiattribute]", [document.getElementById("log")]], + ["Select HTML element with non-ascii attribute 2", "//*[@nonäsciiattribute]", []], + ["Select HTML element with non-ascii attribute 3", "//*[@nonÄsciiAttribute]", [document.getElementById("log")]], + ["Select SVG element based on mixed case attribute", "//svg:path[@Id]", [], ns_resolver], + ["Select both HTML and SVG elements based on mixed case attribute", "//*[@Id]", [document.getElementById("log")]], + ["Select SVG elements with refX attribute", "//*[@refX]", [document.getElementById("a")]], + ["Select SVG elements with refX attribute incorrect case", "//*[@Refx]", []], + ["Select SVG elements with refX attribute lowercase", "//*[@refx]", []], + ["Select SVG element with non-ascii attribute 1", "//*[@nonÄscii]", [document.getElementById("b")]], + ["Select SVG element with non-ascii attribute 2", "//*[@nonäscii]", []], + ["xmlns attribute", "//*[@xmlns]", []], + ["svg element with XLink attribute", "//*[@xlink:href]", [document.getElementById("b")], ns_resolver] +]) +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js index 0891811..8c754716 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
@@ -592,7 +592,7 @@ var endLine = startLine + lineCount - 1; var endColumn = lineCount === 1 ? startColumn + source.length : source.length - source.computeLineEndings()[lineCount - 2]; var hasSourceURL = !!source.match(/\/\/#\ssourceURL=\s*(\S*?)\s*$/m) || !!source.match(/\/\/@\ssourceURL=\s*(\S*?)\s*$/m); - var script = new SDK.Script(debuggerModel, scriptId, url, startLine, startColumn, endLine, endColumn, 0, "", isContentScript, false, undefined, hasSourceURL); + var script = new SDK.Script(debuggerModel, scriptId, url, startLine, startColumn, endLine, endColumn, 0, "", isContentScript, false, undefined, hasSourceURL, source.length); script.requestContent = function() { var trimmedSource = SDK.Script._trimSourceURLComment(source);
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-deny-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-deny-expected.txt index 069159e..6df5f4f 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-deny-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-deny-expected.txt
@@ -1,7 +1,7 @@ http://127.0.0.1:8000/security/XFrameOptions/resources/x-frame-options-deny.cgi - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/security/XFrameOptions/resources/x-frame-options-deny.cgi, main document URL http://127.0.0.1:8000/security/XFrameOptions/x-frame-options-deny.html, http method GET> CONSOLE ERROR: Refused to display 'http://127.0.0.1:8000/security/XFrameOptions/resources/x-frame-options-deny.cgi' in a frame because it set 'X-Frame-Options' to 'deny'. data:, - willSendRequest <NSURLRequest URL data:,, main document URL http://127.0.0.1:8000/security/XFrameOptions/x-frame-options-deny.html, http method GET> -data:, - didReceiveResponse <NSURLResponse data:,, http status code 200> +data:, - didReceiveResponse <NSURLResponse data:,, http status code 0> CONSOLE MESSAGE: line 14: PASS: Access to contentWindow.location.href threw an exception. There should be no content in the iframe below
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-multiple-headers-conflict-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-multiple-headers-conflict-expected.txt index 8baa87f84..67179210 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-multiple-headers-conflict-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/XFrameOptions/x-frame-options-multiple-headers-conflict-expected.txt
@@ -1,7 +1,7 @@ http://127.0.0.1:8000/security/XFrameOptions/resources/x-frame-options-multiple-headers-conflict.cgi - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/security/XFrameOptions/resources/x-frame-options-multiple-headers-conflict.cgi, main document URL http://127.0.0.1:8000/security/XFrameOptions/x-frame-options-multiple-headers-conflict.html, http method GET> CONSOLE ERROR: Refused to display 'http://127.0.0.1:8000/security/XFrameOptions/resources/x-frame-options-multiple-headers-conflict.cgi' in a frame because it set multiple 'X-Frame-Options' headers with conflicting values ('ALLOWALL, DENY'). Falling back to 'deny'. data:, - willSendRequest <NSURLRequest URL data:,, main document URL http://127.0.0.1:8000/security/XFrameOptions/x-frame-options-multiple-headers-conflict.html, http method GET> -data:, - didReceiveResponse <NSURLResponse data:,, http status code 200> +data:, - didReceiveResponse <NSURLResponse data:,, http status code 0> The frame below should not load, and a console message should be generated that notes the invalid header.
diff --git a/third_party/WebKit/LayoutTests/paint/selection/drag-caret.html b/third_party/WebKit/LayoutTests/paint/selection/drag-caret.html new file mode 100644 index 0000000..b076b02 --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/selection/drag-caret.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +Passes if no crash. +<input id="fileinput" type="file"> +<script src="../../resources/run-after-layout-and-paint.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> +if (window.testRunner && window.eventSender) { + internals.runtimeFlags.paintUnderInvalidationCheckingEnabled = true; + document.designMode="on"; + async_test(t => { + runAfterLayoutAndPaint(t.step_func_done(() => { + eventSender.beginDragWithFiles(['testpath1/testfile1.txt']); + var centerX = fileinput.offsetLeft + fileinput.offsetWidth / 2; + var centerY = fileinput.offsetTop + fileinput.offsetHeight / 2; + eventSender.mouseMoveTo(centerX, centerY); + eventSender.mouseUp(); + })); + }); +} +</script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt index d341afd0..e64cfa1 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -32,6 +32,11 @@ "object": "LayoutBlockFlow DIV id='inner-editor'", "rect": [3, 1003, 200, 16], "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [3, 1003, 1, 16], + "reason": "caret" } ] },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-subpixel-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-subpixel-expected.txt index 05c1760..98abd75 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-subpixel-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-subpixel-expected.txt
@@ -15,6 +15,11 @@ "object": "LayoutBlockFlow DIV id='inner-editor'", "rect": [11, 11, 201, 13], "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [210, 11, 2, 13], + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt index 69ee0c96f..564242d 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -32,6 +32,11 @@ "object": "LayoutBlockFlow DIV id='inner-editor'", "rect": [3, 1003, 200, 13], "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [3, 1003, 1, 13], + "reason": "caret" } ] },
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-subpixel-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-subpixel-expected.txt index ea861c1f..e345820 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-subpixel-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-subpixel-expected.txt
@@ -15,6 +15,11 @@ "object": "LayoutBlockFlow DIV id='inner-editor'", "rect": [10, 11, 201, 16], "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [209, 11, 2, 16], + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt index 1795923f..dd4d9ddc 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -32,6 +32,11 @@ "object": "LayoutBlockFlow DIV id='inner-editor'", "rect": [3, 1003, 200, 16], "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [3, 1003, 1, 16], + "reason": "caret" } ] },
diff --git a/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp b/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp index f31f5fcf..0990fdef 100644 --- a/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp +++ b/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp
@@ -260,8 +260,7 @@ drawingRect.moveBy(paintOffset); IntRect paintRect = pixelSnappedIntRect(drawingRect); - DrawingRecorder drawingRecorder(context, *this, DisplayItem::kCaret, - paintRect); + DrawingRecorder drawingRecorder(context, *this, displayItemType, paintRect); context.fillRect(paintRect, m_color); }
diff --git a/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.cpp b/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.cpp index 6a2e8505..b859e892e 100644 --- a/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.cpp +++ b/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.cpp
@@ -22,7 +22,6 @@ #include "core/svg/SVGDocumentExtensions.h" #include "core/dom/Document.h" -#include "core/inspector/ConsoleMessage.h" #include "core/svg/SVGSVGElement.h" #include "core/svg/animation/SMILTimeContainer.h" #include "wtf/AutoReset.h" @@ -113,12 +112,6 @@ } } -void SVGDocumentExtensions::reportError(const String& message) { - ConsoleMessage* consoleMessage = ConsoleMessage::create( - RenderingMessageSource, ErrorMessageLevel, "Error: " + message); - m_document->addConsoleMessage(consoleMessage); -} - void SVGDocumentExtensions::addSVGRootWithRelativeLengthDescendents( SVGSVGElement* svgRoot) { ASSERT(!m_inRelativeLengthSVGRootsInvalidation);
diff --git a/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.h b/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.h index f92bbcb..6d4671f 100644 --- a/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.h +++ b/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.h
@@ -53,9 +53,9 @@ void startAnimations(); void pauseAnimations(); - void dispatchSVGLoadEventToOutermostSVGElements(); + void serviceAnimations(); - void reportError(const String&); + void dispatchSVGLoadEventToOutermostSVGElements(); SVGResourcesCache& resourcesCache() { return m_resourcesCache; } @@ -86,9 +86,6 @@ #if DCHECK_IS_ON() bool m_inRelativeLengthSVGRootsInvalidation = false; #endif - - public: - void serviceAnimations(); }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGElement.cpp index b2a5fb7..dd0aac5f 100644 --- a/third_party/WebKit/Source/core/svg/SVGElement.cpp +++ b/third_party/WebKit/Source/core/svg/SVGElement.cpp
@@ -41,6 +41,7 @@ #include "core/events/Event.h" #include "core/frame/Settings.h" #include "core/html/HTMLElement.h" +#include "core/inspector/ConsoleMessage.h" #include "core/layout/LayoutObject.h" #include "core/layout/svg/LayoutSVGResourceContainer.h" #include "core/svg/SVGDocumentExtensions.h" @@ -157,8 +158,9 @@ // Don't report any errors on attribute removal. if (value.isNull()) return; - document().accessSVGExtensions().reportError( - error.format(tagName(), name, value)); + document().addConsoleMessage( + ConsoleMessage::create(RenderingMessageSource, ErrorMessageLevel, + "Error: " + error.format(tagName(), name, value))); } String SVGElement::title() const {
diff --git a/third_party/WebKit/Source/core/svg/SVGFEImageElement.cpp b/third_party/WebKit/Source/core/svg/SVGFEImageElement.cpp index c0127df..c339338 100644 --- a/third_party/WebKit/Source/core/svg/SVGFEImageElement.cpp +++ b/third_party/WebKit/Source/core/svg/SVGFEImageElement.cpp
@@ -21,9 +21,11 @@ #include "core/svg/SVGFEImageElement.h" +#include "core/SVGNames.h" #include "core/dom/Document.h" +#include "core/dom/IdTargetObserver.h" +#include "core/loader/resource/ImageResourceContent.h" #include "core/svg/SVGPreserveAspectRatio.h" -#include "core/svg/SVGTreeScopeResources.h" #include "core/svg/graphics/filters/SVGFEImage.h" #include "platform/graphics/Image.h" #include "platform/loader/fetch/FetchRequest.h" @@ -43,15 +45,13 @@ DEFINE_NODE_FACTORY(SVGFEImageElement) SVGFEImageElement::~SVGFEImageElement() { - if (m_cachedImage) { - m_cachedImage->removeObserver(this); - m_cachedImage = nullptr; - } + clearImageResource(); } DEFINE_TRACE(SVGFEImageElement) { visitor->trace(m_preserveAspectRatio); visitor->trace(m_cachedImage); + visitor->trace(m_targetIdObserver); SVGFilterPrimitiveStandardAttributes::trace(visitor); SVGURIReference::trace(visitor); } @@ -64,38 +64,36 @@ } void SVGFEImageElement::clearResourceReferences() { - if (m_cachedImage) { - m_cachedImage->removeObserver(this); - m_cachedImage = nullptr; - } - + clearImageResource(); + unobserveTarget(m_targetIdObserver); removeAllOutgoingReferences(); } void SVGFEImageElement::fetchImageResource() { - FetchRequest request( - ResourceRequest(ownerDocument()->completeURL(hrefString())), localName()); + FetchRequest request(ResourceRequest(document().completeURL(hrefString())), + localName()); m_cachedImage = ImageResourceContent::fetch(request, document().fetcher()); if (m_cachedImage) m_cachedImage->addObserver(this); } +void SVGFEImageElement::clearImageResource() { + if (!m_cachedImage) + return; + m_cachedImage->removeObserver(this); + m_cachedImage = nullptr; +} + void SVGFEImageElement::buildPendingResource() { clearResourceReferences(); if (!isConnected()) return; - AtomicString id; - Element* target = SVGURIReference::targetElementFromIRIString( - hrefString(), treeScope(), &id); + Element* target = observeTarget(m_targetIdObserver, *this); if (!target) { - if (id.isEmpty()) { + if (!SVGURLReferenceResolver(hrefString(), document()).isLocal()) fetchImageResource(); - } else { - treeScope().ensureSVGTreeScopedResources().addPendingResource(id, *this); - DCHECK(hasPendingResources()); - } } else if (target->isSVGElement()) { // Register us with the target in the dependencies map. Any change of // hrefElement that leads to relayout/repainting now informs us, so we can
diff --git a/third_party/WebKit/Source/core/svg/SVGFEImageElement.h b/third_party/WebKit/Source/core/svg/SVGFEImageElement.h index 111df6a..7d1c271 100644 --- a/third_party/WebKit/Source/core/svg/SVGFEImageElement.h +++ b/third_party/WebKit/Source/core/svg/SVGFEImageElement.h
@@ -21,8 +21,6 @@ #ifndef SVGFEImageElement_h #define SVGFEImageElement_h -#include "core/SVGNames.h" -#include "core/loader/resource/ImageResourceContent.h" #include "core/loader/resource/ImageResourceObserver.h" #include "core/svg/SVGAnimatedPreserveAspectRatio.h" #include "core/svg/SVGFilterPrimitiveStandardAttributes.h" @@ -31,6 +29,8 @@ namespace blink { +class ImageResourceContent; + class SVGFEImageElement final : public SVGFilterPrimitiveStandardAttributes, public SVGURIReference, public ImageResourceObserver { @@ -62,6 +62,7 @@ void clearResourceReferences(); void fetchImageResource(); + void clearImageResource(); void buildPendingResource() override; InsertionNotificationRequest insertedInto(ContainerNode*) override; @@ -70,6 +71,7 @@ Member<SVGAnimatedPreserveAspectRatio> m_preserveAspectRatio; Member<ImageResourceContent> m_cachedImage; + Member<IdTargetObserver> m_targetIdObserver; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGURIReference.cpp b/third_party/WebKit/Source/core/svg/SVGURIReference.cpp index 86b61bdf..3606053 100644 --- a/third_party/WebKit/Source/core/svg/SVGURIReference.cpp +++ b/third_party/WebKit/Source/core/svg/SVGURIReference.cpp
@@ -21,6 +21,7 @@ #include "core/svg/SVGURIReference.h" #include "core/XLinkNames.h" +#include "core/dom/Document.h" #include "core/dom/IdTargetObserver.h" #include "core/html/parser/HTMLParserIdioms.h" #include "core/svg/SVGElement.h" @@ -117,15 +118,21 @@ Element* SVGURIReference::observeTarget(Member<IdTargetObserver>& observer, SVGElement& contextElement) { - DCHECK(!observer); TreeScope& treeScope = contextElement.treeScope(); AtomicString id = fragmentIdentifierFromIRIString(hrefString(), treeScope); + return observeTarget(observer, treeScope, id, + WTF::bind(&SVGElement::buildPendingResource, + wrapWeakPersistent(&contextElement))); +} + +Element* SVGURIReference::observeTarget(Member<IdTargetObserver>& observer, + TreeScope& treeScope, + const AtomicString& id, + std::unique_ptr<WTF::Closure> closure) { + DCHECK(!observer); if (id.isEmpty()) return nullptr; - observer = new SVGElementReferenceObserver( - treeScope, id, - WTF::bind(&SVGElement::buildPendingResource, - wrapWeakPersistent(&contextElement))); + observer = new SVGElementReferenceObserver(treeScope, id, std::move(closure)); return treeScope.getElementById(id); }
diff --git a/third_party/WebKit/Source/core/svg/SVGURIReference.h b/third_party/WebKit/Source/core/svg/SVGURIReference.h index 83887b1..c25314b 100644 --- a/third_party/WebKit/Source/core/svg/SVGURIReference.h +++ b/third_party/WebKit/Source/core/svg/SVGURIReference.h
@@ -23,13 +23,13 @@ #include <memory> #include "core/CoreExport.h" -#include "core/dom/Document.h" #include "core/svg/SVGAnimatedHref.h" #include "platform/heap/Handle.h" #include "wtf/Functional.h" namespace blink { +class Document; class Element; class IdTargetObserver; @@ -61,6 +61,12 @@ // |contextElement|.) Will call buildPendingResource() on |contextElement| // when changes to the 'id' are noticed. Element* observeTarget(Member<IdTargetObserver>&, SVGElement&); + // Create an 'id' observer for |id| in the specified TreeScope. On changes, + // the passed Closure will be called. + static Element* observeTarget(Member<IdTargetObserver>&, + TreeScope&, + const AtomicString& id, + std::unique_ptr<WTF::Closure>); // Unregister and destroy the observer. static void unobserveTarget(Member<IdTargetObserver>&);
diff --git a/third_party/WebKit/Source/core/svg/SVGUseElement.cpp b/third_party/WebKit/Source/core/svg/SVGUseElement.cpp index 0a35269..a4ff25cb 100644 --- a/third_party/WebKit/Source/core/svg/SVGUseElement.cpp +++ b/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
@@ -25,14 +25,13 @@ #include "core/svg/SVGUseElement.h" -#include "bindings/core/v8/ExceptionState.h" #include "core/SVGNames.h" #include "core/XLinkNames.h" #include "core/dom/Document.h" #include "core/dom/ElementTraversal.h" +#include "core/dom/IdTargetObserver.h" #include "core/dom/StyleChangeReason.h" #include "core/dom/TaskRunnerHelper.h" -#include "core/dom/shadow/ElementShadow.h" #include "core/dom/shadow/ShadowRoot.h" #include "core/events/Event.h" #include "core/layout/svg/LayoutSVGTransformableContainer.h" @@ -41,7 +40,6 @@ #include "core/svg/SVGSVGElement.h" #include "core/svg/SVGSymbolElement.h" #include "core/svg/SVGTitleElement.h" -#include "core/svg/SVGTreeScopeResources.h" #include "core/xml/parser/XMLDocumentParser.h" #include "platform/loader/fetch/FetchRequest.h" #include "platform/loader/fetch/ResourceFetcher.h" @@ -98,6 +96,7 @@ visitor->trace(m_width); visitor->trace(m_height); visitor->trace(m_targetElementInstance); + visitor->trace(m_targetIdObserver); visitor->trace(m_resource); SVGGraphicsElement::trace(visitor); SVGURIReference::trace(visitor); @@ -128,8 +127,7 @@ void SVGUseElement::removedFrom(ContainerNode* rootParent) { SVGGraphicsElement::removedFrom(rootParent); if (rootParent->isConnected()) { - clearInstanceRoot(); - removeAllOutgoingReferences(); + clearResourceReference(); cancelShadowTreeRecreation(); } } @@ -287,52 +285,40 @@ } void SVGUseElement::clearInstanceRoot() { - if (m_targetElementInstance) - m_targetElementInstance = nullptr; + m_targetElementInstance = nullptr; } -void SVGUseElement::clearShadowTree() { +void SVGUseElement::clearResourceReference() { + unobserveTarget(m_targetIdObserver); clearInstanceRoot(); - - // FIXME: We should try to optimize this, to at least allow partial reclones. - if (ShadowRoot* shadowTreeRootElement = userAgentShadowRoot()) - shadowTreeRootElement->removeChildren(OmitSubtreeModifiedEvent); - removeAllOutgoingReferences(); } Element* SVGUseElement::resolveTargetElement() { if (m_elementIdentifier.isEmpty()) return nullptr; - const TreeScope* lookupScope = nullptr; - if (m_elementIdentifierIsLocal) - lookupScope = &treeScope(); - else if (resourceIsValid()) - lookupScope = m_resource->document(); - else - return nullptr; - Element* target = lookupScope->getElementById(m_elementIdentifier); - // TODO(fs): Why would the Element not be "connected" at this point? - if (target && target->isConnected()) - return target; - // Don't record any pending references for external resources. - if (!m_resource) { - treeScope().ensureSVGTreeScopedResources().addPendingResource( - m_elementIdentifier, *this); - DCHECK(hasPendingResources()); + if (m_elementIdentifierIsLocal) { + return observeTarget(m_targetIdObserver, treeScope(), m_elementIdentifier, + WTF::bind(&SVGUseElement::invalidateShadowTree, + wrapWeakPersistent(this))); } - return nullptr; + if (!resourceIsValid()) + return nullptr; + return m_resource->document()->getElementById(m_elementIdentifier); } void SVGUseElement::buildPendingResource() { if (inUseShadowTree()) return; - clearShadowTree(); + // FIXME: We should try to optimize this, to at least allow partial reclones. + userAgentShadowRoot()->removeChildren(OmitSubtreeModifiedEvent); + clearResourceReference(); cancelShadowTreeRecreation(); if (!isConnected()) return; Element* target = resolveTargetElement(); - if (target && target->isSVGElement()) { + // TODO(fs): Why would the Element not be "connected" at this point? + if (target && target->isConnected() && target->isSVGElement()) { buildShadowAndInstanceTree(toSVGElement(*target)); invalidateDependentShadowTrees(); } @@ -463,7 +449,8 @@ // Expand all <use> elements in the shadow tree. // Expand means: replace the actual <use> element by what it references. if (!expandUseElementsInShadowTree()) { - clearShadowTree(); + shadowTreeRootElement->removeChildren(OmitSubtreeModifiedEvent); + clearResourceReference(); return; }
diff --git a/third_party/WebKit/Source/core/svg/SVGUseElement.h b/third_party/WebKit/Source/core/svg/SVGUseElement.h index 4c0b5b4..0b67aa3 100644 --- a/third_party/WebKit/Source/core/svg/SVGUseElement.h +++ b/third_party/WebKit/Source/core/svg/SVGUseElement.h
@@ -94,7 +94,7 @@ void buildShadowAndInstanceTree(SVGElement& target); void clearInstanceRoot(); Element* createInstanceTree(SVGElement& targetRoot) const; - void clearShadowTree(); + void clearResourceReference(); bool hasCycleUseReferencing(const SVGUseElement&, const ContainerNode& targetInstance, SVGElement*& newTarget) const; @@ -121,6 +121,7 @@ bool m_haveFiredLoadEvent; bool m_needsShadowTreeRecreation; Member<SVGElement> m_targetElementInstance; + Member<IdTargetObserver> m_targetIdObserver; Member<DocumentResource> m_resource; };
diff --git a/third_party/WebKit/Source/devtools/front_end/coverage/CoverageModel.js b/third_party/WebKit/Source/devtools/front_end/coverage/CoverageModel.js index d3617df..3f9d743 100644 --- a/third_party/WebKit/Source/devtools/front_end/coverage/CoverageModel.js +++ b/third_party/WebKit/Source/devtools/front_end/coverage/CoverageModel.js
@@ -7,9 +7,9 @@ /** @typedef {{ * contentProvider: !Common.ContentProvider, - * size: (number|undefined), - * unusedSize: (number|undefined), - * usedSize: (number|undefined), + * size: number, + * unusedSize: number, + * usedSize: number, * type: !Coverage.CoverageType, * lineOffset: number, * columnOffset: number, @@ -99,10 +99,10 @@ /** * @param {!SDK.DebuggerModel} debuggerModel * @param {!Array<!Protocol.Profiler.ScriptCoverage>} scriptsCoverage - * @return {!Promise<!Array<!Coverage.CoverageInfo>>} + * @return {!Array<!Coverage.CoverageInfo>} */ - static async _processJSCoverage(debuggerModel, scriptsCoverage) { - var promises = []; + static _processJSCoverage(debuggerModel, scriptsCoverage) { + var result = []; for (var entry of scriptsCoverage) { var script = debuggerModel.scriptForId(entry.scriptId); if (!script) @@ -112,10 +112,10 @@ for (var range of func.ranges) ranges.push({startOffset: range.startOffset, endOffset: range.endOffset, count: range.count}); } - promises.push( - Coverage.CoverageModel._coverageInfoForText(script, script.lineOffset, script.columnOffset, ranges)); + result.push(Coverage.CoverageModel._buildCoverageInfo( + script, script.contentLength, script.lineOffset, script.columnOffset, ranges)); } - return Promise.all(promises); + return result; } /** @@ -133,9 +133,9 @@ /** * @param {!SDK.CSSModel} cssModel * @param {!Array<!Protocol.CSS.RuleUsage>} ruleUsageList - * @return {!Promise<!Array<!Coverage.CoverageInfo>>} + * @return {!Array<!Coverage.CoverageInfo>} */ - static async _processCSSCoverage(cssModel, ruleUsageList) { + static _processCSSCoverage(cssModel, ruleUsageList) { /** @type {!Map<?SDK.CSSStyleSheetHeader, !Array<!Coverage.RangeUseCount>>} */ var rulesByStyleSheet = new Map(); for (var rule of ruleUsageList) { @@ -147,20 +147,22 @@ } ranges.push({startOffset: rule.startOffset, endOffset: rule.endOffset, count: Number(rule.used)}); } - return Promise.all(Array.from( + return Array.from( rulesByStyleSheet.entries(), - entry => - Coverage.CoverageModel._coverageInfoForText(entry[0], entry[0].startLine, entry[0].startColumn, entry[1]))); + entry => Coverage.CoverageModel._buildCoverageInfo( + entry[0], entry[0].contentLength, entry[0].startLine, entry[0].startColumn, entry[1])); } /** * @param {!Common.ContentProvider} contentProvider + * @param {number} contentLength * @param {number} startLine * @param {number} startColumn * @param {!Array<!Coverage.RangeUseCount>} ranges - * @return {!Promise<?Coverage.CoverageInfo>} + * @return {!Coverage.CoverageInfo} */ - static async _coverageInfoForText(contentProvider, startLine, startColumn, ranges) { + static _buildCoverageInfo(contentProvider, contentLength, startLine, startColumn, ranges) { + /** @type Coverage.CoverageType */ var coverageType; var url = contentProvider.contentURL(); if (contentProvider.contentType().isScript()) @@ -197,16 +199,11 @@ unusedSize += entry.ownSize; } - // FIXME: get rid of this when we get the size upfront. - var content = await contentProvider.requestContent(); - if (typeof content !== 'string') - return null; - var coverageInfo = { contentProvider: contentProvider, ranges: ranges, type: coverageType, - size: content.length, + size: contentLength, usedSize: usedSize, unusedSize: unusedSize, lineOffset: startLine,
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleSheetHeader.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleSheetHeader.js index b17c162..e3863709 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleSheetHeader.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleSheetHeader.js
@@ -22,6 +22,7 @@ this.isInline = payload.isInline; this.startLine = payload.startLine; this.startColumn = payload.startColumn; + this.contentLength = payload.length; if (payload.ownerNode) this.ownerNode = new SDK.DeferredDOMNode(cssModel.target(), payload.ownerNode); this.setSourceMapURL(payload.sourceMapURL);
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js index e6e758e..e132c7c 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
@@ -458,25 +458,15 @@ * @param {string} hash * @param {*|undefined} executionContextAuxData * @param {boolean} isLiveEdit - * @param {string=} sourceMapURL - * @param {boolean=} hasSourceURL - * @param {boolean=} hasSyntaxError + * @param {string|undefined} sourceMapURL + * @param {boolean} hasSourceURL + * @param {boolean} hasSyntaxError + * @param {number} length * @return {!SDK.Script} */ _parsedScriptSource( - scriptId, - sourceURL, - startLine, - startColumn, - endLine, - endColumn, - executionContextId, - hash, - executionContextAuxData, - isLiveEdit, - sourceMapURL, - hasSourceURL, - hasSyntaxError) { + scriptId, sourceURL, startLine, startColumn, endLine, endColumn, executionContextId, hash, + executionContextAuxData, isLiveEdit, sourceMapURL, hasSourceURL, hasSyntaxError, length) { var isContentScript = false; if (executionContextAuxData && ('isDefault' in executionContextAuxData)) isContentScript = !executionContextAuxData['isDefault']; @@ -491,7 +481,7 @@ } var script = new SDK.Script( this, scriptId, sourceURL, startLine, startColumn, endLine, endColumn, executionContextId, - this._internString(hash), isContentScript, isLiveEdit, sourceMapURL, hasSourceURL); + this._internString(hash), isContentScript, isLiveEdit, sourceMapURL, hasSourceURL, length); this._registerScript(script); if (!hasSyntaxError) this.dispatchEventToListeners(SDK.DebuggerModel.Events.ParsedScriptSource, script); @@ -933,23 +923,15 @@ * @param {boolean=} isLiveEdit * @param {string=} sourceMapURL * @param {boolean=} hasSourceURL + * @param {boolean=} isModule + * @param {number=} length */ scriptParsed( - scriptId, - sourceURL, - startLine, - startColumn, - endLine, - endColumn, - executionContextId, - hash, - executionContextAuxData, - isLiveEdit, - sourceMapURL, - hasSourceURL) { + scriptId, sourceURL, startLine, startColumn, endLine, endColumn, executionContextId, hash, + executionContextAuxData, isLiveEdit, sourceMapURL, hasSourceURL, isModule, length) { this._debuggerModel._parsedScriptSource( scriptId, sourceURL, startLine, startColumn, endLine, endColumn, executionContextId, hash, - executionContextAuxData, !!isLiveEdit, sourceMapURL, hasSourceURL, false); + executionContextAuxData, !!isLiveEdit, sourceMapURL, !!hasSourceURL, false, length || 0); } /** @@ -965,22 +947,15 @@ * @param {*=} executionContextAuxData * @param {string=} sourceMapURL * @param {boolean=} hasSourceURL + * @param {boolean=} isModule + * @param {number=} length */ scriptFailedToParse( - scriptId, - sourceURL, - startLine, - startColumn, - endLine, - endColumn, - executionContextId, - hash, - executionContextAuxData, - sourceMapURL, - hasSourceURL) { + scriptId, sourceURL, startLine, startColumn, endLine, endColumn, executionContextId, hash, + executionContextAuxData, sourceMapURL, hasSourceURL, isModule, length) { this._debuggerModel._parsedScriptSource( scriptId, sourceURL, startLine, startColumn, endLine, endColumn, executionContextId, hash, - executionContextAuxData, false, sourceMapURL, hasSourceURL, true); + executionContextAuxData, false, sourceMapURL, !!hasSourceURL, true, length || 0); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/Script.js b/third_party/WebKit/Source/devtools/front_end/sdk/Script.js index 10413cf..eaf3408 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/Script.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/Script.js
@@ -40,23 +40,13 @@ * @param {string} hash * @param {boolean} isContentScript * @param {boolean} isLiveEdit - * @param {string=} sourceMapURL - * @param {boolean=} hasSourceURL + * @param {string|undefined} sourceMapURL + * @param {boolean} hasSourceURL + * @param {number} length */ constructor( - debuggerModel, - scriptId, - sourceURL, - startLine, - startColumn, - endLine, - endColumn, - executionContextId, - hash, - isContentScript, - isLiveEdit, - sourceMapURL, - hasSourceURL) { + debuggerModel, scriptId, sourceURL, startLine, startColumn, endLine, endColumn, executionContextId, hash, + isContentScript, isLiveEdit, sourceMapURL, hasSourceURL, length) { this.debuggerModel = debuggerModel; this.scriptId = scriptId; this.sourceURL = sourceURL; @@ -71,6 +61,7 @@ this._isLiveEdit = isLiveEdit; this.sourceMapURL = sourceMapURL; this.hasSourceURL = hasSourceURL; + this.contentLength = length; this._originalContentProvider = null; this._originalSource = null; }
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp index 4d8e2bb5..e770539 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
@@ -1791,25 +1791,28 @@ // Two content layers for the differentiated rect drawings and three dummy // layers for each of the transform, clip and effect nodes. EXPECT_EQ(5u, rootLayer()->children().size()); - EXPECT_EQ(1, propertyTrees().sequence_number); + int sequenceNumber = propertyTrees().sequence_number; + EXPECT_GT(sequenceNumber, 0); for (auto layer : rootLayer()->children()) { - EXPECT_EQ(1, layer->property_tree_sequence_number()); + EXPECT_EQ(sequenceNumber, layer->property_tree_sequence_number()); } update(artifact.build()); EXPECT_EQ(5u, rootLayer()->children().size()); - EXPECT_EQ(2, propertyTrees().sequence_number); + sequenceNumber++; + EXPECT_EQ(sequenceNumber, propertyTrees().sequence_number); for (auto layer : rootLayer()->children()) { - EXPECT_EQ(2, layer->property_tree_sequence_number()); + EXPECT_EQ(sequenceNumber, layer->property_tree_sequence_number()); } update(artifact.build()); EXPECT_EQ(5u, rootLayer()->children().size()); - EXPECT_EQ(3, propertyTrees().sequence_number); + sequenceNumber++; + EXPECT_EQ(sequenceNumber, propertyTrees().sequence_number); for (auto layer : rootLayer()->children()) { - EXPECT_EQ(3, layer->property_tree_sequence_number()); + EXPECT_EQ(sequenceNumber, layer->property_tree_sequence_number()); } }
diff --git a/third_party/WebKit/Source/platform/heap/Member.h b/third_party/WebKit/Source/platform/heap/Member.h index b2bac89..a4d34431 100644 --- a/third_party/WebKit/Source/platform/heap/Member.h +++ b/third_party/WebKit/Source/platform/heap/Member.h
@@ -179,14 +179,6 @@ #if DCHECK_IS_ON() const ThreadState* m_creationThreadState; #endif - - template <bool x, - WTF::WeakHandlingFlag y, - WTF::ShouldWeakPointersBeMarkedStrongly z, - typename U, - typename V> - friend struct CollectionBackingTraceTrait; - friend class Visitor; }; // Members are used in classes to contain strong pointers to other oilpan heap @@ -240,15 +232,6 @@ Parent::operator=(nullptr); return *this; } - - protected: - template <bool x, - WTF::WeakHandlingFlag y, - WTF::ShouldWeakPointersBeMarkedStrongly z, - typename U, - typename V> - friend struct CollectionBackingTraceTrait; - friend class Visitor; }; // A checked version of Member<>, verifying that only same-thread references @@ -333,15 +316,6 @@ return *this; } - protected: - template <bool x, - WTF::WeakHandlingFlag y, - WTF::ShouldWeakPointersBeMarkedStrongly z, - typename U, - typename V> - friend struct CollectionBackingTraceTrait; - friend class Visitor; - private: void checkPointer() { if (!this->m_raw)
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp index 59f8255a..3340537d7 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
@@ -387,8 +387,10 @@ } ResourceResponse response(url, mimetype, data->size(), charset); - response.setHTTPStatusCode(200); - response.setHTTPStatusText("OK"); + if (!substituteData.isValid() && url.protocolIsData()) { + response.setHTTPStatusCode(200); + response.setHTTPStatusText("OK"); + } Resource* resource = factory.create(request.resourceRequest(), request.options(), request.charset());
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc index d941575..509b289 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -1204,14 +1204,18 @@ if (old_task_queue_policy.time_domain_type != new_task_queue_policy.time_domain_type) { if (old_task_queue_policy.time_domain_type == TimeDomainType::THROTTLED) { + task_queue->SetTimeDomain(real_time_domain()); task_queue_throttler_->DecreaseThrottleRefCount(task_queue); } else if (new_task_queue_policy.time_domain_type == TimeDomainType::THROTTLED) { + task_queue->SetTimeDomain(real_time_domain()); task_queue_throttler_->IncreaseThrottleRefCount(task_queue); } else if (new_task_queue_policy.time_domain_type == TimeDomainType::VIRTUAL) { DCHECK(virtual_time_domain_); task_queue->SetTimeDomain(virtual_time_domain_.get()); + } else { + task_queue->SetTimeDomain(real_time_domain()); } } } @@ -1822,6 +1826,17 @@ ForceUpdatePolicy(); } +void RendererSchedulerImpl::DisableVirtualTimeForTesting() { + MainThreadOnly().use_virtual_time = false; + + RealTimeDomain* time_domain = real_time_domain(); + // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy(). + for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_) + task_queue->SetTimeDomain(time_domain); + + ForceUpdatePolicy(); +} + bool RendererSchedulerImpl::ShouldDisableThrottlingBecauseOfAudio( base::TimeTicks now) { if (!MainThreadOnly().last_audio_state_change)
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h index 4b94b721..45652f3 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
@@ -158,6 +158,9 @@ // Tells the scheduler that all TaskQueues should use virtual time. void EnableVirtualTime(); + // Migrates all task queues to real time. + void DisableVirtualTimeForTesting(); + void AddWebViewScheduler(WebViewSchedulerImpl* web_view_scheduler); void RemoveWebViewScheduler(WebViewSchedulerImpl* web_view_scheduler);
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc index aaab05b3..dbbeb31 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -14,6 +14,7 @@ #include "cc/output/begin_frame_args.h" #include "cc/test/ordered_simple_task_runner.h" #include "platform/WebTaskRunner.h" +#include "platform/scheduler/base/real_time_domain.h" #include "platform/scheduler/base/test_time_source.h" #include "platform/scheduler/child/scheduler_tqm_delegate_for_test.h" #include "platform/scheduler/child/scheduler_tqm_delegate_impl.h" @@ -3682,6 +3683,25 @@ scheduler_->GetVirtualTimeDomain()); } +TEST_F(RendererSchedulerImplTest, DisableVirtualTimeForTesting) { + scheduler_->EnableVirtualTime(); + + scoped_refptr<TaskQueue> timer_tq = + scheduler_->NewTimerTaskRunner(TaskQueue::QueueType::TEST); + scoped_refptr<TaskQueue> unthrottled_tq = + scheduler_->NewUnthrottledTaskRunner(TaskQueue::QueueType::TEST); + + scheduler_->DisableVirtualTimeForTesting(); + EXPECT_EQ(scheduler_->DefaultTaskRunner()->GetTimeDomain(), + scheduler_->real_time_domain()); + EXPECT_EQ(scheduler_->CompositorTaskRunner()->GetTimeDomain(), + scheduler_->real_time_domain()); + EXPECT_EQ(scheduler_->LoadingTaskRunner()->GetTimeDomain(), + scheduler_->real_time_domain()); + EXPECT_EQ(scheduler_->TimerTaskRunner()->GetTimeDomain(), + scheduler_->real_time_domain()); +} + TEST_F(RendererSchedulerImplTest, Tracing) { // This test sets renderer scheduler to some non-trivial state // (by posting tasks, creating child schedulers, etc) and converts it into a
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc index b6a1a3eb..1b47e49 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc +++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc
@@ -105,6 +105,7 @@ should_throttle_frames_(false), disable_background_timer_throttling_(disable_background_timer_throttling), allow_virtual_time_to_advance_(true), + timers_suspended_(false), have_seen_loading_task_(false), virtual_time_(false), is_audio_playing_(false), @@ -178,10 +179,33 @@ allow_virtual_time_to_advance_); renderer_scheduler_->EnableVirtualTime(); + ApplyVirtualTimePolicyToTimers(); +} + +void WebViewSchedulerImpl::disableVirtualTimeForTesting() { + if (!virtual_time_) + return; + virtual_time_ = false; + renderer_scheduler_->DisableVirtualTimeForTesting(); + ApplyVirtualTimePolicyToTimers(); +} + +void WebViewSchedulerImpl::ApplyVirtualTimePolicyToTimers() { + if (!virtual_time_ || allow_virtual_time_to_advance_) { + if (timers_suspended_) { + renderer_scheduler_->ResumeTimerQueue(); + timers_suspended_ = false; + } + } else if (!timers_suspended_) { + renderer_scheduler_->SuspendTimerQueue(); + timers_suspended_ = true; + } } void WebViewSchedulerImpl::setAllowVirtualTimeToAdvance( bool allow_virtual_time_to_advance) { + if (allow_virtual_time_to_advance_ == allow_virtual_time_to_advance) + return; allow_virtual_time_to_advance_ = allow_virtual_time_to_advance; if (!virtual_time_) @@ -189,6 +213,7 @@ renderer_scheduler_->GetVirtualTimeDomain()->SetCanAdvanceVirtualTime( allow_virtual_time_to_advance); + ApplyVirtualTimePolicyToTimers(); } bool WebViewSchedulerImpl::virtualTimeAllowedToAdvance() const { @@ -198,23 +223,23 @@ void WebViewSchedulerImpl::DidStartLoading(unsigned long identifier) { pending_loads_.insert(identifier); have_seen_loading_task_ = true; - ApplyVirtualTimePolicy(); + ApplyVirtualTimePolicyForLoading(); } void WebViewSchedulerImpl::DidStopLoading(unsigned long identifier) { pending_loads_.erase(identifier); - ApplyVirtualTimePolicy(); + ApplyVirtualTimePolicyForLoading(); } void WebViewSchedulerImpl::IncrementBackgroundParserCount() { background_parser_count_++; - ApplyVirtualTimePolicy(); + ApplyVirtualTimePolicyForLoading(); } void WebViewSchedulerImpl::DecrementBackgroundParserCount() { background_parser_count_--; DCHECK_GE(background_parser_count_, 0); - ApplyVirtualTimePolicy(); + ApplyVirtualTimePolicyForLoading(); } void WebViewSchedulerImpl::setVirtualTimePolicy(VirtualTimePolicy policy) { @@ -230,7 +255,7 @@ break; case VirtualTimePolicy::DETERMINISTIC_LOADING: - ApplyVirtualTimePolicy(); + ApplyVirtualTimePolicyForLoading(); break; } } @@ -244,7 +269,7 @@ return has_active_connection_; } -void WebViewSchedulerImpl::ApplyVirtualTimePolicy() { +void WebViewSchedulerImpl::ApplyVirtualTimePolicyForLoading() { if (virtual_time_policy_ != VirtualTimePolicy::DETERMINISTIC_LOADING) { return; }
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h index 4f60861..cd05c25 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h +++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h
@@ -45,6 +45,7 @@ std::unique_ptr<WebFrameScheduler> createFrameScheduler( BlameContext* blame_context) override; void enableVirtualTime() override; + void disableVirtualTimeForTesting() override; bool virtualTimeAllowedToAdvance() const override; void setVirtualTimePolicy(VirtualTimePolicy virtual_time_policy) override; void audioStateChanged(bool is_audio_playing) override; @@ -76,7 +77,8 @@ void MaybeInitializeBackgroundCPUTimeBudgetPool(); void setAllowVirtualTimeToAdvance(bool allow_virtual_time_to_advance); - void ApplyVirtualTimePolicy(); + void ApplyVirtualTimePolicyForLoading(); + void ApplyVirtualTimePolicyToTimers(); void OnThrottlingReported(base::TimeDelta throttling_duration); @@ -104,6 +106,7 @@ bool should_throttle_frames_; bool disable_background_timer_throttling_; bool allow_virtual_time_to_advance_; + bool timers_suspended_; bool have_seen_loading_task_; bool virtual_time_; bool is_audio_playing_;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc index 61961b6..c3aa544 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc +++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
@@ -390,8 +390,8 @@ mock_task_runner_->RunUntilIdle(); - // Immediate tasks are allowed to run even if delayed tasks are not. - EXPECT_THAT(run_order, ElementsAre(0)); + // No timer tasks are allowed to run. + EXPECT_THAT(run_order, ElementsAre()); } TEST_F(WebViewSchedulerImplTest, VirtualTime_AllowedToAdvance) { @@ -606,6 +606,27 @@ EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); } +TEST_F(WebViewSchedulerImplTest, SuspendTimersWhileVirtualTimeIsPaused) { + std::vector<int> run_order; + + std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler = + web_view_scheduler_->createWebFrameSchedulerImpl(nullptr); + web_frame_scheduler->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, WTF::bind(&runOrderTask, 1, WTF::unretained(&run_order)), + 0); + + web_view_scheduler_->setVirtualTimePolicy(VirtualTimePolicy::PAUSE); + web_view_scheduler_->enableVirtualTime(); + + mock_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + web_view_scheduler_->setVirtualTimePolicy(VirtualTimePolicy::ADVANCE); + mock_task_runner_->RunUntilIdle(); + + EXPECT_THAT(run_order, ElementsAre(1)); +} + namespace { using ScopedExpensiveBackgroundTimerThrottlingForTest =
diff --git a/third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp b/third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp index 06c2754..fa5445b 100644 --- a/third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp +++ b/third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/message_loop/message_loop.h" +#include "core/dom/TaskRunnerHelper.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" #include "public/platform/WebViewScheduler.h" @@ -46,9 +47,8 @@ void TearDown() override { // The SimTest destructor calls runPendingTasks. This is a problem because // if there are any repeating tasks, advancing virtual time will cause the - // runloop to busy loop. Pausing virtual time here fixes that. - webView().scheduler()->setVirtualTimePolicy( - WebViewScheduler::VirtualTimePolicy::PAUSE); + // runloop to busy loop. Disabling virtual time here fixes that. + webView().scheduler()->disableVirtualTimeForTesting(); } }; @@ -198,4 +198,40 @@ EXPECT_TRUE(webView().scheduler()->virtualTimeAllowedToAdvance()); } +// http://crbug.com/633321 +#if OS(ANDROID) +#define MAYBE_DOMTimersSuspended DISABLED_DOMTimersSuspended +#else +#define MAYBE_DOMTimersSuspended DOMTimersSuspended +#endif +TEST_F(VirtualTimeTest, MAYBE_DOMTimersSuspended) { + webView().scheduler()->enableVirtualTime(); + + // Schedule a normal DOM timer to run at 1s in the future. + ExecuteJavaScript( + "var run_order = [];" + "setTimeout(() => { run_order.push(1); }, 1000);"); + + RefPtr<WebTaskRunner> runner = + TaskRunnerHelper::get(TaskType::Timer, window().getExecutionContext()); + + // Schedule a task to suspend virtual time at the same point in time. + runner->postDelayedTask(BLINK_FROM_HERE, + WTF::bind( + [](WebViewScheduler* scheduler) { + scheduler->setVirtualTimePolicy( + WebViewScheduler::VirtualTimePolicy::PAUSE); + }, + WTF::unretained(webView().scheduler())), + 1000); + + // ALso schedule a second timer for the same point in time. + ExecuteJavaScript("setTimeout(() => { run_order.push(2); }, 1000);"); + + // The second DOM timer shouldn't have run because pausing virtual time also + // atomically pauses DOM timers. + testing::runPendingTasks(); + EXPECT_EQ("1", ExecuteJavaScript("run_order.join(', ')")); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/wtf/LinkedHashSet.h b/third_party/WebKit/Source/wtf/LinkedHashSet.h index 40f80f5..d9e7429 100644 --- a/third_party/WebKit/Source/wtf/LinkedHashSet.h +++ b/third_party/WebKit/Source/wtf/LinkedHashSet.h
@@ -241,7 +241,7 @@ Value& back(); const Value& back() const; - void removeLast(); + void pop_back(); iterator find(ValuePeekInType); const_iterator find(ValuePeekInType) const; @@ -730,7 +730,7 @@ } template <typename T, typename U, typename V, typename W> -inline void LinkedHashSet<T, U, V, W>::removeLast() { +inline void LinkedHashSet<T, U, V, W>::pop_back() { DCHECK(!isEmpty()); m_impl.remove(static_cast<Node*>(m_anchor.m_prev)); }
diff --git a/third_party/WebKit/Source/wtf/ListHashSet.h b/third_party/WebKit/Source/wtf/ListHashSet.h index ecefd88..3a6dc5d 100644 --- a/third_party/WebKit/Source/wtf/ListHashSet.h +++ b/third_party/WebKit/Source/wtf/ListHashSet.h
@@ -169,7 +169,7 @@ ValueType& back(); const ValueType& back() const; - void removeLast(); + void pop_back(); iterator find(ValuePeekInType); const_iterator find(ValuePeekInType) const; @@ -840,7 +840,7 @@ } template <typename T, size_t inlineCapacity, typename U, typename V> -inline void ListHashSet<T, inlineCapacity, U, V>::removeLast() { +inline void ListHashSet<T, inlineCapacity, U, V>::pop_back() { DCHECK(!isEmpty()); m_impl.remove(m_tail); unlinkAndDelete(m_tail);
diff --git a/third_party/WebKit/Source/wtf/ListHashSetTest.cpp b/third_party/WebKit/Source/wtf/ListHashSetTest.cpp index 226edbe0..9b6ac97 100644 --- a/third_party/WebKit/Source/wtf/ListHashSetTest.cpp +++ b/third_party/WebKit/Source/wtf/ListHashSetTest.cpp
@@ -60,7 +60,7 @@ list.removeFirst(); EXPECT_EQ(0, list.front()); - list.removeLast(); + list.pop_back(); EXPECT_EQ(2, list.back()); list.removeFirst();
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/config/builders.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/config/builders.py index d0d55fa..19c3b6d 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/config/builders.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/config/builders.py
@@ -67,6 +67,10 @@ "port_name": "mac-retina", "specifiers": ['Retina', 'Release'] }, + "WebKit Mac10.12": { + "port_name": "mac-mac10.12", + "specifiers": ['Mac10.12', 'Release'] + }, "WebKit Android (Nexus4)": { "port_name": "android", "specifiers": ['Android', 'Release'] @@ -96,6 +100,11 @@ "specifiers": ['Retina', 'Release'], "is_try_builder": True, }, + "mac10.12_blink_rel": { + "port_name": "mac-mac10.12", + "specifiers": ['Mac10.12', 'Release'], + "is_try_builder": True, + }, "win7_blink_rel": { "port_name": "win-win7", "specifiers": ['Win7', 'Release'],
diff --git a/third_party/WebKit/public/platform/WebViewScheduler.h b/third_party/WebKit/public/platform/WebViewScheduler.h index 77e003ee..09d1c16 100644 --- a/third_party/WebKit/public/platform/WebViewScheduler.h +++ b/third_party/WebKit/public/platform/WebViewScheduler.h
@@ -50,6 +50,10 @@ // |-----------------------------> time virtual void enableVirtualTime() = 0; + // Disables virtual time. Note that this is only used for testing, because + // there's no reason to do this in production. + virtual void disableVirtualTimeForTesting() = 0; + // Returns true if virtual time is currently allowed to advance. virtual bool virtualTimeAllowedToAdvance() const = 0;
diff --git a/third_party/android_platform/OWNERS b/third_party/android_platform/OWNERS index 052f4fae..e86384c 100644 --- a/third_party/android_platform/OWNERS +++ b/third_party/android_platform/OWNERS
@@ -1,3 +1,5 @@ agrieve@chromium.org rmcilroy@chromium.org sgurun@chromium.org + +# COMPONENT: Infra>Client>Android
diff --git a/third_party/apk-patch-size-estimator/OWNERS b/third_party/apk-patch-size-estimator/OWNERS index bec88273..c964495 100644 --- a/third_party/apk-patch-size-estimator/OWNERS +++ b/third_party/apk-patch-size-estimator/OWNERS
@@ -1,2 +1,4 @@ agrieve@chromium.org estevenson@chromium.org + +# COMPONENT: Build
diff --git a/third_party/haha/OWNERS b/third_party/haha/OWNERS index dbccb98..b4eda11 100644 --- a/third_party/haha/OWNERS +++ b/third_party/haha/OWNERS
@@ -1,2 +1,4 @@ agrieve@chromium.org yfriedman@chromium.org + +# COMPONENT: Build
diff --git a/third_party/ijar/OWNERS b/third_party/ijar/OWNERS index e2457f7..e1a6e59 100644 --- a/third_party/ijar/OWNERS +++ b/third_party/ijar/OWNERS
@@ -1,2 +1,4 @@ agrieve@chromium.org dpranke@chromium.org + +# COMPONENT: Build
diff --git a/third_party/jmake/OWNERS b/third_party/jmake/OWNERS index dbccb98..b4eda11 100644 --- a/third_party/jmake/OWNERS +++ b/third_party/jmake/OWNERS
@@ -1,2 +1,4 @@ agrieve@chromium.org yfriedman@chromium.org + +# COMPONENT: Build
diff --git a/third_party/leakcanary/OWNERS b/third_party/leakcanary/OWNERS index dbccb98..b4eda11 100644 --- a/third_party/leakcanary/OWNERS +++ b/third_party/leakcanary/OWNERS
@@ -1,2 +1,4 @@ agrieve@chromium.org yfriedman@chromium.org + +# COMPONENT: Build
diff --git a/third_party/retrolambda/OWNERS b/third_party/retrolambda/OWNERS index e96e054..ea2bde4 100644 --- a/third_party/retrolambda/OWNERS +++ b/third_party/retrolambda/OWNERS
@@ -1,2 +1,4 @@ agrieve@chromium.org zpeng@chromium.org + +# COMPONENT: Build
diff --git a/tools/android/eclipse/.classpath b/tools/android/eclipse/.classpath index 12e7522a..67d205a 100644 --- a/tools/android/eclipse/.classpath +++ b/tools/android/eclipse/.classpath
@@ -229,6 +229,7 @@ <classpathentry kind="lib" path="third_party/android_tools/sdk/extras/android/support/v13/android-support-v13.jar" sourcepath="third_party/android_tools/sdk/sources"/> <classpathentry kind="lib" path="third_party/android_tools/sdk/extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar" sourcepath="third_party/android_tools/sdk/sources"/> <classpathentry kind="lib" path="third_party/android_support_test_runner/lib/runner-0.5-release-no-dep.jar"/> + <classpathentry kind="lib" path="third_party/android_support_test_runner/lib/rules-0.5.jar"/> <classpathentry kind="lib" path="third_party/bouncycastle/lib/bcprov-jdk16-1.46.jar"/> <classpathentry kind="lib" path="third_party/byte_buddy/lib/byte-buddy-1.4.17.jar"/> <classpathentry kind="lib" path="third_party/findbugs/lib/findbugs.jar"/>
diff --git a/tools/metrics/OWNERS b/tools/metrics/OWNERS index cf5b92c1..559d7b21 100644 --- a/tools/metrics/OWNERS +++ b/tools/metrics/OWNERS
@@ -4,3 +4,5 @@ jwd@chromium.org mpearson@chromium.org rkaplow@chromium.org + +# COMPONENT: Internals>Metrics
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index fb7ebd76..21b73e97 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -6605,6 +6605,9 @@ </histogram> <histogram name="ChildProcess.HangRendererType" enum="RendererUnresponsiveType"> + <obsolete> + Deprecated 3/2017. + </obsolete> <owner>clamy@chromium.org</owner> <summary> What the browser was waiting for from the renderer when it was reported as @@ -36852,6 +36855,23 @@ </summary> </histogram> +<histogram name="Net.SSL_Connection_Error_Google" units="NetErrorCodes"> + <owner>svaldez@chromium.org</owner> + <summary> + Counts of specific error codes returned when opening an SSL connection for + google.com and any subdomain of it. + </summary> +</histogram> + +<histogram name="Net.SSL_Connection_Error_TLS13Experiment" + units="NetErrorCodes"> + <owner>svaldez@chromium.org</owner> + <summary> + Counts of specific error codes returned when opening an SSL connection for + an endpoint we are using in the initial TLS 1.3 deployment. + </summary> +</histogram> + <histogram name="Net.SSL_Connection_Latency" units="ms"> <obsolete> Replaced by Net.SSL_Connection_Latency_2 on 2014-10-21. @@ -36967,6 +36987,14 @@ </summary> </histogram> +<histogram name="Net.SSL_Connection_Latency_TLS13Experiment" units="ms"> + <owner>svaldez@chromium.org</owner> + <summary> + Time from when the Connect() starts until it completes for a set of domains + that we are using in the initial TLS 1.3 deployment. + </summary> +</histogram> + <histogram name="Net.SSL_Connection_PostQuantum_Negotiated" enum="BooleanSupported"> <obsolete> @@ -106908,12 +106936,15 @@ </enum> <enum name="RendererUnresponsiveType" type="int"> + <obsolete> + Deprecated 3/2017. + </obsolete> <int value="0" label="Unknown"/> <int value="1" label="Pending in-flight events"/> <int value="2" label="Waiting for dialog closed"/> <int value="3" label="Suppressed dialogs in unload events"/> <int value="4" label="During BeforeUnload"/> - <int value="5" label="During Unload (obsolete)"/> + <int value="5" label="During Unload"/> <int value="6" label="While closing the page"/> </enum>
diff --git a/tools/perf/measurements/clock_domain_test.py b/tools/perf/measurements/clock_domain_test.py index 596439f..3658d6f9 100644 --- a/tools/perf/measurements/clock_domain_test.py +++ b/tools/perf/measurements/clock_domain_test.py
@@ -15,7 +15,9 @@ # Don't run this test on Android; it's not supposed to work on Android # (since when doing Android tracing there are two different devices, # so the clock domains will be different) - @benchmark.Disabled('android') + # TODO(rnephew): Revert change from android to all once + # https://codereview.chromium.org/2741533003/ lands. + @benchmark.Disabled('all') def testTelemetryUsesChromeClockDomain(self): tracing_controller = self._browser.platform.tracing_controller
diff --git a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java index 3415ae5..368d9e78 100644 --- a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java +++ b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
@@ -386,22 +386,18 @@ // now we want to distinguish between generic, photo and visual media pickers. @VisibleForTesting int determineSelectFileDialogScope() { - boolean isGeneric = noSpecificType(); + if (mFileTypes.size() == 0) return SELECT_FILE_DIALOG_SCOPE_GENERIC; - if (!isGeneric && shouldShowImageTypes()) { - return SELECT_FILE_DIALOG_SCOPE_IMAGES; - } else if (!isGeneric && shouldShowVideoTypes()) { - return SELECT_FILE_DIALOG_SCOPE_VIDEOS; - } else if (mFileTypes.size() == 2) { - // The shouldShow{Image,Video}Types() methods cannot be used here since they test for - // a generic dialog, which any request with more than one file type is considered as. - if ((mFileTypes.contains(ALL_IMAGE_TYPES) || acceptSpecificType(IMAGE_TYPE)) - && (mFileTypes.contains(ALL_VIDEO_TYPES) || acceptSpecificType(VIDEO_TYPE))) { - return SELECT_FILE_DIALOG_SCOPE_IMAGES_AND_VIDEOS; - } + int acceptsImages = countAcceptTypesFor(IMAGE_TYPE); + int acceptsVideos = countAcceptTypesFor(VIDEO_TYPE); + int acceptsOthers = mFileTypes.size() - acceptsImages - acceptsVideos; + + if (acceptsOthers > 0) return SELECT_FILE_DIALOG_SCOPE_GENERIC; + if (acceptsVideos > 0) { + return (acceptsImages == 0) ? SELECT_FILE_DIALOG_SCOPE_VIDEOS + : SELECT_FILE_DIALOG_SCOPE_IMAGES_AND_VIDEOS; } - - return SELECT_FILE_DIALOG_SCOPE_GENERIC; + return SELECT_FILE_DIALOG_SCOPE_IMAGES; } private boolean noSpecificType() { @@ -414,7 +410,7 @@ private boolean shouldShowTypes(String allTypes, String specificType) { if (noSpecificType() || mFileTypes.contains(allTypes)) return true; - return acceptSpecificType(specificType); + return countAcceptTypesFor(specificType) > 0; } private boolean shouldShowImageTypes() { @@ -445,13 +441,14 @@ return mCapture && acceptsSpecificType(ALL_AUDIO_TYPES); } - private boolean acceptSpecificType(String accept) { + private int countAcceptTypesFor(String accept) { + int count = 0; for (String type : mFileTypes) { if (type.startsWith(accept)) { - return true; + count++; } } - return false; + return count; } private class GetDisplayNameTask extends AsyncTask<Uri, Void, String[]> {
diff --git a/ui/android/junit/src/org/chromium/ui/base/SelectFileDialogTest.java b/ui/android/junit/src/org/chromium/ui/base/SelectFileDialogTest.java index 9c195f1..aaae9c83 100644 --- a/ui/android/junit/src/org/chromium/ui/base/SelectFileDialogTest.java +++ b/ui/android/junit/src/org/chromium/ui/base/SelectFileDialogTest.java
@@ -51,6 +51,10 @@ SelectFileDialog.SELECT_FILE_DIALOG_SCOPE_VIDEOS, scopeForFileTypes("video/ogg")); assertEquals(SelectFileDialog.SELECT_FILE_DIALOG_SCOPE_GENERIC, scopeForFileTypes("video/*", "test/plain")); + assertEquals(SelectFileDialog.SELECT_FILE_DIALOG_SCOPE_IMAGES, + scopeForFileTypes("image/x-png", "image/gif", "image/jpeg")); + assertEquals(SelectFileDialog.SELECT_FILE_DIALOG_SCOPE_GENERIC, + scopeForFileTypes("image/x-png", "image/gif", "image/jpeg", "text/plain")); assertEquals(SelectFileDialog.SELECT_FILE_DIALOG_SCOPE_IMAGES_AND_VIDEOS, scopeForFileTypes("video/*", "image/*"));
diff --git a/ui/aura/gestures/OWNERS b/ui/aura/gestures/OWNERS index 92704b0..bebf80ff 100644 --- a/ui/aura/gestures/OWNERS +++ b/ui/aura/gestures/OWNERS
@@ -1,3 +1,6 @@ rjkroege@chromium.org sadrul@chromium.org tdresser@chromium.org + +# TEAM: input-dev@chromium.org +# COMPONENT: UI>Input
diff --git a/ui/base/cursor/ozone/OWNERS b/ui/base/cursor/ozone/OWNERS index 479c4d8..1c6f90ab 100644 --- a/ui/base/cursor/ozone/OWNERS +++ b/ui/base/cursor/ozone/OWNERS
@@ -1,2 +1,4 @@ rjkroege@chromium.org spang@chromium.org + +# COMPONENT: UI>GFX
diff --git a/ui/display/mojo/display_constants.mojom b/ui/display/mojo/display_constants.mojom index 7ea2469..eefc4f6 100644 --- a/ui/display/mojo/display_constants.mojom +++ b/ui/display/mojo/display_constants.mojom
@@ -16,3 +16,10 @@ DISPLAY_CONNECTION_TYPE_NETWORK = 64, DISPLAY_CONNECTION_TYPE_VIRTUAL = 128, }; + +// Corresponding to display::HDCPState. +enum HDCPState { + HDCP_STATE_UNDESIRED, + HDCP_STATE_DESIRED, + HDCP_STATE_ENABLED, +}; \ No newline at end of file
diff --git a/ui/display/mojo/display_constants.typemap b/ui/display/mojo/display_constants.typemap index 725ab17..4c0b4ae1 100644 --- a/ui/display/mojo/display_constants.typemap +++ b/ui/display/mojo/display_constants.typemap
@@ -11,5 +11,7 @@ public_deps = [ "//ui/display", ] -type_mappings = - [ "display.mojom.DisplayConnectionType=display::DisplayConnectionType" ] +type_mappings = [ + "display.mojom.DisplayConnectionType=display::DisplayConnectionType", + "display.mojom.HDCPState=display::HDCPState", +]
diff --git a/ui/display/mojo/display_constants_struct_traits.cc b/ui/display/mojo/display_constants_struct_traits.cc index fd71086..80eaedd 100644 --- a/ui/display/mojo/display_constants_struct_traits.cc +++ b/ui/display/mojo/display_constants_struct_traits.cc
@@ -14,33 +14,25 @@ case display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_NONE: return display::mojom::DisplayConnectionType:: DISPLAY_CONNECTION_TYPE_NONE; - case display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_UNKNOWN: return display::mojom::DisplayConnectionType:: DISPLAY_CONNECTION_TYPE_UNKNOWN; - case display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_INTERNAL: return display::mojom::DisplayConnectionType:: DISPLAY_CONNECTION_TYPE_INTERNAL; - case display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_VGA: return display::mojom::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_VGA; - case display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_HDMI: return display::mojom::DisplayConnectionType:: DISPLAY_CONNECTION_TYPE_HDMI; - case display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_DVI: return display::mojom::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_DVI; - case display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_DISPLAYPORT: return display::mojom::DisplayConnectionType:: DISPLAY_CONNECTION_TYPE_DISPLAYPORT; - case display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_NETWORK: return display::mojom::DisplayConnectionType:: DISPLAY_CONNECTION_TYPE_NETWORK; - case display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_VIRTUAL: return display::mojom::DisplayConnectionType:: DISPLAY_CONNECTION_TYPE_VIRTUAL; @@ -57,38 +49,30 @@ case display::mojom::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_NONE: *out = display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_NONE; return true; - case display::mojom::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_UNKNOWN: *out = display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_UNKNOWN; return true; - case display::mojom::DisplayConnectionType:: DISPLAY_CONNECTION_TYPE_INTERNAL: *out = display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_INTERNAL; return true; - case display::mojom::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_VGA: *out = display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_VGA; return true; - case display::mojom::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_HDMI: *out = display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_HDMI; return true; - case display::mojom::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_DVI: *out = display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_DVI; return true; - case display::mojom::DisplayConnectionType:: DISPLAY_CONNECTION_TYPE_DISPLAYPORT: *out = display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_DISPLAYPORT; return true; - case display::mojom::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_NETWORK: *out = display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_NETWORK; return true; - case display::mojom::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_VIRTUAL: *out = display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_VIRTUAL; return true; @@ -96,4 +80,38 @@ return false; } +// static +display::mojom::HDCPState +EnumTraits<display::mojom::HDCPState, display::HDCPState>::ToMojom( + display::HDCPState type) { + switch (type) { + case display::HDCPState::HDCP_STATE_UNDESIRED: + return display::mojom::HDCPState::HDCP_STATE_UNDESIRED; + case display::HDCPState::HDCP_STATE_DESIRED: + return display::mojom::HDCPState::HDCP_STATE_DESIRED; + case display::HDCPState::HDCP_STATE_ENABLED: + return display::mojom::HDCPState::HDCP_STATE_ENABLED; + } + NOTREACHED(); + return display::mojom::HDCPState::HDCP_STATE_UNDESIRED; +} + +// static +bool EnumTraits<display::mojom::HDCPState, display::HDCPState>::FromMojom( + display::mojom::HDCPState type, + display::HDCPState* out) { + switch (type) { + case display::mojom::HDCPState::HDCP_STATE_UNDESIRED: + *out = display::HDCPState::HDCP_STATE_UNDESIRED; + return true; + case display::mojom::HDCPState::HDCP_STATE_DESIRED: + *out = display::HDCPState::HDCP_STATE_DESIRED; + return true; + case display::mojom::HDCPState::HDCP_STATE_ENABLED: + *out = display::HDCPState::HDCP_STATE_ENABLED; + return true; + } + return false; +} + } // namespace mojo
diff --git a/ui/display/mojo/display_constants_struct_traits.h b/ui/display/mojo/display_constants_struct_traits.h index bb7c13e..ca7d9c2 100644 --- a/ui/display/mojo/display_constants_struct_traits.h +++ b/ui/display/mojo/display_constants_struct_traits.h
@@ -19,6 +19,13 @@ display::DisplayConnectionType* out); }; +template <> +struct EnumTraits<display::mojom::HDCPState, display::HDCPState> { + static display::mojom::HDCPState ToMojom(display::HDCPState type); + static bool FromMojom(display::mojom::HDCPState type, + display::HDCPState* out); +}; + }; // namespace mojo #endif // UI_DISPLAY_MOJO_DISPLAY_CONSTANTS_STRUCT_TRAITS_H_ \ No newline at end of file
diff --git a/ui/display/mojo/display_struct_traits_test.mojom b/ui/display/mojo/display_struct_traits_test.mojom index 30c92ff..ba18e61 100644 --- a/ui/display/mojo/display_struct_traits_test.mojom +++ b/ui/display/mojo/display_struct_traits_test.mojom
@@ -5,6 +5,7 @@ module display.mojom; import "ui/display/mojo/display.mojom"; +import "ui/display/mojo/display_constants.mojom"; import "ui/display/mojo/display_layout.mojom"; import "ui/display/mojo/display_mode.mojom"; import "ui/display/mojo/display_snapshot_mojo.mojom"; @@ -28,5 +29,8 @@ EchoDisplayLayout(DisplayLayout in) => (DisplayLayout out); [Sync] + EchoHDCPState(HDCPState in) => (HDCPState out); + + [Sync] EchoGammaRampRGBEntry(GammaRampRGBEntry in) => (GammaRampRGBEntry out); }; \ No newline at end of file
diff --git a/ui/display/mojo/display_struct_traits_unittest.cc b/ui/display/mojo/display_struct_traits_unittest.cc index bc30608..119f768 100644 --- a/ui/display/mojo/display_struct_traits_unittest.cc +++ b/ui/display/mojo/display_struct_traits_unittest.cc
@@ -64,6 +64,11 @@ callback.Run(std::move(in)); } + void EchoHDCPState(display::HDCPState in, + const EchoHDCPStateCallback& callback) override { + callback.Run(in); + } + void EchoGammaRampRGBEntry( const GammaRampRGBEntry& in, const EchoGammaRampRGBEntryCallback& callback) override { @@ -443,4 +448,11 @@ CheckDisplaySnapShotMojoEqual(*input, *output); } +TEST_F(DisplayStructTraitsTest, HDCPStateBasic) { + const display::HDCPState input(HDCP_STATE_ENABLED); + display::HDCPState output; + GetTraitsTestProxy()->EchoHDCPState(input, &output); + EXPECT_EQ(input, output); +} + } // namespace display \ No newline at end of file
diff --git a/ui/events/gestures/OWNERS b/ui/events/gestures/OWNERS index 92704b0..bebf80ff 100644 --- a/ui/events/gestures/OWNERS +++ b/ui/events/gestures/OWNERS
@@ -1,3 +1,6 @@ rjkroege@chromium.org sadrul@chromium.org tdresser@chromium.org + +# TEAM: input-dev@chromium.org +# COMPONENT: UI>Input
diff --git a/ui/events/ozone/OWNERS b/ui/events/ozone/OWNERS index 6b3b975..ce14be6 100644 --- a/ui/events/ozone/OWNERS +++ b/ui/events/ozone/OWNERS
@@ -1,3 +1,5 @@ rjkroege@chromium.org spang@chromium.org kpschoedel@chromium.org + +# TEAM: ozone-dev@chromium.org
diff --git a/ui/ozone/OWNERS b/ui/ozone/OWNERS index ec43a6d..14420658 100644 --- a/ui/ozone/OWNERS +++ b/ui/ozone/OWNERS
@@ -1,3 +1,5 @@ rjkroege@chromium.org spang@chromium.org alexst@chromium.org + +# TEAM: ozone-dev@chromium.org
diff --git a/ui/ozone/platform/cast/platform_window_cast.h b/ui/ozone/platform/cast/platform_window_cast.h index 758e79a..4a494f2 100644 --- a/ui/ozone/platform/cast/platform_window_cast.h +++ b/ui/ozone/platform/cast/platform_window_cast.h
@@ -28,6 +28,7 @@ void Show() override {} void Hide() override {} void Close() override {} + void PrepareForShutdown() override {} void SetCapture() override {} void ReleaseCapture() override {} void ToggleFullscreen() override {}
diff --git a/ui/ozone/platform/drm/host/drm_window_host.cc b/ui/ozone/platform/drm/host/drm_window_host.cc index 86e6388..76e5d355 100644 --- a/ui/ozone/platform/drm/host/drm_window_host.cc +++ b/ui/ozone/platform/drm/host/drm_window_host.cc
@@ -74,6 +74,8 @@ void DrmWindowHost::Close() { } +void DrmWindowHost::PrepareForShutdown() {} + void DrmWindowHost::SetBounds(const gfx::Rect& bounds) { bounds_ = bounds; delegate_->OnBoundsChanged(bounds);
diff --git a/ui/ozone/platform/drm/host/drm_window_host.h b/ui/ozone/platform/drm/host/drm_window_host.h index 1df7c7b2..01f0cce 100644 --- a/ui/ozone/platform/drm/host/drm_window_host.h +++ b/ui/ozone/platform/drm/host/drm_window_host.h
@@ -61,6 +61,7 @@ void Show() override; void Hide() override; void Close() override; + void PrepareForShutdown() override; void SetBounds(const gfx::Rect& bounds) override; gfx::Rect GetBounds() override; void SetTitle(const base::string16& title) override;
diff --git a/ui/ozone/platform/headless/headless_window.cc b/ui/ozone/platform/headless/headless_window.cc index 75f86a1..02821a16 100644 --- a/ui/ozone/platform/headless/headless_window.cc +++ b/ui/ozone/platform/headless/headless_window.cc
@@ -52,6 +52,8 @@ void HeadlessWindow::Close() {} +void HeadlessWindow::PrepareForShutdown() {} + void HeadlessWindow::SetCapture() {} void HeadlessWindow::ReleaseCapture() {}
diff --git a/ui/ozone/platform/headless/headless_window.h b/ui/ozone/platform/headless/headless_window.h index 5587b653..8e02342 100644 --- a/ui/ozone/platform/headless/headless_window.h +++ b/ui/ozone/platform/headless/headless_window.h
@@ -33,6 +33,7 @@ void Show() override; void Hide() override; void Close() override; + void PrepareForShutdown() override; void SetCapture() override; void ReleaseCapture() override; void ToggleFullscreen() override;
diff --git a/ui/ozone/platform/wayland/wayland_window.cc b/ui/ozone/platform/wayland/wayland_window.cc index 3711dbd..85cfee52 100644 --- a/ui/ozone/platform/wayland/wayland_window.cc +++ b/ui/ozone/platform/wayland/wayland_window.cc
@@ -81,6 +81,8 @@ NOTIMPLEMENTED(); } +void WaylandWindow::PrepareForShutdown() {} + void WaylandWindow::SetBounds(const gfx::Rect& bounds) { if (bounds == bounds_) return;
diff --git a/ui/ozone/platform/wayland/wayland_window.h b/ui/ozone/platform/wayland/wayland_window.h index fa004a0..e3785de 100644 --- a/ui/ozone/platform/wayland/wayland_window.h +++ b/ui/ozone/platform/wayland/wayland_window.h
@@ -43,6 +43,7 @@ void Show() override; void Hide() override; void Close() override; + void PrepareForShutdown() override; void SetBounds(const gfx::Rect& bounds) override; gfx::Rect GetBounds() override; void SetTitle(const base::string16& title) override;
diff --git a/ui/ozone/platform/x11/ozone_platform_x11.cc b/ui/ozone/platform/x11/ozone_platform_x11.cc index 09bb43d..ae74f0e 100644 --- a/ui/ozone/platform/x11/ozone_platform_x11.cc +++ b/ui/ozone/platform/x11/ozone_platform_x11.cc
@@ -77,7 +77,7 @@ PlatformWindowDelegate* delegate, const gfx::Rect& bounds) override { std::unique_ptr<X11WindowOzone> window = base::MakeUnique<X11WindowOzone>( - event_source_.get(), window_manager_.get(), delegate, bounds); + window_manager_.get(), delegate, bounds); window->Create(); window->SetTitle(base::ASCIIToUTF16("Ozone X11")); return std::move(window);
diff --git a/ui/platform_window/android/platform_window_android.cc b/ui/platform_window/android/platform_window_android.cc index 1f6dc60..78dd50c0 100644 --- a/ui/platform_window/android/platform_window_android.cc +++ b/ui/platform_window/android/platform_window_android.cc
@@ -178,6 +178,8 @@ delegate_->OnCloseRequest(); } +void PlatformWindowAndroid::PrepareForShutdown() {} + void PlatformWindowAndroid::SetBounds(const gfx::Rect& bounds) { NOTIMPLEMENTED(); }
diff --git a/ui/platform_window/android/platform_window_android.h b/ui/platform_window/android/platform_window_android.h index 329ddc3..6ae0681 100644 --- a/ui/platform_window/android/platform_window_android.h +++ b/ui/platform_window/android/platform_window_android.h
@@ -67,6 +67,7 @@ void Show() override; void Hide() override; void Close() override; + void PrepareForShutdown() override; void SetBounds(const gfx::Rect& bounds) override; gfx::Rect GetBounds() override; void SetTitle(const base::string16& title) override;
diff --git a/ui/platform_window/platform_window.h b/ui/platform_window/platform_window.h index f22a48cd..bd8dbb0 100644 --- a/ui/platform_window/platform_window.h +++ b/ui/platform_window/platform_window.h
@@ -30,6 +30,11 @@ virtual void Hide() = 0; virtual void Close() = 0; + // Informs the window it is going to be destroyed sometime soon. This is only + // called for specific code paths, for example by Ash, so it shouldn't be + // assumed this will get called before destruction. + virtual void PrepareForShutdown() = 0; + // Sets and gets the bounds of the platform-window. Note that the bounds is in // physical pixel coordinates. virtual void SetBounds(const gfx::Rect& bounds) = 0;
diff --git a/ui/platform_window/stub/stub_window.cc b/ui/platform_window/stub/stub_window.cc index 3c562c41..b54ada3 100644 --- a/ui/platform_window/stub/stub_window.cc +++ b/ui/platform_window/stub/stub_window.cc
@@ -30,6 +30,8 @@ delegate_->OnClosed(); } +void StubWindow::PrepareForShutdown() {} + void StubWindow::SetBounds(const gfx::Rect& bounds) { if (bounds_ == bounds) return;
diff --git a/ui/platform_window/stub/stub_window.h b/ui/platform_window/stub/stub_window.h index d4b9be23..4b8d29e 100644 --- a/ui/platform_window/stub/stub_window.h +++ b/ui/platform_window/stub/stub_window.h
@@ -26,6 +26,7 @@ void Show() override; void Hide() override; void Close() override; + void PrepareForShutdown() override; void SetBounds(const gfx::Rect& bounds) override; gfx::Rect GetBounds() override; void SetTitle(const base::string16& title) override;
diff --git a/ui/platform_window/win/win_window.cc b/ui/platform_window/win/win_window.cc index dea56fa2..f2830c1 100644 --- a/ui/platform_window/win/win_window.cc +++ b/ui/platform_window/win/win_window.cc
@@ -74,6 +74,8 @@ Destroy(); } +void WinWindow::PrepareForShutdown() {} + void WinWindow::SetBounds(const gfx::Rect& bounds) { gfx::Rect window_bounds = GetWindowBoundsForClientBounds( GetWindowLong(hwnd(), GWL_STYLE),
diff --git a/ui/platform_window/win/win_window.h b/ui/platform_window/win/win_window.h index 9a734ef..d91d8086 100644 --- a/ui/platform_window/win/win_window.h +++ b/ui/platform_window/win/win_window.h
@@ -28,6 +28,7 @@ void Show() override; void Hide() override; void Close() override; + void PrepareForShutdown() override; void SetBounds(const gfx::Rect& bounds) override; gfx::Rect GetBounds() override; void SetTitle(const base::string16& title) override;
diff --git a/ui/platform_window/x11/x11_window.cc b/ui/platform_window/x11/x11_window.cc index 3c4ee2a..64bd7a8 100644 --- a/ui/platform_window/x11/x11_window.cc +++ b/ui/platform_window/x11/x11_window.cc
@@ -24,6 +24,10 @@ } X11Window::~X11Window() { + X11Window::PrepareForShutdown(); +} + +void X11Window::PrepareForShutdown() { PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); }
diff --git a/ui/platform_window/x11/x11_window.h b/ui/platform_window/x11/x11_window.h index 388aab7..710efa6 100644 --- a/ui/platform_window/x11/x11_window.h +++ b/ui/platform_window/x11/x11_window.h
@@ -20,6 +20,7 @@ ~X11Window() override; // PlatformWindow: + void PrepareForShutdown() override; void SetCursor(PlatformCursor cursor) override; private:
diff --git a/ui/platform_window/x11/x11_window_ozone.cc b/ui/platform_window/x11/x11_window_ozone.cc index c3051cb5..c7a016e4 100644 --- a/ui/platform_window/x11/x11_window_ozone.cc +++ b/ui/platform_window/x11/x11_window_ozone.cc
@@ -16,22 +16,28 @@ namespace ui { -X11WindowOzone::X11WindowOzone(X11EventSourceLibevent* event_source, - X11WindowManagerOzone* window_manager, +X11WindowOzone::X11WindowOzone(X11WindowManagerOzone* window_manager, PlatformWindowDelegate* delegate, const gfx::Rect& bounds) - : X11WindowBase(delegate, bounds), - event_source_(event_source), - window_manager_(window_manager) { - DCHECK(event_source_); + : X11WindowBase(delegate, bounds), window_manager_(window_manager) { DCHECK(window_manager); - event_source_->AddPlatformEventDispatcher(this); - event_source_->AddXEventDispatcher(this); + auto* event_source = X11EventSourceLibevent::GetInstance(); + if (event_source) { + event_source->AddPlatformEventDispatcher(this); + event_source->AddXEventDispatcher(this); + } } X11WindowOzone::~X11WindowOzone() { - event_source_->RemovePlatformEventDispatcher(this); - event_source_->RemoveXEventDispatcher(this); + X11WindowOzone::PrepareForShutdown(); +} + +void X11WindowOzone::PrepareForShutdown() { + auto* event_source = X11EventSourceLibevent::GetInstance(); + if (event_source) { + event_source->RemovePlatformEventDispatcher(this); + event_source->RemoveXEventDispatcher(this); + } } void X11WindowOzone::SetCapture() {
diff --git a/ui/platform_window/x11/x11_window_ozone.h b/ui/platform_window/x11/x11_window_ozone.h index 9f49af4b..4516be2 100644 --- a/ui/platform_window/x11/x11_window_ozone.h +++ b/ui/platform_window/x11/x11_window_ozone.h
@@ -20,13 +20,13 @@ public PlatformEventDispatcher, public XEventDispatcher { public: - X11WindowOzone(X11EventSourceLibevent* event_source, - X11WindowManagerOzone* window_manager, + X11WindowOzone(X11WindowManagerOzone* window_manager, PlatformWindowDelegate* delegate, const gfx::Rect& bounds); ~X11WindowOzone() override; // PlatformWindow: + void PrepareForShutdown() override; void SetCapture() override; void ReleaseCapture() override; void SetCursor(PlatformCursor cursor) override; @@ -39,7 +39,6 @@ bool CanDispatchEvent(const PlatformEvent& event) override; uint32_t DispatchEvent(const PlatformEvent& event) override; - X11EventSourceLibevent* event_source_; X11WindowManagerOzone* window_manager_; DISALLOW_COPY_AND_ASSIGN(X11WindowOzone);