diff --git a/DEPS b/DEPS index b9b6ba5..fd435de 100644 --- a/DEPS +++ b/DEPS
@@ -133,11 +133,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'd425dee662d15a074da981c2fa85d38dc5fd094c', + 'skia_revision': '9e25bb993d819dbd286f6f68d3975354ed388c98', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'bb661bbc49a6e50abdf968530a0472ee8a421eb5', + 'v8_revision': 'b4b310b99bab6da79a53a4c64ee7c1290ea4ae5d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -153,7 +153,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'ae6ebf06c7e85453b91ccd489a6715eb5f013e1b', + 'pdfium_revision': 'cb87127d367c9515d01438c9b369558088683b8c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -200,7 +200,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '72493839e6fd214dca98a9afd0605c01a7a20e05', + 'catapult_revision': '3e4feb80aeab4ce0acf4c959bcc95f544862248e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -434,9 +434,6 @@ 'src/chrome/test/data/xr/webvr_info': Var('chromium_git') + '/external/github.com/toji/webvr.info.git' + '@' + 'c58ae99b9ff9e2aa4c524633519570bf33536248', - 'src/chrome/test/data/xr/webxr_samples': - Var('chromium_git') + '/external/github.com/immersive-web/webxr-samples.git' + '@' + 'cf02f19c4ff6894705a9407722ab52551e010c60', - 'src/ios/third_party/earl_grey/src': { 'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '87ffa7ac2517cc8931e4e6ba11714961cbac6dd7', 'condition': 'checkout_ios', @@ -834,7 +831,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6837707f8009b505eb49ff8323d0a48211fcf255', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8fac969edd875dc6da8d25fbd7f3ccc117a3d83a', 'src/third_party/devtools-node-modules': Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'), @@ -1187,7 +1184,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'c501481303f64664680d953367f5adf5dc8048c0', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '56e48081b4c63e95724a0388322b97f8a0156ac5', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78', @@ -1358,7 +1355,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6f0b34abee8dba611c253738d955c59f703c147a', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '7cca042dd409c08a2a6e2383c39c692626f8a2d9', + Var('webrtc_git') + '/src.git' + '@' + '44125faba5bf646116c5a6335ac46c3b544808e8', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1399,7 +1396,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ca79ffa2937d80c9c79049f77562d5bd886893c6', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@752cd3b2e05004fbf2fb79b0549f024dd5e9112e', 'condition': 'checkout_src_internal', },
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 6783ba18..72ca499 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -728,6 +728,28 @@ True, (), ), + ( + 'StringFromGUID2', + ( + 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.', + 'Use base::win::String16FromGUID instead.' + ), + True, + ( + r'/base/win/win_util_unittest.cc' + ), + ), + ( + 'StringFromCLSID', + ( + 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.', + 'Use base::win::String16FromGUID instead.' + ), + True, + ( + r'/base/win/win_util_unittest.cc' + ), + ), ) @@ -832,6 +854,7 @@ 'build/android/test_runner.pydeps', 'build/android/test_wrapper/logdog_wrapper.pydeps', 'build/protoc_java.pydeps', + 'chrome/android/features/create_stripped_java_factory.pydeps', 'net/tools/testserver/testserver.pydeps', 'third_party/android_platform/development/scripts/stack.pydeps', ] @@ -3286,6 +3309,37 @@ return [] +def _CheckForTooLargeFiles(input_api, output_api): + """Avoid large files, especially binary files, in the repository since + git doesn't scale well for those. They will be in everyone's repo + clones forever, forever making Chromium slower to clone and work + with.""" + + # Uploading files to cloud storage is not trivial so we don't want + # to set the limit too low, but the upper limit for "normal" large + # files seems to be 1-2 MB, with a handful around 5-8 MB, so + # anything over 20 MB is exceptional. + TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB + + too_large_files = [] + for f in input_api.AffectedFiles(): + # Check both added and modified files (but not deleted files). + if f.Action() in ('A', 'M'): + size = input_api.os_path.getsize(f.LocalPath()) + if size > TOO_LARGE_FILE_SIZE_LIMIT: + too_large_files.append("%s: %d bytes" % (f.LocalPath(), size)) + + if too_large_files: + message = ( + 'Do not commit large files to git since git scales badly for those.\n' + + 'Instead put the large files in cloud storage and use DEPS to\n' + + 'fetch them.\n' + '\n'.join(too_large_files) + ) + return [output_api.PresubmitError( + 'Too large files found in commit', long_text=message + '\n')] + else: + return [] + def _AndroidSpecificOnUploadChecks(input_api, output_api): """Groups upload checks that target android code.""" results = [] @@ -3373,6 +3427,7 @@ results.extend(_CheckTranslationScreenshots(input_api, output_api)) results.extend(_CheckCorrectProductNameInMessages(input_api, output_api)) results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api)) + results.extend(_CheckForTooLargeFiles(input_api, output_api)) for f in input_api.AffectedFiles(): path, name = input_api.os_path.split(f.LocalPath())
diff --git a/android_webview/browser/aw_browser_terminator.cc b/android_webview/browser/aw_browser_terminator.cc index ef87bc6..161d23e 100644 --- a/android_webview/browser/aw_browser_terminator.cc +++ b/android_webview/browser/aw_browser_terminator.cc
@@ -51,22 +51,14 @@ } } -void OnRenderProcessGone(content::RenderProcessHost* host) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - std::vector<AwRenderProcessGoneDelegate*> delegates; - GetAwRenderProcessGoneDelegatesForRenderProcess(host, &delegates); - for (auto* delegate : delegates) - delegate->OnRenderProcessGone(host->GetID()); -} - -void OnRenderProcessGoneDetail(content::RenderProcessHost* host, - base::ProcessId child_process_pid, - bool crashed) { +void OnRenderProcessGone(content::RenderProcessHost* host, + base::ProcessId child_process_pid, + bool crashed) { DCHECK_CURRENTLY_ON(BrowserThread::UI); std::vector<AwRenderProcessGoneDelegate*> delegates; GetAwRenderProcessGoneDelegatesForRenderProcess(host, &delegates); for (auto* delegate : delegates) { - if (!delegate->OnRenderProcessGoneDetail(child_process_pid, crashed)) { + if (!delegate->OnRenderProcessGone(child_process_pid, crashed)) { if (crashed) { // Keeps this log unchanged, CTS test uses it to detect crash. std::string message = base::StringPrintf( @@ -102,7 +94,6 @@ const crash_reporter::ChildExitObserver::TerminationInfo& info) { content::RenderProcessHost* rph = content::RenderProcessHost::FromID(info.process_host_id); - OnRenderProcessGone(rph); crash_reporter::CrashMetricsReporter::GetInstance()->ChildProcessExited(info); @@ -113,7 +104,7 @@ LOG(ERROR) << "Renderer process (" << info.pid << ") crash detected (code " << info.crash_signo << ")."; - OnRenderProcessGoneDetail(rph, info.pid, info.is_crashed()); + OnRenderProcessGone(rph, info.pid, info.is_crashed()); } } // namespace android_webview
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc index 1dcdd2d..06e9bda 100644 --- a/android_webview/browser/aw_contents.cc +++ b/android_webview/browser/aw_contents.cc
@@ -94,21 +94,22 @@ #include "ui/gfx/image/image.h" struct AwDrawSWFunctionTable; -using autofill::ContentAutofillDriverFactory; using autofill::AutofillManager; +using autofill::ContentAutofillDriverFactory; using base::android::AttachCurrentThread; using base::android::ConvertJavaStringToUTF16; using base::android::ConvertJavaStringToUTF8; using base::android::ConvertUTF16ToJavaString; using base::android::ConvertUTF8ToJavaString; +using base::android::HasException; using base::android::JavaParamRef; using base::android::JavaRef; using base::android::ScopedJavaGlobalRef; using base::android::ScopedJavaLocalRef; -using navigation_interception::InterceptNavigationDelegate; using content::BrowserThread; using content::RenderFrameHost; using content::WebContents; +using navigation_interception::InterceptNavigationDelegate; namespace android_webview { @@ -1492,25 +1493,15 @@ aw_render_process->GetJavaObject()); } -void AwContents::OnRenderProcessGone(int child_process_id) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); - if (obj.is_null()) - return; - - Java_AwContents_onRenderProcessGone(env, obj, child_process_id); -} - -bool AwContents::OnRenderProcessGoneDetail(int child_process_id, bool crashed) { +bool AwContents::OnRenderProcessGone(int child_process_id, bool crashed) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); if (obj.is_null()) return false; - return Java_AwContents_onRenderProcessGoneDetail(env, obj, child_process_id, - crashed); + return Java_AwContents_onRenderProcessGone(env, obj, child_process_id, + crashed); } } // namespace android_webview
diff --git a/android_webview/browser/aw_contents.h b/android_webview/browser/aw_contents.h index 7776b46f..77d5396 100644 --- a/android_webview/browser/aw_contents.h +++ b/android_webview/browser/aw_contents.h
@@ -365,8 +365,7 @@ const base::android::JavaParamRef<jobject>& callback); // AwRenderProcessGoneDelegate overrides - void OnRenderProcessGone(int child_process_id) override; - bool OnRenderProcessGoneDetail(int child_process_id, bool crashed) override; + bool OnRenderProcessGone(int child_process_id, bool crashed) override; private: void InitAutofillIfNecessary(bool autocomplete_enabled);
diff --git a/android_webview/browser/aw_render_process_gone_delegate.h b/android_webview/browser/aw_render_process_gone_delegate.h index fb8661b..e71629a 100644 --- a/android_webview/browser/aw_render_process_gone_delegate.h +++ b/android_webview/browser/aw_render_process_gone_delegate.h
@@ -19,15 +19,8 @@ static AwRenderProcessGoneDelegate* FromWebContents( content::WebContents* web_contents); - // Notify render process's termination is detected. - virtual void OnRenderProcessGone(int child_process_id) = 0; - - // Notify if render process crashed or was killed, this callback is - // invoked after OnRenderProcessGone() because the detail information - // can't be obtained immediately when render process's termination is - // detected. - virtual bool OnRenderProcessGoneDetail(int child_process_id, - bool crashed) = 0; + // Notify if render process crashed or was killed. + virtual bool OnRenderProcessGone(int child_process_id, bool crashed) = 0; protected: AwRenderProcessGoneDelegate() {}
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index 87de557..d00d5f84 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -460,10 +460,6 @@ // Do not use directly, call isDestroyed() instead. private boolean mIsDestroyed; - // True if this AwContents is in no operation state. - // Do not use directly, call isNoOperation() instead. - private boolean mIsNoOperation; - private AutofillProvider mAutofillProvider; private static String sCurrentLocales = ""; @@ -732,12 +728,12 @@ @Override public void scrollNativeTo(int x, int y) { - if (!isDestroyedOrNoOperation(NO_WARN)) nativeScrollTo(mNativeAwContents, x, y); + if (!isDestroyed(NO_WARN)) nativeScrollTo(mNativeAwContents, x, y); } @Override public void smoothScroll(int targetX, int targetY, long durationMs) { - if (!isDestroyedOrNoOperation(NO_WARN)) { + if (!isDestroyed(NO_WARN)) { nativeSmoothScroll(mNativeAwContents, targetX, targetY, durationMs); } } @@ -810,7 +806,7 @@ boolean visibleRectEmpty = getGlobalVisibleRect().isEmpty(); final boolean visible = mIsViewVisible && mIsWindowVisible && !visibleRectEmpty; ThreadUtils.runOnUiThreadBlocking(() -> { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; if (level >= TRIM_MEMORY_MODERATE) { if (mDrawFunctor != null) { mDrawFunctor.trimMemory(); @@ -895,7 +891,7 @@ mNativeDrawFunctorFactory = nativeDrawFunctorFactory; mContentsClient = contentsClient; mContentsClient.getCallbackHelper().setCancelCallbackPoller( - () -> AwContents.this.isDestroyedOrNoOperation(NO_WARN)); + () -> AwContents.this.isDestroyed(NO_WARN)); mAwViewMethods = new AwViewMethodsImpl(); mFullScreenTransitionsState = new FullScreenTransitionsState( mContainerView, mInternalAccessAdapter, mAwViewMethods); @@ -914,7 +910,7 @@ AwSettings.ZoomSupportChangeListener zoomListener = (supportsDoubleTapZoom, supportsMultiTouchZoom) -> { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; GestureListenerManager gestureManager = GestureListenerManager.fromWebContents(mWebContents); gestureManager.updateDoubleTapSupport(supportsDoubleTapZoom); @@ -984,7 +980,7 @@ */ View enterFullScreen() { assert !isFullScreen(); - if (isDestroyedOrNoOperation(NO_WARN)) return null; + if (isDestroyed(NO_WARN)) return null; // Detach to tear down the GL functor if this is still associated with the old // container view. It will be recreated during the next call to onDraw attached to @@ -1016,7 +1012,7 @@ * Called when the app has requested to exit fullscreen. */ void requestExitFullscreen() { - if (!isDestroyedOrNoOperation(NO_WARN)) mWebContents.exitFullscreen(); + if (!isDestroyed(NO_WARN)) mWebContents.exitFullscreen(); } /** @@ -1024,7 +1020,7 @@ * in the WebView. */ void exitFullScreen() { - if (!isFullScreen() || isDestroyedOrNoOperation(NO_WARN)) { + if (!isFullScreen() || isDestroyed(NO_WARN)) { // exitFullScreen() can be called without a prior call to enterFullScreen() if a // "misbehave" app overrides onShowCustomView but does not add the custom view to // the window. Exiting avoids a crash. @@ -1055,7 +1051,7 @@ mContainerView.requestFocus(); } - if (!isDestroyedOrNoOperation(NO_WARN)) { + if (!isDestroyed(NO_WARN)) { nativeRestoreScrollAfterTransition(mNativeAwContents, mFullScreenTransitionsState.getScrollX(), mFullScreenTransitionsState.getScrollY()); @@ -1284,7 +1280,7 @@ * provide the AwContents to host the pop up content. */ public void supplyContentsForPopup(AwContents newContents) { - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; long popupNativeAwContents = nativeReleasePopupAwContents(mNativeAwContents); if (popupNativeAwContents == 0) { Log.w(TAG, "Popup WebView bind failed: no pending content."); @@ -1302,7 +1298,7 @@ // Recap: supplyContentsForPopup() is called on the parent window's content, this method is // called on the popup window's content. private void receivePopupContents(long popupNativeAwContents) { - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; mDeferredShouldOverrideUrlLoadingIsPendingForPopup = true; // Save existing view state. final boolean wasAttached = mIsAttachedToWindow; @@ -1376,18 +1372,7 @@ @VisibleForTesting @CalledByNative - protected void onRenderProcessGone(int childProcessID) { - // This is the first callback we got for render process gone, we can't destroy the WebView - // now because we need to get next callback onRenderProcessGoneWithDetail() to know whether - // render process crashed or was killed. - // However, we should make WebView no operation to avoid being in weird states. - // TODO: We might be able to combine destroyed and no operation states. - mIsNoOperation = true; - } - - @VisibleForTesting - @CalledByNative - protected boolean onRenderProcessGoneDetail(int childProcessID, boolean crashed) { + protected boolean onRenderProcessGone(int childProcessID, boolean crashed) { if (isDestroyed(NO_WARN)) return true; return mContentsClient.onRenderProcessGone(new AwRenderProcessGoneDetail( crashed, nativeGetEffectivePriority(mNativeAwContents))); @@ -1399,14 +1384,6 @@ return nativeGetEffectivePriority(mNativeAwContents); } - private boolean isNoOperation() { - return mIsNoOperation; - } - - private boolean isDestroyedOrNoOperation(int warnIfDestroyed) { - return isDestroyed(warnIfDestroyed) || isNoOperation(); - } - /** * Destroys this object and deletes its native counterpart. */ @@ -1427,7 +1404,6 @@ // Need to call detach to avoid leaks because the real detach later will be ignored. onDetachedFromWindow(); } - mIsNoOperation = true; mIsDestroyed = true; PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> destroyNatives()); } @@ -1505,7 +1481,7 @@ } public AwPdfExporter getPdfExporter() { - if (isDestroyedOrNoOperation(WARN)) return null; + if (isDestroyed(WARN)) return null; if (mAwPdfExporter == null) { mAwPdfExporter = new AwPdfExporter(mContainerView); nativeCreatePdfExporter(mNativeAwContents, mAwPdfExporter); @@ -1541,7 +1517,7 @@ * to ensure backwards compatible behavior. */ public void disableJavascriptInterfacesInspection() { - if (!isDestroyedOrNoOperation(WARN)) { + if (!isDestroyed(WARN)) { getJavascriptInjector().setAllowInspection(false); } } @@ -1592,18 +1568,18 @@ } public int getContentHeightCss() { - if (isDestroyedOrNoOperation(WARN)) return 0; + if (isDestroyed(WARN)) return 0; return (int) Math.ceil(mContentHeightDip); } public int getContentWidthCss() { - if (isDestroyedOrNoOperation(WARN)) return 0; + if (isDestroyed(WARN)) return 0; return (int) Math.ceil(mContentWidthDip); } public Picture capturePicture() { if (TRACE) Log.i(TAG, "%s capturePicture", this); - if (isDestroyedOrNoOperation(WARN)) return null; + if (isDestroyed(WARN)) return null; return new AwPicture(nativeCapturePicture(mNativeAwContents, mScrollOffsetManager.computeHorizontalScrollRange(), mScrollOffsetManager.computeVerticalScrollRange())); @@ -1611,7 +1587,7 @@ public void clearView() { if (TRACE) Log.i(TAG, "%s clearView", this); - if (!isDestroyedOrNoOperation(WARN)) nativeClearView(mNativeAwContents); + if (!isDestroyed(WARN)) nativeClearView(mNativeAwContents); } /** @@ -1621,7 +1597,7 @@ */ public void enableOnNewPicture(boolean enabled, boolean invalidationOnly) { if (TRACE) Log.i(TAG, "%s enableOnNewPicture=%s", this, enabled); - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; if (invalidationOnly) { mPictureListenerContentProvider = null; } else if (enabled && mPictureListenerContentProvider == null) { @@ -1632,30 +1608,30 @@ public void findAllAsync(String searchString) { if (TRACE) Log.i(TAG, "%s findAllAsync", this); - if (!isDestroyedOrNoOperation(WARN)) nativeFindAllAsync(mNativeAwContents, searchString); + if (!isDestroyed(WARN)) nativeFindAllAsync(mNativeAwContents, searchString); } public void findNext(boolean forward) { if (TRACE) Log.i(TAG, "%s findNext", this); - if (!isDestroyedOrNoOperation(WARN)) nativeFindNext(mNativeAwContents, forward); + if (!isDestroyed(WARN)) nativeFindNext(mNativeAwContents, forward); } public void clearMatches() { if (TRACE) Log.i(TAG, "%s clearMatches", this); - if (!isDestroyedOrNoOperation(WARN)) nativeClearMatches(mNativeAwContents); + if (!isDestroyed(WARN)) nativeClearMatches(mNativeAwContents); } /** * @return load progress of the WebContents. */ public int getMostRecentProgress() { - if (isDestroyedOrNoOperation(WARN)) return 0; + if (isDestroyed(WARN)) return 0; // WebContentsDelegateAndroid conveniently caches the most recent notified value for us. return mWebContentsDelegate.getMostRecentProgress(); } public Bitmap getFavicon() { - if (isDestroyedOrNoOperation(WARN)) return null; + if (isDestroyed(WARN)) return null; return mFavicon; } @@ -1670,7 +1646,7 @@ } PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> { - if (!isDestroyedOrNoOperation(NO_WARN)) { + if (!isDestroyed(NO_WARN)) { nativeAddVisitedLinks(mNativeAwContents, value); } }); @@ -1683,7 +1659,7 @@ */ public void loadUrl(String url, Map<String, String> additionalHttpHeaders) { if (TRACE) Log.i(TAG, "%s loadUrl(extra headers)=%s", this, url); - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; // Early out to match old WebView implementation if (url == null) { return; @@ -1718,7 +1694,7 @@ */ public void loadUrl(String url) { if (TRACE) Log.i(TAG, "%s loadUrl=%s", this, url); - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; // Early out to match old WebView implementation if (url == null) { return; @@ -1731,7 +1707,7 @@ */ public void postUrl(String url, byte[] postData) { if (TRACE) Log.i(TAG, "%s postUrl=%s", this, url); - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; LoadUrlParams params = LoadUrlParams.createLoadHttpPostParams(url, postData); Map<String, String> headers = new HashMap<String, String>(); headers.put("Content-Type", "application/x-www-form-urlencoded"); @@ -1779,7 +1755,7 @@ */ public void loadData(String data, String mimeType, String encoding) { if (TRACE) Log.i(TAG, "%s loadData", this); - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; if (data != null && data.contains("#")) { RecordHistogram.recordBooleanHistogram(DATA_URI_HISTOGRAM_NAME, true); if (!BuildInfo.targetsAtLeastQ() && !isBase64Encoded(encoding)) { @@ -1854,7 +1830,7 @@ public void loadDataWithBaseURL( String baseUrl, String data, String mimeType, String encoding, String historyUrl) { if (TRACE) Log.i(TAG, "%s loadDataWithBaseURL=%s", this, baseUrl); - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; data = fixupData(data); mimeType = fixupMimeType(mimeType); @@ -1983,7 +1959,7 @@ * @return The URL of the current page or null if it's empty. */ public String getUrl() { - if (isDestroyedOrNoOperation(WARN)) return null; + if (isDestroyed(WARN)) return null; String url = mWebContents.getVisibleUrl(); if (url == null || url.trim().isEmpty()) return null; return url; @@ -1996,7 +1972,7 @@ * @return The URL of the current page or null if it's empty. */ public String getLastCommittedUrl() { - if (isDestroyedOrNoOperation(NO_WARN)) return null; + if (isDestroyed(NO_WARN)) return null; String url = mWebContents.getLastCommittedUrl(); if (url == null || url.trim().isEmpty()) return null; return url; @@ -2008,7 +1984,7 @@ public void setBackgroundColor(int color) { mBaseBackgroundColor = color; - if (!isDestroyedOrNoOperation(WARN)) nativeSetBackgroundColor(mNativeAwContents, color); + if (!isDestroyed(WARN)) nativeSetBackgroundColor(mNativeAwContents, color); } /** @@ -2022,8 +1998,7 @@ // Do not ask the WebContents for the background color, as it will always // report white prior to initial navigation or post destruction, whereas we want // to use the client supplied base value in those cases. - if (isDestroyedOrNoOperation(NO_WARN) - || !mContentsClient.isCachedRendererBackgroundColorValid()) { + if (isDestroyed(NO_WARN) || !mContentsClient.isCachedRendererBackgroundColorValid()) { return mBaseBackgroundColor; } return mContentsClient.getCachedRendererBackgroundColor(); @@ -2119,7 +2094,7 @@ * @see android.webkit.WebView#requestChildRectangleOnScreen(View, Rect, boolean) */ public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) { - if (isDestroyedOrNoOperation(WARN)) return false; + if (isDestroyed(WARN)) return false; return mScrollOffsetManager.requestChildRectangleOnScreen( child.getLeft() - child.getScrollX(), child.getTop() - child.getScrollY(), rect, immediate); @@ -2179,7 +2154,7 @@ */ public void stopLoading() { if (TRACE) Log.i(TAG, "%s stopLoading", this); - if (!isDestroyedOrNoOperation(WARN)) mWebContents.stop(); + if (!isDestroyed(WARN)) mWebContents.stop(); } /** @@ -2187,14 +2162,14 @@ */ public void reload() { if (TRACE) Log.i(TAG, "%s reload", this); - if (!isDestroyedOrNoOperation(WARN)) mNavigationController.reload(true); + if (!isDestroyed(WARN)) mNavigationController.reload(true); } /** * @see android.webkit.WebView#canGoBack() */ public boolean canGoBack() { - return isDestroyedOrNoOperation(WARN) ? false : mNavigationController.canGoBack(); + return isDestroyed(WARN) ? false : mNavigationController.canGoBack(); } /** @@ -2202,14 +2177,14 @@ */ public void goBack() { if (TRACE) Log.i(TAG, "%s goBack", this); - if (!isDestroyedOrNoOperation(WARN)) mNavigationController.goBack(); + if (!isDestroyed(WARN)) mNavigationController.goBack(); } /** * @see android.webkit.WebView#canGoForward() */ public boolean canGoForward() { - return isDestroyedOrNoOperation(WARN) ? false : mNavigationController.canGoForward(); + return isDestroyed(WARN) ? false : mNavigationController.canGoForward(); } /** @@ -2217,14 +2192,14 @@ */ public void goForward() { if (TRACE) Log.i(TAG, "%s goForward", this); - if (!isDestroyedOrNoOperation(WARN)) mNavigationController.goForward(); + if (!isDestroyed(WARN)) mNavigationController.goForward(); } /** * @see android.webkit.WebView#canGoBackOrForward(int) */ public boolean canGoBackOrForward(int steps) { - return isDestroyedOrNoOperation(WARN) ? false : mNavigationController.canGoToOffset(steps); + return isDestroyed(WARN) ? false : mNavigationController.canGoToOffset(steps); } /** @@ -2232,7 +2207,7 @@ */ public void goBackOrForward(int steps) { if (TRACE) Log.i(TAG, "%s goBackOrForwad=%d", this, steps); - if (!isDestroyedOrNoOperation(WARN)) mNavigationController.goToOffset(steps); + if (!isDestroyed(WARN)) mNavigationController.goToOffset(steps); } /** @@ -2240,7 +2215,7 @@ */ public void pauseTimers() { if (TRACE) Log.i(TAG, "%s pauseTimers", this); - if (!isDestroyedOrNoOperation(WARN)) { + if (!isDestroyed(WARN)) { ContentViewStatics.setWebKitSharedTimersSuspended(true); } } @@ -2250,7 +2225,7 @@ */ public void resumeTimers() { if (TRACE) Log.i(TAG, "%s resumeTimers", this); - if (!isDestroyedOrNoOperation(WARN)) { + if (!isDestroyed(WARN)) { ContentViewStatics.setWebKitSharedTimersSuspended(false); } } @@ -2260,7 +2235,7 @@ */ public void onPause() { if (TRACE) Log.i(TAG, "%s onPause", this); - if (mIsPaused || isDestroyedOrNoOperation(NO_WARN)) return; + if (mIsPaused || isDestroyed(NO_WARN)) return; mIsPaused = true; nativeSetIsPaused(mNativeAwContents, mIsPaused); @@ -2273,7 +2248,7 @@ */ public void onResume() { if (TRACE) Log.i(TAG, "%s onResume", this); - if (!mIsPaused || isDestroyedOrNoOperation(NO_WARN)) return; + if (!mIsPaused || isDestroyed(NO_WARN)) return; mIsPaused = false; nativeSetIsPaused(mNativeAwContents, mIsPaused); updateWebContentsVisibility(); @@ -2283,7 +2258,7 @@ * @see android.webkit.WebView#isPaused() */ public boolean isPaused() { - return isDestroyedOrNoOperation(WARN) ? false : mIsPaused; + return isDestroyed(WARN) ? false : mIsPaused; } /** @@ -2322,13 +2297,13 @@ */ public void clearCache(boolean includeDiskFiles) { if (TRACE) Log.i(TAG, "%s clearCache", this); - if (!isDestroyedOrNoOperation(WARN)) nativeClearCache(mNativeAwContents, includeDiskFiles); + if (!isDestroyed(WARN)) nativeClearCache(mNativeAwContents, includeDiskFiles); } @VisibleForTesting public void killRenderProcess() { if (TRACE) Log.i(TAG, "%s killRenderProcess", this); - if (isDestroyedOrNoOperation(WARN)) { + if (isDestroyed(WARN)) { throw new IllegalStateException("killRenderProcess() shouldn't be invoked after render" + " process is gone or webview is destroyed"); } @@ -2336,7 +2311,7 @@ } public void documentHasImages(Message message) { - if (!isDestroyedOrNoOperation(WARN)) nativeDocumentHasImages(mNativeAwContents, message); + if (!isDestroyed(WARN)) nativeDocumentHasImages(mNativeAwContents, message); } public void saveWebArchive( @@ -2363,7 +2338,7 @@ } public String getOriginalUrl() { - if (isDestroyedOrNoOperation(WARN)) return null; + if (isDestroyed(WARN)) return null; NavigationHistory history = mNavigationController.getNavigationHistory(); int currentIndex = history.getCurrentEntryIndex(); if (currentIndex >= 0 && currentIndex < history.getEntryCount()) { @@ -2376,14 +2351,14 @@ * @see NavigationController#getNavigationHistory() */ public NavigationHistory getNavigationHistory() { - return isDestroyedOrNoOperation(WARN) ? null : mNavigationController.getNavigationHistory(); + return isDestroyed(WARN) ? null : mNavigationController.getNavigationHistory(); } /** * @see android.webkit.WebView#getTitle() */ public String getTitle() { - return isDestroyedOrNoOperation(WARN) ? null : mWebContents.getTitle(); + return isDestroyed(WARN) ? null : mWebContents.getTitle(); } /** @@ -2391,14 +2366,15 @@ */ public void clearHistory() { if (TRACE) Log.i(TAG, "%s clearHistory", this); - if (!isDestroyedOrNoOperation(WARN)) mNavigationController.clearHistory(); + if (!isDestroyed(WARN)) mNavigationController.clearHistory(); } /** * @see android.webkit.WebView#getCertificate() */ public SslCertificate getCertificate() { - return isDestroyedOrNoOperation(WARN) ? null + return isDestroyed(WARN) + ? null : SslUtil.getCertificateFromDerBytes(nativeGetCertificate(mNativeAwContents)); } @@ -2407,7 +2383,7 @@ */ public void clearSslPreferences() { if (TRACE) Log.i(TAG, "%s clearSslPreferences", this); - if (!isDestroyedOrNoOperation(WARN)) mNavigationController.clearSslPreferences(); + if (!isDestroyed(WARN)) mNavigationController.clearSslPreferences(); } /** @@ -2418,7 +2394,7 @@ */ public HitTestData getLastHitTestResult() { if (TRACE) Log.i(TAG, "%s getLastHitTestResult", this); - if (isDestroyedOrNoOperation(WARN)) return null; + if (isDestroyed(WARN)) return null; nativeUpdateLastHitTestData(mNativeAwContents); return mPossiblyStaleHitTestData; } @@ -2428,7 +2404,7 @@ */ public void requestFocusNodeHref(Message msg) { if (TRACE) Log.i(TAG, "%s requestFocusNodeHref", this); - if (msg == null || isDestroyedOrNoOperation(WARN)) return; + if (msg == null || isDestroyed(WARN)) return; nativeUpdateLastHitTestData(mNativeAwContents); Bundle data = msg.getData(); @@ -2447,7 +2423,7 @@ */ public void requestImageRef(Message msg) { if (TRACE) Log.i(TAG, "%s requestImageRef", this); - if (msg == null || isDestroyedOrNoOperation(WARN)) return; + if (msg == null || isDestroyed(WARN)) return; nativeUpdateLastHitTestData(mNativeAwContents); Bundle data = msg.getData(); @@ -2472,7 +2448,7 @@ * the screen density factor. See CTS WebViewTest.testSetInitialScale. */ public float getScale() { - if (isDestroyedOrNoOperation(WARN)) return 1; + if (isDestroyed(WARN)) return 1; return mPageScaleFactor * getDeviceScaleFactor(); } @@ -2481,7 +2457,7 @@ */ public void flingScroll(int velocityX, int velocityY) { if (TRACE) Log.i(TAG, "%s flingScroll", this); - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; mWebContents.getEventForwarder().startFling( SystemClock.uptimeMillis(), -velocityX, -velocityY, false, true); } @@ -2491,7 +2467,7 @@ */ public boolean pageUp(boolean top) { if (TRACE) Log.i(TAG, "%s pageUp", this); - if (isDestroyedOrNoOperation(WARN)) return false; + if (isDestroyed(WARN)) return false; return mScrollOffsetManager.pageUp(top); } @@ -2500,7 +2476,7 @@ */ public boolean pageDown(boolean bottom) { if (TRACE) Log.i(TAG, "%s pageDown", this); - if (isDestroyedOrNoOperation(WARN)) return false; + if (isDestroyed(WARN)) return false; return mScrollOffsetManager.pageDown(bottom); } @@ -2510,7 +2486,7 @@ // This method uses the term 'zoom' for legacy reasons, but relates // to what chrome calls the 'page scale factor'. public boolean canZoomIn() { - if (isDestroyedOrNoOperation(WARN)) return false; + if (isDestroyed(WARN)) return false; final float zoomInExtent = mMaxPageScaleFactor - mPageScaleFactor; return zoomInExtent > ZOOM_CONTROLS_EPSILON; } @@ -2521,7 +2497,7 @@ // This method uses the term 'zoom' for legacy reasons, but relates // to what chrome calls the 'page scale factor'. public boolean canZoomOut() { - if (isDestroyedOrNoOperation(WARN)) return false; + if (isDestroyed(WARN)) return false; final float zoomOutExtent = mPageScaleFactor - mMinPageScaleFactor; return zoomOutExtent > ZOOM_CONTROLS_EPSILON; } @@ -2558,7 +2534,7 @@ // This method uses the term 'zoom' for legacy reasons, but relates // to what chrome calls the 'page scale factor'. public void zoomBy(float delta) { - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; if (delta < 0.01f || delta > 100.0f) { throw new IllegalStateException("zoom delta value outside [0.01, 100] range."); } @@ -2570,14 +2546,14 @@ */ public void invokeZoomPicker() { if (TRACE) Log.i(TAG, "%s invokeZoomPicker", this); - if (!isDestroyedOrNoOperation(WARN)) mZoomControls.invokeZoomPicker(); + if (!isDestroyed(WARN)) mZoomControls.invokeZoomPicker(); } /** * @see android.webkit.WebView#preauthorizePermission(Uri, long) */ public void preauthorizePermission(Uri origin, long resources) { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; nativePreauthorizePermission(mNativeAwContents, origin.toString(), resources); } @@ -2586,7 +2562,7 @@ */ public void evaluateJavaScript(String script, final Callback<String> callback) { if (TRACE) Log.i(TAG, "%s evaluateJavascript=%s", this, script); - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; JavaScriptCallback jsCallback = null; if (callback != null) { jsCallback = jsonResult -> { @@ -2603,7 +2579,7 @@ public void evaluateJavaScriptForTests(String script, final Callback<String> callback) { if (TRACE) Log.i(TAG, "%s evaluateJavascriptForTests=%s", this, script); - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; JavaScriptCallback jsCallback = null; if (callback != null) { jsCallback = jsonResult -> callback.onResult(jsonResult); @@ -2614,7 +2590,7 @@ public void postMessageToFrame( String frameName, String message, String targetOrigin, MessagePort[] sentPorts) { - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; mWebContents.postMessageToFrame(frameName, message, null, targetOrigin, sentPorts); } @@ -2623,12 +2599,12 @@ */ public MessagePort[] createMessageChannel() { if (TRACE) Log.i(TAG, "%s createMessageChannel", this); - if (isDestroyedOrNoOperation(WARN)) return null; + if (isDestroyed(WARN)) return null; return MessagePort.createPair(); } public boolean hasAccessedInitialDocument() { - if (isDestroyedOrNoOperation(NO_WARN)) return false; + if (isDestroyed(NO_WARN)) return false; return mWebContents.hasAccessedInitialDocument(); } @@ -2638,7 +2614,7 @@ @TargetApi(Build.VERSION_CODES.M) public void onProvideVirtualStructure(ViewStructure structure) { - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; if (!mWebContentsObserver.didEverCommitNavigation()) { // TODO(sgurun) write a test case for this condition crbug/605251 structure.setChildCount(0); @@ -2697,7 +2673,7 @@ } public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; if (requestCode == PROCESS_TEXT_REQUEST_CODE) { SelectionPopupController.fromWebContents(mWebContents) .onReceivedProcessTextResult(resultCode, data); @@ -2724,8 +2700,7 @@ * @see android.view.View#onGenericMotionEvent() */ public boolean onGenericMotionEvent(MotionEvent event) { - return isDestroyedOrNoOperation(NO_WARN) ? false - : mAwViewMethods.onGenericMotionEvent(event); + return isDestroyed(NO_WARN) ? false : mAwViewMethods.onGenericMotionEvent(event); } /** @@ -2808,7 +2783,7 @@ private void setViewVisibilityInternal(boolean visible) { mIsViewVisible = visible; - if (!isDestroyedOrNoOperation(NO_WARN)) { + if (!isDestroyed(NO_WARN)) { nativeSetViewVisibility(mNativeAwContents, mIsViewVisible); } postUpdateWebContentsVisibility(); @@ -2818,7 +2793,7 @@ mInvalidateRootViewOnNextDraw |= Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP && visible && !mIsWindowVisible; mIsWindowVisible = visible; - if (!isDestroyedOrNoOperation(NO_WARN)) { + if (!isDestroyed(NO_WARN)) { nativeSetWindowVisibility(mNativeAwContents, mIsWindowVisible); } postUpdateWebContentsVisibility(); @@ -2842,7 +2817,7 @@ private void updateWebContentsVisibility() { mIsUpdateVisibilityTaskPending = false; - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; boolean contentVisible = nativeIsVisible(mNativeAwContents); if (contentVisible && !mIsContentVisible) { @@ -2862,7 +2837,7 @@ */ @VisibleForTesting public boolean isPageVisible() { - if (isDestroyedOrNoOperation(NO_WARN)) return mIsContentVisible; + if (isDestroyed(NO_WARN)) return mIsContentVisible; return nativeIsVisible(mNativeAwContents); } @@ -2877,7 +2852,7 @@ */ public boolean saveState(Bundle outState) { if (TRACE) Log.i(TAG, "%s saveState", this); - if (isDestroyedOrNoOperation(WARN) || outState == null) return false; + if (isDestroyed(WARN) || outState == null) return false; byte[] state = nativeGetOpaqueState(mNativeAwContents); if (state == null) return false; @@ -2893,7 +2868,7 @@ */ public boolean restoreState(Bundle inState) { if (TRACE) Log.i(TAG, "%s restoreState", this); - if (isDestroyedOrNoOperation(WARN) || inState == null) return false; + if (isDestroyed(WARN) || inState == null) return false; byte[] state = inState.getByteArray(SAVE_RESTORE_STATE_KEY); if (state == null) return false; @@ -2915,7 +2890,7 @@ @SuppressLint("NewApi") // JavascriptInterface requires API level 17. public void addJavascriptInterface(Object object, String name) { if (TRACE) Log.i(TAG, "%s addJavascriptInterface=%s", this, name); - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; Class<? extends Annotation> requiredAnnotation = null; if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) { requiredAnnotation = JavascriptInterface.class; @@ -2929,7 +2904,7 @@ */ public void removeJavascriptInterface(String interfaceName) { if (TRACE) Log.i(TAG, "%s removeInterface=%s", this, interfaceName); - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; getJavascriptInjector().removeInterface(interfaceName); } @@ -2945,9 +2920,7 @@ } public boolean supportsAccessibilityAction(int action) { - return isDestroyedOrNoOperation(WARN) - ? false - : getWebContentsAccessibility().supportsAction(action); + return isDestroyed(WARN) ? false : getWebContentsAccessibility().supportsAction(action); } /** @@ -2969,7 +2942,7 @@ public void setNetworkAvailable(boolean networkUp) { if (TRACE) Log.i(TAG, "%s setNetworkAvailable=%s", this, networkUp); - if (!isDestroyedOrNoOperation(WARN)) { + if (!isDestroyed(WARN)) { // For backward compatibility when an app uses this API disable the // Network Information API to prevent inconsistencies, // see crbug.com/520088. @@ -3057,7 +3030,7 @@ } public AwRenderProcess getRenderProcess() { - if (isDestroyedOrNoOperation(WARN)) { + if (isDestroyed(WARN)) { return null; } return nativeGetRenderProcess(mNativeAwContents); @@ -3108,13 +3081,13 @@ } public void invokeGeolocationCallback(boolean value, String requestingFrame) { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; nativeInvokeGeolocationCallback(mNativeAwContents, value, requestingFrame); } @CalledByNative private void onGeolocationPermissionsShowPrompt(String origin) { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; AwGeolocationPermissions permissions = mBrowserContext.getGeolocationPermissions(); // Reject if geoloaction is disabled, or the origin has a retained deny if (!mSettings.getGeolocationEnabled()) { @@ -3170,7 +3143,7 @@ @CalledByNative public void invokeVisualStateCallback( final VisualStateCallback callback, final long requestId) { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; // Posting avoids invoking the callback inside invoking_composite_ // (see synchronous_compositor_impl.cc and crbug/452530). PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> callback.onComplete(requestId)); @@ -3328,7 +3301,7 @@ public void evaluateJavaScriptOnInterstitialForTesting( String script, final Callback<String> callback) { if (TRACE) Log.i(TAG, "%s evaluateJavaScriptOnInterstitialForTesting=%s", this, script); - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; JavaScriptCallback jsCallback = null; if (callback != null) { jsCallback = jsonResult -> callback.onResult(jsonResult); @@ -3375,7 +3348,7 @@ } private void saveWebArchiveInternal(String path, final Callback<String> callback) { - if (path == null || isDestroyedOrNoOperation(WARN)) { + if (path == null || isDestroyed(WARN)) { if (callback == null) return; PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> callback.onResult(null)); @@ -3420,14 +3393,14 @@ @Override public void extractSmartClipData(int x, int y, int width, int height) { - if (!isDestroyedOrNoOperation(WARN)) { + if (!isDestroyed(WARN)) { mWebContents.requestSmartClipExtract(x, y, width, height); } } @Override public void setSmartClipResultHandler(final Handler resultHandler) { - if (isDestroyedOrNoOperation(WARN)) return; + if (isDestroyed(WARN)) return; mWebContents.setSmartClipResultHandler(resultHandler); } @@ -3435,7 +3408,7 @@ protected void insertVisualStateCallbackIfNotDestroyed( long requestId, VisualStateCallback callback) { if (TRACE) Log.i(TAG, "%s insertVisualStateCallbackIfNotDestroyed", this); - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; nativeInsertVisualStateCallback(mNativeAwContents, requestId, callback); } @@ -3467,7 +3440,7 @@ @SuppressLint("DrawAllocation") // For new AwFunctor. @Override public void onDraw(Canvas canvas) { - if (isDestroyedOrNoOperation(NO_WARN)) { + if (isDestroyed(NO_WARN)) { TraceEvent.instant("EarlyOut_destroyed"); canvas.drawColor(getEffectiveBackgroundColor()); return; @@ -3552,7 +3525,7 @@ @Override public void requestFocus() { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; if (!mContainerView.isInTouchMode() && mSettings.shouldFocusFirstNode()) { nativeFocusFirstNode(mNativeAwContents); } @@ -3573,28 +3546,27 @@ @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { - return isDestroyedOrNoOperation(NO_WARN) + return isDestroyed(NO_WARN) ? null : ImeAdapter.fromWebContents(mWebContents).onCreateInputConnection(outAttrs); } @Override public boolean onDragEvent(DragEvent event) { - return isDestroyedOrNoOperation(NO_WARN) + return isDestroyed(NO_WARN) ? false : mWebContents.getEventForwarder().onDragEvent(event, mContainerView); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - return isDestroyedOrNoOperation(NO_WARN) - ? false - : mWebContents.getEventForwarder().onKeyUp(keyCode, event); + return isDestroyed(NO_WARN) ? false + : mWebContents.getEventForwarder().onKeyUp(keyCode, event); } @Override public boolean dispatchKeyEvent(KeyEvent event) { - if (isDestroyedOrNoOperation(NO_WARN)) return false; + if (isDestroyed(NO_WARN)) return false; if (isDpadEvent(event)) { mSettings.setSpatialNavigationEnabled(true); } @@ -3613,7 +3585,7 @@ @Override public boolean onTouchEvent(MotionEvent event) { - if (isDestroyedOrNoOperation(NO_WARN)) return false; + if (isDestroyed(NO_WARN)) return false; if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { mSettings.setSpatialNavigationEnabled(false); } @@ -3652,21 +3624,20 @@ @Override public boolean onHoverEvent(MotionEvent event) { - return isDestroyedOrNoOperation(NO_WARN) - ? false - : mWebContents.getEventForwarder().onHoverEvent(event); + return isDestroyed(NO_WARN) ? false + : mWebContents.getEventForwarder().onHoverEvent(event); } @Override public boolean onGenericMotionEvent(MotionEvent event) { - return isDestroyedOrNoOperation(NO_WARN) + return isDestroyed(NO_WARN) ? false : mWebContents.getEventForwarder().onGenericMotionEvent(event); } @Override public void onConfigurationChanged(Configuration newConfig) { - if (!isDestroyedOrNoOperation(NO_WARN)) { + if (!isDestroyed(NO_WARN)) { mViewEventSink.onConfigurationChanged(newConfig); mInternalAccessAdapter.super_onConfigurationChanged(newConfig); } @@ -3674,7 +3645,7 @@ @Override public void onAttachedToWindow() { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; if (mIsAttachedToWindow) { Log.w(TAG, "onAttachedToWindow called when already attached. Ignoring"); return; @@ -3696,7 +3667,7 @@ @Override public void onDetachedFromWindow() { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; if (!mIsAttachedToWindow) { Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring"); return; @@ -3721,7 +3692,7 @@ @Override public void onWindowFocusChanged(boolean hasWindowFocus) { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; mWindowFocused = hasWindowFocus; mViewEventSink.onWindowFocusChanged(hasWindowFocus); Clipboard.getInstance().onWindowFocusChanged(hasWindowFocus); @@ -3729,14 +3700,14 @@ @Override public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; mContainerViewFocused = focused; mViewEventSink.onViewFocusChanged(focused); } @Override public void onSizeChanged(int w, int h, int ow, int oh) { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; mScrollOffsetManager.setContainerViewSize(w, h); // The AwLayoutSizer needs to go first so that if we're in // fixedLayoutSize mode the update @@ -3812,27 +3783,27 @@ @Override public void computeScroll() { - if (isDestroyedOrNoOperation(NO_WARN)) return; + if (isDestroyed(NO_WARN)) return; nativeOnComputeScroll(mNativeAwContents, AnimationUtils.currentAnimationTimeMillis()); } @Override public boolean onCheckIsTextEditor() { - if (isDestroyedOrNoOperation(NO_WARN)) return false; + if (isDestroyed(NO_WARN)) return false; ImeAdapter imeAdapter = ImeAdapter.fromWebContents(mWebContents); return imeAdapter != null ? imeAdapter.onCheckIsTextEditor() : false; } @Override public AccessibilityNodeProvider getAccessibilityNodeProvider() { - if (isDestroyedOrNoOperation(NO_WARN)) return null; + if (isDestroyed(NO_WARN)) return null; WebContentsAccessibility wcax = getWebContentsAccessibility(); return wcax != null ? wcax.getAccessibilityNodeProvider() : null; } @Override public boolean performAccessibilityAction(final int action, final Bundle arguments) { - if (isDestroyedOrNoOperation(NO_WARN)) return false; + if (isDestroyed(NO_WARN)) return false; WebContentsAccessibility wcax = getWebContentsAccessibility(); return wcax != null ? wcax.performAction(action, arguments) : false; }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java index a2c38165..1eaedee 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
@@ -2347,6 +2347,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Preferences"}) + @DisabledTest(message = "crbug.com/957626") public void testJavaScriptPopupsOpenTwice() throws Throwable { final ViewPair views = createViews(); runPerViewSettingsTest(new AwSettingsJavaScriptPopupsTestHelper(
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/RenderProcessGoneHelper.java b/android_webview/javatests/src/org/chromium/android_webview/test/RenderProcessGoneHelper.java index b32d48e..6a2bac1e 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/RenderProcessGoneHelper.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/RenderProcessGoneHelper.java
@@ -13,9 +13,8 @@ * The helper class for test to wait for render process gone related events. */ public class RenderProcessGoneHelper implements RenderProcessGoneObserver { - private static final int RENDER_PROCESS_GONE_NOTIFIED_TO_AW_CONTENTS = 1; - private static final int RENDER_PROCESS_GONE_NOTIFIED_TO_AW_CONTENTS_CLIENT = 2; - private static final int AW_CONTENTS_DESTROYED = 3; + private static final int RENDER_PROCESS_GONE_NOTIFIED_TO_AW_CONTENTS_CLIENT = 1; + private static final int AW_CONTENTS_DESTROYED = 2; private int mState; private CallbackHelper mCallbackHelper; @@ -25,10 +24,6 @@ mCallbackHelper = new CallbackHelper(); } - public void waitForRenderProcessGone() throws Exception { - waitForState(RENDER_PROCESS_GONE_NOTIFIED_TO_AW_CONTENTS); - } - public void waitForRenderProcessGoneNotifiedToAwContentsClient() throws Exception { waitForState(RENDER_PROCESS_GONE_NOTIFIED_TO_AW_CONTENTS_CLIENT); } @@ -48,14 +43,6 @@ } @Override - public void onRenderProcessGone() { - if (mOnRenderProcessGoneTask != null) mOnRenderProcessGoneTask.run(); - - mState = RENDER_PROCESS_GONE_NOTIFIED_TO_AW_CONTENTS; - mCallbackHelper.notifyCalled(); - } - - @Override public void onRenderProcessGoneNotifiedToAwContentsClient() { mState = RENDER_PROCESS_GONE_NOTIFIED_TO_AW_CONTENTS_CLIENT; mCallbackHelper.notifyCalled(); @@ -70,4 +57,4 @@ public void setOnRenderProcessGoneTask(Runnable task) { mOnRenderProcessGoneTask = task; } -} \ No newline at end of file +}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContents.java b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContents.java index bfaf711..5c840b91 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContents.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContents.java
@@ -24,11 +24,6 @@ */ public interface RenderProcessGoneObserver { /** - * Invoked when AwContents knows about render process gone - */ - void onRenderProcessGone(); - - /** * Invoked when AwContents notified AwContentsClient about render * process gone */ @@ -60,16 +55,8 @@ } @Override - protected void onRenderProcessGone(int childProcessID) { - super.onRenderProcessGone(childProcessID); - for (RenderProcessGoneObserver observer : mRenderProcessGoneObservers) { - observer.onRenderProcessGone(); - } - } - - @Override - protected boolean onRenderProcessGoneDetail(int childProcessID, boolean crashed) { - boolean ret = super.onRenderProcessGoneDetail(childProcessID, crashed); + protected boolean onRenderProcessGone(int childProcessID, boolean crashed) { + boolean ret = super.onRenderProcessGone(childProcessID, crashed); for (RenderProcessGoneObserver observer : mRenderProcessGoneObservers) { observer.onRenderProcessGoneNotifiedToAwContentsClient(); }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/services/VisualStateCallbackTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/services/VisualStateCallbackTest.java index 18a08fe..37e3b5c 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/services/VisualStateCallbackTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/services/VisualStateCallbackTest.java
@@ -34,11 +34,7 @@ import org.chromium.base.task.PostTask; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.Feature; -import org.chromium.base.test.util.RetryOnFailure; import org.chromium.content_public.browser.UiThreadTaskTraits; -import org.chromium.content_public.common.ContentUrlConstants; - -import java.util.concurrent.TimeUnit; /** * Test VisualStateCallback when render process is gone. @@ -172,35 +168,4 @@ mHelper.waitForAwContentsDestroyed(); Assert.assertFalse(vsImpl.called()); } - - // Tests the callback isn't invoked when AwContents knows about render process being gone. - @Test - @Feature({"AndroidWebView"}) - @SmallTest - @RetryOnFailure - @OnlyRunIn(MULTI_PROCESS) - public void testVisualStateCallbackNotCalledAfterRendererGone() throws Throwable { - VisualStateCallbackImpl vsImpl = new VisualStateCallbackImpl(); - mActivityTestRule.insertVisualStateCallbackOnUIThread( - mAwContents, vsImpl.requestId(), vsImpl); - VisualStateCallbackHelper vsCallbackHelper = mAwContents.getVisualStateCallbackHelper(); - int callCount = vsCallbackHelper.getCallCount(); - mActivityTestRule.loadUrlAsync(mAwContents, ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL); - vsCallbackHelper.waitForCallback( - callCount, 1, CallbackHelper.WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS); - Assert.assertEquals(callCount + 1, vsCallbackHelper.getCallCount()); - Assert.assertTrue(vsCallbackHelper.visualStateCallbackArrived()); - mActivityTestRule.killRenderProcessOnUiThreadAsync(mAwContents); - - mHelper.waitForRenderProcessGone(); - mAwContents.doInvokeVisualStateCallbackOnUiThread(); - - mHelper.waitForRenderProcessGoneNotifiedToAwContentsClient(); - Assert.assertFalse(vsImpl.called()); - - mActivityTestRule.destroyAwContentsOnMainSync(mAwContents); - - mHelper.waitForAwContentsDestroyed(); - Assert.assertFalse(vsImpl.called()); - } }
diff --git a/ash/app_list/resources/app_list_resources.grd b/ash/app_list/resources/app_list_resources.grd index 7ff114d..07b24e5 100644 --- a/ash/app_list/resources/app_list_resources.grd +++ b/ash/app_list/resources/app_list_resources.grd
@@ -14,9 +14,6 @@ BECAUSE YOUR RESOURCES ARE FUNCTIONALLY RELATED OR FALL UNDER THE SAME CONDITIONALS. --> <structure type="chrome_scaled_image" name="IDR_APP_LIST_FOLDER_BACK_NORMAL" file="common/app_list_folder_back_normal.png" /> - <structure type="chrome_scaled_image" name="IDR_APP_LIST_SPEECH_MIC_ON" file="common/app_list_mic_on.png" /> - <structure type="chrome_scaled_image" name="IDR_APP_LIST_SPEECH_MIC_OFF" file="common/app_list_mic_off.png" /> - <structure type="chrome_scaled_image" name="IDR_APP_LIST_SPEECH_MIC_RECORDING" file="common/app_list_mic_recording.png" /> </structures> </release> </grit>
diff --git a/ash/app_list/resources/default_100_percent/common/app_list_mic_off.png b/ash/app_list/resources/default_100_percent/common/app_list_mic_off.png deleted file mode 100644 index 35a9ab8f..0000000 --- a/ash/app_list/resources/default_100_percent/common/app_list_mic_off.png +++ /dev/null Binary files differ
diff --git a/ash/app_list/resources/default_100_percent/common/app_list_mic_on.png b/ash/app_list/resources/default_100_percent/common/app_list_mic_on.png deleted file mode 100644 index 96e0036..0000000 --- a/ash/app_list/resources/default_100_percent/common/app_list_mic_on.png +++ /dev/null Binary files differ
diff --git a/ash/app_list/resources/default_100_percent/common/app_list_mic_recording.png b/ash/app_list/resources/default_100_percent/common/app_list_mic_recording.png deleted file mode 100644 index a8fdd876..0000000 --- a/ash/app_list/resources/default_100_percent/common/app_list_mic_recording.png +++ /dev/null Binary files differ
diff --git a/ash/app_list/resources/default_200_percent/common/app_list_mic_off.png b/ash/app_list/resources/default_200_percent/common/app_list_mic_off.png deleted file mode 100644 index 319ed6b..0000000 --- a/ash/app_list/resources/default_200_percent/common/app_list_mic_off.png +++ /dev/null Binary files differ
diff --git a/ash/app_list/resources/default_200_percent/common/app_list_mic_on.png b/ash/app_list/resources/default_200_percent/common/app_list_mic_on.png deleted file mode 100644 index 740acdb..0000000 --- a/ash/app_list/resources/default_200_percent/common/app_list_mic_on.png +++ /dev/null Binary files differ
diff --git a/ash/app_list/resources/default_200_percent/common/app_list_mic_recording.png b/ash/app_list/resources/default_200_percent/common/app_list_mic_recording.png deleted file mode 100644 index 5c1a76ce..0000000 --- a/ash/app_list/resources/default_200_percent/common/app_list_mic_recording.png +++ /dev/null Binary files differ
diff --git a/ash/autoclick/autoclick_controller.cc b/ash/autoclick/autoclick_controller.cc index b6dab61..0c08108 100644 --- a/ash/autoclick/autoclick_controller.cc +++ b/ash/autoclick/autoclick_controller.cc
@@ -183,7 +183,9 @@ } void AutoclickController::DoAutoclickAction() { - aura::Window* root_window = wm::GetRootWindowAt(anchor_location_); + // The gesture_anchor_location_ is the position at which the animation is + // anchored, and where the click should occur. + aura::Window* root_window = wm::GetRootWindowAt(gesture_anchor_location_); DCHECK(root_window) << "Root window not found while attempting autoclick."; // But if the thing that would be acted upon is an autoclick menu button, do a @@ -191,8 +193,9 @@ // ensures that no matter the autoclick setting, users can always change to // another autoclick setting. By using a fake click we avoid closing dialogs // and menus, allowing autoclick users to interact with those items. - if (!DragInProgress() && AutoclickMenuContainsPoint(anchor_location_)) { - menu_bubble_controller_->ClickOnBubble(anchor_location_, + if (!DragInProgress() && + AutoclickMenuContainsPoint(gesture_anchor_location_)) { + menu_bubble_controller_->ClickOnBubble(gesture_anchor_location_, mouse_event_flags_); // Reset UI. CancelAutoclickAction(); @@ -204,7 +207,7 @@ mojom::AutoclickEventType in_progress_event_type = event_type_; RecordUserAction(in_progress_event_type); - gfx::Point location_in_pixels(anchor_location_); + gfx::Point location_in_pixels(gesture_anchor_location_); ::wm::ConvertPointFromScreen(root_window, &location_in_pixels); aura::WindowTreeHost* host = root_window->GetHost(); host->ConvertDIPToPixels(&location_in_pixels); @@ -283,7 +286,9 @@ } // Otherwise, go ahead and start the gesture. } - // The anchor is always the point in the screen where the timer starts. + // The anchor is always the point in the screen where the timer starts, and is + // used to determine when the cursor has moved far enough to cancel the + // autoclick. anchor_location_ = gesture_anchor_location_; autoclick_ring_handler_->StartGesture( delay_ - CalculateStartGestureDelay(delay_), anchor_location_, @@ -324,6 +329,10 @@ void AutoclickController::InitClickTimers() { CancelAutoclickAction(); base::TimeDelta start_gesture_delay = CalculateStartGestureDelay(delay_); + if (autoclick_timer_ && autoclick_timer_->IsRunning()) + autoclick_timer_->Stop(); + if (start_gesture_timer_ && start_gesture_timer_->IsRunning()) + start_gesture_timer_->Stop(); autoclick_timer_ = std::make_unique<base::RetainingOneShotTimer>( FROM_HERE, delay_ - start_gesture_delay, base::BindRepeating(&AutoclickController::DoAutoclickAction, @@ -428,7 +437,7 @@ } else if (autoclick_timer_->IsRunning() && !stabilize_click_position_) { // If we are not stabilizing the click position, update the gesture // center with each mouse move event. - anchor_location_ = point_in_screen; + gesture_anchor_location_ = point_in_screen; autoclick_ring_handler_->SetGestureCenter(point_in_screen, widget_.get()); } } else if (event->type() == ui::ET_MOUSE_PRESSED ||
diff --git a/ash/autoclick/autoclick_unittest.cc b/ash/autoclick/autoclick_unittest.cc index 508186e..11949f24 100644 --- a/ash/autoclick/autoclick_unittest.cc +++ b/ash/autoclick/autoclick_unittest.cc
@@ -232,9 +232,20 @@ aura::Window::Windows root_windows = Shell::GetAllRootWindows(); EXPECT_EQ(2u, root_windows.size()); - // Try at a couple different thresholds. - for (int movement_threshold = 10; movement_threshold < 50; - movement_threshold += 10) { + int animation_delay = 5; + + const struct { + int movement_threshold; + bool stabilize_click_position; + } kTestCases[] = { + {10, false}, {20, false}, {30, false}, {40, false}, {50, false}, + {10, true}, {20, true}, {30, true}, {40, true}, {50, true}, + }; + + for (const auto& test : kTestCases) { + GetAutoclickController()->set_stabilize_click_position( + test.stabilize_click_position); + int movement_threshold = test.movement_threshold; GetAutoclickController()->SetMovementThreshold(movement_threshold); // Run test for the secondary display too to test fix for crbug.com/449870. @@ -243,6 +254,7 @@ GetAutoclickController()->SetEnabled(true); GetEventGenerator()->MoveMouseTo(center); + ClearMouseEvents(); EXPECT_EQ(2u, WaitForMouseEvents().size()); // Small mouse movements should not trigger an autoclick, i.e. movements @@ -265,11 +277,37 @@ center + gfx::Vector2d(movement_threshold + 1, movement_threshold + 1)); EXPECT_EQ(2u, WaitForMouseEvents().size()); + + // Moving outside the threshold after the gesture begins should cancel + // the autoclick. Update the delay so we can do events between the initial + // trigger of the feature and the click. + int full_delay = UpdateAnimationDelayAndGetFullDelay(animation_delay); + GetEventGenerator()->MoveMouseTo( + center - gfx::Vector2d(movement_threshold, movement_threshold)); + FastForwardBy(animation_delay + 1); + GetEventGenerator()->MoveMouseTo(center); + ClearMouseEvents(); + + // After a time, a new click will occur at the second location. The first + // location should never get a click. + FastForwardBy(full_delay * 2); + EXPECT_EQ(2u, GetMouseEvents().size()); + gfx::Rect display_bounds = display::Screen::GetScreen() + ->GetDisplayNearestWindow(root_window) + .bounds(); + EXPECT_EQ(center - gfx::Vector2d(display_bounds.origin().x(), + display_bounds.origin().y()), + GetMouseEvents()[0].location()); + + // Move it out of the way so the next cycle starts properly. + GetEventGenerator()->MoveMouseTo(gfx::Point(0, 0)); + GetAutoclickController()->SetAutoclickDelay(base::TimeDelta()); } } - // Reset to default threshold. + // Reset to defaults. GetAutoclickController()->SetMovementThreshold(20); + GetAutoclickController()->set_stabilize_click_position(false); } TEST_F(AutoclickTest, MovementWithinThresholdWhileTimerRunning) {
diff --git a/ash/wm/immersive_fullscreen_controller_unittest.cc b/ash/wm/immersive_fullscreen_controller_unittest.cc index fcf247f..6ce22b7 100644 --- a/ash/wm/immersive_fullscreen_controller_unittest.cc +++ b/ash/wm/immersive_fullscreen_controller_unittest.cc
@@ -781,7 +781,7 @@ &child_delegate, aura::client::WINDOW_TYPE_CONTROL, 1234, gfx::Rect())); content_view()->Attach(child.get()); - child->Show(); + content_view()->Layout(); ConsumeEventHandler handler; child->AddPreTargetHandler(&handler);
diff --git a/base/BUILD.gn b/base/BUILD.gn index 41180c5a..d7a39e4 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -429,6 +429,8 @@ "memory/memory_pressure_monitor_chromeos.h", "memory/memory_pressure_monitor_mac.cc", "memory/memory_pressure_monitor_mac.h", + "memory/memory_pressure_monitor_notifying_chromeos.cc", + "memory/memory_pressure_monitor_notifying_chromeos.h", "memory/memory_pressure_monitor_win.cc", "memory/memory_pressure_monitor_win.h", "memory/platform_shared_memory_region.cc", @@ -2471,6 +2473,7 @@ "memory/memory_pressure_listener_unittest.cc", "memory/memory_pressure_monitor_chromeos_unittest.cc", "memory/memory_pressure_monitor_mac_unittest.cc", + "memory/memory_pressure_monitor_notifying_chromeos_unittest.cc", "memory/memory_pressure_monitor_unittest.cc", "memory/memory_pressure_monitor_win_unittest.cc", "memory/platform_shared_memory_region_unittest.cc",
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc index fbf9bee..b5e0fcb6 100644 --- a/base/allocator/partition_allocator/partition_alloc.cc +++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -64,9 +64,10 @@ static bool g_initialized = false; void (*internal::PartitionRootBase::gOomHandlingFunction)() = nullptr; -PartitionAllocHooks::AllocationHook* PartitionAllocHooks::allocation_hook_ = - nullptr; -PartitionAllocHooks::FreeHook* PartitionAllocHooks::free_hook_ = nullptr; +PartitionAllocHooks::AllocationObserverHook* + PartitionAllocHooks::allocation_observer_hook_ = nullptr; +PartitionAllocHooks::FreeObserverHook* + PartitionAllocHooks::free_observer_hook_ = nullptr; static void PartitionAllocBaseInit(internal::PartitionRootBase* root) { DCHECK(!root->initialized); @@ -290,7 +291,8 @@ // accessibility of memory pages and, if reducing the size, decommitting // them. if (PartitionReallocDirectMappedInPlace(root, page, new_size)) { - PartitionAllocHooks::ReallocHookIfEnabled(ptr, ptr, new_size, type_name); + PartitionAllocHooks::ObserverReallocHookIfEnabled(ptr, ptr, new_size, + type_name); return ptr; } }
diff --git a/base/allocator/partition_allocator/partition_alloc.h b/base/allocator/partition_allocator/partition_alloc.h index 66c79c2..c8145fa 100644 --- a/base/allocator/partition_allocator/partition_alloc.h +++ b/base/allocator/partition_allocator/partition_alloc.h
@@ -213,54 +213,53 @@ class BASE_EXPORT PartitionAllocHooks { public: - typedef void AllocationHook(void* address, size_t, const char* type_name); - typedef void FreeHook(void* address); - - // To unhook, call Set*Hook with nullptr. - static void SetAllocationHook(AllocationHook* hook) { - // Chained allocation hooks are not supported. Registering a non-null - // hook when a non-null hook is already registered indicates somebody is - // trying to overwrite a hook. - CHECK(!hook || !allocation_hook_) << "Overwriting allocation hook"; - allocation_hook_ = hook; - } - static void SetFreeHook(FreeHook* hook) { - CHECK(!hook || !free_hook_) << "Overwriting free hook"; - free_hook_ = hook; - } - - static void AllocationHookIfEnabled(void* address, + // Log allocation and free events. + typedef void AllocationObserverHook(void* address, size_t size, - const char* type_name) { - AllocationHook* hook = allocation_hook_; - if (UNLIKELY(hook != nullptr)) + const char* type_name); + typedef void FreeObserverHook(void* address); + + // To unhook, call SetObserverHooks with nullptrs. + static void SetObserverHooks(AllocationObserverHook* alloc_hook, + FreeObserverHook* free_hook) { + // Chained hooks are not supported. Registering a non-null hook when a + // non-null hook is already registered indicates somebody is trying to + // overwrite a hook. + CHECK((!allocation_observer_hook_ && !free_observer_hook_) || + (!alloc_hook && !free_hook)) + << "Overwriting already set observer hooks"; + allocation_observer_hook_ = alloc_hook; + free_observer_hook_ = free_hook; + } + + static void AllocationObserverHookIfEnabled(void* address, + size_t size, + const char* type_name) { + if (AllocationObserverHook* hook = allocation_observer_hook_) hook(address, size, type_name); } - static void FreeHookIfEnabled(void* address) { - FreeHook* hook = free_hook_; - if (UNLIKELY(hook != nullptr)) + static void FreeObserverHookIfEnabled(void* address) { + if (FreeObserverHook* hook = free_observer_hook_) hook(address); } - static void ReallocHookIfEnabled(void* old_address, - void* new_address, - size_t size, - const char* type_name) { + static void ObserverReallocHookIfEnabled(void* old_address, + void* new_address, + size_t size, + const char* type_name) { // Report a reallocation as a free followed by an allocation. - AllocationHook* allocation_hook = allocation_hook_; - FreeHook* free_hook = free_hook_; - if (UNLIKELY(allocation_hook && free_hook)) { + AllocationObserverHook* allocation_hook = allocation_observer_hook_; + FreeObserverHook* free_hook = free_observer_hook_; + if (allocation_hook && free_hook) { free_hook(old_address); allocation_hook(new_address, size, type_name); } } private: - // Pointers to hook functions that PartitionAlloc will call on allocation and - // free if the pointers are non-null. - static AllocationHook* allocation_hook_; - static FreeHook* free_hook_; + static AllocationObserverHook* allocation_observer_hook_; + static FreeObserverHook* free_observer_hook_; }; ALWAYS_INLINE void* PartitionRoot::Alloc(size_t size, const char* type_name) { @@ -287,8 +286,8 @@ DCHECK(size == index << kBucketShift); internal::PartitionBucket* bucket = &this->buckets()[index]; void* result = AllocFromBucket(bucket, flags, size); - PartitionAllocHooks::AllocationHookIfEnabled(result, requested_size, - type_name); + PartitionAllocHooks::AllocationObserverHookIfEnabled(result, requested_size, + type_name); return result; #endif // defined(MEMORY_TOOL_REPLACES_ALLOCATOR) } @@ -320,7 +319,7 @@ void* original_ptr = ptr; // TODO(palmer): Check ptr alignment before continuing. Shall we do the check // inside PartitionCookieFreePointerAdjust? - PartitionAllocHooks::FreeHookIfEnabled(original_ptr); + PartitionAllocHooks::FreeObserverHookIfEnabled(original_ptr); ptr = internal::PartitionCookieFreePointerAdjust(ptr); internal::PartitionPage* page = internal::PartitionPage::FromPointer(ptr); // TODO(palmer): See if we can afford to make this a CHECK. @@ -372,7 +371,8 @@ subtle::SpinLock::Guard guard(root->lock); ret = root->AllocFromBucket(bucket, flags, size); } - PartitionAllocHooks::AllocationHookIfEnabled(ret, requested_size, type_name); + PartitionAllocHooks::AllocationObserverHookIfEnabled(ret, requested_size, + type_name); return ret; #endif @@ -398,7 +398,7 @@ if (UNLIKELY(!ptr)) return; - PartitionAllocHooks::FreeHookIfEnabled(ptr); + PartitionAllocHooks::FreeObserverHookIfEnabled(ptr); ptr = internal::PartitionCookieFreePointerAdjust(ptr); internal::PartitionPage* page = internal::PartitionPage::FromPointer(ptr); // TODO(palmer): See if we can afford to make this a CHECK.
diff --git a/base/android/child_process_service.cc b/base/android/child_process_service.cc index 9297b98..8ec6e62 100644 --- a/base/android/child_process_service.cc +++ b/base/android/child_process_service.cc
@@ -27,13 +27,11 @@ const JavaParamRef<jlongArray>& j_offsets, const JavaParamRef<jlongArray>& j_sizes) { std::vector<base::Optional<std::string>> keys; - jsize keys_size = env->GetArrayLength(j_keys); - keys.reserve(keys_size); - for (jsize i = 0; i < keys_size; i++) { - base::android::ScopedJavaLocalRef<jstring> str( - env, static_cast<jstring>(env->GetObjectArrayElement(j_keys, i))); + JavaObjectArrayReader<jstring> keys_array(j_keys); + keys.reserve(keys_array.size()); + for (auto str : keys_array) { base::Optional<std::string> key; - if (!str.is_null()) { + if (str) { key = base::android::ConvertJavaStringToUTF8(env, str); } keys.push_back(std::move(key));
diff --git a/base/android/scoped_java_ref.h b/base/android/scoped_java_ref.h index 5e8bc04..95625678 100644 --- a/base/android/scoped_java_ref.h +++ b/base/android/scoped_java_ref.h
@@ -96,6 +96,10 @@ DISALLOW_COPY_AND_ASSIGN(JavaRef); }; +// Forward declare the object array reader for the convenience function. +template <typename T> +class JavaObjectArrayReader; + // Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful // for allowing functions to accept a reference without having to mandate // whether it is a local or global type. @@ -108,6 +112,17 @@ T obj() const { return static_cast<T>(JavaRef<jobject>::obj()); } + // Get a JavaObjectArrayReader for the array pointed to by this reference. + // Only defined for JavaRef<jobjectArray>. + // You must pass the type of the array elements (usually jobject) as the + // template parameter. + template <typename ElementType, + typename T_ = T, + typename = std::enable_if_t<std::is_same<T_, jobjectArray>::value>> + JavaObjectArrayReader<ElementType> ReadElements() const { + return JavaObjectArrayReader<ElementType>(*this); + } + protected: JavaRef(JNIEnv* env, T obj) : JavaRef<jobject>(env, obj) {} @@ -283,6 +298,10 @@ // Friend required to get env_ from conversions. template <typename U> friend class ScopedJavaLocalRef; + + // Avoids JavaObjectArrayReader having to accept and store its own env. + template <typename U> + friend class JavaObjectArrayReader; }; // Holds a global reference to a Java object. The global reference is scoped @@ -387,6 +406,135 @@ T Release() { return static_cast<T>(JavaRef<T>::ReleaseInternal()); } }; +// Wrapper for a jobjectArray which supports input iteration, allowing Java +// arrays to be iterated over with a range-based for loop, or used with +// <algorithm> functions that accept input iterators. +// +// The iterator returns each object in the array in turn, wrapped in a +// ScopedJavaLocalRef<T>. T will usually be jobject, but if you know that the +// array contains a more specific type (such as jstring) you can use that +// instead. This does not check the type at runtime! +// +// The wrapper holds a local reference to the array and only queries the size of +// the array once, so must only be used as a stack-based object from the current +// thread. +// +// Note that this does *not* update the contents of the array if you mutate the +// returned ScopedJavaLocalRef. +template <typename T> +class JavaObjectArrayReader { + public: + class iterator { + public: + // We can only be an input iterator, as all richer iterator types must + // implement the multipass guarantee (always returning the same object for + // the same iterator position), which is not practical when returning + // temporary objects. + using iterator_category = std::input_iterator_tag; + + using difference_type = ptrdiff_t; + using value_type = ScopedJavaLocalRef<T>; + + // It doesn't make sense to return a reference type as the iterator creates + // temporary wrapper objects when dereferenced. Fortunately, it's not + // required that input iterators actually use references, and defining it + // as value_type is valid. + using reference = value_type; + + // This exists to make operator-> work as expected: its return value must + // resolve to an actual pointer (otherwise the compiler just keeps calling + // operator-> on the return value until it does), so we need an extra level + // of indirection. This is sometimes called an "arrow proxy" or similar, and + // this version is adapted from base/value_iterators.h. + class pointer { + public: + explicit pointer(const reference& ref) : ref_(ref) {} + pointer(const pointer& ptr) = default; + pointer& operator=(const pointer& ptr) = delete; + reference* operator->() { return &ref_; } + + private: + reference ref_; + }; + + iterator(const iterator&) = default; + ~iterator() = default; + + iterator& operator=(const iterator&) = default; + + bool operator==(const iterator& other) const { + DCHECK(reader_ == other.reader_); + return i_ == other.i_; + } + + bool operator!=(const iterator& other) const { + DCHECK(reader_ == other.reader_); + return i_ != other.i_; + } + + reference operator*() const { + DCHECK(i_ < reader_->size_); + // JNIEnv functions return unowned local references; take ownership with + // Adopt so that ~ScopedJavaLocalRef will release it automatically later. + return value_type::Adopt( + reader_->array_.env_, + static_cast<T>(reader_->array_.env_->GetObjectArrayElement( + reader_->array_.obj(), i_))); + } + + pointer operator->() const { return pointer(operator*()); } + + iterator& operator++() { + DCHECK(i_ < reader_->size_); + ++i_; + return *this; + } + + iterator operator++(int) { + iterator old = *this; + ++*this; + return old; + } + + private: + iterator(const JavaObjectArrayReader* reader, jsize i) + : reader_(reader), i_(i) {} + const JavaObjectArrayReader* reader_; + jsize i_; + + friend JavaObjectArrayReader; + }; + + JavaObjectArrayReader(const JavaRef<jobjectArray>& array) : array_(array) { + size_ = array_.env_->GetArrayLength(array_.obj()); + } + + // Copy constructor to allow returning it from JavaRef::ReadElements(). + JavaObjectArrayReader(const JavaObjectArrayReader& other) = default; + + // Assignment operator for consistency with copy constructor. + JavaObjectArrayReader& operator=(const JavaObjectArrayReader& other) = + default; + + // Allow move constructor and assignment since this owns a local ref. + JavaObjectArrayReader(JavaObjectArrayReader&& other) = default; + JavaObjectArrayReader& operator=(JavaObjectArrayReader&& other) = default; + + bool empty() const { return size_ == 0; } + + jsize size() const { return size_; } + + iterator begin() const { return iterator(this, 0); } + + iterator end() const { return iterator(this, size_); } + + private: + ScopedJavaLocalRef<jobjectArray> array_; + jsize size_; + + friend iterator; +}; + } // namespace android } // namespace base
diff --git a/base/android/scoped_java_ref_unittest.cc b/base/android/scoped_java_ref_unittest.cc index d46c5ac..b7355aa 100644 --- a/base/android/scoped_java_ref_unittest.cc +++ b/base/android/scoped_java_ref_unittest.cc
@@ -4,12 +4,15 @@ #include "base/android/scoped_java_ref.h" +#include <iterator> +#include <type_traits> + #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "testing/gtest/include/gtest/gtest.h" #define EXPECT_SAME_OBJECT(a, b) \ - EXPECT_TRUE(env->IsSameObject(a.obj(), b.obj())) + EXPECT_TRUE(env->IsSameObject((a).obj(), (b).obj())) namespace base { namespace android { @@ -229,5 +232,112 @@ EXPECT_EQ(0, g_global_refs); } +class JavaObjectArrayReaderTest : public testing::Test { + protected: + void SetUp() override { + JNIEnv* env = AttachCurrentThread(); + int_class_ = GetClass(env, "java/lang/Integer"); + int_constructor_ = MethodID::Get<MethodID::TYPE_INSTANCE>( + env, int_class_.obj(), "<init>", "(I)V"); + array_ = MakeArray(array_len_); + + // Make array_len_ different Integer objects, keep a reference to each, + // and add them to the array. + for (jint i = 0; i < array_len_; ++i) { + jobject member = env->NewObject(int_class_.obj(), int_constructor_, i); + ASSERT_NE(member, nullptr); + array_members_[i] = ScopedJavaLocalRef<jobject>::Adopt(env, member); + env->SetObjectArrayElement(array_.obj(), i, member); + } + } + + // Make an Integer[] with len elements, all initialized to null. + ScopedJavaLocalRef<jobjectArray> MakeArray(jsize len) { + JNIEnv* env = AttachCurrentThread(); + jobjectArray array = env->NewObjectArray(len, int_class_.obj(), nullptr); + EXPECT_NE(array, nullptr); + return ScopedJavaLocalRef<jobjectArray>::Adopt(env, array); + } + + static constexpr jsize array_len_ = 10; + ScopedJavaLocalRef<jclass> int_class_; + jmethodID int_constructor_; + ScopedJavaLocalRef<jobject> array_members_[array_len_]; + ScopedJavaLocalRef<jobjectArray> array_; +}; + +// Must actually define the variable until C++17 :( +constexpr jsize JavaObjectArrayReaderTest::array_len_; + +TEST_F(JavaObjectArrayReaderTest, ZeroLengthArray) { + JavaObjectArrayReader<jobject> zero_length(MakeArray(0)); + EXPECT_TRUE(zero_length.empty()); + EXPECT_EQ(zero_length.size(), 0); + EXPECT_EQ(zero_length.begin(), zero_length.end()); + for (auto element : zero_length) { + FAIL() << "Loop body should not execute"; + } +} + +// Verify that we satisfy the C++ "InputIterator" named requirements. +TEST_F(JavaObjectArrayReaderTest, InputIteratorRequirements) { + typedef JavaObjectArrayReader<jobject>::iterator It; + + JNIEnv* env = AttachCurrentThread(); + JavaObjectArrayReader<jobject> reader(array_); + It i = reader.begin(); + + EXPECT_TRUE(std::is_copy_constructible<It>::value); + It copy = i; + EXPECT_EQ(copy, i); + EXPECT_EQ(It(i), i); + + EXPECT_TRUE(std::is_copy_assignable<It>::value); + It assign = reader.end(); + It& assign2 = (assign = i); + EXPECT_EQ(assign, i); + EXPECT_EQ(assign2, assign); + + EXPECT_TRUE(std::is_destructible<It>::value); + + // Swappable + It left = reader.begin(), right = reader.end(); + std::swap(left, right); + EXPECT_EQ(left, reader.end()); + EXPECT_EQ(right, reader.begin()); + + // Basic check that iterator_traits works + bool same_type = std::is_same<std::iterator_traits<It>::iterator_category, + std::input_iterator_tag>::value; + EXPECT_TRUE(same_type); + + // Comparisons + EXPECT_EQ(reader.begin(), reader.begin()); + EXPECT_NE(reader.begin(), reader.end()); + + // Dereferencing + ScopedJavaLocalRef<jobject> o = *(reader.begin()); + EXPECT_SAME_OBJECT(o, array_members_[0]); + EXPECT_TRUE(env->IsSameObject(o.obj(), reader.begin()->obj())); + + // Incrementing + It preinc = ++(reader.begin()); + EXPECT_SAME_OBJECT(*preinc, array_members_[1]); + It postinc = reader.begin(); + EXPECT_SAME_OBJECT(*postinc++, array_members_[0]); + EXPECT_SAME_OBJECT(*postinc, array_members_[1]); +} + +// Check that range-based for and the convenience function work as expected. +TEST_F(JavaObjectArrayReaderTest, RangeBasedFor) { + JNIEnv* env = AttachCurrentThread(); + + int i = 0; + for (ScopedJavaLocalRef<jobject> element : array_.ReadElements<jobject>()) { + EXPECT_SAME_OBJECT(element, array_members_[i++]); + } + EXPECT_EQ(i, array_len_); +} + } // namespace android } // namespace base
diff --git a/base/memory/memory_pressure_monitor.cc b/base/memory/memory_pressure_monitor.cc index ed350b8..bab52f37 100644 --- a/base/memory/memory_pressure_monitor.cc +++ b/base/memory/memory_pressure_monitor.cc
@@ -40,6 +40,9 @@ } // namespace +const base::TimeDelta MemoryPressureMonitor::kUMAMemoryPressureLevelPeriod = + base::TimeDelta::FromSeconds(5); + MemoryPressureMonitor::MemoryPressureMonitor() { DCHECK(!g_monitor); g_monitor = this;
diff --git a/base/memory/memory_pressure_monitor.h b/base/memory/memory_pressure_monitor.h index b56a6605..13bc483 100644 --- a/base/memory/memory_pressure_monitor.h +++ b/base/memory/memory_pressure_monitor.h
@@ -9,6 +9,7 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/memory_pressure_listener.h" +#include "base/time/time.h" namespace base { @@ -35,6 +36,9 @@ // Record memory pressure UMA statistic. A tick is 5 seconds. static void RecordMemoryPressure(MemoryPressureLevel level, int ticks); + // Defines the time between UMA events, currently 5s. + static const base::TimeDelta kUMAMemoryPressureLevelPeriod; + // Returns the currently observed memory pressure. virtual MemoryPressureLevel GetCurrentPressureLevel() = 0;
diff --git a/base/memory/memory_pressure_monitor_chromeos.cc b/base/memory/memory_pressure_monitor_chromeos.cc index 018f25f..2b4ff01c 100644 --- a/base/memory/memory_pressure_monitor_chromeos.cc +++ b/base/memory/memory_pressure_monitor_chromeos.cc
@@ -20,12 +20,17 @@ namespace chromeos { namespace { - -// Type-safe version of |g_monitor| from base/memory/memory_pressure_monitor.cc. +// Type-safe version of |g_monitor| from base/memory/memory_pressure_monitor.cc, +// this was originally added because TabManagerDelegate for chromeos needs to +// call into ScheduleEarlyCheck which isn't a public API in the base +// MemoryPressureMonitor. This matters because ChromeOS may create a +// FakeMemoryPressureMonitor for browser tests and that's why this type-specific +// version was added. MemoryPressureMonitor* g_monitor = nullptr; // The time between memory pressure checks. While under critical pressure, this -// is also the timer to repeat cleanup attempts. +// is also the timer to repeat cleanup attempts. Note: this is only for the UMA +// ChromeOS.MemoryPressureLevel. const int kMemoryPressureIntervalMs = 1000; // The time which should pass between two moderate memory pressure calls. @@ -168,7 +173,10 @@ void MemoryPressureMonitor::CheckMemoryPressureAndRecordStatistics() { CheckMemoryPressure(); - if (seconds_since_reporting_++ == 5) { + // We report the platform independent Memory.PressureLevel after + // kUMAMemoryPressureLevelPeriod which is 5s. + if (seconds_since_reporting_++ == + base::MemoryPressureMonitor::kUMAMemoryPressureLevelPeriod.InSeconds()) { seconds_since_reporting_ = 0; RecordMemoryPressure(current_memory_pressure_level_, 1); } @@ -188,6 +196,8 @@ break; } + // TODO(bgeffon): Remove this platform specific metric once all work has + // been completed to deal with the 5s Memory.PressureLevel metric. UMA_HISTOGRAM_ENUMERATION("ChromeOS.MemoryPressureLevel", memory_pressure_level_uma, NUM_MEMORY_PRESSURE_LEVELS);
diff --git a/base/memory/memory_pressure_monitor_mac.cc b/base/memory/memory_pressure_monitor_mac.cc index 4a19eac..a91e52a 100644 --- a/base/memory/memory_pressure_monitor_mac.cc +++ b/base/memory/memory_pressure_monitor_mac.cc
@@ -20,10 +20,6 @@ DISPATCH_EXPORT const struct dispatch_source_type_s _dispatch_source_type_memorypressure; -namespace { -static const int kUMATickSize = 5; -} // namespace - namespace base { namespace mac { @@ -72,7 +68,8 @@ } // Create a CFRunLoopObserver to check the memory pressure at the end of - // every pass through the event loop (modulo kUMATickSize). + // every pass through the event loop (modulo + // MemoryPressureMonitor::kUMAMemoryPressureLevelPeriod). CFRunLoopObserverContext observer_context = {0, this, NULL, NULL, NULL}; exit_observer_.reset( @@ -122,9 +119,13 @@ last_statistic_report_time_ = now; double accumulated_time = time_since_last_report + subtick_seconds_; - int ticks_to_report = static_cast<int>(accumulated_time / kUMATickSize); + int ticks_to_report = static_cast<int>( + accumulated_time / + base::MemoryPressureMonitor::kUMAMemoryPressureLevelPeriod.InSeconds()); // Save for later the seconds that didn't make it into a full tick. - subtick_seconds_ = std::fmod(accumulated_time, kUMATickSize); + subtick_seconds_ = std::fmod( + accumulated_time, + base::MemoryPressureMonitor::kUMAMemoryPressureLevelPeriod.InSeconds()); // Round the tick count up on a pressure level change to ensure we capture it. bool pressure_level_changed = (new_pressure_level != last_pressure_level_); @@ -148,16 +149,19 @@ if (now >= next_run_loop_update_time_) { UpdatePressureLevel(); - // Update again in kUMATickSize seconds. We can update at any frequency, - // but because we're only checking memory pressure levels for UMA there's - // no need to update more frequently than we're keeping statistics on. - next_run_loop_update_time_ = now + kUMATickSize - subtick_seconds_; + // Update again in MemoryPressureMonitor::kUMAMemoryPressureLevelPeriod + // seconds. We can update at any frequency, but because we're only checking + // memory pressure levels for UMA there's no need to update more frequently + // than we're keeping statistics on. + next_run_loop_update_time_ = + now + MemoryPressureMonitor::kUMAMemoryPressureLevelPeriod.InSeconds() - + subtick_seconds_; } } // Static. int MemoryPressureMonitor::GetSecondsPerUMATick() { - return kUMATickSize; + return base::MemoryPressureMonitor::kUMAMemoryPressureLevelPeriod.InSeconds(); } MemoryPressureListener::MemoryPressureLevel
diff --git a/base/memory/memory_pressure_monitor_notifying_chromeos.cc b/base/memory/memory_pressure_monitor_notifying_chromeos.cc new file mode 100644 index 0000000..139da40 --- /dev/null +++ b/base/memory/memory_pressure_monitor_notifying_chromeos.cc
@@ -0,0 +1,312 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "base/memory/memory_pressure_monitor_notifying_chromeos.h" + +#include <fcntl.h> +#include <sys/poll.h> +#include <string> +#include <vector> + +#include "base/bind.h" +#include "base/files/file_util.h" +#include "base/metrics/histogram_macros.h" +#include "base/no_destructor.h" +#include "base/posix/eintr_wrapper.h" +#include "base/process/process_metrics.h" +#include "base/single_thread_task_runner.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "base/system/sys_info.h" +#include "base/task/post_task.h" +#include "base/threading/scoped_blocking_call.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" + +namespace base { +namespace chromeos { + +namespace { +// Type-safe version of |g_monitor| from base/memory/memory_pressure_monitor.cc, +// this was originally added because TabManagerDelegate for chromeos needs to +// call into ScheduleEarlyCheck which isn't a public API in the base +// MemoryPressureMonitor. This matters because ChromeOS may create a +// FakeMemoryPressureMonitor for browser tests and that's why this type-specific +// version was added. +MemoryPressureMonitorNotifying* g_monitor = nullptr; + +// We try not to re-notify on moderate too frequently, this time +// controls how frequently we will notify after our first notification. +constexpr base::TimeDelta kModerateMemoryPressureCooldownTime = + base::TimeDelta::FromSeconds(10); + +// The margin mem file contains the two memory levels, the first is the +// critical level and the second is the moderate level. Note, this +// file may contain more values but only the first two are used for +// memory pressure notifications in chromeos. +constexpr char kMarginMemFile[] = "/sys/kernel/mm/chromeos-low_mem/margin"; + +// The available memory file contains the available memory as determined +// by the kernel. +constexpr char kAvailableMemFile[] = + "/sys/kernel/mm/chromeos-low_mem/available"; + +// Converts an available memory value in MB to a memory pressure level. +MemoryPressureListener::MemoryPressureLevel GetMemoryPressureLevelFromAvailable( + int available_mb, + int moderate_avail_mb, + int critical_avail_mb) { + if (available_mb < critical_avail_mb) + return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; + if (available_mb < moderate_avail_mb) + return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE; + + return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; +} + +int64_t ReadAvailableMemoryMB(int available_fd) { + // Read the available memory. + char buf[32] = {}; + + // kernfs/file.c: + // "Once poll/select indicates that the value has changed, you + // need to close and re-open the file, or seek to 0 and read again. + ssize_t bytes_read = HANDLE_EINTR(pread(available_fd, buf, sizeof(buf), 0)); + PCHECK(bytes_read != -1); + + std::string mem_str(buf, bytes_read); + int64_t available = -1; + CHECK(base::StringToInt64( + base::TrimWhitespaceASCII(mem_str, base::TrimPositions::TRIM_ALL), + &available)); + + return available; +} + +// This function will wait until the /sys/kernel/mm/chromeos-low_mem/available +// file becomes readable and then read the latest value. This file will only +// become readable once the available memory cross through one of the margin +// values specified in /sys/kernel/mm/chromeos-low_mem/margin, for more +// details see https://crrev.com/c/536336. +bool WaitForMemoryPressureChanges(int available_fd) { + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, + base::BlockingType::WILL_BLOCK); + + pollfd pfd = {available_fd, POLLPRI | POLLERR, 0}; + int res = HANDLE_EINTR(poll(&pfd, 1, -1)); // Wait indefinitely. + PCHECK(res != -1); + + if (pfd.revents != (POLLPRI | POLLERR)) { + // If we didn't receive POLLPRI | POLLERR it means we likely received + // POLLNVAL because the fd has been closed. + LOG(ERROR) << "WaitForMemoryPressureChanges received unexpected revents: " + << pfd.revents; + + // We no longer want to wait for a kernel notification if the fd has been + // closed. + return false; + } + + return true; +} + +} // namespace + +MemoryPressureMonitorNotifying::MemoryPressureMonitorNotifying() + : MemoryPressureMonitorNotifying( + kMarginMemFile, + kAvailableMemFile, + base::BindRepeating(&WaitForMemoryPressureChanges), + /*enable_metrics=*/true) {} + +MemoryPressureMonitorNotifying::MemoryPressureMonitorNotifying( + const std::string& margin_file, + const std::string& available_file, + base::RepeatingCallback<bool(int)> kernel_waiting_callback, + bool enable_metrics) + : available_mem_file_(HANDLE_EINTR(open(available_file.c_str(), O_RDONLY))), + dispatch_callback_( + base::BindRepeating(&MemoryPressureListener::NotifyMemoryPressure)), + kernel_waiting_callback_( + base::BindRepeating(std::move(kernel_waiting_callback), + available_mem_file_.get())), + weak_ptr_factory_(this) { + DCHECK(g_monitor == nullptr); + g_monitor = this; + + CHECK(available_mem_file_.is_valid()); + std::vector<int> margin_parts = + MemoryPressureMonitorNotifying::GetMarginFileParts(margin_file); + + // This class SHOULD have verified kernel support by calling + // SupportsKernelNotifications() before creating a new instance of this. + // Therefore we will check fail if we don't have multiple margin values. + CHECK_LE(2u, margin_parts.size()); + critical_pressure_threshold_mb_ = margin_parts[0]; + moderate_pressure_threshold_mb_ = margin_parts[1]; + + if (enable_metrics) { + // We will report the current memory pressure at some periodic interval, + // the metric ChromeOS.MemoryPRessureLevel is currently reported every 1s. + reporting_timer_.Start( + FROM_HERE, base::TimeDelta::FromSeconds(1), + base::BindRepeating(&MemoryPressureMonitorNotifying:: + CheckMemoryPressureAndRecordStatistics, + weak_ptr_factory_.GetWeakPtr())); + } + + ScheduleWaitForKernelNotification(); +} + +MemoryPressureMonitorNotifying::~MemoryPressureMonitorNotifying() { + DCHECK(g_monitor); + g_monitor = nullptr; +} + +std::vector<int> MemoryPressureMonitorNotifying::GetMarginFileParts() { + static const base::NoDestructor<std::vector<int>> margin_file_parts( + GetMarginFileParts(kMarginMemFile)); + return *margin_file_parts; +} + +std::vector<int> MemoryPressureMonitorNotifying::GetMarginFileParts( + const std::string& file) { + std::vector<int> margin_values; + std::string margin_contents; + if (base::ReadFileToString(base::FilePath(file), &margin_contents)) { + std::vector<std::string> margins = + base::SplitString(margin_contents, base::kWhitespaceASCII, + base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + for (const auto& v : margins) { + int value = -1; + if (!base::StringToInt(v, &value)) { + // If any of the values weren't parseable as an int we return + // nothing as the file format is unexpected. + LOG(ERROR) << "Unable to parse margin file contents as integer: " << v; + return std::vector<int>(); + } + margin_values.push_back(value); + } + } else { + LOG(ERROR) << "Unable to read margin file: " << kMarginMemFile; + } + return margin_values; +} + +bool MemoryPressureMonitorNotifying::SupportsKernelNotifications() { + // Unfortunately at the moment the only way to determine if the chromeos + // kernel supports polling on the available file is to observe two values + // in the margin file, if the critical and moderate levels are specified + // there then we know the kernel must support polling on available. + return MemoryPressureMonitorNotifying::GetMarginFileParts().size() >= 2; +} + +MemoryPressureListener::MemoryPressureLevel +MemoryPressureMonitorNotifying::GetCurrentPressureLevel() { + return current_memory_pressure_level_; +} + +// CheckMemoryPressure will get the current memory pressure level by reading +// the available file. +void MemoryPressureMonitorNotifying::CheckMemoryPressure() { + auto previous_memory_pressure = current_memory_pressure_level_; + int64_t mem_avail = ReadAvailableMemoryMB(available_mem_file_.get()); + current_memory_pressure_level_ = GetMemoryPressureLevelFromAvailable( + mem_avail, moderate_pressure_threshold_mb_, + critical_pressure_threshold_mb_); + if (current_memory_pressure_level_ == + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) { + last_moderate_notification_ = base::TimeTicks(); + return; + } + + // In the case of MODERATE memory pressure we may be in this state for quite + // some time so we limit the rate at which we dispatch notifications. + if (current_memory_pressure_level_ == + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE) { + if (previous_memory_pressure == current_memory_pressure_level_) { + if (base::TimeTicks::Now() - last_moderate_notification_ < + kModerateMemoryPressureCooldownTime) { + return; + } else if (previous_memory_pressure == + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { + // Reset the moderate notification time if we just crossed back. + last_moderate_notification_ = base::TimeTicks::Now(); + return; + } + } + + last_moderate_notification_ = base::TimeTicks::Now(); + } + + VLOG(1) << "MemoryPressureMonitorNotifying::CheckMemoryPressure dispatching " + "at level: " + << current_memory_pressure_level_; + dispatch_callback_.Run(current_memory_pressure_level_); +} + +void MemoryPressureMonitorNotifying::HandleKernelNotification(bool result) { + // If WaitForKernelNotification returned false then the FD has been closed and + // we just exit without waiting again. + if (!result) { + return; + } + + CheckMemoryPressure(); + + // Now we need to schedule back our blocking task to wait for more + // kernel notifications. + ScheduleWaitForKernelNotification(); +} + +void MemoryPressureMonitorNotifying::CheckMemoryPressureAndRecordStatistics() { + // Note: If we support notifications of memory pressure changes in both + // directions we will not have to update the cached value as it will always + // be correct. + CheckMemoryPressure(); + + // We only report Memory.PressureLevel every 5seconds while + // we report ChromeOS.MemoryPressureLevel every 1s. + if (base::TimeTicks::Now() - last_pressure_level_report_ > + base::MemoryPressureMonitor::kUMAMemoryPressureLevelPeriod) { + // Record to UMA "Memory.PressureLevel" a tick is 5seconds. + RecordMemoryPressure(current_memory_pressure_level_, 1); + last_pressure_level_report_ = base::TimeTicks::Now(); + } + + // Record UMA histogram statistics for the current memory pressure level, it + // would seem that only Memory.PressureLevel would be necessary. + constexpr int kNumberPressureLevels = 3; + UMA_HISTOGRAM_ENUMERATION("ChromeOS.MemoryPressureLevel", + current_memory_pressure_level_, + kNumberPressureLevels); +} + +void MemoryPressureMonitorNotifying::ScheduleEarlyCheck() { + ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(&MemoryPressureMonitorNotifying::CheckMemoryPressure, + weak_ptr_factory_.GetWeakPtr())); +} + +void MemoryPressureMonitorNotifying::ScheduleWaitForKernelNotification() { + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, kernel_waiting_callback_, + base::BindRepeating( + &MemoryPressureMonitorNotifying::HandleKernelNotification, + weak_ptr_factory_.GetWeakPtr())); +} + +void MemoryPressureMonitorNotifying::SetDispatchCallback( + const DispatchCallback& callback) { + dispatch_callback_ = callback; +} + +// static +MemoryPressureMonitorNotifying* MemoryPressureMonitorNotifying::Get() { + return g_monitor; +} + +} // namespace chromeos +} // namespace base
diff --git a/base/memory/memory_pressure_monitor_notifying_chromeos.h b/base/memory/memory_pressure_monitor_notifying_chromeos.h new file mode 100644 index 0000000..5af176f --- /dev/null +++ b/base/memory/memory_pressure_monitor_notifying_chromeos.h
@@ -0,0 +1,130 @@ +// Copyright 2019 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 BASE_MEMORY_MEMORY_PRESSURE_MONITOR_NOTIFYING_CHROMEOS_H_ +#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_NOTIFYING_CHROMEOS_H_ + +#include <vector> + +#include "base/base_export.h" +#include "base/files/scoped_file.h" +#include "base/macros.h" +#include "base/memory/memory_pressure_listener.h" +#include "base/memory/memory_pressure_monitor.h" +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "base/timer/timer.h" + +namespace base { +namespace chromeos { + +//////////////////////////////////////////////////////////////////////////////// +// MemoryPressureMonitorNotifying +// +// A class to handle the observation of our free memory. It notifies the +// MemoryPressureListener of memory fill level changes, so that it can take +// action to reduce memory resources accordingly. +// +// TODO(bgeffon): This class should become chromeos::MemoryPressureMonitor +// once all kernels support notifications. +// +class BASE_EXPORT MemoryPressureMonitorNotifying + : public base::MemoryPressureMonitor { + public: + // The MemoryPressureMonitorNotifying reads the pressure levels from the + // /sys/kernel/mm/chromeos-low_mem/margin and does not need to be configured. + // + // NOTE: You should check that the kernel supports notifications by calling + // SupportsKernelNotifications() before constructing a new instance of this + // class. + MemoryPressureMonitorNotifying(); + ~MemoryPressureMonitorNotifying() override; + + // Get the current memory pressure level. + MemoryPressureListener::MemoryPressureLevel GetCurrentPressureLevel() + override; + void SetDispatchCallback(const DispatchCallback& callback) override; + + // GetMarginFileParts returns a vector of the configured margin file values. + // The margin file contains two or more values, but we're only concerned with + // the first two. The first represents critical memory pressure, the second + // is moderate memory pressure level. + static std::vector<int> GetMarginFileParts(); + + // SupportsKernelNotifications will return true if the kernel supports and is + // configured for notifications on memory availability changes. + static bool SupportsKernelNotifications(); + + // ScheduleEarlyCheck is used by the ChromeOS tab manager delegate to force it + // to quickly recheck pressure levels after a tab discard or some other + // action. + void ScheduleEarlyCheck(); + + // Returns the moderate pressure threshold as read from the margin file. + int ModeratePressureThresholdMBForTesting() const { + return moderate_pressure_threshold_mb_; + } + + // Returns the critical pressure threshold as read from the margin file. + int CriticalPressureThresholdMBForTesting() const { + return critical_pressure_threshold_mb_; + } + + // Returns a type-casted version of the current memory pressure monitor. A + // simple wrapper to base::MemoryPressureMonitor::Get. + static MemoryPressureMonitorNotifying* Get(); + + protected: + // This constructor is only used for testing. + MemoryPressureMonitorNotifying( + const std::string& margin_file, + const std::string& available_file, + base::RepeatingCallback<bool(int)> kernel_waiting_callback, + bool enable_metrics); + + static std::vector<int> GetMarginFileParts(const std::string& margin_file); + void CheckMemoryPressure(); + + private: + void HandleKernelNotification(bool result); + void ScheduleWaitForKernelNotification(); + void CheckMemoryPressureAndRecordStatistics(); + + int moderate_pressure_threshold_mb_ = 0; + int critical_pressure_threshold_mb_ = 0; + + // We keep track of how long it has been since we last notified at the + // moderate level. + base::TimeTicks last_moderate_notification_; + + // We keep track of how long it's been since we notified on the + // Memory.PressureLevel metric. + base::TimeTicks last_pressure_level_report_; + + MemoryPressureListener::MemoryPressureLevel current_memory_pressure_level_ = + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; + + // File descriptor used to read and poll(2) available memory from sysfs, + // In /sys/kernel/mm/chromeos-low_mem/available. + ScopedFD available_mem_file_; + + DispatchCallback dispatch_callback_; + + // A periodic timer which will be used to report a UMA metric on the current + // memory pressure level as theoretically we could go a very long time without + // ever receiving a notification. + base::RepeatingTimer reporting_timer_; + + // Kernel waiting callback which is responsible for blocking on the + // available file until it receives a kernel notification, this is + // configurable to make testing easier. + base::RepeatingCallback<bool()> kernel_waiting_callback_; + + base::WeakPtrFactory<MemoryPressureMonitorNotifying> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitorNotifying); +}; + +} // namespace chromeos +} // namespace base +#endif // BASE_MEMORY_MEMORY_PRESSURE_MONITOR_NOTIFYING_CHROMEOS_H_
diff --git a/base/memory/memory_pressure_monitor_notifying_chromeos_unittest.cc b/base/memory/memory_pressure_monitor_notifying_chromeos_unittest.cc new file mode 100644 index 0000000..b9dfe6c --- /dev/null +++ b/base/memory/memory_pressure_monitor_notifying_chromeos_unittest.cc
@@ -0,0 +1,234 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/memory_pressure_monitor_notifying_chromeos.h" + +#include <unistd.h> +#include <string> + +#include "base/bind.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/macros.h" +#include "base/memory/memory_pressure_listener.h" +#include "base/run_loop.h" +#include "base/synchronization/waitable_event.h" +#include "base/system/sys_info.h" +#include "base/task/post_task.h" +#include "base/test/scoped_task_environment.h" +#include "base/test/test_timeouts.h" +#include "base/threading/platform_thread.h" +#include "base/threading/scoped_blocking_call.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace base { +namespace chromeos { + +namespace { +bool SetFileContents(const FilePath& path, const std::string& contents) { + return static_cast<std::string::size_type>(base::WriteFile( + path, contents.c_str(), contents.size())) == contents.size(); +} + +// Since it would be very hard to mock sysfs instead we will send in our own +// implementation of WaitForKernelNotification which instead will block on a +// pipe that we can trigger for the test to cause a mock kernel notification. +bool WaitForMockKernelNotification(int pipe_read_fd, int available_fd) { + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, + base::BlockingType::WILL_BLOCK); + + // We just use a pipe to block our kernel notification thread until we have + // a fake kernel notification. + char buf = 0; + int res = HANDLE_EINTR(read(pipe_read_fd, &buf, sizeof(buf))); + + // Fail if we encounter any error. + return res > 0; +} + +void TriggerKernelNotification(int pipe_write_fd) { + char buf = '1'; + HANDLE_EINTR(write(pipe_write_fd, &buf, sizeof(buf))); +} + +// Processes OnMemoryPressure calls by just storing the sequence of events so we +// can validate that we received the expected pressure levels as the test runs. +void OnMemoryPressure( + std::vector<MemoryPressureListener::MemoryPressureLevel>* history, + MemoryPressureListener::MemoryPressureLevel level) { + history->push_back(level); +} + +} // namespace + +class TestMemoryPressureMonitorNotifying + : public MemoryPressureMonitorNotifying { + public: + TestMemoryPressureMonitorNotifying( + const std::string& mock_margin_file, + const std::string& mock_available_file, + base::RepeatingCallback<bool(int)> kernel_waiting_callback, + bool enable_metrics) + : MemoryPressureMonitorNotifying(mock_margin_file, + mock_available_file, + std::move(kernel_waiting_callback), + enable_metrics) {} + + static std::vector<int> GetMarginFileParts(const std::string& file) { + return MemoryPressureMonitorNotifying::GetMarginFileParts(file); + } + + ~TestMemoryPressureMonitorNotifying() override = default; + + private: + DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitorNotifying); +}; + +TEST(ChromeOSMemoryPressureMonitorNotifyingTest, ParseMarginFileGood) { + base::ScopedTempDir tmp_dir; + ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); + + FilePath margin_file = tmp_dir.GetPath().Append("margin"); + + ASSERT_TRUE(SetFileContents(margin_file, "123")); + const std::vector<int> parts1 = + TestMemoryPressureMonitorNotifying::GetMarginFileParts( + margin_file.value()); + ASSERT_EQ(1u, parts1.size()); + ASSERT_EQ(123, parts1[0]); + + ASSERT_TRUE(SetFileContents(margin_file, "123 456")); + const std::vector<int> parts2 = + TestMemoryPressureMonitorNotifying::GetMarginFileParts( + margin_file.value()); + ASSERT_EQ(2u, parts2.size()); + ASSERT_EQ(123, parts2[0]); + ASSERT_EQ(456, parts2[1]); +} + +TEST(ChromeOSMemoryPressureMonitorNotifyingTest, ParseMarginFileBad) { + base::ScopedTempDir tmp_dir; + ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); + FilePath margin_file = tmp_dir.GetPath().Append("margin"); + + // An empty margin file is bad. + ASSERT_TRUE(SetFileContents(margin_file, "")); + ASSERT_TRUE(TestMemoryPressureMonitorNotifying::GetMarginFileParts( + margin_file.value()) + .empty()); + + // The numbers will be in base10, so 4a6 would be invalid. + ASSERT_TRUE(SetFileContents(margin_file, "123 4a6")); + ASSERT_TRUE(TestMemoryPressureMonitorNotifying::GetMarginFileParts( + margin_file.value()) + .empty()); + + // The numbers must be integers. + ASSERT_TRUE(SetFileContents(margin_file, "123.2 412.3")); + ASSERT_TRUE(TestMemoryPressureMonitorNotifying::GetMarginFileParts( + margin_file.value()) + .empty()); +} + +TEST(ChromeOSMemoryPressureMonitorNotifyingTest, CheckMemoryPressure) { + // Create a temporary directory for our margin and available files. + base::ScopedTempDir tmp_dir; + ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); + + FilePath margin_file = tmp_dir.GetPath().Append("margin"); + FilePath available_file = tmp_dir.GetPath().Append("available"); + + // Set the margin values to 500 (critical) and 1000 (moderate). + const std::string kMarginContents = "500 1000"; + ASSERT_TRUE(SetFileContents(margin_file, kMarginContents)); + + // Write the initial available contents. + const std::string kInitialAvailableContents = "1500"; + ASSERT_TRUE(SetFileContents(available_file, kInitialAvailableContents)); + + test::ScopedTaskEnvironment scoped_task_environment( + test::ScopedTaskEnvironment::MainThreadType::UI); + + // We will use a mock listener to keep track of our kernel notifications which + // cause event to be fired. We can just examine the sequence of pressure + // events when we're done to validate that the pressure events were as + // expected. + std::vector<MemoryPressureListener::MemoryPressureLevel> pressure_events; + auto listener = std::make_unique<MemoryPressureListener>( + base::BindRepeating(&OnMemoryPressure, &pressure_events)); + + // We use a pipe to notify our blocked kernel notification thread that there + // is a kernel notification we need to use a simple blocking syscall and + // read(2)/write(2) will work. + int fds[2] = {}; + ASSERT_EQ(0, HANDLE_EINTR(pipe(fds))); + + // Make sure the pipe FDs get closed. + ScopedFD write_end(fds[1]); + ScopedFD read_end(fds[0]); + + auto monitor = std::make_unique<TestMemoryPressureMonitorNotifying>( + margin_file.value(), available_file.value(), + // Bind the read end to WaitForMockKernelNotification. + base::BindRepeating(&WaitForMockKernelNotification, read_end.get()), + /*enable_metrics=*/false); + + // Validate that our margin levels are as expected after being parsed from our + // synthetic margin file. + ASSERT_EQ(500, monitor->CriticalPressureThresholdMBForTesting()); + ASSERT_EQ(1000, monitor->ModeratePressureThresholdMBForTesting()); + + // At this point we have no memory pressure. + ASSERT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, + monitor->GetCurrentPressureLevel()); + + // Moderate Pressure. + ASSERT_TRUE(SetFileContents(available_file, "900")); + TriggerKernelNotification(write_end.get()); + RunLoop().RunWithTimeout(base::TimeDelta::FromSeconds(1)); + ASSERT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, + monitor->GetCurrentPressureLevel()); + + // Critical Pressure. + ASSERT_TRUE(SetFileContents(available_file, "450")); + TriggerKernelNotification(write_end.get()); + RunLoop().RunWithTimeout(base::TimeDelta::FromSeconds(1)); + ASSERT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, + monitor->GetCurrentPressureLevel()); + + // Moderate Pressure. + ASSERT_TRUE(SetFileContents(available_file, "550")); + TriggerKernelNotification(write_end.get()); + RunLoop().RunWithTimeout(base::TimeDelta::FromSeconds(1)); + ASSERT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, + monitor->GetCurrentPressureLevel()); + + // No pressure, note: this will not cause any event. + ASSERT_TRUE(SetFileContents(available_file, "1150")); + TriggerKernelNotification(write_end.get()); + RunLoop().RunWithTimeout(base::TimeDelta::FromSeconds(1)); + ASSERT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, + monitor->GetCurrentPressureLevel()); + + // Back into moderate. + ASSERT_TRUE(SetFileContents(available_file, "950")); + TriggerKernelNotification(write_end.get()); + RunLoop().RunWithTimeout(base::TimeDelta::FromSeconds(1)); + ASSERT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, + monitor->GetCurrentPressureLevel()); + + // Now our events should be MODERATE, CRITICAL, MODERATE. + ASSERT_EQ(4u, pressure_events.size()); + ASSERT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, + pressure_events[0]); + ASSERT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, + pressure_events[1]); + ASSERT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, + pressure_events[2]); + ASSERT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, + pressure_events[3]); +} + +} // namespace chromeos +} // namespace base
diff --git a/base/memory/memory_pressure_monitor_win.cc b/base/memory/memory_pressure_monitor_win.cc index 396daf5..34a3d71 100644 --- a/base/memory/memory_pressure_monitor_win.cc +++ b/base/memory/memory_pressure_monitor_win.cc
@@ -24,10 +24,7 @@ // memory pressure monitor. The values were determined experimentally to ensure // sufficient responsiveness of the memory pressure subsystem, and minimal // overhead. -const int MemoryPressureMonitor::kPollingIntervalMs = 5000; const int MemoryPressureMonitor::kModeratePressureCooldownMs = 10000; -const int MemoryPressureMonitor::kModeratePressureCooldownCycles = - kModeratePressureCooldownMs / kPollingIntervalMs; // TODO(chrisha): Explore the following constants further with an experiment. @@ -119,7 +116,7 @@ DCHECK(thread_checker_.CalledOnValidThread()); timer_.Start( - FROM_HERE, TimeDelta::FromMilliseconds(kPollingIntervalMs), + FROM_HERE, base::MemoryPressureMonitor::kUMAMemoryPressureLevelPeriod, BindRepeating( &MemoryPressureMonitor::CheckMemoryPressureAndRecordStatistics, weak_ptr_factory_.GetWeakPtr())); @@ -155,6 +152,10 @@ } else { // Already in moderate pressure, only notify if sustained over the // cooldown period. + const int kModeratePressureCooldownCycles = + kModeratePressureCooldownMs / + base::MemoryPressureMonitor::kUMAMemoryPressureLevelPeriod + .InMilliseconds(); if (++moderate_pressure_repeat_count_ == kModeratePressureCooldownCycles) { moderate_pressure_repeat_count_ = 0;
diff --git a/base/memory/memory_pressure_monitor_win.h b/base/memory/memory_pressure_monitor_win.h index a65c191..6a7d0bb8 100644 --- a/base/memory/memory_pressure_monitor_win.h +++ b/base/memory/memory_pressure_monitor_win.h
@@ -24,16 +24,9 @@ class BASE_EXPORT MemoryPressureMonitor : public base::MemoryPressureMonitor { public: // Constants governing the polling and hysteresis behaviour of the observer. - - // The polling interval, in milliseconds. While under critical pressure, this - // is also the timer to repeat cleanup attempts. - static const int kPollingIntervalMs; // The time which should pass between 2 successive moderate memory pressure // signals, in milliseconds. static const int kModeratePressureCooldownMs; - // The number of cycles that should pass between 2 successive moderate memory - // pressure signals. - static const int kModeratePressureCooldownCycles; // Constants governing the memory pressure level detection.
diff --git a/base/memory/memory_pressure_monitor_win_unittest.cc b/base/memory/memory_pressure_monitor_win_unittest.cc index ec64c547..60e4da5f 100644 --- a/base/memory/memory_pressure_monitor_win_unittest.cc +++ b/base/memory/memory_pressure_monitor_win_unittest.cc
@@ -227,8 +227,13 @@ testing::Mock::VerifyAndClearExpectations(&monitor); // Check that the event gets reposted after a while. - for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) { - if (i + 1 == monitor.kModeratePressureCooldownCycles) { + const int kModeratePressureCooldownCycles = + monitor.kModeratePressureCooldownMs / + base::MemoryPressureMonitor::kUMAMemoryPressureLevelPeriod + .InMilliseconds(); + + for (int i = 0; i < kModeratePressureCooldownCycles; ++i) { + if (i + 1 == kModeratePressureCooldownCycles) { EXPECT_CALL(monitor, OnMemoryPressure(MemoryPressureListener:: MEMORY_PRESSURE_LEVEL_MODERATE)); @@ -274,8 +279,8 @@ testing::Mock::VerifyAndClearExpectations(&monitor); // Check that the event gets reposted after a while. - for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) { - if (i + 1 == monitor.kModeratePressureCooldownCycles) { + for (int i = 0; i < kModeratePressureCooldownCycles; ++i) { + if (i + 1 == kModeratePressureCooldownCycles) { EXPECT_CALL(monitor, OnMemoryPressure(MemoryPressureListener:: MEMORY_PRESSURE_LEVEL_MODERATE));
diff --git a/base/sampling_heap_profiler/module_cache_win.cc b/base/sampling_heap_profiler/module_cache_win.cc index 639cbc9..ee62cd62 100644 --- a/base/sampling_heap_profiler/module_cache_win.cc +++ b/base/sampling_heap_profiler/module_cache_win.cc
@@ -15,6 +15,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/win/pe_image.h" #include "base/win/scoped_handle.h" +#include "base/win/win_util.h" namespace base { @@ -52,12 +53,7 @@ return; *pdb_name = FilePath(std::move(pdb_filename)).BaseName(); - const int kGUIDSize = 39; - string16 buffer; - int result = ::StringFromGUID2( - guid, as_writable_wcstr(WriteInto(&buffer, kGUIDSize)), kGUIDSize); - if (result != kGUIDSize) - return; + auto buffer = win::String16FromGUID(guid); RemoveChars(buffer, STRING16_LITERAL("{}-"), &buffer); buffer.append(NumberToString16(age)); *build_id = UTF16ToUTF8(buffer);
diff --git a/base/sampling_heap_profiler/poisson_allocation_sampler.cc b/base/sampling_heap_profiler/poisson_allocation_sampler.cc index 1168ee82b..16bb6fe 100644 --- a/base/sampling_heap_profiler/poisson_allocation_sampler.cc +++ b/base/sampling_heap_profiler/poisson_allocation_sampler.cc
@@ -350,8 +350,8 @@ #endif // BUILDFLAG(USE_ALLOCATOR_SHIM) #if BUILDFLAG(USE_PARTITION_ALLOC) && !defined(OS_NACL) - PartitionAllocHooks::SetAllocationHook(&PartitionAllocHook); - PartitionAllocHooks::SetFreeHook(&PartitionFreeHook); + PartitionAllocHooks::SetObserverHooks(&PartitionAllocHook, + &PartitionFreeHook); #endif // BUILDFLAG(USE_PARTITION_ALLOC) && !defined(OS_NACL) bool expected = false;
diff --git a/base/win/win_util.cc b/base/win/win_util.cc index 4c99ad9..8bfe84d9 100644 --- a/base/win/win_util.cc +++ b/base/win/win_util.cc
@@ -22,6 +22,7 @@ #include <signal.h> #include <stddef.h> #include <stdlib.h> +#include <strsafe.h> #include <tchar.h> // Must be before tpcshrd.h or for any use of _T macro #include <tpcshrd.h> #include <uiviewsettingsinterop.h> @@ -71,13 +72,12 @@ if (SUCCEEDED(result)) return true; #if DCHECK_IS_ON() - ScopedCoMem<OLECHAR> guidString; - ::StringFromCLSID(property_key.fmtid, &guidString); if (HRESULT_FACILITY(result) == FACILITY_WIN32) ::SetLastError(HRESULT_CODE(result)); // See third_party/perl/c/i686-w64-mingw32/include/propkey.h for GUID and // PID definitions. - DPLOG(ERROR) << "Failed to set property with GUID " << guidString << " PID " + DPLOG(ERROR) << "Failed to set property with GUID " + << String16FromGUID(property_key.fmtid) << " PID " << property_key.pid; #endif return false; @@ -721,6 +721,21 @@ } } +string16 String16FromGUID(REFGUID rguid) { + // This constant counts the number of characters in the formatted string, + // including the null termination character. + constexpr int kGuidStringCharacters = + 1 + 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1; + wchar_t guid_string[kGuidStringCharacters]; + CHECK(SUCCEEDED(StringCchPrintfW( + guid_string, kGuidStringCharacters, + L"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", rguid.Data1, + rguid.Data2, rguid.Data3, rguid.Data4[0], rguid.Data4[1], rguid.Data4[2], + rguid.Data4[3], rguid.Data4[4], rguid.Data4[5], rguid.Data4[6], + rguid.Data4[7]))); + return string16(as_u16cstr(guid_string), kGuidStringCharacters - 1); +} + ScopedDomainStateForTesting::ScopedDomainStateForTesting(bool state) : initial_state_(IsEnrolledToDomain()) { *GetDomainEnrollmentStateStorage() = state;
diff --git a/base/win/win_util.h b/base/win/win_util.h index 1806689..fcbca51 100644 --- a/base/win/win_util.h +++ b/base/win/win_util.h
@@ -184,6 +184,9 @@ // Enable high-DPI support for the current process. BASE_EXPORT void EnableHighDPISupport(); +// Returns a string representation of |rguid|. +BASE_EXPORT string16 String16FromGUID(REFGUID rguid); + // Allows changing the domain enrolled state for the life time of the object. // The original state is restored upon destruction. class BASE_EXPORT ScopedDomainStateForTesting {
diff --git a/base/win/win_util_unittest.cc b/base/win/win_util_unittest.cc index 7d63027..a9d98fd 100644 --- a/base/win/win_util_unittest.cc +++ b/base/win/win_util_unittest.cc
@@ -4,12 +4,15 @@ #include "base/win/win_util.h" +#include <objbase.h> + #include "base/files/file_path.h" #include "base/macros.h" #include "base/scoped_native_library.h" #include "base/stl_util.h" #include "base/strings/string16.h" #include "base/strings/string_util.h" +#include "base/win/scoped_co_mem.h" #include "base/win/win_client_metrics.h" #include "testing/gtest/include/gtest/gtest.h" @@ -80,5 +83,22 @@ EXPECT_EQ(INVALID_HANDLE_VALUE, base::win::Uint32ToHandle(invalid_handle)); } +TEST(BaseWinUtilTest, String16FromGUID) { + const GUID kGuid = {0x7698f759, + 0xf5b0, + 0x4328, + {0x92, 0x38, 0xbd, 0x70, 0x8a, 0x6d, 0xc9, 0x63}}; + const base::StringPiece16 kGuidStr( + STRING16_LITERAL("{7698F759-F5B0-4328-9238-BD708A6DC963}")); + auto guid_string16 = String16FromGUID(kGuid); + EXPECT_EQ(guid_string16, kGuidStr); + wchar_t guid_wchar[39]; + ::StringFromGUID2(kGuid, guid_wchar, base::size(guid_wchar)); + EXPECT_STREQ(as_wcstr(guid_string16), guid_wchar); + ScopedCoMem<OLECHAR> clsid_string; + ::StringFromCLSID(kGuid, &clsid_string); + EXPECT_STREQ(as_wcstr(guid_string16), clsid_string.get()); +} + } // namespace win } // namespace base
diff --git a/base/win/windows_types.h b/base/win/windows_types.h index 13067d5..a57277a7 100644 --- a/base/win/windows_types.h +++ b/base/win/windows_types.h
@@ -68,6 +68,11 @@ typedef DWORD ACCESS_MASK; typedef ACCESS_MASK REGSAM; +// As defined in guiddef.h. +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID& +#endif // Forward declare Windows compatible handles.
diff --git a/build/android/resource_sizes.py b/build/android/resource_sizes.py index db4d089..2dbaf9c 100755 --- a/build/android/resource_sizes.py +++ b/build/android/resource_sizes.py
@@ -204,8 +204,7 @@ # If there are multiple .arsc files, use the resource packaged APK instead. if num_arsc_files > 1: if not out_dir: - print('Skipping resources.arsc normalization (output directory required)') - return 0 + return -float('inf') ap_name = os.path.basename(apk_path).replace('.apk', '.ap_') ap_path = os.path.join(out_dir, 'arsc/apks', ap_name) if not os.path.exists(ap_path): @@ -231,7 +230,7 @@ # other languages generally having longer strings than english. size += config_count * (7 + string_size * 1.5) - return size + return int(size) def _CreateResourceIdValueMap(aapt_output, lang): @@ -511,11 +510,15 @@ # WebView (which supports more locales), but these should mostly be # empty so ignore them here. num_arsc_translations = num_translations - normalized_apk_size += int( - _NormalizeResourcesArsc(apk_filename, arsc.GetNumEntries(), - num_arsc_translations, out_dir)) + normalized_apk_size += _NormalizeResourcesArsc( + apk_filename, arsc.GetNumEntries(), num_arsc_translations, out_dir) - report_func('Specifics', 'normalized apk size', normalized_apk_size, 'bytes') + # It will be -Inf for .apk files with multiple .arsc files and no out_dir set. + if normalized_apk_size < 0: + print('Skipping normalized_apk_size because no output directory was set.') + else: + report_func('Specifics', 'normalized apk size', normalized_apk_size, + 'bytes') # The "file count" metric cannot be grouped with any other metrics when the # end result is going to be uploaded to the perf dashboard in the HistogramSet # format due to mixed units (bytes vs. zip entries) causing malformed @@ -529,33 +532,6 @@ 'Unknown entry: %s %d\n' % (info.filename, info.compress_size)) -def _AnnotatePakResources(out_dir): - """Returns a pair of maps: id_name_map, id_header_map.""" - print('Looking at resources in: %s' % out_dir) - - grit_headers = [] - for root, _, files in os.walk(out_dir): - if root.endswith('grit'): - grit_headers += [os.path.join(root, f) for f in files if f.endswith('.h')] - assert grit_headers, 'Failed to find grit headers in %s' % out_dir - - id_name_map = {} - id_header_map = {} - for header in grit_headers: - with open(header, 'r') as f: - for line in f.readlines(): - m = _RC_HEADER_RE.match(line.strip()) - if m: - i = int(m.group('id')) - name = m.group('name') - if i in id_name_map and name != id_name_map[i]: - print('WARNING: Resource ID conflict %s (%s vs %s)' % ( - i, id_name_map[i], name)) - id_name_map[i] = name - id_header_map[i] = os.path.relpath(header, out_dir) - return id_name_map, id_header_map - - def _CalculateCompressedSize(file_path): CHUNK_SIZE = 256 * 1024 compressor = zlib.compressobj() @@ -616,13 +592,15 @@ if out_dir: constants.SetOutputDirectory(out_dir) else: - out_dir = constants.GetOutDirectory() - if out_dir: - build_vars = build_utils.ReadBuildVars( - os.path.join(out_dir, "build_vars.txt")) - tool_prefix = os.path.join(out_dir, build_vars['android_tool_prefix']) - else: - tool_prefix = '' + try: + # Triggers auto-detection when CWD == output directory. + constants.CheckOutputDirectory() + out_dir = constants.GetOutDirectory() + except Exception: # pylint: disable=broad-except + return out_dir, '' + build_vars = build_utils.ReadBuildVars( + os.path.join(out_dir, "build_vars.txt")) + tool_prefix = os.path.join(out_dir, build_vars['android_tool_prefix']) return out_dir, tool_prefix
diff --git a/build/util/version.gni b/build/util/version.gni index 4db593b..ef52bf6 100644 --- a/build/util/version.gni +++ b/build/util/version.gni
@@ -121,9 +121,9 @@ "Monochrome: $monochrome_version_code", "TrichromeChrome: $trichrome_version_code", "MonochromeFP: $notouch_chrome_version_code", - "WebviewStable: $webview_stable_version_code", - "WebviewBeta: $webview_beta_version_code", - "WebviewDev: $webview_dev_version_code", + "AndroidWebviewStable: $webview_stable_version_code", + "AndroidWebviewBeta: $webview_beta_version_code", + "AndroidWebviewDev: $webview_dev_version_code", ] if (target_cpu == "arm64" || target_cpu == "x64") {
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc index cd56fec..e46a166 100644 --- a/cc/trees/layer_tree_host_common.cc +++ b/cc/trees/layer_tree_host_common.cc
@@ -326,23 +326,17 @@ bool non_root_copy_request = effect_node->closest_ancestor_with_copy_request_id > EffectTree::kContentsRootNodeId; + gfx::Transform from_target; // If there is a copy request, we check the invertibility of the transform // between the node corresponding to the layer and the node corresponding to // the copy request. Otherwise, we are interested in the invertibility of // screen space transform which is already cached on the transform node. - if (non_root_copy_request) { - // Null check is a temporary fix for crasher: https://crbug.com/939342 - if (effect_node == nullptr) - return false; - gfx::Transform from_target; - return !property_trees->GetFromTarget( - layer->transform_tree_index(), - effect_node->closest_ancestor_with_copy_request_id, &from_target); - } - // Null check is a temporary fix for crasher: https://crbug.com/939342 - if (transform_node == nullptr) - return false; - return !transform_node->ancestors_are_invertible; + return non_root_copy_request + ? !property_trees->GetFromTarget( + layer->transform_tree_index(), + effect_node->closest_ancestor_with_copy_request_id, + &from_target) + : !transform_node->ancestors_are_invertible; } static void ComputeInitialRenderSurfaceList(
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 05c1e95..247cf36 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -271,8 +271,7 @@ "$google_play_services_package:google_play_services_tasks_java", "//base:base_java", "//base:jni_java", - "//chrome/android/features/keyboard_accessory/factory:java", - "//chrome/android/features/keyboard_accessory/public:java", + "//chrome/android/features/keyboard_accessory:public_java", "//chrome/android/public/lifecycle:java", "//chrome/android/third_party/compositor_animator:compositor_animator_java", "//chrome/android/webapk/libs/client:client_java", @@ -476,7 +475,7 @@ java_group("chrome_all_java") { deps = [ ":chrome_java", - "//chrome/android/features/keyboard_accessory/internal:java", + "//chrome/android/features/keyboard_accessory:internal_java", "//chrome/android/features/media_router:java", ] } @@ -623,7 +622,7 @@ "//base:base_java", "//base:base_java_test_support", "//base:base_junit_test_support", - "//chrome/android/features/keyboard_accessory/internal:java", + "//chrome/android/features/keyboard_accessory:internal_java", "//chrome/android/features/tab_ui:java", "//chrome/android/webapk/libs/client:client_java", "//chrome/android/webapk/libs/common:common_java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index 83dd17ae..fa153c8 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -116,6 +116,7 @@ "java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java", "java/src/org/chromium/chrome/browser/bookmarks/BookmarkPromoHeader.java", "java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java", + "java/src/org/chromium/chrome/browser/bookmarks/BookmarkTextInputLayout.java", "java/src/org/chromium/chrome/browser/bookmarks/BookmarkUIObserver.java", "java/src/org/chromium/chrome/browser/bookmarks/BookmarkUIState.java", "java/src/org/chromium/chrome/browser/bookmarks/BookmarkUndoController.java", @@ -1725,7 +1726,6 @@ "java/src/org/chromium/chrome/browser/widget/ControlContainer.java", "java/src/org/chromium/chrome/browser/widget/DateDividedAdapter.java", "java/src/org/chromium/chrome/browser/widget/DualControlLayout.java", - "java/src/org/chromium/chrome/browser/widget/EmptyAlertEditText.java", "java/src/org/chromium/chrome/browser/widget/FadingEdgeScrollView.java", "java/src/org/chromium/chrome/browser/widget/FadingShadow.java", "java/src/org/chromium/chrome/browser/widget/FadingShadowView.java",
diff --git a/chrome/android/features/android_library_factory_tmpl.gni b/chrome/android/features/android_library_factory_tmpl.gni new file mode 100644 index 0000000..d59fd8e --- /dev/null +++ b/chrome/android/features/android_library_factory_tmpl.gni
@@ -0,0 +1,79 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/android/rules.gni") + +# Declare an Android library factory target. +# +# This target creates an Android library target containing stripped java +# factory files. The generated target will not contain any .class files as all +# of them are excluded by jar_excluded_patterns. This target is intended to +# generate an empty factory that will be swapped out at build time by the real +# factory. +# +# Specific requirements for the java factory files are listed in the script: +# //chrome/android/features/create_stripped_java_factory.py +# +# Variables: +# sources: A list of all java factory files to be stripped. +# deps: Any deps needed by the generated Android library target. +# +# Example: +# android_library_factory("foo_java") { +# sources = [ +# "android/org/chromium/foo/FooFactory.java", +# ] +# deps = [ +# ":foo_public_interface" +# ] +# } +# +# //android/org/chromium/foo/FooFactory.java: +# public class FooFactory { +# private FooFactory () {} +# +# public static Foo createFoo() { +# return new FooImpl(); +# } +# } +# +# //generated/org/chromium/foo/FooFactory.java: +# public class FooFactory { +# private FooFactory () {} +# +# public static Foo createFoo() { +# return null; +# } +# } +template("android_library_factory") { + forward_variables_from(invoker, [ "testonly" ]) + + # No underscores for factory target name to avoid crbug.com/908819. + _process_factory_target_name = "${target_name}factory" + _base_gen_dir = "${target_gen_dir}/${target_name}" + + action_foreach_with_pydeps(_process_factory_target_name) { + script = "//chrome/android/features/create_stripped_java_factory.py" + sources = invoker.sources + outputs = [ + "$_base_gen_dir/{{source_root_relative_dir}}/{{source_file_part}}", + ] + args = [ + "--output", + rebase_path(outputs[0], root_build_dir), + "--input={{source}}", + ] + } + + android_library(target_name) { + deps = [ + ":$_process_factory_target_name", + ] + if (defined(invoker.deps)) { + deps += invoker.deps + } + java_files = get_target_outputs(":$_process_factory_target_name") + jar_excluded_patterns = [ "*" ] + } +}
diff --git a/chrome/android/features/create_stripped_java_factory.py b/chrome/android/features/create_stripped_java_factory.py new file mode 100755 index 0000000..4536fa6d43 --- /dev/null +++ b/chrome/android/features/create_stripped_java_factory.py
@@ -0,0 +1,115 @@ +#!/usr/bin/env python +# +# Copyright 2019 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. + +"""Generates a stripped down version of a java factory file. + +A stripped down factory file is required in a feature's public_java target +during the compilation process so that features can depend on each other +without creating circular dependencies. + +Afterwards, the stripped down factory's .class file is excluded from the +resulting target. The real factory uses the feature's internal implementations, +which is why it is not included in the feature's public_java target. + +This script generates stripped down factory files from real factory files to +reduce the burden of maintenance. It checks to make sure that these factory +files are as simple as possible and replaces multi-line java return statements +with 'return null;'. + +In order to keep the regex simple and easily understood, the java factory files +have a few strict requirements. This avoids the need to take care of every +corner case involving comments or strings. Since the generated factory file is +only used during the build, and the real one is used at runtime, it is +sufficient to have the build pass with simple modifications. + +We require that these factory files to: + - Contain exactly one top-level class. + - Avoid inner classes. + - Avoid explicitly importing internal classes. + - One option is to be in the same package as internal classes. + - Only contain public static methods apart from the constructor. +""" + +import argparse +import re +import os +import sys + +sys.path.append(os.path.join(os.path.dirname(__file__), + os.pardir, os.pardir, os.pardir, + 'build', 'android', 'gyp')) +from util import build_utils + + +# Matches multi-line public static methods: +# '^( public static ' - Matches the first part of the method signature. +# '(?!void)' - Do not match methods signatures that return void. +# '[^{]+ {)' - Matches the rest of the method signature until the opening brace. +# '.+?' - Non-greedy match to only match one method body. +# '^( })$' - Matches the closing brace of the method. +_RE_PUBLIC_STATIC_NOT_VOID_METHOD = re.compile( + r'^( public static (?!void)[^{]+ {).+?^( })$', + re.DOTALL | re.MULTILINE) +# Replacement string to replace the entire method body with a null return. +_RETURN_NULL = r'''\g<1> + return null; +\g<2>''' + +# Matches multi-line public static void methods: +# Same as for public static methods, explicitly specify void return type. +_RE_PUBLIC_STATIC_VOID_METHOD = re.compile( + r'^( public static void [^{]+ {).+?^( })$', re.DOTALL | re.MULTILINE) +# Replacement string to replace the entire method body with an empty return. +_RETURN = r'''\g<1> + return; +\g<2>''' + +_RE_CLASS = re.compile(r'\bclass (\w+)\b') +_PRIVATE_CONSTRUCTOR = 'private {0}() {{}}\n' + + +def _ParseArgs(args): + parser = argparse.ArgumentParser() + parser.add_argument('--input', required=True, help='Input java file path.') + parser.add_argument('--output', required=True, help='Output java file path.') + options = parser.parse_args(args) + return options + + +def _EnsureSimpleFactory(content): + """Assert that the java factory file is very simple. + + This is important since we are using the build system to swap out .class + files of corresponding generated and internal java factory files. Keeping the + factory files as simple as possible minimizes the overhead of reasoning about + the factory code. It is already sufficiently complex to deduce which file a + target is actually using when calling one of these factories. + """ + classes = _RE_CLASS.findall(content) + assert len(classes) == 1, 'Factory must contain exactly one class.' + class_name = classes[0] + assert _PRIVATE_CONSTRUCTOR.format(class_name) in content, ( + 'Factory must have a private constructor with no arguments.') + + +def _ReplaceMethodBodies(content): + content = _RE_PUBLIC_STATIC_NOT_VOID_METHOD.sub(_RETURN_NULL, content) + content = _RE_PUBLIC_STATIC_VOID_METHOD.sub(_RETURN, content) + return content + + +def main(args): + options = _ParseArgs(args) + with open(options.input, 'r') as f: + content = f.read() + _EnsureSimpleFactory(content) + replaced_content = _ReplaceMethodBodies(content) + with build_utils.AtomicOutput(options.output) as f: + f.write(replaced_content) + + +if __name__ == '__main__': + main(sys.argv[1:])
diff --git a/chrome/android/features/create_stripped_java_factory.pydeps b/chrome/android/features/create_stripped_java_factory.pydeps new file mode 100644 index 0000000..db7ee793 --- /dev/null +++ b/chrome/android/features/create_stripped_java_factory.pydeps
@@ -0,0 +1,7 @@ +# Generated by running: +# build/print_python_deps.py --root chrome/android/features --output chrome/android/features/create_stripped_java_factory.pydeps chrome/android/features/create_stripped_java_factory.py +../../../build/android/gyp/util/__init__.py +../../../build/android/gyp/util/build_utils.py +../../../build/android/gyp/util/md5_check.py +../../../build/gn_helpers.py +create_stripped_java_factory.py
diff --git a/chrome/android/features/keyboard_accessory/BUILD.gn b/chrome/android/features/keyboard_accessory/BUILD.gn index bd670cc..43d7093 100644 --- a/chrome/android/features/keyboard_accessory/BUILD.gn +++ b/chrome/android/features/keyboard_accessory/BUILD.gn
@@ -4,6 +4,21 @@ import("//build/config/android/rules.gni") +java_group("public_java") { + deps = [ + "factory:public_java", + "public:public_java", + ] +} + +# Only chrome_all_java and test targets should depend on this internal target. +java_group("internal_java") { + deps = [ + "factory:internal_java", + "internal:internal_java", + ] +} + generate_jni("jni_headers") { sources = [ "internal/java/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryViewBridge.java", @@ -34,8 +49,8 @@ ] deps = [ - "internal:java", - "public:java", + "internal:internal_java", + "public:public_java", "//base:base_java", "//base:base_java_test_support", "//chrome/android:chrome_java", @@ -69,8 +84,7 @@ ] deps = [ - "internal:java", - "public:java", + ":internal_java", "//base:base_java_test_support", "//base:base_junit_test_support", "//chrome/android:chrome_junit_test_support",
diff --git a/chrome/android/features/keyboard_accessory/factory/BUILD.gn b/chrome/android/features/keyboard_accessory/factory/BUILD.gn index 89e7000..f92b7d0a 100644 --- a/chrome/android/features/keyboard_accessory/factory/BUILD.gn +++ b/chrome/android/features/keyboard_accessory/factory/BUILD.gn
@@ -3,12 +3,20 @@ # found in the LICENSE file. import("//build/config/android/rules.gni") +import("//chrome/android/features/android_library_factory_tmpl.gni") -# Only need to depend on this target if explicitly calling ManualFillingComponent#createComponent. -android_library("java") { +_factory_sources = [ "java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentFactory.java" ] + +android_library_factory("public_java") { deps = [ - "//chrome/android/features/keyboard_accessory/public:java", + "//chrome/android/features/keyboard_accessory/public:public_java", ] - java_files = [ "generated/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentFactory.java" ] - jar_excluded_patterns = [ "*" ] + sources = _factory_sources +} + +android_library("internal_java") { + deps = [ + "//chrome/android/features/keyboard_accessory/internal:internal_java", + ] + java_files = _factory_sources }
diff --git a/chrome/android/features/keyboard_accessory/factory/generated/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentFactory.java b/chrome/android/features/keyboard_accessory/factory/generated/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentFactory.java deleted file mode 100644 index 8310e65e..0000000 --- a/chrome/android/features/keyboard_accessory/factory/generated/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentFactory.java +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.keyboard_accessory; - -/** - * Use {@link #createComponent()} to instantiate a {@link ManualFillingComponent}. - */ -public class ManualFillingComponentFactory { - private ManualFillingComponentFactory() {} - - /** - * Creates a {@link ManualFillingComponent} if the implementation is available. If it isn't, - * null is returned instead which doesn't do anything. - * @return null. - */ - public static ManualFillingComponent createComponent() { - return null; - } -}
diff --git a/chrome/android/features/keyboard_accessory/internal/BUILD.gn b/chrome/android/features/keyboard_accessory/internal/BUILD.gn index 4c966b6..c5681774 100644 --- a/chrome/android/features/keyboard_accessory/internal/BUILD.gn +++ b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
@@ -5,7 +5,7 @@ import("//build/config/android/rules.gni") import("//chrome/common/features.gni") -android_library("java") { +android_library("internal_java") { deps = [ ":java_resources", "//base:base_java", @@ -13,7 +13,7 @@ # TODO(crbug/951695): Cyclic dependency. Depend on public only when ready. "//chrome/android:chrome_java", "//chrome/android:chrome_public_java", - "//chrome/android/features/keyboard_accessory/public:java", + "//chrome/android/features/keyboard_accessory/public:public_java", "//components/autofill/android:autofill_java", "//content/public/android:content_java", "//third_party/android_deps:android_support_v7_appcompat_java", @@ -23,7 +23,6 @@ "//ui/android:ui_utils_java", ] java_files = [ - "../factory/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentFactory.java", "java/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryViewBridge.java", "java/src/org/chromium/chrome/browser/keyboard_accessory/KeyboardExtensionViewResizer.java", "java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java",
diff --git a/chrome/android/features/keyboard_accessory/public/BUILD.gn b/chrome/android/features/keyboard_accessory/public/BUILD.gn index 2bc922b..4739805 100644 --- a/chrome/android/features/keyboard_accessory/public/BUILD.gn +++ b/chrome/android/features/keyboard_accessory/public/BUILD.gn
@@ -4,7 +4,7 @@ import("//build/config/android/rules.gni") -android_library("java") { +android_library("public_java") { deps = [ "//base:base_java", "//chrome/android:chrome_public_java",
diff --git a/chrome/android/java/res/layout/bookmark_add_edit_folder_activity.xml b/chrome/android/java/res/layout/bookmark_add_edit_folder_activity.xml index e676be23..d0da1ac0 100644 --- a/chrome/android/java/res/layout/bookmark_add_edit_folder_activity.xml +++ b/chrome/android/java/res/layout/bookmark_add_edit_folder_activity.xml
@@ -21,7 +21,7 @@ android:orientation="vertical" android:clipToPadding="false" > - <org.chromium.chrome.browser.widget.EmptyAlertEditText + <org.chromium.chrome.browser.bookmarks.BookmarkTextInputLayout android:id="@+id/folder_title" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -29,10 +29,15 @@ android:layout_marginStart="12dp" android:layout_marginTop="24dp" android:hint="@string/title" - android:imeOptions="flagNoExtractUi" - android:inputType="textCapSentences|textAutoCorrect" - android:textAppearance="@style/TextAppearance.BlackHeadline" - app:alertMessage="@string/bookmark_missing_title" /> + app:emptyErrorMessage="@string/bookmark_missing_title"> + + <android.support.design.widget.TextInputEditText + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.BlackHeadline" + android:imeOptions="flagNoExtractUi" + android:inputType="textCapSentences|textAutoCorrect" /> + </org.chromium.chrome.browser.bookmarks.BookmarkTextInputLayout> <TextView android:layout_width="wrap_content"
diff --git a/chrome/android/java/res/layout/bookmark_edit.xml b/chrome/android/java/res/layout/bookmark_edit.xml index 06b13a2a..3d5dbbe 100644 --- a/chrome/android/java/res/layout/bookmark_edit.xml +++ b/chrome/android/java/res/layout/bookmark_edit.xml
@@ -21,20 +21,20 @@ android:layout_marginStart="16dp" android:orientation="vertical" > - <org.chromium.chrome.browser.widget.CompatibilityTextInputLayout + <org.chromium.chrome.browser.bookmarks.BookmarkTextInputLayout + android:id="@+id/title_text" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="22dp" > - <org.chromium.chrome.browser.widget.EmptyAlertEditText - android:id="@+id/title_text" + android:layout_marginTop="22dp" + android:hint="@string/bookmark_name" + app:emptyErrorMessage="@string/bookmark_missing_title"> + <android.support.design.widget.TextInputEditText android:layout_width="match_parent" android:layout_height="wrap_content" - android:hint="@string/bookmark_name" android:imeOptions="flagNoExtractUi" android:inputType="textCapSentences|textAutoCorrect" - android:singleLine="true" - app:alertMessage="@string/bookmark_missing_title" /> - </org.chromium.chrome.browser.widget.CompatibilityTextInputLayout> + android:singleLine="true" /> + </org.chromium.chrome.browser.bookmarks.BookmarkTextInputLayout> <TextView android:layout_width="wrap_content" @@ -54,21 +54,21 @@ android:layout_marginEnd="3dp" android:textAppearance="@style/TextAppearance.BookmarkEditFolderName" /> - <org.chromium.chrome.browser.widget.CompatibilityTextInputLayout + <org.chromium.chrome.browser.bookmarks.BookmarkTextInputLayout + android:id="@+id/url_text" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="24dp" > + android:layout_marginTop="24dp" + android:hint="@string/bookmark_url" + app:emptyErrorMessage="@string/bookmark_missing_url"> - <org.chromium.chrome.browser.widget.EmptyAlertEditText - android:id="@+id/url_text" + <android.support.design.widget.TextInputEditText android:layout_width="match_parent" android:layout_height="wrap_content" - android:hint="@string/bookmark_url" android:imeOptions="flagNoExtractUi" android:inputType="textUri" - android:singleLine="true" - app:alertMessage="@string/bookmark_missing_url" /> - </org.chromium.chrome.browser.widget.CompatibilityTextInputLayout> + android:singleLine="true" /> + </org.chromium.chrome.browser.bookmarks.BookmarkTextInputLayout> </LinearLayout> </ScrollView>
diff --git a/chrome/android/java/res/layout/powered_by_chrome_footer.xml b/chrome/android/java/res/layout/powered_by_chrome_footer.xml index 88a7513..1e6d0a4 100644 --- a/chrome/android/java/res/layout/powered_by_chrome_footer.xml +++ b/chrome/android/java/res/layout/powered_by_chrome_footer.xml
@@ -21,5 +21,5 @@ <View android:layout_width="match_parent" android:layout_height="1dp" - android:background="#e0e0e0" /> + android:background="@color/divider_bg_color" /> </FrameLayout>
diff --git a/chrome/android/java/res/values/attrs.xml b/chrome/android/java/res/values/attrs.xml index 097ea1d..a56ca1c 100644 --- a/chrome/android/java/res/values/attrs.xml +++ b/chrome/android/java/res/values/attrs.xml
@@ -39,8 +39,8 @@ <attr name="floatLabelHint" format="reference|string" /> </declare-styleable> - <declare-styleable name="EmptyAlertEditText"> - <attr name="alertMessage" format="string" /> + <declare-styleable name="BookmarkTextInputLayout"> + <attr name="emptyErrorMessage" format="string" /> </declare-styleable> <declare-styleable name="PaddedFrameLayout">
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillUiUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillUiUtils.java index 019bb97..4ee877f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillUiUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillUiUtils.java
@@ -4,7 +4,9 @@ package org.chromium.chrome.browser.autofill; +import android.content.ComponentCallbacks; import android.content.Context; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.ColorFilter; import android.graphics.PorterDuff; @@ -21,6 +23,7 @@ import android.widget.TextView; import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.base.ContextUtils; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; @@ -85,10 +88,32 @@ popup.setOutsideTouchable(true); popup.setBackgroundDrawable(ApiCompatibilityUtils.getDrawable( resources, R.drawable.store_locally_tooltip_background)); + + // An alternate solution is to extend TextView and override onConfigurationChanged. However, + // due to lemon compression, onConfigurationChanged never gets called. + final ComponentCallbacks componentCallbacks = new ComponentCallbacks() { + @Override + public void onConfigurationChanged(Configuration configuration) { + // If the popup was already showing dismiss it. This may happen during an + // orientation change. + if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE + && popup != null) { + popup.dismiss(); + } + } + + @Override + public void onLowMemory() {} + }; + + ContextUtils.getApplicationContext().registerComponentCallbacks(componentCallbacks); + popup.setOnDismissListener(() -> { Handler h = new Handler(); h.postDelayed(dismissAction, TOOLTIP_DEFERRED_PERIOD_MS); + ContextUtils.getApplicationContext().unregisterComponentCallbacks(componentCallbacks); }); + popup.showAsDropDown(anchorView, offsetProvider.getXOffset(textView), offsetProvider.getYOffset(textView)); textView.announceForAccessibility(textView.getText());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkAddEditFolderActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkAddEditFolderActivity.java index 9725de8..a1b0dba 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkAddEditFolderActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkAddEditFolderActivity.java
@@ -12,13 +12,13 @@ import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; +import android.widget.EditText; import android.widget.TextView; import org.chromium.chrome.R; import org.chromium.chrome.browser.SynchronousInitializationActivity; import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem; import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkModelObserver; -import org.chromium.chrome.browser.widget.EmptyAlertEditText; import org.chromium.chrome.browser.widget.TintedDrawable; import org.chromium.components.bookmarks.BookmarkId; @@ -42,7 +42,7 @@ private BookmarkId mParentId; private BookmarkModel mModel; private TextView mParentTextView; - private EmptyAlertEditText mFolderTitle; + private BookmarkTextInputLayout mFolderTitle; // Add mode member variable private List<BookmarkId> mBookmarksToMove; @@ -133,8 +133,8 @@ } setContentView(R.layout.bookmark_add_edit_folder_activity); - mParentTextView = (TextView) findViewById(R.id.parent_folder); - mFolderTitle = (EmptyAlertEditText) findViewById(R.id.folder_title); + mParentTextView = findViewById(R.id.parent_folder); + mFolderTitle = findViewById(R.id.folder_title); mParentTextView.setOnClickListener(this); @@ -150,8 +150,9 @@ getSupportActionBar().setTitle(R.string.edit_folder); BookmarkItem bookmarkItem = mModel.getBookmarkById(mFolderId); updateParent(bookmarkItem.getParentId()); - mFolderTitle.setText(bookmarkItem.getTitle()); - mFolderTitle.setSelection(mFolderTitle.getText().length()); + final EditText editText = mFolderTitle.getEditText(); + editText.setText(bookmarkItem.getTitle()); + editText.setSelection(editText.getText().length()); mParentTextView.setEnabled(bookmarkItem.isMovable()); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkEditActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkEditActivity.java index 3750d3e..c065e5b3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkEditActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkEditActivity.java
@@ -17,7 +17,6 @@ import org.chromium.chrome.browser.SynchronousInitializationActivity; import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem; import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkModelObserver; -import org.chromium.chrome.browser.widget.EmptyAlertEditText; import org.chromium.chrome.browser.widget.TintedDrawable; import org.chromium.components.bookmarks.BookmarkId; import org.chromium.components.url_formatter.UrlFormatter; @@ -33,8 +32,8 @@ private BookmarkModel mModel; private BookmarkId mBookmarkId; - private EmptyAlertEditText mTitleEditText; - private EmptyAlertEditText mUrlEditText; + private BookmarkTextInputLayout mTitleEditText; + private BookmarkTextInputLayout mUrlEditText; private TextView mFolderTextView; private MenuItem mDeleteButton; @@ -67,9 +66,9 @@ } setContentView(R.layout.bookmark_edit); - mTitleEditText = (EmptyAlertEditText) findViewById(R.id.title_text); + mTitleEditText = findViewById(R.id.title_text); mFolderTextView = (TextView) findViewById(R.id.folder_text); - mUrlEditText = (EmptyAlertEditText) findViewById(R.id.url_text); + mUrlEditText = findViewById(R.id.url_text); mFolderTextView.setOnClickListener(new View.OnClickListener() { @Override @@ -99,8 +98,8 @@ BookmarkItem bookmarkItem = mModel.getBookmarkById(mBookmarkId); // While the user is editing the bookmark, do not override user's input. if (!modelChanged) { - mTitleEditText.setText(bookmarkItem.getTitle()); - mUrlEditText.setText(bookmarkItem.getUrl()); + mTitleEditText.getEditText().setText(bookmarkItem.getTitle()); + mUrlEditText.getEditText().setText(bookmarkItem.getUrl()); } mFolderTextView.setText(mModel.getBookmarkTitle(bookmarkItem.getParentId())); mTitleEditText.setEnabled(bookmarkItem.isEditable());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkTextInputLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkTextInputLayout.java new file mode 100644 index 0000000..d0a93db1 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkTextInputLayout.java
@@ -0,0 +1,79 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.bookmarks; + +import android.content.Context; +import android.content.res.TypedArray; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.AttributeSet; + +import org.chromium.chrome.R; +import org.chromium.chrome.browser.widget.CompatibilityTextInputLayout; + +/** + * Wraps around {@link CompatibilityTextInputLayout} to implement a basic empty field error behavior + * for the Bookmark related TextInputLayouts. + */ +public class BookmarkTextInputLayout extends CompatibilityTextInputLayout { + private String mEmptyErrorMessage; + + public BookmarkTextInputLayout(Context context, AttributeSet attrs) { + super(context, attrs); + + final TypedArray a = + context.obtainStyledAttributes(attrs, R.styleable.BookmarkTextInputLayout); + final int emptyErrorMessageId = + a.getResourceId(R.styleable.BookmarkTextInputLayout_emptyErrorMessage, 0); + if (emptyErrorMessageId != 0) { + mEmptyErrorMessage = context.getResources().getString(emptyErrorMessageId); + } + + a.recycle(); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + getEditText().addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + validate(); + } + }); + } + + /** + * @return Trimmed text for validation. + */ + String getTrimmedText() { + return getEditText().getText().toString().trim(); + } + + /** + * @return Whether the content is empty. + */ + boolean isEmpty() { + return TextUtils.isEmpty(getTrimmedText()); + } + + /** + * Check the text and show or hide error message if needed. + * If there is a need for extra validation, this method should be overridden + * and extra validation statements should be added after calling super.validate() + */ + void validate() { + if (mEmptyErrorMessage != null) { + setError(isEmpty() ? mEmptyErrorMessage : null); + } + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetProvider.java index e365b13..2002d292 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetProvider.java
@@ -66,7 +66,7 @@ public void onDeleted(Context context, int[] appWidgetIds) { super.onDeleted(context, appWidgetIds); for (int widgetId : appWidgetIds) { - BookmarkWidgetService.deleteWidgetState(context, widgetId); + BookmarkWidgetService.deleteWidgetState(widgetId); } removeOrphanedStates(context); } @@ -100,7 +100,7 @@ AppWidgetManager wm = AppWidgetManager.getInstance(context); int[] ids = wm.getAppWidgetIds(getComponentName(context)); for (int id : ids) { - BookmarkWidgetService.deleteWidgetState(context, id); + BookmarkWidgetService.deleteWidgetState(id); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetProxy.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetProxy.java index b966bc20..e63b587 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetProxy.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetProxy.java
@@ -21,9 +21,8 @@ @Override public void onReceive(Context context, Intent intent) { - if (BookmarkWidgetService.getChangeFolderAction(context) - .equals(intent.getAction())) { - BookmarkWidgetService.changeFolder(context, intent); + if (BookmarkWidgetService.getChangeFolderAction().equals(intent.getAction())) { + BookmarkWidgetService.changeFolder(intent); } else { Intent view = new Intent(intent); view.setClass(context, ChromeLauncherActivity.class);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java index 0aa19c1..53f551a69 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java
@@ -23,6 +23,7 @@ import com.google.android.apps.chrome.appwidget.bookmarks.BookmarkThumbnailWidgetProvider; import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.library_loader.ProcessInitException; import org.chromium.base.metrics.RecordUserAction; @@ -77,35 +78,34 @@ return new BookmarkAdapter(this, widgetId); } - static String getChangeFolderAction(Context context) { - return context.getPackageName() + ACTION_CHANGE_FOLDER_SUFFIX; + static String getChangeFolderAction() { + return ContextUtils.getApplicationContext().getPackageName() + ACTION_CHANGE_FOLDER_SUFFIX; } // TODO(crbug.com/635567): Fix this properly. @SuppressLint("DefaultLocale") - static SharedPreferences getWidgetState(Context context, int widgetId) { + static SharedPreferences getWidgetState(int widgetId) { StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); try { - return context.getSharedPreferences( - String.format("widgetState-%d", widgetId), - Context.MODE_PRIVATE); + return ContextUtils.getApplicationContext().getSharedPreferences( + String.format("widgetState-%d", widgetId), Context.MODE_PRIVATE); } finally { StrictMode.setThreadPolicy(oldPolicy); } } - static void deleteWidgetState(Context context, int widgetId) { - SharedPreferences preferences = getWidgetState(context, widgetId); + static void deleteWidgetState(int widgetId) { + SharedPreferences preferences = getWidgetState(widgetId); if (preferences != null) preferences.edit().clear().apply(); } - static void changeFolder(Context context, Intent intent) { + static void changeFolder(Intent intent) { int widgetId = IntentUtils.safeGetIntExtra(intent, AppWidgetManager.EXTRA_APPWIDGET_ID, -1); String serializedFolder = IntentUtils.safeGetStringExtra(intent, EXTRA_FOLDER_ID); if (widgetId >= 0 && serializedFolder != null) { - SharedPreferences prefs = getWidgetState(context, widgetId); + SharedPreferences prefs = getWidgetState(widgetId); prefs.edit().putString(PREF_CURRENT_FOLDER, serializedFolder).apply(); - AppWidgetManager.getInstance(context) + AppWidgetManager.getInstance(ContextUtils.getApplicationContext()) .notifyAppWidgetViewDataChanged(widgetId, R.id.bookmarks_list); } } @@ -287,7 +287,7 @@ public BookmarkAdapter(Context context, int widgetId) { mContext = context; mWidgetId = widgetId; - mPreferences = getWidgetState(mContext, mWidgetId); + mPreferences = getWidgetState(mWidgetId); mIconColor = ApiCompatibilityUtils.getColor( mContext.getResources(), R.color.default_icon_color_dark); } @@ -354,7 +354,7 @@ PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> { if (mBookmarkModel != null) mBookmarkModel.destroy(); }); - deleteWidgetState(mContext, mWidgetId); + deleteWidgetState(mWidgetId); } @BinderThread @@ -493,9 +493,9 @@ Intent fillIn; if (bookmark.isFolder) { - fillIn = new Intent(getChangeFolderAction(mContext)) - .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mWidgetId) - .putExtra(EXTRA_FOLDER_ID, id.toString()); + fillIn = new Intent(getChangeFolderAction()) + .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mWidgetId) + .putExtra(EXTRA_FOLDER_ID, id.toString()); } else { fillIn = new Intent(Intent.ACTION_VIEW); if (!TextUtils.isEmpty(url)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java index 116f6e7..6b57a5f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
@@ -277,7 +277,7 @@ private boolean mWarmupHasBeenCalled; public ClientManager() { - RequestThrottler.loadInBackground(ContextUtils.getApplicationContext()); + RequestThrottler.loadInBackground(); } /** Creates a new session. @@ -346,8 +346,7 @@ TextUtils.isEmpty(url) && lowConfidence && !params.lowConfidencePrediction; params.setPredictionMetrics(url, SystemClock.elapsedRealtime(), lowConfidence); if (firstLowConfidencePrediction) return true; - RequestThrottler throttler = - RequestThrottler.getForUid(ContextUtils.getApplicationContext(), uid); + RequestThrottler throttler = RequestThrottler.getForUid(uid); return throttler.updateStatsAndReturnWhetherAllowed(); } @@ -401,8 +400,7 @@ if (outcome == PredictionStatus.GOOD) { long elapsedTimeMs = SystemClock.elapsedRealtime() - params.getLastMayLaunchUrlTimestamp(); - RequestThrottler.getForUid(ContextUtils.getApplicationContext(), params.uid) - .registerSuccess(params.mPredictedUrl); + RequestThrottler.getForUid(params.uid).registerSuccess(params.mPredictedUrl); RecordHistogram.recordCustomTimesHistogram("CustomTabs.PredictionToLaunch", elapsedTimeMs, 1, DateUtils.MINUTE_IN_MILLIS * 3, 100); } @@ -769,24 +767,22 @@ /** See {@link RequestThrottler#isPrerenderingAllowed()} */ public synchronized boolean isPrerenderingAllowed(int uid) { - return RequestThrottler.getForUid(ContextUtils.getApplicationContext(), uid) - .isPrerenderingAllowed(); + return RequestThrottler.getForUid(uid).isPrerenderingAllowed(); } /** See {@link RequestThrottler#registerPrerenderRequest(String)} */ public synchronized void registerPrerenderRequest(int uid, String url) { - RequestThrottler.getForUid(ContextUtils.getApplicationContext(), uid) - .registerPrerenderRequest(url); + RequestThrottler.getForUid(uid).registerPrerenderRequest(url); } /** See {@link RequestThrottler#reset()} */ public synchronized void resetThrottling(int uid) { - RequestThrottler.getForUid(ContextUtils.getApplicationContext(), uid).reset(); + RequestThrottler.getForUid(uid).reset(); } /** See {@link RequestThrottler#ban()} */ public synchronized void ban(int uid) { - RequestThrottler.getForUid(ContextUtils.getApplicationContext(), uid).ban(); + RequestThrottler.getForUid(uid).ban(); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java index 27c9b4e0..27e5636 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -460,7 +460,7 @@ // The throttling database uses shared preferences, that can cause a // StrictMode violation on the first access. Make sure that this access is // not in mayLauchUrl. - RequestThrottler.loadInBackground(ContextUtils.getApplicationContext()); + RequestThrottler.loadInBackground(); } }); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java index 07eced08..028c4ba 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java
@@ -31,7 +31,7 @@ public void onCreate() { ProcessInitializationHandler.getInstance().initializePreNative(); // Kick off the first access to avoid random StrictMode violations in clients. - RequestThrottler.loadInBackground(getApplication()); + RequestThrottler.loadInBackground(); super.onCreate(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/RequestThrottler.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/RequestThrottler.java index 749b5ec..97ce68b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/RequestThrottler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/RequestThrottler.java
@@ -5,13 +5,13 @@ package org.chromium.chrome.browser.customtabs; import android.annotation.SuppressLint; -import android.content.Context; import android.content.SharedPreferences; import android.os.SystemClock; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.SparseArray; +import org.chromium.base.ContextUtils; import org.chromium.base.VisibleForTesting; import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; @@ -126,14 +126,14 @@ } /** @return the {@link Throttler} for a given UID. */ - public static RequestThrottler getForUid(Context context, int uid) { + public static RequestThrottler getForUid(int uid) { if (sUidToThrottler == null) { sUidToThrottler = new SparseArray<>(); - purgeOldEntries(context); + purgeOldEntries(); } RequestThrottler throttler = sUidToThrottler.get(uid); if (throttler == null) { - throttler = new RequestThrottler(context, uid); + throttler = new RequestThrottler(uid); sUidToThrottler.put(uid, throttler); } return throttler; @@ -162,8 +162,9 @@ editor.putFloat(SCORE + mUid, mScore); } - private RequestThrottler(Context context, int uid) { - mSharedPreferences = context.getSharedPreferences(PREFERENCES_NAME, 0); + private RequestThrottler(int uid) { + mSharedPreferences = + ContextUtils.getApplicationContext().getSharedPreferences(PREFERENCES_NAME, 0); mUid = uid; mScore = mSharedPreferences.getFloat(SCORE + uid, MAX_SCORE); mLastPrerenderRequestMs = mSharedPreferences.getLong(LAST_REQUEST + uid, 0); @@ -196,20 +197,21 @@ * the background to hopefully avoid the violation (if the next edit() call happens once the * preferences are loaded). * - * @param context The application context. */ // TODO(crbug.com/635567): Fix this properly. @SuppressLint("CommitPrefEdits") - static void loadInBackground(final Context context) { + static void loadInBackground() { boolean alreadyDone = !sAccessedSharedPreferences.compareAndSet(false, true); if (alreadyDone) return; - PostTask.postTask(TaskTraits.BEST_EFFORT_MAY_BLOCK, - () -> { context.getSharedPreferences(PREFERENCES_NAME, 0).edit(); }); + PostTask.postTask(TaskTraits.BEST_EFFORT_MAY_BLOCK, () -> { + ContextUtils.getApplicationContext().getSharedPreferences(PREFERENCES_NAME, 0).edit(); + }); } /** Removes all the UIDs that haven't been seen since at least {@link FORGET_AFTER_MS}. */ - private static void purgeOldEntries(Context context) { - SharedPreferences sharedPreferences = context.getSharedPreferences(PREFERENCES_NAME, 0); + private static void purgeOldEntries() { + SharedPreferences sharedPreferences = + ContextUtils.getApplicationContext().getSharedPreferences(PREFERENCES_NAME, 0); SharedPreferences.Editor editor = sharedPreferences.edit(); long now = System.currentTimeMillis(); for (Map.Entry<String, ?> entry : sharedPreferences.getAll().entrySet()) { @@ -231,8 +233,9 @@ } @VisibleForTesting - static void purgeAllEntriesForTesting(Context context) { - SharedPreferences sharedPreferences = context.getSharedPreferences(PREFERENCES_NAME, 0); + static void purgeAllEntriesForTesting() { + SharedPreferences sharedPreferences = + ContextUtils.getApplicationContext().getSharedPreferences(PREFERENCES_NAME, 0); sharedPreferences.edit().clear().apply(); if (sUidToThrottler != null) sUidToThrottler.clear(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentUtils.java index d4bf99c5..5855975 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentUtils.java
@@ -124,12 +124,11 @@ /** * Returns the ID of the last shown Tab for the given DocumentTabModel type. - * @param context Context to pull SharedPrefs from. * @param isIncognito Whether to get the ID for the regular or Incognito TabModel. * @return ID of the last shown Tab for the given TabModel type. */ - public static int getLastShownTabIdFromPrefs(Context context, boolean isIncognito) { - SharedPreferences prefs = context.getSharedPreferences( + public static int getLastShownTabIdFromPrefs(boolean isIncognito) { + SharedPreferences prefs = ContextUtils.getApplicationContext().getSharedPreferences( DocumentTabModelImpl.PREF_PACKAGE, Context.MODE_PRIVATE); String prefName = isIncognito ? DocumentTabModelImpl.PREF_LAST_SHOWN_TAB_ID_INCOGNITO
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java index 4055e2a8..f357604 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -677,7 +677,7 @@ context.startActivity(viewIntent); service.updateLastAccessTime(downloadGuid, isOffTheRecord); return true; - } catch (ActivityNotFoundException e) { + } catch (Exception e) { // Can't launch the Intent. if (source != DownloadMetrics.DownloadOpenSource.DOWNLOAD_PROGRESS_INFO_BAR) { Toast.makeText(context, context.getString(R.string.download_cant_open_file),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassin.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassin.java index 5823988..00472c60 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassin.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassin.java
@@ -492,7 +492,7 @@ if (newStage == STAGE_INITIALIZED) { Log.d(TAG, "Migrating user into tabbed mode."); - int selectedTabId = DocumentUtils.getLastShownTabIdFromPrefs(getContext(), false); + int selectedTabId = DocumentUtils.getLastShownTabIdFromPrefs(false); copyTabStateFiles(selectedTabId); } else if (newStage == STAGE_COPY_TAB_STATES_DONE) { Log.d(TAG, "Writing tabbed mode metadata file.");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java index cff02c8c..35013b8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java
@@ -104,9 +104,6 @@ /** Delegate for working with the filesystem. */ private final StorageDelegate mStorageDelegate; - /** Context to use. */ - private final Context mContext; - private final TabModelDelegate mTabModelDelegate; /** Current loading status. */ @@ -131,15 +128,13 @@ * @param tabCreatorManager Used to create Tabs. * @param isIncognito Whether or not the TabList is managing incognito tabs. * @param prioritizedTabId ID of the tab to prioritize when loading. - * @param context Context to use for accessing SharedPreferences. */ public DocumentTabModelImpl(ActivityDelegate activityDelegate, StorageDelegate storageDelegate, TabCreatorManager tabCreatorManager, boolean isIncognito, int prioritizedTabId, - Context context, TabModelDelegate tabModelDelegate) { + TabModelDelegate tabModelDelegate) { super(isIncognito, false); mActivityDelegate = activityDelegate; mStorageDelegate = storageDelegate; - mContext = context; mTabModelDelegate = tabModelDelegate; mCurrentState = STATE_UNINITIALIZED; @@ -147,7 +142,7 @@ mEntryMap = new SparseArray<Entry>(); mHistoricalTabs = new ArrayList<Integer>(); - mLastShownTabId = DocumentUtils.getLastShownTabIdFromPrefs(mContext, isIncognito()); + mLastShownTabId = DocumentUtils.getLastShownTabIdFromPrefs(isIncognito()); // Restore the tab list. setCurrentState(STATE_READ_RECENT_TASKS_START);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelSelector.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelSelector.java index 5803520..8a3965e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelSelector.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelSelector.java
@@ -90,15 +90,14 @@ mRegularTabDelegate = regularTabDelegate; mIncognitoTabDelegate = incognitoTabDelegate; - final Context context = ContextUtils.getApplicationContext(); mRegularTabModel = new DocumentTabModelImpl( - mActivityDelegate, mStorageDelegate, this, false, sPrioritizedTabId, context, this); + mActivityDelegate, mStorageDelegate, this, false, sPrioritizedTabId, this); mIncognitoTabModel = new IncognitoDocumentTabModel(new IncognitoTabModelDelegate() { @Override public TabModel createTabModel() { DocumentTabModel incognitoModel = new DocumentTabModelImpl(mActivityDelegate, mStorageDelegate, DocumentTabModelSelector.this, true, sPrioritizedTabId, - context, DocumentTabModelSelector.this); + DocumentTabModelSelector.this); return incognitoModel; } @@ -119,7 +118,8 @@ initializeTabIdCounter(); // Re-select the previously selected TabModel. - SharedPreferences prefs = context.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE); + SharedPreferences prefs = ContextUtils.getApplicationContext().getSharedPreferences( + PREF_PACKAGE, Context.MODE_PRIVATE); boolean startIncognito = prefs.getBoolean(PREF_IS_INCOGNITO_SELECTED, false); initialize(startIncognito, mRegularTabModel, mIncognitoTabModel); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/CompatibilityTextInputLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/CompatibilityTextInputLayout.java index 64b4406..22fec00d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/CompatibilityTextInputLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/CompatibilityTextInputLayout.java
@@ -12,6 +12,8 @@ import android.view.ViewGroup; import android.widget.EditText; +import org.chromium.chrome.R; + import java.util.ArrayList; /** @@ -25,6 +27,9 @@ public CompatibilityTextInputLayout(Context context, AttributeSet attrs) { super(context, attrs); + + setErrorTextAppearance(R.style.TextAppearance_ErrorCaption); + // Disable the hint animation initially to work around a bug in the support library that // causes the hint text and text in populated EditText views to overlap when first // displayed on M-. See https://crbug.com/740057. @@ -38,7 +43,7 @@ } @Override - public void onFinishInflate() { + protected void onFinishInflate() { super.onFinishInflate(); // If there is an EditText descendant, make this serve as the label for it.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/EmptyAlertEditText.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/EmptyAlertEditText.java deleted file mode 100644 index c1ae32a..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/EmptyAlertEditText.java +++ /dev/null
@@ -1,83 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.widget; - -import android.content.Context; -import android.content.res.TypedArray; -import android.support.v7.widget.AppCompatEditText; -import android.text.Editable; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.util.AttributeSet; - -import org.chromium.chrome.R; - -/** - * An EditText that shows an alert message when the content is empty. - */ -public class EmptyAlertEditText extends AppCompatEditText { - - private String mAlertMessage; - - /** - * Constructor for inflating from XML. - */ - public EmptyAlertEditText(Context context, AttributeSet attrs) { - super(context, attrs); - final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.EmptyAlertEditText); - int resId = a.getResourceId(R.styleable.EmptyAlertEditText_alertMessage, 0); - if (resId != 0) mAlertMessage = context.getResources().getString(resId); - a.recycle(); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) {} - - @Override - public void afterTextChanged(Editable s) { - validate(); - } - }); - } - - /** - * @return Trimmed text for validation. - */ - public String getTrimmedText() { - return getText().toString().trim(); - } - - /** - * Sets the alert message to be shown when the text content is empty. - */ - public void setAlertMessage(String message) { - mAlertMessage = message; - } - - /** - * @return Whether the content is empty. - */ - public boolean isEmpty() { - return TextUtils.isEmpty(getTrimmedText()); - } - - /** - * Check the text and show or hide error message if needed. - */ - public void validate() { - if (isEmpty()) { - setError(mAlertMessage); - } else { - if (getError() != null) setError(null); - } - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/ClientManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/ClientManagerTest.java index ae07b2e7..df2f619 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/ClientManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/ClientManagerTest.java
@@ -52,7 +52,7 @@ .getTargetContext() .getApplicationContext(); mActivityTestRule.loadNativeLibraryNoBrowserProcess(); - RequestThrottler.purgeAllEntriesForTesting(context); + RequestThrottler.purgeAllEntriesForTesting(); mClientManager = new ClientManager(); TestThreadUtils.runOnUiThreadBlocking( () -> OriginVerifier.clearCachedVerificationsForTesting()); @@ -295,7 +295,7 @@ mClientManager.registerLaunch(mSession, URL); // Low -> High as well. - RequestThrottler.purgeAllEntriesForTesting(context); + RequestThrottler.purgeAllEntriesForTesting(); Assert.assertTrue( mClientManager.updateStatsAndReturnWhetherAllowed(mSession, mUid, null, true)); Assert.assertTrue( @@ -303,7 +303,7 @@ mClientManager.registerLaunch(mSession, URL); // High -> Low as well. - RequestThrottler.purgeAllEntriesForTesting(context); + RequestThrottler.purgeAllEntriesForTesting(); Assert.assertTrue( mClientManager.updateStatsAndReturnWhetherAllowed(mSession, mUid, URL, false)); Assert.assertTrue( @@ -335,21 +335,21 @@ Assert.assertEquals(1, noMayLaunchUrlDelta.getDelta()); // Low confidence. - RequestThrottler.purgeAllEntriesForTesting(context); + RequestThrottler.purgeAllEntriesForTesting(); Assert.assertTrue( mClientManager.updateStatsAndReturnWhetherAllowed(mSession, mUid, null, true)); mClientManager.registerLaunch(mSession, URL); Assert.assertEquals(1, lowConfidenceDelta.getDelta()); // High confidence. - RequestThrottler.purgeAllEntriesForTesting(context); + RequestThrottler.purgeAllEntriesForTesting(); Assert.assertTrue( mClientManager.updateStatsAndReturnWhetherAllowed(mSession, mUid, URL, false)); mClientManager.registerLaunch(mSession, URL); Assert.assertEquals(1, highConfidenceDelta.getDelta()); // Low and High confidence. - RequestThrottler.purgeAllEntriesForTesting(context); + RequestThrottler.purgeAllEntriesForTesting(); Assert.assertTrue( mClientManager.updateStatsAndReturnWhetherAllowed(mSession, mUid, URL, false)); Assert.assertTrue( @@ -358,7 +358,7 @@ Assert.assertEquals(1, bothDelta.getDelta()); // Low and High confidence, same call. - RequestThrottler.purgeAllEntriesForTesting(context); + RequestThrottler.purgeAllEntriesForTesting(); bothDelta = new MetricsUtils.HistogramDelta(name, ClientManager.MayLaunchUrlType.BOTH); Assert.assertTrue( mClientManager.updateStatsAndReturnWhetherAllowed(mSession, mUid, URL, true));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java index aa91eae92..fb22d69 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java
@@ -38,12 +38,12 @@ @Before public void setUp() throws Exception { mContext = InstrumentationRegistry.getTargetContext(); - RequestThrottler.purgeAllEntriesForTesting(mContext); + RequestThrottler.purgeAllEntriesForTesting(); } @After public void tearDown() throws Exception { - RequestThrottler.purgeAllEntriesForTesting(mContext); + RequestThrottler.purgeAllEntriesForTesting(); } /** Tests that a client starts not banned. */ @@ -51,7 +51,7 @@ @SmallTest @UiThreadTest public void testIsInitiallyNotBanned() { - Assert.assertTrue(RequestThrottler.getForUid(mContext, UID).isPrerenderingAllowed()); + Assert.assertTrue(RequestThrottler.getForUid(UID).isPrerenderingAllowed()); } /** Tests that a misbehaving client gets banned. */ @@ -59,7 +59,7 @@ @SmallTest @UiThreadTest public void testBansUid() { - RequestThrottler throttler = RequestThrottler.getForUid(mContext, UID); + RequestThrottler throttler = RequestThrottler.getForUid(UID); Assert.assertTrue(throttler.isPrerenderingAllowed()); for (int i = 0; i < 100; i++) throttler.registerPrerenderRequest(URL); Assert.assertFalse(throttler.isPrerenderingAllowed()); @@ -70,7 +70,7 @@ @SmallTest @UiThreadTest public void testBanningMatchesUrls() { - RequestThrottler throttler = RequestThrottler.getForUid(mContext, UID); + RequestThrottler throttler = RequestThrottler.getForUid(UID); Assert.assertTrue(throttler.isPrerenderingAllowed()); for (int i = 0; i < 100; i++) { throttler.registerPrerenderRequest(URL); @@ -85,7 +85,7 @@ @SmallTest @UiThreadTest public void testDontBanAccurateClients() { - RequestThrottler throttler = RequestThrottler.getForUid(mContext, UID); + RequestThrottler throttler = RequestThrottler.getForUid(UID); Assert.assertTrue(throttler.isPrerenderingAllowed()); for (int i = 0; i < 100; i++) { throttler.registerPrerenderRequest(URL); @@ -99,7 +99,7 @@ @SmallTest @UiThreadTest public void testDontBanPartiallyAccurateClients() { - RequestThrottler throttler = RequestThrottler.getForUid(mContext, UID); + RequestThrottler throttler = RequestThrottler.getForUid(UID); Assert.assertTrue(throttler.isPrerenderingAllowed()); for (int j = 0; j < 10; j++) { throttler.registerPrerenderRequest(URL); @@ -115,10 +115,10 @@ @SmallTest @UiThreadTest public void testThrottlingBanIsByUid() { - RequestThrottler throttler = RequestThrottler.getForUid(mContext, UID); + RequestThrottler throttler = RequestThrottler.getForUid(UID); Assert.assertTrue(throttler.isPrerenderingAllowed()); for (int i = 0; i < 100; i++) throttler.registerPrerenderRequest(URL); Assert.assertFalse(throttler.isPrerenderingAllowed()); - Assert.assertTrue(RequestThrottler.getForUid(mContext, UID2).isPrerenderingAllowed()); + Assert.assertTrue(RequestThrottler.getForUid(UID2).isPrerenderingAllowed()); } }
diff --git a/chrome/android/touchless/java/res/layout/touchless_suggestions_tile_view.xml b/chrome/android/touchless/java/res/layout/touchless_suggestions_tile_view.xml index cf50acd..8259302 100644 --- a/chrome/android/touchless/java/res/layout/touchless_suggestions_tile_view.xml +++ b/chrome/android/touchless/java/res/layout/touchless_suggestions_tile_view.xml
@@ -6,15 +6,15 @@ <org.chromium.chrome.browser.touchless.SiteSuggestionsTileView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="@dimen/tile_view_icon_size" + android:layout_height="@dimen/tile_view_icon_size" android:layout_gravity="center" android:background="@drawable/suggestion_tile"> <!-- The icon background. --> <View android:id="@+id/tile_view_icon_background" - android:layout_width="@dimen/tile_view_icon_size" - android:layout_height="@dimen/tile_view_icon_size" + android:layout_width="match_parent" + android:layout_height="match_parent" android:background="@drawable/tile_view_icon_background_modern" /> <!-- The main icon. --> @@ -27,8 +27,8 @@ <!-- Focus highlight. --> <View - android:layout_width="@dimen/tile_view_icon_size" - android:layout_height="@dimen/tile_view_icon_size" + android:layout_width="match_parent" + android:layout_height="match_parent" android:background="@drawable/suggestion_tile" android:duplicateParentState="true"/>
diff --git a/chrome/android/touchless/java/res/values-v17/dimens.xml b/chrome/android/touchless/java/res/values-v17/dimens.xml index 2544a76..ccbe0d6fa 100644 --- a/chrome/android/touchless/java/res/values-v17/dimens.xml +++ b/chrome/android/touchless/java/res/values-v17/dimens.xml
@@ -27,8 +27,8 @@ <!-- Most likely carousel dimensions. --> <dimen name="most_likely_tile_focus_stroke_width">2dp</dimen> - <dimen name="most_likely_tile_horizontal_spacer">6dp</dimen> <dimen name="most_likely_carousel_edge_spacer">8dp</dimen> + <dimen name="most_likely_tile_size">40dp</dimen> <!-- Desired 24dp, but the edge spacer is also in effect. 8 + 16 = 24 --> <dimen name="above_the_fold_bottom_margin">16dp</dimen>
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsAdapter.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsAdapter.java index cb25342..d821cc0 100644 --- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsAdapter.java +++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsAdapter.java
@@ -6,6 +6,7 @@ import static org.chromium.chrome.browser.touchless.SiteSuggestionsCoordinator.ASYNC_FOCUS_DELEGATE; import static org.chromium.chrome.browser.touchless.SiteSuggestionsCoordinator.CURRENT_INDEX_KEY; +import static org.chromium.chrome.browser.touchless.SiteSuggestionsCoordinator.INITIAL_INDEX_KEY; import static org.chromium.chrome.browser.touchless.SiteSuggestionsCoordinator.ITEM_COUNT_KEY; import static org.chromium.chrome.browser.touchless.SiteSuggestionsCoordinator.ON_FOCUS_CALLBACK; import static org.chromium.chrome.browser.touchless.SiteSuggestionsCoordinator.REMOVAL_KEY; @@ -15,7 +16,6 @@ import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.support.graphics.drawable.VectorDrawableCompat; -import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.ContextMenu; import android.view.View; @@ -77,10 +77,8 @@ @Override public void removeItem() { - // Remove the suggestion, which requests layout. - mModel.get(SUGGESTIONS_KEY).remove(mSuggestion); // Notify about removal. - mModel.set(REMOVAL_KEY, mSuggestion.get(SiteSuggestionModel.URL_KEY)); + mModel.set(REMOVAL_KEY, mSuggestion); // Force-trigger rebind of current_index to update text. onPropertyChanged(mModel, CURRENT_INDEX_KEY); } @@ -108,7 +106,7 @@ private RoundedIconGenerator mIconGenerator; private SuggestionsNavigationDelegate mNavDelegate; private ContextMenuManager mContextMenuManager; - private LinearLayoutManager mLayoutManager; + private SiteSuggestionsLayoutManager mLayoutManager; private TextView mTitleView; private final RecyclerView mRecyclerView; @@ -123,7 +121,8 @@ */ SiteSuggestionsAdapter(PropertyModel model, RoundedIconGenerator iconGenerator, SuggestionsNavigationDelegate navigationDelegate, ContextMenuManager contextMenuManager, - LinearLayoutManager layoutManager, TextView titleView, RecyclerView recyclerView) { + SiteSuggestionsLayoutManager layoutManager, TextView titleView, + RecyclerView recyclerView) { mModel = model; mIconGenerator = iconGenerator; mNavDelegate = navigationDelegate; @@ -204,10 +203,9 @@ public void onPropertyChanged( PropertyObservable<PropertyKey> source, @Nullable PropertyKey propertyKey) { if (propertyKey == CURRENT_INDEX_KEY) { - // When the current index changes, we want to scroll to position and update the title. + // When the current index changes, we want to update the title. int position = mModel.get(CURRENT_INDEX_KEY); int itemCount = mModel.get(ITEM_COUNT_KEY); - mLayoutManager.scrollToPosition(position); if (itemCount == 1 || position % itemCount == 0) { mTitleView.setText(R.string.ntp_all_apps); } else { @@ -219,6 +217,8 @@ && mModel.get(ASYNC_FOCUS_DELEGATE) != null) { mModel.get(ASYNC_FOCUS_DELEGATE).onResult(mRecyclerView); mModel.set(SHOULD_FOCUS_VIEW, false); + } else if (propertyKey == INITIAL_INDEX_KEY) { + mLayoutManager.scrollToPosition(mModel.get(INITIAL_INDEX_KEY)); } }
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsCoordinator.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsCoordinator.java index 4fca165..57cb334f 100644 --- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsCoordinator.java +++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsCoordinator.java
@@ -6,7 +6,6 @@ import android.content.Context; import android.graphics.Rect; -import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewStub; @@ -30,12 +29,14 @@ class SiteSuggestionsCoordinator { static final PropertyModel.WritableIntPropertyKey CURRENT_INDEX_KEY = new PropertyModel.WritableIntPropertyKey(); + static final PropertyModel.WritableIntPropertyKey INITIAL_INDEX_KEY = + new PropertyModel.WritableIntPropertyKey(); static final PropertyModel .ReadableObjectPropertyKey<PropertyListModel<PropertyModel, PropertyKey>> SUGGESTIONS_KEY = new PropertyModel.ReadableObjectPropertyKey<>(); static final PropertyModel.WritableIntPropertyKey ITEM_COUNT_KEY = new PropertyModel.WritableIntPropertyKey(); - static final PropertyModel.WritableObjectPropertyKey<String> REMOVAL_KEY = + static final PropertyModel.WritableObjectPropertyKey<PropertyModel> REMOVAL_KEY = new PropertyModel.WritableObjectPropertyKey<>(); public static final PropertyModel.WritableObjectPropertyKey<Runnable> ON_FOCUS_CALLBACK = new PropertyModel.WritableObjectPropertyKey<>(); @@ -50,10 +51,13 @@ SiteSuggestionsCoordinator(View parentView, Profile profile, SuggestionsNavigationDelegate navigationDelegate, ContextMenuManager contextMenuManager, ImageFetcher imageFetcher, TouchlessLayoutManager touchlessLayoutManager) { + Context context = parentView.getContext(); + SiteSuggestionsLayoutManager layoutManager = new SiteSuggestionsLayoutManager(context); PropertyModel model = new PropertyModel - .Builder(CURRENT_INDEX_KEY, SUGGESTIONS_KEY, ITEM_COUNT_KEY, REMOVAL_KEY, - ON_FOCUS_CALLBACK, SHOULD_FOCUS_VIEW, ASYNC_FOCUS_DELEGATE) + .Builder(CURRENT_INDEX_KEY, INITIAL_INDEX_KEY, SUGGESTIONS_KEY, + ITEM_COUNT_KEY, REMOVAL_KEY, ON_FOCUS_CALLBACK, SHOULD_FOCUS_VIEW, + ASYNC_FOCUS_DELEGATE) .with(SUGGESTIONS_KEY, new PropertyListModel<>()) .with(ITEM_COUNT_KEY, 1) .with(ASYNC_FOCUS_DELEGATE, @@ -61,14 +65,12 @@ .build(); View suggestionsView = ((ViewStub) parentView.findViewById(R.id.most_likely_stub)).inflate(); - Context context = parentView.getContext(); RoundedIconGenerator iconGenerator = ViewUtils.createDefaultRoundedIconGenerator( context.getResources(), /* circularIcon = */ true); int iconSize = context.getResources().getDimensionPixelSize(R.dimen.tile_view_icon_min_size); - LinearLayoutManager layoutManager = new SiteSuggestionsLayoutManager(context); RecyclerView recyclerView = suggestionsView.findViewById(R.id.most_likely_launcher_recycler); SiteSuggestionsAdapter adapterDelegate = new SiteSuggestionsAdapter(model, iconGenerator, @@ -87,10 +89,8 @@ Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { outRect.bottom = context.getResources().getDimensionPixelSize( R.dimen.most_likely_carousel_edge_spacer); - outRect.left = context.getResources().getDimensionPixelSize( - R.dimen.most_likely_tile_horizontal_spacer); - outRect.right = context.getResources().getDimensionPixelSize( - R.dimen.most_likely_tile_horizontal_spacer); + outRect.left = 0; + outRect.right = 0; outRect.top = context.getResources().getDimensionPixelSize( R.dimen.most_likely_carousel_edge_spacer); }
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsLayoutManager.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsLayoutManager.java index ade379c1..fe7721ee 100644 --- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsLayoutManager.java +++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsLayoutManager.java
@@ -7,7 +7,11 @@ import android.content.Context; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.util.SparseArray; import android.view.View; +import android.view.ViewGroup; + +import org.chromium.chrome.touchless.R; /** * Custom layout manager for site suggestions carousel. Handles custom effects such as @@ -15,23 +19,260 @@ * to the middle of the view. */ class SiteSuggestionsLayoutManager extends LinearLayoutManager { + private static final float[] SCALE_FACTORS = {0.8f, 0.9f, 1f, 0.9f, 0.8f}; + private static final float SUM_FACTORS; + // Initialize SUM_FACTORS to be sum of scale factors. + static { + float sum = 0f; + for (float num : SCALE_FACTORS) { + sum += num; + } + SUM_FACTORS = sum; + } + private static final int MAX_TILES = 5; + + private int mFocusPosition; + private boolean mNeedRebind; + private Context mContext; + SiteSuggestionsLayoutManager(Context context) { - super(context, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false); + super(context); + setReverseLayout(false); + setOrientation(LinearLayoutManager.HORIZONTAL); + mContext = context; + mFocusPosition = 0; + mNeedRebind = false; } @Override public boolean onRequestChildFocus( RecyclerView parent, RecyclerView.State state, View child, View focused) { if (focused != null) { - // Gets the adapter position of the child. - int position = getPosition(child); - // Calculates the offset for the child's left edge such that the child would be - // perfectly centered in the view. - int childHalfWidth = child.getWidth() / 2 + getLeftDecorationWidth(child); - int offset = parent.getWidth() / 2 - childHalfWidth; - // Scroll to child with calculated offset. - scrollToPositionWithOffset(position, offset); + int newChildPos = getPosition(focused); + scrollToPosition(newChildPos); } return true; } + + @Override + public boolean supportsPredictiveItemAnimations() { + return false; + } + + @Override + public RecyclerView.LayoutParams generateDefaultLayoutParams() { + return new RecyclerView.LayoutParams( + RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.WRAP_CONTENT); + } + + /** + * Calculates what views should be shown in the viewport and lays them out. Inherently does not + * support animations. + * + * @param recycler Recycler to use for fetching potentially cached views for a position. + * @param state Transient state of the RecyclerView. + */ + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + if (getItemCount() == 0) { + return; + } + int currentFirstPosition = 0; + if (getChildCount() != 0) { + currentFirstPosition = getPosition(getChildAt(0)); + } + + SparseArray<View> viewCache = new SparseArray<>(); + if (mNeedRebind) { + // If we need to re-bind all the data, recycle everything to force re-bind. + removeAndRecycleAllViews(recycler); + mNeedRebind = false; + } else { + // Temporarily cache all views. + for (int i = 0; i < getChildCount(); i++) { + viewCache.append(currentFirstPosition + i, getChildAt(i)); + } + + // Temporarily detach all views. + for (int i = 0; i < viewCache.size(); i++) { + detachView(viewCache.valueAt(i)); + } + } + + int futureFirstPosition = findFirstVisibleItemPosition(); + int futureLastPosition = findLastVisibleItemPosition(); + + // Adds all the views necessary. + for (int i = futureFirstPosition; i <= futureLastPosition; i++) { + View child = viewCache.get(i); + if (child == null) { + // If only 1 view, set spacers around the view such that it appears in the center. + child = recycler.getViewForPosition(i); + addView(child); + } else { + viewCache.remove(i); + attachView(child); + } + } + + resizeViews(); + + // Recycle all unused views. + for (int i = 0; i < viewCache.size(); i++) { + removeDetachedView(viewCache.valueAt(i)); + recycler.recycleView(viewCache.valueAt(i)); + } + } + + @Override + public boolean canScrollHorizontally() { + return getItemCount() > 1; + } + + /** + * Scrolls the views by a delta. Layout new views only when one has been completely + * scrolled off the screen. + * + * Note that this method does not scale the children as they move across the screen and does not + * layout partial views, which may be a suboptimal visual experience on a normal device. + * + * TODO(chili): Soften the jump when the new tile appears. + */ + @Override + public int scrollHorizontallyBy( + int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { + if (getItemCount() <= 1 || getChildCount() == 0) return 0; + + // Move all children by -dx. This is because if we're dragging the elements to the left + // (<0), scrollbar is moving to the right (>0). + offsetChildrenHorizontal(-dx); + + // Whether the first item is completely visible. + boolean isFirstItemVisible = getDecoratedRight(getChildAt(0)) > 0; + // Whether the last item is completely visible. + boolean isLastItemVisible = getDecoratedLeft(getChildAt(getChildCount() - 1)) < getWidth(); + + if (!isFirstItemVisible || !isLastItemVisible) { + if (dx > 0) { + mFocusPosition++; + } else { + mFocusPosition--; + } + onLayoutChildren(recycler, state); + } + + return dx; + } + + @Override + public void scrollToPosition(int position) { + if (position == mFocusPosition) return; + mFocusPosition = position; + assertNotInLayoutOrScroll("Scroll called within scroll"); + requestLayout(); + } + + /** + * Returns what the first visible item position should be. Might not be accurate during layout. + */ + @Override + public int findFirstVisibleItemPosition() { + return Math.max(0, mFocusPosition - 2); + } + + /** + * Returns what the last visible item position should be. Might not be accurate during layout. + */ + @Override + public int findLastVisibleItemPosition() { + int lastVisiblePosition = mFocusPosition + 2; + if (lastVisiblePosition < 0 || lastVisiblePosition == Integer.MAX_VALUE) { + lastVisiblePosition = Integer.MAX_VALUE - 1; + } + if (lastVisiblePosition >= getItemCount()) { + lastVisiblePosition = getItemCount() - 1; + } + return lastVisiblePosition; + } + + @Override + public void onItemsChanged(RecyclerView recyclerView) { + requestFullRebind(); + } + + @Override + public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) { + requestFullRebind(); + } + + @Override + public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) { + requestFullRebind(); + } + + @Override + public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount) { + requestFullRebind(); + } + + @Override + public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) { + requestFullRebind(); + } + + /** + * Requests layout such that it forces rebind of all visible items with + * updated data from the adapter. + */ + private void requestFullRebind() { + mNeedRebind = true; + requestLayout(); + } + + /** + * Resizes currently attached views based on their position (larger in the middle). + * + * Views are centered, with increasing space between them as the screen widens. We assume + * that the screens are at least wide enough to display all of the icons at with minimal space. + * The tiles will overlap if there is a screen too small to do so. + */ + private void resizeViews() { + int leftOffset = 0; + // Amount of space to leave between items such that it would take up all available width. + final int horizontalSpacer = + (int) ((getWidth() + - SUM_FACTORS + * mContext.getResources().getDimensionPixelSize( + R.dimen.most_likely_tile_size)) + / (MAX_TILES - 1)); + + for (int i = 0; i < Math.min(getChildCount(), MAX_TILES); i++) { + View child = getChildAt(i); + + // Scale according to position. + ViewGroup.LayoutParams params = child.getLayoutParams(); + int iconSize = (int) (mContext.getResources().getDimensionPixelSize( + R.dimen.most_likely_tile_size) + * SCALE_FACTORS[i]); + params.height = iconSize; + params.width = iconSize; + child.setLayoutParams(params); + + // Offset the top so that it's centered vertically. + int topOffset = + (mContext.getResources().getDimensionPixelSize(R.dimen.most_likely_tile_size) + - iconSize) + / 2; + + measureChildWithMargins(child, 0, 0); + int decoratedChildWidth = getDecoratedMeasuredWidth(child); + int decoratedChildHeight = getDecoratedMeasuredHeight(child); + + layoutDecoratedWithMargins(child, leftOffset, topOffset, + leftOffset + decoratedChildWidth, topOffset + decoratedChildHeight); + + // The next tile needs to be <horizontal spacer> padded away from this tile. + leftOffset += decoratedChildWidth + horizontalSpacer; + } + } }
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsMediator.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsMediator.java index c23f178f..8b903c2 100644 --- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsMediator.java +++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsMediator.java
@@ -25,6 +25,7 @@ import org.chromium.ui.modelutil.PropertyObservable; import org.chromium.ui.widget.Toast; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -42,7 +43,7 @@ // we divide by 240 (which is 5!) before multiplying by 120. // TODO(chili): Maybe better formula for if this needs to be more generic. private static final int INITIAL_SCROLLED_POSITION = Integer.MAX_VALUE / 240 * 120; - private static final int MAX_DISPLAYED_TILES = 5; + private static final int MAX_DISPLAYED_TILES = 4; private PropertyModel mModel; private ImageFetcher mImageFetcher; @@ -70,13 +71,16 @@ urls.add(model.get(SiteSuggestionModel.URL_KEY)); } + // Because of the way we calculate mods, it's better to add suggestions all at once. + List<PropertyModel> modelList = new ArrayList<>(siteSuggestions.size()); + // Map each SiteSuggestion into a PropertyModel representation and fetch the icon. for (SiteSuggestion suggestion : siteSuggestions) { // Do not put duplicates. if (urls.contains(suggestion.url)) continue; PropertyModel siteSuggestion = SiteSuggestionModel.getSiteSuggestionModel(suggestion); - mModel.get(SiteSuggestionsCoordinator.SUGGESTIONS_KEY).add(siteSuggestion); + modelList.add(siteSuggestion); if (suggestion.whitelistIconPath.isEmpty()) { makeIconRequest(siteSuggestion); } else { @@ -93,13 +97,20 @@ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } } - // Total item count is 1 more than number of site suggestions to account for "all apps". - mModel.set(SiteSuggestionsCoordinator.ITEM_COUNT_KEY, getItemCount()); - // If we fetched site suggestions the first time, set initial scrolled position. - // We don't want to set scrolled position if we've already set position before. + // If everything was duplicate. don't do anything. + if (modelList.isEmpty()) return; + + // Total item count is 1 more than number of site suggestions to account for "all apps". + mModel.set(SiteSuggestionsCoordinator.ITEM_COUNT_KEY, + getItemCount(modelList.size() + urls.size())); + mModel.get(SiteSuggestionsCoordinator.SUGGESTIONS_KEY).addAll(modelList); + + // If we fetched site suggestions the first time, set initial and current position. + // We don't want to set position if we've already set position before. if (siteSuggestions.size() > 0 - && mModel.get(SiteSuggestionsCoordinator.CURRENT_INDEX_KEY) == 0) { + && mModel.get(SiteSuggestionsCoordinator.INITIAL_INDEX_KEY) == 0) { + mModel.set(SiteSuggestionsCoordinator.INITIAL_INDEX_KEY, INITIAL_SCROLLED_POSITION); mModel.set(SiteSuggestionsCoordinator.CURRENT_INDEX_KEY, INITIAL_SCROLLED_POSITION); } } @@ -118,17 +129,19 @@ public void onPropertyChanged( PropertyObservable<PropertyKey> source, @Nullable PropertyKey propertyKey) { if (propertyKey == SiteSuggestionsCoordinator.REMOVAL_KEY) { - String removalUrl = mModel.get(SiteSuggestionsCoordinator.REMOVAL_KEY); - mMostVisitedSites.addBlacklistedUrl(removalUrl); + PropertyModel suggestion = mModel.get(SiteSuggestionsCoordinator.REMOVAL_KEY); + mMostVisitedSites.addBlacklistedUrl(suggestion.get(SiteSuggestionModel.URL_KEY)); Toast.makeText(ContextUtils.getApplicationContext(), R.string.most_visited_item_removed, Toast.LENGTH_SHORT) .show(); - // When we remove an item, reset the item count key. - int itemCount = getItemCount(); - // Total item count is 1 more to account for "all apps". + // When we remove an item, reset the item count key first + int itemCount = + getItemCount(mModel.get(SiteSuggestionsCoordinator.SUGGESTIONS_KEY).size() - 1); mModel.set(SiteSuggestionsCoordinator.ITEM_COUNT_KEY, itemCount); + // Actually remove the suggestion. + mModel.get(SiteSuggestionsCoordinator.SUGGESTIONS_KEY).remove(suggestion); // When removal of a site causes us to have fewer sites than we want to display, fetch // again. if (itemCount < MAX_DISPLAYED_TILES) { @@ -151,13 +164,10 @@ mModel.set(SiteSuggestionsCoordinator.ON_FOCUS_CALLBACK, listener); } - private int getItemCount() { + private int getItemCount(int listSize) { // Item count is number of site suggestions available, up to MAX_DISPLAYED_TILES, + 1 for // "All apps". - return (mModel.get(SiteSuggestionsCoordinator.SUGGESTIONS_KEY).size() > MAX_DISPLAYED_TILES - ? MAX_DISPLAYED_TILES - : mModel.get(SiteSuggestionsCoordinator.SUGGESTIONS_KEY).size()) - + 1; + return (listSize > MAX_DISPLAYED_TILES ? MAX_DISPLAYED_TILES : listSize) + 1; } private void makeIconRequest(PropertyModel suggestion) {
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsTileView.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsTileView.java index e52d939..cdf1316 100644 --- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsTileView.java +++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsTileView.java
@@ -26,7 +26,7 @@ public SiteSuggestionsTileView(Context ctx, AttributeSet attrs) { super(ctx, attrs); - mIconSizePx = getResources().getDimensionPixelSize(R.dimen.tile_view_icon_size); + mIconSizePx = getResources().getDimensionPixelSize(R.dimen.most_likely_tile_size); } /**
diff --git a/chrome/app/OWNERS b/chrome/app/OWNERS index a4f3eaa8..c936108 100644 --- a/chrome/app/OWNERS +++ b/chrome/app/OWNERS
@@ -15,6 +15,7 @@ per-file generated_resources.grd=* per-file google_chrome_strings.grd=* per-file extensions_strings.grdp=* +per-file os_settings_strings.grdp=* per-file app_management_strings.grdp=file://chrome/browser/ui/webui/app_management/OWNERS
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index a0535d8..a8c0e0c 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -200,6 +200,7 @@ <!-- Chrome-OS-specific strings --> <if expr="chromeos"> <part file="chromeos_strings.grdp" /> + <part file="os_settings_strings.grdp" /> </if> <!-- Settings specific strings -->
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp new file mode 100644 index 0000000..c5b26cc --- /dev/null +++ b/chrome/app/os_settings_strings.grdp
@@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Settings-specific strings (included from generated_resources.grd). --> +<grit-part> +<if expr="chromeos"> + <!-- Personalizaton Page (OS settings) --> + <message name="IDS_OS_SETTINGS_PERSONALIZATION" desc="Name of the OS settings page which displays personalization preferences."> + Personalization + </message> + + <!-- Personalization Page (OS settings) and Appearance Page (Browser settings) --> + <message name="IDS_OS_SETTINGS_SET_WALLPAPER" desc="Name of the control which allows the user to set the wallpaper."> + Wallpaper + </message> + <message name="IDS_OS_SETTINGS_OPEN_WALLPAPER_APP" desc="Sub-label about opening the wallpaper app."> + Open the wallpaper app + </message> +</if> +</grit-part>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 9066292..9bf4914 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -636,9 +636,6 @@ <message name="IDS_SETTINGS_HOME_BUTTON_DISABLED" desc="Sub label for the Show home button setting when disabled."> Disabled </message> - <message name="IDS_SETTINGS_SET_WALLPAPER" desc="Name of the control which allows the user to set the wallpaper."> - Wallpaper - </message> <if expr="chromeos"> <message name="IDS_SETTINGS_THEMES" desc="Name of the control which allows the user to get a theme for the browser."> Browser themes @@ -683,9 +680,6 @@ <message name="IDS_SETTINGS_WEB_STORE" desc="Sub-label about choosing something from the Chrome Web Store."> Open Chrome Web Store </message> - <message name="IDS_SETTINGS_OPEN_WALLPAPER_APP" desc="Sub-label about opening the wallpaper app."> - Open the wallpaper app - </message> <if expr="is_macosx"> <message name="IDS_SETTINGS_TABS_TO_LINKS_PREF" desc="The documentation string of the 'Tabs to Links' preference"> Pressing Tab on a webpage highlights links, as well as form fields
diff --git a/chrome/app/theme/default_100_percent/chromium/product_logo_name_48.png b/chrome/app/theme/default_100_percent/chromium/product_logo_name_48.png deleted file mode 100644 index 89879b8..0000000 --- a/chrome/app/theme/default_100_percent/chromium/product_logo_name_48.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/extensions_rating_star_half_right.png b/chrome/app/theme/default_100_percent/common/extensions_rating_star_half_right.png deleted file mode 100644 index 6b62d13..0000000 --- a/chrome/app/theme/default_100_percent/common/extensions_rating_star_half_right.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/frozen_tab.png b/chrome/app/theme/default_100_percent/common/frozen_tab.png deleted file mode 100644 index 70ce71e..0000000 --- a/chrome/app/theme/default_100_percent/common/frozen_tab.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/notification_screenshot_icon.png b/chrome/app/theme/default_100_percent/common/notification_screenshot_icon.png deleted file mode 100644 index 1467941..0000000 --- a/chrome/app/theme/default_100_percent/common/notification_screenshot_icon.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/translate_bubble_icon.png b/chrome/app/theme/default_100_percent/common/translate_bubble_icon.png deleted file mode 100644 index 8e74612..0000000 --- a/chrome/app/theme/default_100_percent/common/translate_bubble_icon.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/buildings_illustration.png b/chrome/app/theme/default_100_percent/cros/buildings_illustration.png deleted file mode 100644 index 4f0ac26..0000000 --- a/chrome/app/theme/default_100_percent/cros/buildings_illustration.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/file_types/thumbnails/image.png b/chrome/app/theme/default_100_percent/cros/file_types/thumbnails/image.png deleted file mode 100644 index 9fa3f31..0000000 --- a/chrome/app/theme/default_100_percent/cros/file_types/thumbnails/image.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/login_back_button_masked.png b/chrome/app/theme/default_100_percent/cros/login_back_button_masked.png deleted file mode 100644 index be057af..0000000 --- a/chrome/app/theme/default_100_percent/cros/login_back_button_masked.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/notification_fingerprint.png b/chrome/app/theme/default_100_percent/cros/notification_fingerprint.png deleted file mode 100644 index 554aab4..0000000 --- a/chrome/app/theme/default_100_percent/cros/notification_fingerprint.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/printer_detected_notification.png b/chrome/app/theme/default_100_percent/cros/printer_detected_notification.png deleted file mode 100644 index 0dd3d3d..0000000 --- a/chrome/app/theme/default_100_percent/cros/printer_detected_notification.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/printer_notification.png b/chrome/app/theme/default_100_percent/cros/printer_notification.png deleted file mode 100644 index e7ce355..0000000 --- a/chrome/app/theme/default_100_percent/cros/printer_notification.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/supervised_illsutration_done.png b/chrome/app/theme/default_100_percent/cros/supervised_illsutration_done.png deleted file mode 100644 index d602b0f..0000000 --- a/chrome/app/theme/default_100_percent/cros/supervised_illsutration_done.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/supervised_illustration_start.png b/chrome/app/theme/default_100_percent/cros/supervised_illustration_start.png deleted file mode 100644 index 743c78c..0000000 --- a/chrome/app/theme/default_100_percent/cros/supervised_illustration_start.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/technical_error.png b/chrome/app/theme/default_100_percent/cros/technical_error.png deleted file mode 100644 index b75efa06..0000000 --- a/chrome/app/theme/default_100_percent/cros/technical_error.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/mac/bookmark_bar_folder_managed_white.png b/chrome/app/theme/default_100_percent/mac/bookmark_bar_folder_managed_white.png deleted file mode 100644 index dd21508..0000000 --- a/chrome/app/theme/default_100_percent/mac/bookmark_bar_folder_managed_white.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/mac/theme_default_active_background.png b/chrome/app/theme/default_100_percent/mac/theme_default_active_background.png deleted file mode 100644 index 14ed8960..0000000 --- a/chrome/app/theme/default_100_percent/mac/theme_default_active_background.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/buildings_illustration.png b/chrome/app/theme/default_200_percent/cros/buildings_illustration.png deleted file mode 100644 index b490220..0000000 --- a/chrome/app/theme/default_200_percent/cros/buildings_illustration.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/file_types/thumbnails/image.png b/chrome/app/theme/default_200_percent/cros/file_types/thumbnails/image.png deleted file mode 100644 index 70043d53..0000000 --- a/chrome/app/theme/default_200_percent/cros/file_types/thumbnails/image.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/login_back_button_masked.png b/chrome/app/theme/default_200_percent/cros/login_back_button_masked.png deleted file mode 100644 index 3399fdc9..0000000 --- a/chrome/app/theme/default_200_percent/cros/login_back_button_masked.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/notification_3g.png b/chrome/app/theme/default_200_percent/cros/notification_3g.png deleted file mode 100644 index 6c0407679..0000000 --- a/chrome/app/theme/default_200_percent/cros/notification_3g.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/notification_fingerprint.png b/chrome/app/theme/default_200_percent/cros/notification_fingerprint.png deleted file mode 100644 index ccc5a64..0000000 --- a/chrome/app/theme/default_200_percent/cros/notification_fingerprint.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/notification_lte.png b/chrome/app/theme/default_200_percent/cros/notification_lte.png deleted file mode 100644 index 0ca53f71..0000000 --- a/chrome/app/theme/default_200_percent/cros/notification_lte.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/printer_detected_notification.png b/chrome/app/theme/default_200_percent/cros/printer_detected_notification.png deleted file mode 100644 index 9fee2ca1..0000000 --- a/chrome/app/theme/default_200_percent/cros/printer_detected_notification.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/printer_notification.png b/chrome/app/theme/default_200_percent/cros/printer_notification.png deleted file mode 100644 index af05833..0000000 --- a/chrome/app/theme/default_200_percent/cros/printer_notification.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/status_cellular_failed.png b/chrome/app/theme/default_200_percent/cros/status_cellular_failed.png deleted file mode 100644 index 282cc07..0000000 --- a/chrome/app/theme/default_200_percent/cros/status_cellular_failed.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/supervised_illsutration_done.png b/chrome/app/theme/default_200_percent/cros/supervised_illsutration_done.png deleted file mode 100644 index e76393e3..0000000 --- a/chrome/app/theme/default_200_percent/cros/supervised_illsutration_done.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/supervised_illustration_start.png b/chrome/app/theme/default_200_percent/cros/supervised_illustration_start.png deleted file mode 100644 index def55eb..0000000 --- a/chrome/app/theme/default_200_percent/cros/supervised_illustration_start.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/technical_error.png b/chrome/app/theme/default_200_percent/cros/technical_error.png deleted file mode 100644 index 30953a1..0000000 --- a/chrome/app/theme/default_200_percent/cros/technical_error.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index c2c47a2b5..b8f40e4 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd
@@ -67,7 +67,6 @@ </if> <if expr="is_macosx"> <structure type="chrome_scaled_image" name="IDR_BOOKMARK_BAR_FOLDER_WHITE" file="mac/bookmark_bar_folder_white.png" /> - <structure type="chrome_scaled_image" name="IDR_BOOKMARK_BAR_FOLDER_MANAGED_WHITE" file="mac/bookmark_bar_folder_managed_white.png" /> </if> <if expr="is_win"> <structure type="chrome_scaled_image" name="IDR_BOOKMARK_BAR_FOLDER" file="win/bookmark_bar_folder.png" /> @@ -78,9 +77,6 @@ <structure type="chrome_scaled_image" name="IDR_BUTTON_USER_IMAGE_CHOOSE_FILE" file="cros/choose_file.png" /> <structure type="chrome_scaled_image" name="IDR_BUTTON_USER_IMAGE_TAKE_PHOTO" file="cros/take_photo.png" /> </if> - <if expr="chromeos"> - <structure type="chrome_scaled_image" name="IDR_BUILDINGS_ILLUSTRATION" file="cros/buildings_illustration.png" /> - </if> <structure type="chrome_scaled_image" name="IDR_CLOSE_BUTTON_MASK" file="common/close_button_mask.png" /> <if expr="is_win"> <structure type="chrome_scaled_image" name="IDR_CONFLICT_FAVICON" file="common/favicon_conflicts.png" /> @@ -94,7 +90,6 @@ <if expr="enable_extensions"> <structure type="chrome_scaled_image" name="IDR_EXTENSIONS_FAVICON" file="common/favicon_extensions.png" /> <structure type="chrome_scaled_image" name="IDR_EXTENSIONS_RATING_STAR_HALF_LEFT" file="common/extensions_rating_star_half_left.png" /> - <structure type="chrome_scaled_image" name="IDR_EXTENSIONS_RATING_STAR_HALF_RIGHT" file="common/extensions_rating_star_half_right.png" /> <structure type="chrome_scaled_image" name="IDR_EXTENSIONS_RATING_STAR_OFF" file="common/extensions_rating_star_off.png" /> <structure type="chrome_scaled_image" name="IDR_EXTENSIONS_RATING_STAR_ON" file="common/extensions_rating_star_on.png" /> </if> @@ -109,7 +104,6 @@ <structure type="chrome_scaled_image" name="IDR_FILETYPE_VIDEO" file="cros/file_types/video.png" /> <structure type="chrome_scaled_image" name="IDR_FILETYPE_LARGE_AUDIO" file="cros/file_types/thumbnails/audio.png" /> <structure type="chrome_scaled_image" name="IDR_FILETYPE_LARGE_GENERIC" file="cros/file_types/thumbnails/generic.png" /> - <structure type="chrome_scaled_image" name="IDR_FILETYPE_LARGE_IMAGE" file="cros/file_types/thumbnails/image.png" /> <structure type="chrome_scaled_image" name="IDR_FILETYPE_LARGE_VIDEO" file="cros/file_types/thumbnails/video.png" /> </if> @@ -125,7 +119,6 @@ <structure type="chrome_scaled_image" name="IDR_FORWARD_H" file="common/browser_forward_hover.png" /> <structure type="chrome_scaled_image" name="IDR_FORWARD_P" file="common/browser_forward_pressed.png" /> </if> - <structure type="chrome_scaled_image" name="IDR_FROZEN_TAB_ICON" file="common/frozen_tab.png" /> <structure type="chrome_scaled_image" name="IDR_FULLSCREEN_MENU_BUTTON" file="common/fullscreen_menu_button.png" /> <if expr="_google_chrome"> <structure type="chrome_scaled_image" name="IDR_GOOGLE_ICON" file="google_chrome/google_icon.png" /> @@ -151,16 +144,11 @@ <structure type="chrome_scaled_image" name="IDR_MINIMIZE_BUTTON_MASK" file="common/minimize_button_mask.png" /> <if expr="chromeos"> <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_DRIVE" file="cros/notification_drive.png" /> - <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_FINGERPRINT" file="cros/notification_fingerprint.png" /> <structure type="chrome_scaled_image" name="IDR_ARC_PLAY_STORE_OPTIN_IN_PROGRESS_NOTIFICATION" file="cros/notification_play_store_optin_in_progress.png" /> <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_EASYUNLOCK_ENABLED" file="cros/notification_easyunlock_enabled.png" /> </if> <structure type="chrome_scaled_image" name="IDR_PLUGINS_FAVICON" file="common/favicon_extensions.png" /> <structure type="chrome_scaled_image" name="IDR_PRERENDER" file="common/prerender_succeed_icon.png" /> - <if expr="chromeos"> - <structure type="chrome_scaled_image" name="IDR_PRINTER_NOTIFICATION" file="cros/printer_notification.png" /> - <structure type="chrome_scaled_image" name="IDR_PRINTER_DETECTED_NOTIFICATION" file="cros/printer_detected_notification.png" /> - </if> <if expr="not _google_chrome"> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_16" file="chromium/product_logo_16.png" /> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32" file="chromium/product_logo_32.png" /> @@ -244,7 +232,6 @@ </if> <structure type="chrome_scaled_image" name="IDR_RESTORE_BUTTON_MASK" file="common/restore_button_mask.png" /> <structure type="chrome_scaled_image" name="IDR_SCREEN_CAPTURE_NOTIFICATION_GRIP" file="screen_capture_notification_grip.png" /> - <structure type="chrome_scaled_image" name="IDR_SCREENSHOT_NOTIFICATION_ICON" file="common/notification_screenshot_icon.png" /> <if expr="chromeos"> <structure type="chrome_scaled_image" name="IDR_SECONDARY_USER_SETTINGS" file="cros/secondary_user_settings.png" /> </if> @@ -253,8 +240,6 @@ <structure type="chrome_scaled_image" name="IDR_SHOW_PASSWORD_HOVER" file="common/show_password_hover.png" /> <if expr="chromeos"> <structure type="chrome_scaled_image" name="IDR_SMB_ICON" file="cros/smb_icon.png" /> - <structure type="chrome_scaled_image" name="IDR_SUPERVISED_ILLUSTRATION_START" file="cros/supervised_illustration_start.png" /> - <structure type="chrome_scaled_image" name="IDR_SUPERVISED_ILLUSTRATION_DONE" file="cros/supervised_illsutration_done.png" /> <structure type="chrome_scaled_image" name="IDR_LOGO_AVATAR_CIRCLE_BLUE_COLOR" file="cros/logo_avatar_circle_blue_color.png" /> <structure type="chrome_scaled_image" name="IDR_LOGO_GOOGLE_COLOR_90" file="cros/logo_google_color_90.png" /> </if> @@ -271,13 +256,9 @@ <!-- Used by Chrome OS login page. --> <if expr="chromeos"> <structure type="chrome_scaled_image" name="IDR_TAB_RECORDING_INDICATOR" file="cros/tab_recording_indicator.png" /> - </if> <structure type="chrome_scaled_image" name="IDR_TAB_DROP_DOWN" file="tab_drop_down.png" /> <structure type="chrome_scaled_image" name="IDR_TAB_DROP_UP" file="tab_drop_up.png" /> - <if expr="chromeos"> - <structure type="chrome_scaled_image" name="IDR_TECHNICAL_ERROR" file="cros/technical_error.png" /> - </if> <structure type="chrome_scaled_image" name="IDR_THEME_BUTTON_BACKGROUND" file="notused.png" /> <structure type="chrome_scaled_image" name="IDR_THEME_FRAME" file="notused.png" /> <structure type="chrome_scaled_image" name="IDR_THEME_FRAME_INACTIVE" file="notused.png" /> @@ -302,7 +283,6 @@ <structure type="chrome_scaled_image" name="IDR_THEME_TAB_BACKGROUND_V" file="notused.png" /> <if expr="is_macosx"> <structure type="chrome_scaled_image" name="IDR_THEME_TOOLBAR" file="mac/theme_default_active.png" /> - <structure type="chrome_scaled_image" name="IDR_THEME_TOOLBAR_INACTIVE" file="mac/theme_default_active_background.png" /> </if> <if expr="not is_macosx"> <!-- This identifier exists to give us something to associate with a custom image that a theme can provide. @@ -311,7 +291,6 @@ </if> <!-- Instant Extended API toolbar background is common for all platforms. --> <structure type="chrome_scaled_image" name="IDR_THEME_WINDOW_CONTROL_BACKGROUND" file="notused.png" /> - <structure type="chrome_scaled_image" name="IDR_TRANSLATE_BUBBLE_ICON" file="common/translate_bubble_icon.png" /> <if expr="not _google_chrome"> <structure type="chrome_scaled_image" name="IDR_WEBSTORE_ICON" file="chromium/webstore_icon.png" /> <structure type="chrome_scaled_image" name="IDR_WEBSTORE_ICON_16" file="chromium/webstore_icon_16.png" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 7cb1945..78fb1a21 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -3550,7 +3550,7 @@ "//chrome/chrome_watcher:client", "//chrome/common:metrics_constants_util_win", "//chrome/common:version_header", - "//chrome/credential_provider/gaiacp:common", + "//chrome/credential_provider/common:common_constants", "//chrome/install_static:install_static_util", "//chrome/notification_helper:constants", "//chrome/services/util_win/public/mojom",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 7093c7c..1417f51 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1100,10 +1100,6 @@ flag_descriptions::kExtensionsOnChromeUrlsDescription, kOsAll, SINGLE_VALUE_TYPE(extensions::switches::kExtensionsOnChromeURLs)}, #endif // ENABLE_EXTENSIONS - {"enable-history-entry-requires-user-gesture", - flag_descriptions::kHistoryRequiresUserGestureName, - flag_descriptions::kHistoryRequiresUserGestureDescription, kOsAll, - SINGLE_VALUE_TYPE(switches::kHistoryEntryRequiresUserGesture)}, {"enable-history-manipulation-intervention", flag_descriptions::kHistoryManipulationIntervention, flag_descriptions::kHistoryManipulationInterventionDescription, kOsAll,
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc index b9259fe..7fab0bf4 100644 --- a/chrome/browser/android/download/download_manager_service.cc +++ b/chrome/browser/android/download/download_manager_service.cc
@@ -23,6 +23,7 @@ #include "chrome/browser/android/feature_utilities.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/download/offline_item_utils.h" +#include "chrome/browser/download/simple_download_manager_coordinator_factory.h" #include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/chrome_constants.h" @@ -31,6 +32,7 @@ #include "components/download/public/common/download_item.h" #include "components/download/public/common/download_item_impl.h" #include "components/download/public/common/download_url_loader_factory_getter_impl.h" +#include "components/download/public/common/simple_download_manager_coordinator.h" #include "components/download/public/task/task_manager_impl.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/download_item_utils.h" @@ -199,7 +201,9 @@ DownloadManagerService::DownloadManagerService() : is_manager_initialized_(false), is_pending_downloads_loaded_(false), - pending_get_downloads_actions_(NONE) {} + pending_get_downloads_actions_(NONE), + original_coordinator_(nullptr), + off_the_record_coordinator_(nullptr) {} DownloadManagerService::~DownloadManagerService() {} @@ -222,17 +226,7 @@ registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, content::NotificationService::AllSources()); Profile* profile = ProfileManager::GetActiveUserProfile(); - content::DownloadManager* download_manager = - content::BrowserContext::GetDownloadManager(profile); - if (!download_manager) - return; - - // Waiting for DownloadManager to initialize and carry out all the pending - // actions - if (download_manager->IsManagerInitialized()) - OnManagerInitialized(); - else - download_manager->AddObserver(this); + ResetCoordinatorIfNeeded(profile); } void DownloadManagerService::Observe( @@ -242,19 +236,7 @@ switch (type) { case chrome::NOTIFICATION_PROFILE_CREATED: { Profile* profile = content::Source<Profile>(source).ptr(); - content::DownloadManager* manager = - content::BrowserContext::GetDownloadManager(profile); - if (!manager) - break; - - auto& notifier = profile->IsOffTheRecord() ? off_the_record_notifier_ - : original_notifier_; - - // Update notifiers to monitor any newly created DownloadManagers. - if (!notifier || notifier->GetManager() != manager) { - notifier = - std::make_unique<download::AllDownloadItemNotifier>(manager, this); - } + ResetCoordinatorIfNeeded(profile); } break; default: NOTREACHED(); @@ -445,7 +427,11 @@ EnqueueDownloadAction(download_guid, DownloadActionParams(CANCEL)); } -void DownloadManagerService::OnManagerInitialized() { +void DownloadManagerService::OnDownloadsInitialized( + download::SimpleDownloadManagerCoordinator* coordinator, + bool active_downloads_only) { + if (active_downloads_only) + return; is_manager_initialized_ = true; OnPendingDownloadsLoaded(); @@ -456,11 +442,16 @@ GetAllDownloadsInternal(true); } -void DownloadManagerService::OnManagerInitialized( - content::DownloadManager* manager) {} +void DownloadManagerService::OnManagerGoingDown( + download::SimpleDownloadManagerCoordinator* coordinator) { + if (original_coordinator_ == coordinator) + original_coordinator_ = nullptr; + else if (off_the_record_coordinator_ == coordinator) + off_the_record_coordinator_ = nullptr; +} void DownloadManagerService::OnDownloadCreated( - content::DownloadManager* manager, + download::SimpleDownloadManagerCoordinator* coordinator, download::DownloadItem* item) { if (item->IsTransient()) return; @@ -472,7 +463,7 @@ } void DownloadManagerService::OnDownloadUpdated( - content::DownloadManager* manager, + download::SimpleDownloadManagerCoordinator* coordinator, download::DownloadItem* item) { if (java_ref_.is_null()) return; @@ -487,7 +478,7 @@ } void DownloadManagerService::OnDownloadRemoved( - content::DownloadManager* manager, + download::SimpleDownloadManagerCoordinator* coordinator, download::DownloadItem* item) { if (java_ref_.is_null() || item->IsTransient()) return; @@ -773,23 +764,27 @@ if (is_off_the_record) profile = profile->GetOffTheRecordProfile(); - auto& notifier = - is_off_the_record ? off_the_record_notifier_ : original_notifier_; content::DownloadManager* manager = content::BrowserContext::GetDownloadManager(profile); - if (!manager) { - notifier.reset(); - return nullptr; - } - - // Update notifiers to monitor any newly created DownloadManagers. - if (!notifier || notifier->GetManager() != manager) { - notifier = - std::make_unique<download::AllDownloadItemNotifier>(manager, this); - } + ResetCoordinatorIfNeeded(profile); return manager; } +void DownloadManagerService::ResetCoordinatorIfNeeded(Profile* profile) { + auto*& coordinator = profile->IsOffTheRecord() ? off_the_record_coordinator_ + : original_coordinator_; + + download::SimpleDownloadManagerCoordinator* new_coordinator = + SimpleDownloadManagerCoordinatorFactory::GetForKey( + profile->GetProfileKey()); + if (!coordinator || coordinator != new_coordinator) { + if (coordinator) + coordinator->GetNotifier()->RemoveObserver(this); + coordinator = new_coordinator; + coordinator->GetNotifier()->AddObserver(this); + } +} + void DownloadManagerService::RenameDownload( JNIEnv* env, const JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/download/download_manager_service.h b/chrome/browser/android/download/download_manager_service.h index 173df9b..9bb8fca 100644 --- a/chrome/browser/android/download/download_manager_service.h +++ b/chrome/browser/android/download/download_manager_service.h
@@ -14,7 +14,7 @@ #include "base/macros.h" #include "base/memory/singleton.h" #include "chrome/browser/android/download/download_controller.h" -#include "components/download/content/public/all_download_item_notifier.h" +#include "components/download/public/common/all_download_event_notifier.h" #include "components/download/public/common/in_progress_download_manager.h" #include "content/public/browser/download_manager.h" #include "content/public/browser/notification_observer.h" @@ -25,16 +25,18 @@ using base::android::JavaParamRef; +class Profile; + namespace download { class DownloadItem; +class SimpleDownloadManagerCoordinator; } // Native side of DownloadManagerService.java. The native object is owned by its // Java object. class DownloadManagerService - : public download::AllDownloadItemNotifier::Observer, + : public download::AllDownloadEventNotifier::Observer, public download::InProgressDownloadManager::Delegate, - public content::DownloadManager::Observer, public content::NotificationObserver, public service_manager::Service { public: @@ -144,17 +146,21 @@ const JavaParamRef<jstring>& jdownload_guid, bool is_off_the_record); - // content::DownloadManager::Observer methods. - void OnManagerInitialized() override; - - // AllDownloadItemNotifier::Observer methods. - void OnManagerInitialized(content::DownloadManager* manager) override; - void OnDownloadCreated(content::DownloadManager* manager, - download::DownloadItem* item) override; - void OnDownloadUpdated(content::DownloadManager* manager, - download::DownloadItem* item) override; - void OnDownloadRemoved(content::DownloadManager* manager, - download::DownloadItem* item) override; + // AllDownloadEventNotifier::Observer methods. + void OnDownloadsInitialized( + download::SimpleDownloadManagerCoordinator* coordinator, + bool active_downloads_only) override; + void OnManagerGoingDown( + download::SimpleDownloadManagerCoordinator* coordinator) override; + void OnDownloadCreated( + download::SimpleDownloadManagerCoordinator* coordinator, + download::DownloadItem* item) override; + void OnDownloadUpdated( + download::SimpleDownloadManagerCoordinator* coordinator, + download::DownloadItem* item) override; + void OnDownloadRemoved( + download::SimpleDownloadManagerCoordinator* coordinator, + download::DownloadItem* item) override; // content::NotificationObserver methods. void Observe(int type, @@ -239,6 +245,9 @@ resume_callback_for_testing_ = resume_cb; } + // Helper method to reset the SimpleDownloadManagerCoordinator if needed. + void ResetCoordinatorIfNeeded(Profile* profile); + service_manager::ServiceBinding service_binding_{this}; // Reference to the Java object. @@ -279,13 +288,13 @@ // The Registrar used to register for notifications. content::NotificationRegistrar registrar_; - std::unique_ptr<download::AllDownloadItemNotifier> original_notifier_; - std::unique_ptr<download::AllDownloadItemNotifier> off_the_record_notifier_; - // In-progress download manager when download is running as a service. Will // pass this object to DownloadManagerImpl once it is created. std::unique_ptr<download::InProgressDownloadManager> in_progress_manager_; + download::SimpleDownloadManagerCoordinator* original_coordinator_; + download::SimpleDownloadManagerCoordinator* off_the_record_coordinator_; + DISALLOW_COPY_AND_ASSIGN(DownloadManagerService); };
diff --git a/chrome/browser/android/download/download_manager_service_unittest.cc b/chrome/browser/android/download/download_manager_service_unittest.cc index 40b6857..a7315bcf 100644 --- a/chrome/browser/android/download/download_manager_service_unittest.cc +++ b/chrome/browser/android/download/download_manager_service_unittest.cc
@@ -13,6 +13,7 @@ #include "components/download/public/common/download_item.h" #include "components/download/public/common/download_url_parameters.h" #include "components/download/public/common/mock_download_item.h" +#include "components/download/public/common/simple_download_manager_coordinator.h" #include "content/public/browser/download_manager.h" #include "content/public/test/mock_download_manager.h" #include "testing/gmock/include/gmock/gmock.h" @@ -21,13 +22,6 @@ using ::testing::_; -namespace content { -class BrowserContext; -class ByteStreamReader; -class DownloadManagerDelegate; -struct DownloadCreateInfo; -} - class MockDownloadManagerService : public DownloadManagerService { public: MockDownloadManagerService() : DownloadManagerService() { @@ -80,7 +74,7 @@ base::android::ConvertUTF8ToJavaString(env, download_guid).obj()), false, false); EXPECT_FALSE(success_); - service_->OnManagerInitialized(); + service_->OnDownloadsInitialized(&coordinator_, false); while (!finished_) base::RunLoop().RunUntilIdle(); } @@ -88,6 +82,7 @@ protected: base::MessageLoop message_loop_; MockDownloadManagerService* service_; + download::SimpleDownloadManagerCoordinator coordinator_; bool finished_; bool success_;
diff --git a/chrome/browser/android/payments/service_worker_payment_app_bridge.cc b/chrome/browser/android/payments/service_worker_payment_app_bridge.cc index 274a74d..1c1e1bf 100644 --- a/chrome/browser/android/payments/service_worker_payment_app_bridge.cc +++ b/chrome/browser/android/payments/service_worker_payment_app_bridge.cc
@@ -191,9 +191,7 @@ JNIEnv* env, const JavaParamRef<jobjectArray>& jmethod_data) { std::vector<PaymentMethodDataPtr> result; - for (jsize i = 0; i < env->GetArrayLength(jmethod_data); i++) { - ScopedJavaLocalRef<jobject> element( - env, env->GetObjectArrayElement(jmethod_data, i)); + for (auto element : jmethod_data.ReadElements<jobject>()) { PaymentMethodDataPtr method_data_item = PaymentMethodData::New(); method_data_item->supported_method = ConvertJavaStringToUTF8( env, @@ -253,9 +251,7 @@ env, Java_ServiceWorkerPaymentAppBridge_getValueFromPaymentItem(env, jtotal)); - for (jsize i = 0; i < env->GetArrayLength(jmodifiers); i++) { - ScopedJavaLocalRef<jobject> jmodifier( - env, env->GetObjectArrayElement(jmodifiers, i)); + for (auto jmodifier : jmodifiers.ReadElements<jobject>()) { PaymentDetailsModifierPtr modifier = PaymentDetailsModifier::New(); ScopedJavaLocalRef<jobject> jmodifier_total = @@ -360,9 +356,7 @@ event_data->method_data = ConvertPaymentMethodDataFromJavaToNative(env, jmethod_data); - for (jsize i = 0; i < env->GetArrayLength(jmodifiers); i++) { - ScopedJavaLocalRef<jobject> jmodifier( - env, env->GetObjectArrayElement(jmodifiers, i)); + for (auto jmodifier : jmodifiers.ReadElements<jobject>()) { PaymentDetailsModifierPtr modifier = PaymentDetailsModifier::New(); ScopedJavaLocalRef<jobject> jmodifier_total =
diff --git a/chrome/browser/android/provider/chrome_browser_provider.cc b/chrome/browser/android/provider/chrome_browser_provider.cc index 019586ce..36e397d7 100644 --- a/chrome/browser/android/provider/chrome_browser_provider.cc +++ b/chrome/browser/android/provider/chrome_browser_provider.cc
@@ -917,10 +917,7 @@ // Used to store the projection column names according their sequence. std::vector<std::string> columns_name; if (projection) { - jsize len = env->GetArrayLength(projection); - for (int i = 0; i < len; i++) { - ScopedJavaLocalRef<jstring> j_name( - env, static_cast<jstring>(env->GetObjectArrayElement(projection, i))); + for (auto j_name : projection.ReadElements<jstring>()) { std::string name = ConvertJavaStringToUTF8(env, j_name); history::HistoryAndBookmarkRow::ColumnID id = history::HistoryAndBookmarkRow::GetColumnID(name); @@ -1059,10 +1056,7 @@ // Used to store the projection column names according their sequence. std::vector<std::string> columns_name; if (projection) { - jsize len = env->GetArrayLength(projection); - for (int i = 0; i < len; i++) { - ScopedJavaLocalRef<jstring> j_name( - env, static_cast<jstring>(env->GetObjectArrayElement(projection, i))); + for (auto j_name : projection.ReadElements<jstring>()) { std::string name = ConvertJavaStringToUTF8(env, j_name); history::SearchRow::ColumnID id = history::SearchRow::GetColumnID(name);
diff --git a/chrome/browser/android/webapk/webapk_icon_hasher_unittest.cc b/chrome/browser/android/webapk/webapk_icon_hasher_unittest.cc index 08d42ba2..2211223 100644 --- a/chrome/browser/android/webapk/webapk_icon_hasher_unittest.cc +++ b/chrome/browser/android/webapk/webapk_icon_hasher_unittest.cc
@@ -143,8 +143,8 @@ std::string icon_url = "http://www.google.com/404"; network::ResourceResponseHead head; std::string headers("HTTP/1.1 404 Not Found\nContent-type: text/html\n\n"); - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); head.mime_type = "text/html"; network::URLLoaderCompletionStatus status; status.decoded_body_length = 0;
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc index bf2ef92..68d3825 100644 --- a/chrome/browser/autocomplete/search_provider_unittest.cc +++ b/chrome/browser/autocomplete/search_provider_unittest.cc
@@ -3443,8 +3443,8 @@ network::ResourceResponseHead head; std::string headers("HTTP/1.1 500 Owiee\nContent-type: application/json\n\n"); - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); head.mime_type = "application/json"; test_url_loader_factory_.AddResponse(GURL(kDeleteUrl), head, "", network::URLLoaderCompletionStatus());
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc index b58a7a7..10884bf6 100644 --- a/chrome/browser/captive_portal/captive_portal_browsertest.cc +++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -945,7 +945,7 @@ kMockHttpsUrl); net::HttpResponseInfo info; info.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length())); + net::HttpUtil::AssembleRawHeaders(headers)); network::ResourceResponseHead response; response.headers = info.headers; response.headers->GetMimeType(&response.mime_type);
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index d50c9144..b144befd 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -5468,13 +5468,15 @@ ui_tab_helper->GetPreviewsUserData(navigation_handle); // Certain PreviewsStates are used within URLLoaders (Offline, server - // previews) and cannot re-evaluate PreviewsState during a redirect, so they - // should not change. Assume this is a redirect when PreviewsUserData already - // exists and a Lite Page Redirect preview is not being attempted, since it - // may also create a previews_data before this point. - bool is_redirect = false; + // previews) and cannot re-evaluate PreviewsState once previews triggering + // logic has already been run, so they should not change. Assume that + // previews triggering logic has run when PreviewsUserData already exists and + // a Lite Page Redirect preview is not being attempted, since it may also + // create a previews_data before this point. + bool previews_triggering_logic_already_ran = false; if (previews_data) { - is_redirect = !previews_data->server_lite_page_info(); + previews_triggering_logic_already_ran = + !previews_data->server_lite_page_info(); } else { previews_data = ui_tab_helper->CreatePreviewsUserDataForNavigationHandle( navigation_handle, previews_decider_impl->GeneratePageId()); @@ -5492,7 +5494,7 @@ // re-evaluate upon redirect. Plumbing does not exist to modify the CPAT // header, nor does the plumbing exist to modify the PreviewsState within the // URLLoader. - if (is_redirect) { + if (previews_triggering_logic_already_ran) { // Copy the server state that was used before the redirect for the initial // URL. previews_state |= (previews_data->allowed_previews_state() & @@ -5507,7 +5509,7 @@ // Evaluate client LoFi, Offline, NoScript, and ResourceBlocking previews. previews_state |= previews::DetermineAllowedClientPreviewsState( - previews_data, current_navigation_url, is_reload, is_redirect, + previews_data, previews_triggering_logic_already_ran, data_reduction_proxy_settings->IsDataReductionProxyEnabled(), previews_decider_impl, navigation_handle);
diff --git a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc index 7550271..c025bd08 100644 --- a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc +++ b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
@@ -433,8 +433,8 @@ network::ResourceResponseHead head; std::string status_line("HTTP/1.1 904 ARC Disabled"); std::string headers = status_line + "\nContent-type: text/html\n\n"; - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); network::URLLoaderCompletionStatus status; test_url_loader_factory_.AddResponse(request.url, head, std::string(),
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc index b06ad3f8..cea42d7 100644 --- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc +++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
@@ -53,6 +53,11 @@ namespace { +constexpr char kSetFontScaleAction[] = + "org.chromium.arc.intent_helper.SET_FONT_SCALE"; +constexpr char kSetPageZoomAction[] = + "org.chromium.arc.intent_helper.SET_PAGE_ZOOM"; + bool GetHttpProxyServer(const ProxyConfigDictionary* proxy_config_dict, std::string* host, int* port) { @@ -167,6 +172,12 @@ void SyncTimeZoneByGeolocation() const; void SyncUse24HourClock() const; + // Resets Android's font scale to the default value. + void ResetFontScaleToDefault() const; + + // Resets Android's display density to the default value. + void ResetPageZoomToDefault() const; + // Registers to listen to a particular perf. void AddPrefToObserve(const std::string& pref_name); @@ -364,8 +375,6 @@ SyncAccessibilityLargeMouseCursorEnabled(); SyncAccessibilityVirtualKeyboardEnabled(); SyncFocusHighlightEnabled(); - SyncFontSize(); - SyncPageZoom(); SyncProxySettings(); SyncReportingConsent(/*initial_sync=*/false); SyncSelectToSpeakEnabled(); @@ -374,6 +383,17 @@ SyncTimeZone(); SyncTimeZoneByGeolocation(); SyncUse24HourClock(); + + // SplitSettings decouples browser font size and page zoom from Android's + // font size and display scale. Reset the values to default in case the user + // had a custom value. https://crbug.com/955071 + if (base::FeatureList::IsEnabled(chromeos::features::kSplitSettings)) { + ResetFontScaleToDefault(); + ResetPageZoomToDefault(); + } else { + SyncFontSize(); + SyncPageZoom(); + } } void ArcSettingsServiceImpl::SyncAppTimeSettings() { @@ -441,8 +461,7 @@ base::DictionaryValue extras; extras.SetDouble("scale", android_scale); - SendSettingsBroadcast("org.chromium.arc.intent_helper.SET_FONT_SCALE", - extras); + SendSettingsBroadcast(kSetFontScaleAction, extras); } void ArcSettingsServiceImpl::SyncPageZoom() const { @@ -456,7 +475,7 @@ base::DictionaryValue extras; extras.SetDouble("zoomFactor", zoom_factor); - SendSettingsBroadcast("org.chromium.arc.intent_helper.SET_PAGE_ZOOM", extras); + SendSettingsBroadcast(kSetPageZoomAction, extras); } void ArcSettingsServiceImpl::SyncLocale() const { @@ -621,6 +640,18 @@ extras); } +void ArcSettingsServiceImpl::ResetFontScaleToDefault() const { + base::DictionaryValue extras; + extras.SetDouble("scale", kAndroidFontScaleNormal); + SendSettingsBroadcast(kSetFontScaleAction, extras); +} + +void ArcSettingsServiceImpl::ResetPageZoomToDefault() const { + base::DictionaryValue extras; + extras.SetDouble("zoomFactor", 1.0); + SendSettingsBroadcast(kSetPageZoomAction, extras); +} + void ArcSettingsServiceImpl::AddPrefToObserve(const std::string& pref_name) { registrar_.Add(pref_name, base::Bind(&ArcSettingsServiceImpl::OnPrefChanged, base::Unretained(this)));
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_unittest.cc b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_unittest.cc index de8ba2f1..705d0b71 100644 --- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_unittest.cc +++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_unittest.cc
@@ -246,13 +246,16 @@ base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(chromeos::features::kSplitSettings); - // No initial broadcast. + // Initial broadcast resets to 100%. arc_session_manager()->RequestEnable(); SetInstances(); FakeIntentHelperInstance* intent_helper = intent_helper_instance(); - EXPECT_EQ(0U, intent_helper->GetBroadcastsForAction(kSetFontScale).size()); + auto broadcasts = intent_helper->GetBroadcastsForAction(kSetFontScale); + ASSERT_EQ(1U, broadcasts.size()); + EXPECT_EQ("{\"scale\":1.0}", broadcasts[0].extras); // No broadcast after update. + intent_helper->clear_broadcasts(); profile()->GetPrefs()->SetInteger(::prefs::kWebKitDefaultFontSize, 20); EXPECT_EQ(0U, intent_helper->GetBroadcastsForAction(kSetFontScale).size()); } @@ -264,13 +267,16 @@ base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(chromeos::features::kSplitSettings); - // No initial broadcast. + // Initial broadcast resets to 100%. arc_session_manager()->RequestEnable(); SetInstances(); FakeIntentHelperInstance* intent_helper = intent_helper_instance(); - EXPECT_EQ(0U, intent_helper->GetBroadcastsForAction(kSetPageZoom).size()); + auto broadcasts = intent_helper->GetBroadcastsForAction(kSetPageZoom); + ASSERT_EQ(1U, broadcasts.size()); + EXPECT_EQ("{\"zoomFactor\":1.0}", broadcasts[0].extras); // No broadcast after update. + intent_helper->clear_broadcasts(); profile()->GetZoomLevelPrefs()->SetDefaultZoomLevelPref(150.0); EXPECT_EQ(0U, intent_helper->GetBroadcastsForAction(kSetPageZoom).size()); }
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc index 4011865..73cd8e2 100644 --- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc +++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -1330,6 +1330,17 @@ nullptr); } } + + if (policy.has_device_usb_power_share()) { + const em::DeviceUsbPowerShareProto& container( + policy.device_usb_power_share()); + if (container.has_enabled()) { + policies->Set(key::kDeviceUsbPowerShareEnabled, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + std::make_unique<base::Value>(container.enabled()), + nullptr); + } + } } } // namespace
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_unittest.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_unittest.cc index 24f3864..30a564af 100644 --- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_unittest.cc +++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_unittest.cc
@@ -384,9 +384,8 @@ TEST_F(DataReductionProxyChromeSettingsTest, CreateDataBasic) { content::MockNavigationHandle handle(GURL(kUrl), main_rfh()); std::string raw_headers = "HTTP/1.0 200 OK\n"; - scoped_refptr<net::HttpResponseHeaders> headers = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - raw_headers.c_str(), raw_headers.size())); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_headers)); handle.set_response_headers(headers); auto data = drp_chrome_settings_->CreateDataFromNavigationHandle( &handle, headers.get()); @@ -403,9 +402,8 @@ content::MockNavigationHandle handle(GURL(kUrl), main_rfh()); handle.set_proxy_server(net::ProxyServer::FromPacString(kProxyPac)); std::string raw_headers = "HTTP/1.0 200 OK\n"; - scoped_refptr<net::HttpResponseHeaders> headers = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - raw_headers.c_str(), raw_headers.size())); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_headers)); handle.set_response_headers(headers); auto data = drp_chrome_settings_->CreateDataFromNavigationHandle( &handle, headers.get()); @@ -418,9 +416,8 @@ "HTTP/1.0 200 OK\n" "chrome-proxy: foo\n"; content::MockNavigationHandle handle(GURL(kUrl), main_rfh()); - scoped_refptr<net::HttpResponseHeaders> headers = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - raw_headers.c_str(), raw_headers.size())); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_headers)); handle.set_response_headers(headers); handle.set_was_response_cached(true); auto data = drp_chrome_settings_->CreateDataFromNavigationHandle( @@ -432,9 +429,8 @@ TEST_F(DataReductionProxyChromeSettingsTest, CreateHTTPSDataCachedResponse) { std::string raw_headers = "HTTP/1.0 200 OK\nchrome-proxy: foo\n"; content::MockNavigationHandle handle(GURL("https://secure.com"), main_rfh()); - scoped_refptr<net::HttpResponseHeaders> headers = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - raw_headers.c_str(), raw_headers.size())); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_headers)); handle.set_response_headers(headers); handle.set_was_response_cached(true); auto data = drp_chrome_settings_->CreateDataFromNavigationHandle( @@ -449,9 +445,8 @@ "HTTP/1.0 200 OK\n" "via: 1.1 Chrome-Compression-Proxy\n"; content::MockNavigationHandle handle(GURL(kUrl), main_rfh()); - scoped_refptr<net::HttpResponseHeaders> headers = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - raw_headers.c_str(), raw_headers.size())); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_headers)); handle.set_response_headers(headers); handle.set_was_response_cached(true); auto data = drp_chrome_settings_->CreateDataFromNavigationHandle( @@ -465,9 +460,8 @@ "HTTP/1.0 200 OK\n" "chrome-proxy-content-transform: lite-page\n"; content::MockNavigationHandle handle(GURL(kUrl), main_rfh()); - scoped_refptr<net::HttpResponseHeaders> headers = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - raw_headers.c_str(), raw_headers.size())); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_headers)); handle.set_response_headers(headers); auto data = drp_chrome_settings_->CreateDataFromNavigationHandle( &handle, headers.get()); @@ -482,9 +476,8 @@ "HTTP/1.0 200 OK\n" "chrome-proxy: page-policies=empty-image\n"; content::MockNavigationHandle handle(GURL(kUrl), main_rfh()); - scoped_refptr<net::HttpResponseHeaders> headers = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - raw_headers.c_str(), raw_headers.size())); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_headers)); handle.set_response_headers(headers); auto data = drp_chrome_settings_->CreateDataFromNavigationHandle( &handle, headers.get()); @@ -499,9 +492,8 @@ "HTTP/1.0 200 OK\n" "chrome-proxy-content-transform: empty-image\n"; content::MockNavigationHandle handle(GURL(kUrl), main_rfh()); - scoped_refptr<net::HttpResponseHeaders> headers = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - raw_headers.c_str(), raw_headers.size())); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_headers)); handle.set_response_headers(headers); auto data = drp_chrome_settings_->CreateDataFromNavigationHandle( &handle, headers.get());
diff --git a/chrome/browser/download/download_core_service_impl.cc b/chrome/browser/download/download_core_service_impl.cc index 7d097df..76a70c88 100644 --- a/chrome/browser/download/download_core_service_impl.cc +++ b/chrome/browser/download/download_core_service_impl.cc
@@ -13,9 +13,11 @@ #include "chrome/browser/download/download_status_updater.h" #include "chrome/browser/download/download_ui_controller.h" #include "chrome/browser/download/offline_item_utils.h" +#include "chrome/browser/download/simple_download_manager_coordinator_factory.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/offline_items_collection/offline_content_aggregator_factory.h" #include "chrome/browser/profiles/profile.h" +#include "components/download/public/common/simple_download_manager_coordinator.h" #include "components/history/core/browser/history_service.h" #include "components/offline_items_collection/core/offline_content_aggregator.h" #include "content/public/browser/download_manager.h" @@ -45,6 +47,10 @@ if (download_manager_created_) return manager_delegate_.get(); download_manager_created_ = true; + download::SimpleDownloadManagerCoordinator* coordinator = + SimpleDownloadManagerCoordinatorFactory::GetForKey( + profile_->GetProfileKey()); + coordinator->SetSimpleDownloadManager(manager, true); // In case the delegate has already been set by // SetDownloadManagerDelegateForTesting.
diff --git a/chrome/browser/download/download_service_factory.cc b/chrome/browser/download/download_service_factory.cc index f89e2a30..74571fb 100644 --- a/chrome/browser/download/download_service_factory.cc +++ b/chrome/browser/download/download_service_factory.cc
@@ -131,14 +131,14 @@ #else task_scheduler = std::make_unique<DownloadTaskSchedulerImpl>(context); #endif - download::SimpleDownloadManagerCoordinator* coordinator = - SimpleDownloadManagerCoordinatorFactory::GetForKey( - profile->GetProfileKey()); - coordinator->SetSimpleDownloadManager( - content::BrowserContext::GetDownloadManager(context), true); + content::DownloadManager* manager = + content::BrowserContext::GetDownloadManager(context); + DCHECK(manager); return download::BuildDownloadService( profile->GetProfileKey(), profile->GetPrefs(), std::move(clients), - content::GetNetworkConnectionTracker(), storage_dir, coordinator, + content::GetNetworkConnectionTracker(), storage_dir, + SimpleDownloadManagerCoordinatorFactory::GetForKey( + profile->GetProfileKey()), background_task_runner, std::move(task_scheduler)); } }
diff --git a/chrome/browser/download/notification/download_notification_browsertest.cc b/chrome/browser/download/notification/download_notification_browsertest.cc index e1d5f90..9a9811da 100644 --- a/chrome/browser/download/notification/download_notification_browsertest.cc +++ b/chrome/browser/download/notification/download_notification_browsertest.cc
@@ -211,8 +211,8 @@ headers += base::StringPrintf("Content-Length: %ld\n", content_length); head.content_length = content_length; } - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); head.headers->GetMimeType(&head.mime_type); params->client->OnReceiveResponse(head); }
diff --git a/chrome/browser/download/simple_download_manager_coordinator_factory.cc b/chrome/browser/download/simple_download_manager_coordinator_factory.cc index 3160183..3e8baf2 100644 --- a/chrome/browser/download/simple_download_manager_coordinator_factory.cc +++ b/chrome/browser/download/simple_download_manager_coordinator_factory.cc
@@ -37,3 +37,8 @@ SimpleFactoryKey* key) const { return std::make_unique<download::SimpleDownloadManagerCoordinator>(); } + +SimpleFactoryKey* SimpleDownloadManagerCoordinatorFactory::GetKeyToUse( + SimpleFactoryKey* key) const { + return key; +}
diff --git a/chrome/browser/download/simple_download_manager_coordinator_factory.h b/chrome/browser/download/simple_download_manager_coordinator_factory.h index fc57dc5..bead09e 100644 --- a/chrome/browser/download/simple_download_manager_coordinator_factory.h +++ b/chrome/browser/download/simple_download_manager_coordinator_factory.h
@@ -43,6 +43,7 @@ // SimpleKeyedServiceFactory overrides. std::unique_ptr<KeyedService> BuildServiceInstanceFor( SimpleFactoryKey* key) const override; + SimpleFactoryKey* GetKeyToUse(SimpleFactoryKey* key) const override; DISALLOW_COPY_AND_ASSIGN(SimpleDownloadManagerCoordinatorFactory); };
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc index 86fcf66..efb0e32 100644 --- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -1709,8 +1709,7 @@ "X-Chrome-ID-Consistency-Response: Value6\r\n" "\r\n"; auto base_headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(base_headers_string.c_str(), - base_headers_string.size())); + net::HttpUtil::AssembleRawHeaders(base_headers_string)); ResponseHeaders new_headers = { {"kEy1", "Value1"}, // Unchanged @@ -1759,8 +1758,7 @@ "HTTP/1.0 200 OK\r\n" "Key1: Value1\r\n"; auto base_headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(base_headers_string.c_str(), - base_headers_string.size())); + net::HttpUtil::AssembleRawHeaders(base_headers_string)); ResponseHeaders new_headers = { {"Key1", "Value1"}, @@ -2338,10 +2336,8 @@ "Set-Cookie: sessionCookie=removed; Max-Age=INVALID\r\n" "Set-Cookie: sessionCookie2=removed\r\n" "\r\n"; - scoped_refptr<net::HttpResponseHeaders> base_headers( - new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders( - base_headers_string.c_str(), base_headers_string.size()))); + auto base_headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(base_headers_string)); // Check that we can handle if not touching the response headers. { @@ -2496,10 +2492,8 @@ deltas.push_back(std::move(delta)); } deltas.sort(&InDecreasingExtensionInstallationTimeOrder); - scoped_refptr<net::HttpResponseHeaders> headers1( - new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders( - base_headers_string.c_str(), base_headers_string.size()))); + auto headers1 = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(base_headers_string)); scoped_refptr<net::HttpResponseHeaders> new_headers1; MergeCookiesInOnHeadersReceivedResponses(GURL(), deltas, headers1.get(), &new_headers1, &logger); @@ -2539,10 +2533,8 @@ "Key1: Value1\r\n" "Key2: Value2, Foo\r\n" "\r\n"; - scoped_refptr<net::HttpResponseHeaders> base_headers( - new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders( - base_headers_string, sizeof(base_headers_string)))); + auto base_headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(base_headers_string)); // Check that we can handle if not touching the response headers. { @@ -2683,10 +2675,8 @@ "Key1: Value3\r\n" "Key2: Value4\r\n" "\r\n"; - scoped_refptr<net::HttpResponseHeaders> base_headers( - new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders( - base_headers_string, sizeof(base_headers_string)))); + auto base_headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(base_headers_string)); { EventResponseDelta d1("extid1", base::Time::FromInternalValue(2000)); @@ -2737,9 +2727,8 @@ char base_headers_string[] = "HTTP/1.0 200 OK\r\n" "\r\n"; - scoped_refptr<net::HttpResponseHeaders> base_headers( - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - base_headers_string, sizeof(base_headers_string)))); + auto base_headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(base_headers_string)); // No redirect {
diff --git a/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc index 293b67a0..13a7ae3 100644 --- a/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc
@@ -84,9 +84,8 @@ "Key1: Value1\r\n" "X-Chrome-ID-Consistency-Response: Value2\r\n" "\r\n"; - scoped_refptr<net::HttpResponseHeaders> headers( - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - headers_string, sizeof(headers_string)))); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers_string)); { // Non-Gaia URL.
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 3bdc30b..f312f6fe 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1148,11 +1148,6 @@ "expiry_milestone": 80 }, { - "name": "enable-history-entry-requires-user-gesture", - // "owners": [ "your-team" ], - "expiry_milestone": 76 - }, - { "name": "enable-history-manipulation-intervention", "owners": [ "shivanisha" ], "expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 885e365..e9cd8d9 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1091,11 +1091,6 @@ const char kHideActiveAppsFromShelfDescription[] = "Save space in the shelf by hiding running apps (that are not pinned)."; -const char kHistoryRequiresUserGestureName[] = - "New history entries require a user gesture."; -const char kHistoryRequiresUserGestureDescription[] = - "Require a user gesture to add a history entry."; - const char kHorizontalTabSwitcherAndroidName[] = "Enable horizontal tab switcher"; const char kHorizontalTabSwitcherAndroidDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index eae7139c..bcc1850 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -672,9 +672,6 @@ extern const char kHideActiveAppsFromShelfName[]; extern const char kHideActiveAppsFromShelfDescription[]; -extern const char kHistoryRequiresUserGestureName[]; -extern const char kHistoryRequiresUserGestureDescription[]; - extern const char kHostedAppQuitNotificationName[]; extern const char kHostedAppQuitNotificationDescription[];
diff --git a/chrome/browser/google/google_update_win.cc b/chrome/browser/google/google_update_win.cc index dd2ff72b..3e1ab1a 100644 --- a/chrome/browser/google/google_update_win.cc +++ b/chrome/browser/google/google_update_win.cc
@@ -33,6 +33,7 @@ #include "base/version.h" #include "base/win/atl.h" #include "base/win/scoped_bstr.h" +#include "base/win/win_util.h" #include "chrome/common/url_constants.h" #include "chrome/grit/generated_resources.h" #include "chrome/install_static/install_util.h" @@ -137,11 +138,10 @@ // For Vista+, need to instantiate the class factory via the elevation // moniker. This ensures that the UAC dialog shows up. - wchar_t class_id_as_string[MAX_PATH] = {}; - StringFromGUID2(class_id, class_id_as_string, base::size(class_id_as_string)); + auto class_id_as_string = base::win::String16FromGUID(class_id); base::string16 elevation_moniker_name = base::StringPrintf( - L"Elevation:Administrator!clsid:%ls", class_id_as_string); + L"Elevation:Administrator!clsid:%ls", class_id_as_string.c_str()); BIND_OPTS3 bind_opts; // An explicit memset is needed rather than relying on value initialization
diff --git a/chrome/browser/installable/installed_webapp_bridge.cc b/chrome/browser/installable/installed_webapp_bridge.cc index cfa7500..48eac0c 100644 --- a/chrome/browser/installable/installed_webapp_bridge.cc +++ b/chrome/browser/installable/installed_webapp_bridge.cc
@@ -26,13 +26,9 @@ JNIEnv* env = base::android::AttachCurrentThread(); ScopedJavaLocalRef<jobjectArray> j_permissions = Java_InstalledWebappBridge_getNotificationPermissions(env); - jsize size = env->GetArrayLength(j_permissions.obj()); InstalledWebappProvider::RuleList rules; - for (jsize i = 0; i < size; i++) { - ScopedJavaLocalRef<jobject> j_permission( - env, env->GetObjectArrayElement(j_permissions.obj(), i)); - + for (auto j_permission : j_permissions.ReadElements<jobject>()) { GURL origin(ConvertJavaStringToUTF8( Java_InstalledWebappBridge_getOriginFromPermission(env, j_permission))); ContentSetting setting = IntToContentSetting(
diff --git a/chrome/browser/media/router/discovery/dial/dial_service.cc b/chrome/browser/media/router/discovery/dial/dial_service.cc index 60e7d334..8693149 100644 --- a/chrome/browser/media/router/discovery/dial/dial_service.cc +++ b/chrome/browser/media/router/discovery/dial/dial_service.cc
@@ -355,11 +355,10 @@ VLOG(1) << "Headers invalid or empty, ignoring: " << response; return false; } - std::string raw_headers = - HttpUtil::AssembleRawHeaders(response.c_str(), headers_end); + std::string raw_headers = HttpUtil::AssembleRawHeaders( + base::StringPiece(response.c_str(), headers_end)); VLOG(3) << "raw_headers: " << raw_headers << "\n"; - scoped_refptr<HttpResponseHeaders> headers = - new HttpResponseHeaders(raw_headers); + auto headers = base::MakeRefCounted<HttpResponseHeaders>(raw_headers); std::string device_url_str; if (!GetHeader(headers.get(), kSsdpLocationHeader, &device_url_str) ||
diff --git a/chrome/browser/notifications/notification_channels_provider_android.cc b/chrome/browser/notifications/notification_channels_provider_android.cc index c9bc009..589747c5 100644 --- a/chrome/browser/notifications/notification_channels_provider_android.cc +++ b/chrome/browser/notifications/notification_channels_provider_android.cc
@@ -92,11 +92,8 @@ JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobjectArray> raw_channels = Java_NotificationSettingsBridge_getSiteChannels(env); - jsize num_channels = env->GetArrayLength(raw_channels.obj()); std::vector<NotificationChannel> channels; - for (jsize i = 0; i < num_channels; ++i) { - ScopedJavaLocalRef<jobject> jchannel( - env, env->GetObjectArrayElement(raw_channels.obj(), i)); + for (auto jchannel : raw_channels.ReadElements<jobject>()) { channels.push_back(NotificationChannel( ConvertJavaStringToUTF8(Java_SiteChannel_getId(env, jchannel)), ConvertJavaStringToUTF8(Java_SiteChannel_getOrigin(env, jchannel)),
diff --git a/chrome/browser/offline_pages/offline_page_request_handler.cc b/chrome/browser/offline_pages/offline_page_request_handler.cc index 4daa8e8..3b0eee4 100644 --- a/chrome/browser/offline_pages/offline_page_request_handler.cc +++ b/chrome/browser/offline_pages/offline_page_request_handler.cc
@@ -689,9 +689,8 @@ net::URLRequestRedirectJob::REDIRECT_302_FOUND, redirected_url.spec().c_str()); - fake_headers_for_redirect_ = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - header_string.c_str(), header_string.length())); + fake_headers_for_redirect_ = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(header_string)); DCHECK(fake_headers_for_redirect_->IsRedirect(nullptr)); delegate_->NotifyHeadersComplete(0);
diff --git a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc index c5656b0..7d774c4 100644 --- a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc +++ b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
@@ -78,7 +78,6 @@ WebFeature::kDocumentLevelPassiveDefaultEventListenerPreventedWheel, WebFeature::kDocumentDomainBlockedCrossOriginAccess, WebFeature::kDocumentDomainEnabledCrossOriginAccess, - WebFeature::kSuppressHistoryEntryWithoutUserGesture, WebFeature::kCursorImageGT32x32, WebFeature::kCursorImageLE32x32, WebFeature::kHistoryPushState,
diff --git a/chrome/browser/payments/android/payment_manifest_web_data_service_android.cc b/chrome/browser/payments/android/payment_manifest_web_data_service_android.cc index 4b0cfa0b..0ccfed8 100644 --- a/chrome/browser/payments/android/payment_manifest_web_data_service_android.cc +++ b/chrome/browser/payments/android/payment_manifest_web_data_service_android.cc
@@ -148,12 +148,9 @@ std::vector<WebAppManifestSection> manifest; - jsize jcount_of_sections = env->GetArrayLength(jmanifest_sections.obj()); - for (jsize i = 0; i < jcount_of_sections; i++) { + for (auto jsection : jmanifest_sections.ReadElements<jobject>()) { WebAppManifestSection section; - base::android::ScopedJavaLocalRef<jobject> jsection( - env, env->GetObjectArrayElement(jmanifest_sections.obj(), i)); section.id = base::android::ConvertJavaStringToUTF8( Java_PaymentManifestWebDataService_getIdFromSection(env, jsection)); section.min_version = static_cast<int64_t>( @@ -163,13 +160,8 @@ base::android::ScopedJavaLocalRef<jobjectArray> jsection_fingerprints( Java_PaymentManifestWebDataService_getFingerprintsFromSection( env, jsection)); - jsize jcount_of_fingerprints = - env->GetArrayLength(jsection_fingerprints.obj()); - for (jsize j = 0; j < jcount_of_fingerprints; j++) { + for (auto jfingerprint : jsection_fingerprints.ReadElements<jbyteArray>()) { std::vector<uint8_t> fingerprint; - base::android::ScopedJavaLocalRef<jbyteArray> jfingerprint( - env, (jbyteArray)env->GetObjectArrayElement( - jsection_fingerprints.obj(), j)); base::android::JavaByteArrayToByteVector(env, jfingerprint, &fingerprint); section.fingerprints.emplace_back(fingerprint); }
diff --git a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.cc b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.cc index 58adba3..741c010 100644 --- a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.cc +++ b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.cc
@@ -228,12 +228,12 @@ // static bool PageAlmostIdleDecorator::IsIdling(const PageNodeImpl* page_node) { - // Get the Frame CU for the main frame associated with this page. + // Get the frame node for the main frame associated with this page. const FrameNodeImpl* main_frame_node = page_node->GetMainFrameNode(); if (!main_frame_node) return false; - // Get the process CU associated with this main frame. + // Get the process node associated with this main frame. const auto* process_node = main_frame_node->process_node(); if (!process_node) return false;
diff --git a/chrome/browser/performance_manager/graph/graph.cc b/chrome/browser/performance_manager/graph/graph.cc index 3e5a63c..6f4207b 100644 --- a/chrome/browser/performance_manager/graph/graph.cc +++ b/chrome/browser/performance_manager/graph/graph.cc
@@ -86,7 +86,8 @@ SystemNodeImpl* Graph::FindOrCreateSystemNode() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!system_node_) { - // Create the singleton SystemCU instance. Ownership is taken by the graph. + // Create the singleton system node instance. Ownership is taken by the + // graph. system_node_ = std::make_unique<SystemNodeImpl>(this); AddNewNode(system_node_.get()); } @@ -170,9 +171,9 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // On Windows, PIDs are aggressively reused, and because not all process // creation/death notifications are synchronized, it's possible for more than - // one CU to have the same PID. To handle this, the second and subsequent - // registration override earlier registrations, while unregistration will only - // unregister the current holder of the PID. + // one process node to have the same PID. To handle this, the second and + // subsequent registration override earlier registrations, while + // unregistration will only unregister the current holder of the PID. if (process->process_id() != base::kNullProcessId) { auto it = processes_by_pid_.find(process->process_id()); if (it != processes_by_pid_.end() && it->second == process)
diff --git a/chrome/browser/performance_manager/graph/graph_unittest.cc b/chrome/browser/performance_manager/graph/graph_unittest.cc index 133318b..6781e58 100644 --- a/chrome/browser/performance_manager/graph/graph_unittest.cc +++ b/chrome/browser/performance_manager/graph/graph_unittest.cc
@@ -75,7 +75,7 @@ process2->SetProcess(self.Duplicate(), base::Time::Now()); EXPECT_EQ(process2.get(), graph.GetProcessNodeByPid(self.Pid())); - // The destruction of the first process CU shouldn't clear the PID + // The destruction of the first process node shouldn't clear the PID // registration. process1.reset(); EXPECT_EQ(process2.get(), graph.GetProcessNodeByPid(self.Pid()));
diff --git a/chrome/browser/performance_manager/graph/mock_graphs.h b/chrome/browser/performance_manager/graph/mock_graphs.h index 99cf9e8..94d7a00a 100644 --- a/chrome/browser/performance_manager/graph/mock_graphs.h +++ b/chrome/browser/performance_manager/graph/mock_graphs.h
@@ -26,8 +26,8 @@ base::Time launch_time); }; -// The following coordination unit graph topology is created to emulate a -// scenario when a single page executes in a single process: +// The following graph topology is created to emulate a scenario when a single +// page executes in a single process: // // Pr Pg // \ / @@ -46,8 +46,8 @@ TestNodeWrapper<FrameNodeImpl> frame; }; -// The following coordination unit graph topology is created to emulate a -// scenario where multiple pages are executing in a single process: +// The following graph topology is created to emulate a scenario where multiple +// pages are executing in a single process: // // Pg Pr OPg // \ / \ / @@ -67,9 +67,9 @@ TestNodeWrapper<FrameNodeImpl> other_frame; }; -// The following coordination unit graph topology is created to emulate a -// scenario where a single page that has frames is executing in different -// processes (e.g. out-of-process iFrames): +// The following graph topology is created to emulate a scenario where a single +// page that has frames is executing in different processes (e.g. out-of-process +// iFrames): // // Pg Pr // |\ / @@ -91,9 +91,9 @@ TestNodeWrapper<FrameNodeImpl> child_frame; }; -// The following coordination unit graph topology is created to emulate a -// scenario where multiple pages are utilizing multiple processes (e.g. -// out-of-process iFrames and multiple pages in a process): +// The following graph topology is created to emulate a scenario where multiple +// pages are utilizing multiple processes (e.g. out-of-process iFrames and +// multiple pages in a process): // // Pg Pr OPg___ // \ / \ / |
diff --git a/chrome/browser/performance_manager/graph/node_base.h b/chrome/browser/performance_manager/graph/node_base.h index 3841924d..6345d776 100644 --- a/chrome/browser/performance_manager/graph/node_base.h +++ b/chrome/browser/performance_manager/graph/node_base.h
@@ -27,9 +27,9 @@ class Graph; -// NodeBase implements shared functionality among different types of -// coordination units. A specific type of coordination unit will derive from -// this class and can override shared funtionality when needed. +// NodeBase implements shared functionality among different types of graph +// nodes. A specific type of graph node will derive from this class and can +// override shared functionality when needed. // All node classes allow construction on one sequence and subsequent use from // another sequence. // All methods not documented otherwise are single-threaded. @@ -89,14 +89,14 @@ explicit TypedNodeBase(Graph* graph) : NodeBase(NodeClass::Type(), graph) {} - static const NodeClass* FromNodeBase(const NodeBase* cu) { - DCHECK_EQ(cu->type(), NodeClass::Type()); - return static_cast<const NodeClass*>(cu); + static const NodeClass* FromNodeBase(const NodeBase* node) { + DCHECK_EQ(node->type(), NodeClass::Type()); + return static_cast<const NodeClass*>(node); } - static NodeClass* FromNodeBase(NodeBase* cu) { - DCHECK(cu->type() == NodeClass::Type()); - return static_cast<NodeClass*>(cu); + static NodeClass* FromNodeBase(NodeBase* node) { + DCHECK(node->type() == NodeClass::Type()); + return static_cast<NodeClass*>(node); } };
diff --git a/chrome/browser/performance_manager/graph/page_node_impl.h b/chrome/browser/performance_manager/graph/page_node_impl.h index 7f6fb9f..d3320a0 100644 --- a/chrome/browser/performance_manager/graph/page_node_impl.h +++ b/chrome/browser/performance_manager/graph/page_node_impl.h
@@ -64,12 +64,12 @@ // Returns the time since the last visibility change, it should always have a // value since we set the visibility property when we create a - // PageCoordinationUnit. + // page node. base::TimeDelta TimeSinceLastVisibilityChange() const; std::vector<FrameNodeImpl*> GetFrameNodes() const; - // Returns the main frame CU or nullptr if this page has no main frame. + // Returns the main frame node or nullptr if this page has no main frame. FrameNodeImpl* GetMainFrameNode() const; // Accessors.
diff --git a/chrome/browser/performance_manager/graph/page_node_impl_unittest.cc b/chrome/browser/performance_manager/graph/page_node_impl_unittest.cc index 86f3a8a..b9f78ea 100644 --- a/chrome/browser/performance_manager/graph/page_node_impl_unittest.cc +++ b/chrome/browser/performance_manager/graph/page_node_impl_unittest.cc
@@ -245,8 +245,8 @@ TEST_F(PageNodeImplTest, InitialInterventionPolicy) { auto* mock_graph = graph(); - // Tests all possible transitions where the frame CU has its policy values - // set before being attached to the page CU. This affectively tests the + // Tests all possible transitions where the frame node has its policy values + // set before being attached to the page node. This affectively tests the // aggregation logic in isolation. // Default x [Default, OptIn, OptOut] @@ -355,7 +355,7 @@ EXPECT_EQ(0u, page->GetInterventionPolicyFramesReportedForTesting()); // Set the policies on the first frame. This should be observed by the page - // CU, but aggregation should still not be possible. + // node, but aggregation should still not be possible. f0->SetAllInterventionPoliciesForTesting( resource_coordinator::mojom::InterventionPolicy::kDefault); EXPECT_EQ(1u, page->GetInterventionPolicyFramesReportedForTesting());
diff --git a/chrome/browser/performance_manager/graph/process_node_impl.cc b/chrome/browser/performance_manager/graph/process_node_impl.cc index f4e06c7..58c3a07 100644 --- a/chrome/browser/performance_manager/graph/process_node_impl.cc +++ b/chrome/browser/performance_manager/graph/process_node_impl.cc
@@ -60,7 +60,7 @@ base::Time launch_time) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(process.IsValid()); - // Either this is the initial process associated with this process CU, + // Either this is the initial process associated with this process node, // or it's a subsequent process. In the latter case, there must have been // an exit status associated with the previous process. DCHECK(!process_.IsValid() || exit_status_.has_value());
diff --git a/chrome/browser/performance_manager/graph/process_node_impl.h b/chrome/browser/performance_manager/graph/process_node_impl.h index 1537ea6..b9affea 100644 --- a/chrome/browser/performance_manager/graph/process_node_impl.h +++ b/chrome/browser/performance_manager/graph/process_node_impl.h
@@ -20,11 +20,11 @@ class FrameNodeImpl; -// A process coordination unit follows the lifetime of a RenderProcessHost. +// A process node follows the lifetime of a RenderProcessHost. // It may reference zero or one processes at a time, but during its lifetime, it // may reference more than one process. This can happen if the associated // renderer crashes, and an associated frame is then reloaded or re-navigated. -// The state of the process CU goes through: +// The state of the process node goes through: // 1. Created, no PID. // 2. Process started, have PID - in the case where the associated render // process fails to start, this state may not occur.
diff --git a/chrome/browser/performance_manager/graph/process_node_impl_unittest.cc b/chrome/browser/performance_manager/graph/process_node_impl_unittest.cc index 8f3575c..23f6454 100644 --- a/chrome/browser/performance_manager/graph/process_node_impl_unittest.cc +++ b/chrome/browser/performance_manager/graph/process_node_impl_unittest.cc
@@ -28,7 +28,7 @@ TEST_F(ProcessNodeImplTest, ProcessLifeCycle) { auto process_node = CreateNode<ProcessNodeImpl>(); - // Test the potential lifecycles of a process CU. + // Test the potential lifecycles of a process node. // First go to exited without an intervening process attached, as would happen // in the case the process fails to start. EXPECT_FALSE(process_node->process().IsValid());
diff --git a/chrome/browser/performance_manager/observers/graph_observer.h b/chrome/browser/performance_manager/observers/graph_observer.h index 7be9a66..4e48a89 100644 --- a/chrome/browser/performance_manager/observers/graph_observer.h +++ b/chrome/browser/performance_manager/observers/graph_observer.h
@@ -17,15 +17,11 @@ class ProcessNodeImpl; class SystemNodeImpl; -// An observer API for the coordination unit graph maintained by GRC. +// An observer API for the graph. // -// Observers are instantiated when the resource_coordinator service -// is created and are destroyed when the resource_coordinator service -// is destroyed. Therefore observers are guaranteed to be alive before -// any coordination unit is created and will be alive after any -// coordination unit is destroyed. Additionally, any -// Coordination Unit reachable within a callback will always be -// initialized and valid. +// Observers are generally instantiated when the graph is empty, and outlive it, +// though it's valid for an observer to be registered at any time. Observers +// must unregister before they're destroyed. // // To create and install a new observer: // (1) Derive from this class. @@ -50,10 +46,10 @@ // invoked for, the |node|. virtual bool ShouldObserve(const NodeBase* node) = 0; - // Called whenever a CoordinationUnit is created. + // Called whenever a node has been added to the graph. virtual void OnNodeAdded(NodeBase* node) {} - // Called when the |node| is about to be destroyed. + // Called when the |node| is about to be removed from the graph. virtual void OnBeforeNodeRemoved(NodeBase* node) {} // FrameNodeImpl notifications.
diff --git a/chrome/browser/performance_manager/observers/metrics_collector.h b/chrome/browser/performance_manager/observers/metrics_collector.h index a0e4515..8ead22b 100644 --- a/chrome/browser/performance_manager/observers/metrics_collector.h +++ b/chrome/browser/performance_manager/observers/metrics_collector.h
@@ -28,8 +28,7 @@ extern const base::TimeDelta kMetricsReportDelayTimeout; extern const int kDefaultFrequencyUkmEQTReported; -// A MetricsCollector observes changes happened inside CoordinationUnit Graph, -// and reports UMA/UKM. +// The MetricsCollector is a graph observer that reports UMA/UKM. class MetricsCollector : public GraphObserver { public: MetricsCollector();
diff --git a/chrome/browser/performance_manager/observers/working_set_trimmer_win_unittest.cc b/chrome/browser/performance_manager/observers/working_set_trimmer_win_unittest.cc index 2576ccb..8b85acc 100644 --- a/chrome/browser/performance_manager/observers/working_set_trimmer_win_unittest.cc +++ b/chrome/browser/performance_manager/observers/working_set_trimmer_win_unittest.cc
@@ -119,11 +119,11 @@ } // namespace TEST_F(WorkingSetTrimmerTest, EmptyWorkingSet) { - // Set the launch time of the process CU to match |child_process_|. + // Set the launch time of the process node to match |child_process_|. process_node_->SetProcess(child_process_.Duplicate(), child_process_.CreationTime()); - // When all frames in the Process CU are frozen, the working set of + // When all frames in the process node are frozen, the working set of // |child_process_| should be emptied. size_t working_set_before = GetWorkingSetSizeMb(child_process_.Handle()); working_set_trimmer_.OnAllFramesInProcessFrozen(process_node_.get());
diff --git a/chrome/browser/plugins/pdf_iframe_navigation_throttle_unittest.cc b/chrome/browser/plugins/pdf_iframe_navigation_throttle_unittest.cc index 67e5415..7d40bde 100644 --- a/chrome/browser/plugins/pdf_iframe_navigation_throttle_unittest.cc +++ b/chrome/browser/plugins/pdf_iframe_navigation_throttle_unittest.cc
@@ -48,8 +48,7 @@ "content-type: " + mime_type + "\r\n"; return base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(raw_response_headers.c_str(), - raw_response_headers.size())); + net::HttpUtil::AssembleRawHeaders(raw_response_headers)); } content::RenderFrameHost* subframe() { return subframe_; }
diff --git a/chrome/browser/previews/previews_content_util.cc b/chrome/browser/previews/previews_content_util.cc index af87ffc..cafbb0e 100644 --- a/chrome/browser/previews/previews_content_util.cc +++ b/chrome/browser/previews/previews_content_util.cc
@@ -62,6 +62,11 @@ if (!navigation_handle) return true; + // This should only occur in unit tests; this behavior is tested in browser + // tests. + if (navigation_handle->GetWebContents() == nullptr) + return true; + const GURL& url = navigation_handle->GetURL(); content::WebContents* web_contents = navigation_handle->GetWebContents(); auto* previews_service = PreviewsServiceFactory::GetForProfile( @@ -165,6 +170,9 @@ content::NavigationHandle* navigation_handle) { auto server_lite_page_info = std::make_unique<PreviewsUserData::ServerLitePageInfo>(); + // This is only for unit testing. + if (!navigation_handle->GetWebContents()) + return nullptr; server_lite_page_info->original_navigation_start = navigation_handle->NavigationStart(); @@ -209,14 +217,16 @@ content::PreviewsState DetermineAllowedClientPreviewsState( previews::PreviewsUserData* previews_data, - const GURL& url, - bool is_reload, - bool is_redirect, + bool previews_triggering_logic_already_ran, bool is_data_saver_user, previews::PreviewsDecider* previews_decider, content::NavigationHandle* navigation_handle) { content::PreviewsState previews_state = content::PREVIEWS_UNSPECIFIED; + const GURL& url = navigation_handle->GetURL(); + bool is_reload = + navigation_handle->GetReloadType() != content::ReloadType::NONE; + // Either this is a navigation to the lite page via the redirect mechanism and // only Lite Page redirect should be served, or this is a reload in which case // the Lite Page mechanism should redirect to the original URL. Either way, @@ -240,15 +250,16 @@ return previews_state; auto* previews_service = - navigation_handle + navigation_handle && navigation_handle->GetWebContents() ? PreviewsServiceFactory::GetForProfile(Profile::FromBrowserContext( navigation_handle->GetWebContents()->GetBrowserContext())) : nullptr; - // Offline previews state should not be updated during a redirect. The Offline - // Previews URLLoader will not receive an updated PreviewsState, so the state - // should stay consistent throughout the navigation. - if (is_redirect) { + // Offline previews state should not be updated if previews triggering + // logic has already been run. The Offline Previews URLLoader will not receive + // an updated PreviewsState, so the state should stay consistent throughout + // the navigation. + if (previews_triggering_logic_already_ran) { // Record that the navigation was redirected. previews_data->set_is_redirect(true); // Keep the same OFFLINE previews bit as the original URL.
diff --git a/chrome/browser/previews/previews_content_util.h b/chrome/browser/previews/previews_content_util.h index bd5373f..c47f434 100644 --- a/chrome/browser/previews/previews_content_util.h +++ b/chrome/browser/previews/previews_content_util.h
@@ -17,19 +17,16 @@ // Returns whether |previews_state| has any enabled previews. bool HasEnabledPreviews(content::PreviewsState previews_state); -// Returns the bitmask of enabled client-side previews for |url| and the +// Returns the bitmask of enabled client-side previews and the // current effective network connection given |previews_decider|. // This handles the mapping of previews::PreviewsType enum values to bitmask // definitions for content::PreviewsState. -// |is_reload| is used to eliminate certain preview types, and |previews_data| -// is populated with relevant information. -// TODO(ryansturm): |navigation_handle| has all of the other information, so -// remove extra arguments. https://crbug.com/934400 +// |previews_triggering_logic_already_ran| is used to prevent offline previews +// from being updated if previews triggering logic has already run. +// |previews_data| is populated with relevant information. content::PreviewsState DetermineAllowedClientPreviewsState( previews::PreviewsUserData* previews_data, - const GURL& url, - bool is_reload, - bool is_redirect, + bool previews_triggering_logic_already_ran, bool is_data_saver_user, previews::PreviewsDecider* previews_decider, content::NavigationHandle* navigation_handle);
diff --git a/chrome/browser/previews/previews_content_util_unittest.cc b/chrome/browser/previews/previews_content_util_unittest.cc index c733185..9fbf7f5 100644 --- a/chrome/browser/previews/previews_content_util_unittest.cc +++ b/chrome/browser/previews/previews_content_util_unittest.cc
@@ -14,6 +14,7 @@ #include "components/previews/core/previews_experiments.h" #include "components/previews/core/previews_features.h" #include "content/public/common/previews_state.h" +#include "content/public/test/mock_navigation_handle.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -21,6 +22,30 @@ namespace { +// Creates and populates a MockNavigationHandle to pass to +// DetermineAllowedClientPreveiwsState. +content::PreviewsState CallDetermineAllowedClientPreviewsState( + previews::PreviewsUserData* previews_data, + const GURL& url, + bool is_reload, + bool previews_triggering_logic_already_ran, + bool is_data_saver_user, + previews::PreviewsDecider* previews_decider, + content::NavigationHandle* navigation_handle) { + EXPECT_TRUE(!navigation_handle); + content::MockNavigationHandle mock_navigation_handle; + mock_navigation_handle.set_url(url); + if (is_reload) { + mock_navigation_handle.set_reload_type(content::ReloadType::NORMAL); + } else { + mock_navigation_handle.set_reload_type(content::ReloadType::NONE); + } + + return DetermineAllowedClientPreviewsState( + previews_data, previews_triggering_logic_already_ran, is_data_saver_user, + previews_decider, &mock_navigation_handle); +} + // A test implementation of PreviewsDecider that simply returns whether the // preview type feature is enabled (ignores ECT and blacklist considerations). class PreviewEnabledPreviewsDecider : public PreviewsDecider { @@ -105,18 +130,18 @@ "Previews" /* disable_features */); PreviewsUserData user_data(1); bool is_reload = false; - bool is_redirect = false; + bool previews_triggering_logic_already_ran = false; bool is_data_saver_user = true; - EXPECT_EQ( - content::PREVIEWS_UNSPECIFIED, - previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("http://www.google.com"), is_reload, is_redirect, - is_data_saver_user, enabled_previews_decider(), nullptr)); - EXPECT_EQ( - content::PREVIEWS_UNSPECIFIED, - previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("http://www.google.com"), is_reload, is_redirect, - is_data_saver_user, enabled_previews_decider(), nullptr)); + EXPECT_EQ(content::PREVIEWS_UNSPECIFIED, + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("http://www.google.com"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); + EXPECT_EQ(content::PREVIEWS_UNSPECIFIED, + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("http://www.google.com"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); } TEST_F(PreviewsContentUtilTest, @@ -127,20 +152,20 @@ {} /* disable_features */); PreviewsUserData user_data(1); bool is_reload = false; - bool is_redirect = false; + bool previews_triggering_logic_already_ran = false; bool is_data_saver_user = true; - EXPECT_EQ( - content::OFFLINE_PAGE_ON | content::CLIENT_LOFI_ON | - content::RESOURCE_LOADING_HINTS_ON | content::NOSCRIPT_ON, - previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("http://www.google.com"), is_reload, is_redirect, - is_data_saver_user, enabled_previews_decider(), nullptr)); + EXPECT_EQ(content::OFFLINE_PAGE_ON | content::CLIENT_LOFI_ON | + content::RESOURCE_LOADING_HINTS_ON | content::NOSCRIPT_ON, + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("http://www.google.com"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); is_data_saver_user = false; - EXPECT_EQ( - content::PREVIEWS_UNSPECIFIED, - previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("http://www.google.com"), is_reload, is_redirect, - is_data_saver_user, enabled_previews_decider(), nullptr)); + EXPECT_EQ(content::PREVIEWS_UNSPECIFIED, + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("http://www.google.com"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); } TEST_F(PreviewsContentUtilTest, @@ -150,34 +175,34 @@ "Previews", "ClientLoFi,ResourceLoadingHints,NoScriptPreviews"); PreviewsUserData user_data(1); bool is_reload = false; - bool is_redirect = false; + bool previews_triggering_logic_already_ran = false; bool is_data_saver_user = true; - EXPECT_EQ( - content::OFFLINE_PAGE_ON, - previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("http://www.google.com"), is_reload, is_redirect, - is_data_saver_user, enabled_previews_decider(), nullptr)); + EXPECT_EQ(content::OFFLINE_PAGE_ON, + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("http://www.google.com"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); EXPECT_FALSE(user_data.is_redirect()); user_data.set_allowed_previews_state(content::OFFLINE_PAGE_ON); - is_redirect = true; - EXPECT_EQ( - content::OFFLINE_PAGE_ON, - previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("http://www.google.com"), is_reload, is_redirect, - is_data_saver_user, enabled_previews_decider(), nullptr)); + previews_triggering_logic_already_ran = true; + EXPECT_EQ(content::OFFLINE_PAGE_ON, + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("http://www.google.com"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); EXPECT_TRUE(user_data.is_redirect()); user_data.set_allowed_previews_state(content::PREVIEWS_OFF); - EXPECT_EQ( - content::PREVIEWS_UNSPECIFIED, - previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("http://www.google.com"), is_reload, is_redirect, - is_data_saver_user, enabled_previews_decider(), nullptr)); - is_redirect = false; - EXPECT_EQ( - content::OFFLINE_PAGE_ON, - previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("http://www.google.com"), is_reload, is_redirect, - is_data_saver_user, enabled_previews_decider(), nullptr)); + EXPECT_EQ(content::PREVIEWS_UNSPECIFIED, + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("http://www.google.com"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); + previews_triggering_logic_already_ran = false; + EXPECT_EQ(content::OFFLINE_PAGE_ON, + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("http://www.google.com"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); } TEST_F(PreviewsContentUtilTest, DetermineAllowedClientPreviewsStateClientLoFi) { @@ -185,18 +210,18 @@ scoped_feature_list.InitFromCommandLine("Previews,ClientLoFi", std::string()); PreviewsUserData user_data(1); bool is_reload = false; - bool is_redirect = false; + bool previews_triggering_logic_already_ran = false; bool is_data_saver_user = true; EXPECT_TRUE(content::CLIENT_LOFI_ON & - previews::DetermineAllowedClientPreviewsState( + previews::CallDetermineAllowedClientPreviewsState( &user_data, GURL("https://www.google.com"), is_reload, - is_redirect, is_data_saver_user, enabled_previews_decider(), - nullptr)); + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); EXPECT_TRUE(content::CLIENT_LOFI_ON & - previews::DetermineAllowedClientPreviewsState( + previews::CallDetermineAllowedClientPreviewsState( &user_data, GURL("http://www.google.com"), is_reload, - is_redirect, is_data_saver_user, enabled_previews_decider(), - nullptr)); + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); } TEST_F(PreviewsContentUtilTest, @@ -206,18 +231,20 @@ std::string()); PreviewsUserData user_data(1); bool is_reload = false; - bool is_redirect = false; + bool previews_triggering_logic_already_ran = false; bool is_data_saver_user = true; - EXPECT_LT(0, content::RESOURCE_LOADING_HINTS_ON & - previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("https://www.google.com"), is_reload, - is_redirect, is_data_saver_user, - enabled_previews_decider(), nullptr)); - EXPECT_LT(0, content::RESOURCE_LOADING_HINTS_ON & - previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("http://www.google.com"), is_reload, - is_redirect, is_data_saver_user, - enabled_previews_decider(), nullptr)); + EXPECT_LT(0, + content::RESOURCE_LOADING_HINTS_ON & + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("https://www.google.com"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); + EXPECT_LT(0, + content::RESOURCE_LOADING_HINTS_ON & + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("http://www.google.com"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); } TEST_F(PreviewsContentUtilTest, @@ -229,25 +256,26 @@ PreviewsUserData user_data(1); bool is_reload = false; - bool is_redirect = false; + bool previews_triggering_logic_already_ran = false; bool is_data_saver_user = true; // Verify both are enabled. EXPECT_TRUE((content::NOSCRIPT_ON | content::CLIENT_LOFI_ON) & - previews::DetermineAllowedClientPreviewsState( + previews::CallDetermineAllowedClientPreviewsState( &user_data, GURL("https://www.google.com"), is_reload, - is_redirect, is_data_saver_user, enabled_previews_decider(), - nullptr)); + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); EXPECT_TRUE((content::NOSCRIPT_ON | content::CLIENT_LOFI_ON) & - previews::DetermineAllowedClientPreviewsState( + previews::CallDetermineAllowedClientPreviewsState( &user_data, GURL("http://www.google.com"), is_reload, - is_redirect, is_data_saver_user, enabled_previews_decider(), - nullptr)); + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); // Verify non-HTTP[S] URL has no previews enabled. EXPECT_EQ(content::PREVIEWS_UNSPECIFIED, - previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("data://someblob"), is_reload, is_redirect, - is_data_saver_user, enabled_previews_decider(), nullptr)); + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("data://someblob"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); } TEST_F(PreviewsContentUtilTest, @@ -258,20 +286,20 @@ PreviewsUserData user_data(1); bool is_reload = false; - bool is_redirect = false; + bool previews_triggering_logic_already_ran = false; bool is_data_saver_user = true; // Verify preview is enabled on HTTPS. EXPECT_TRUE(content::LITE_PAGE_REDIRECT_ON & - previews::DetermineAllowedClientPreviewsState( + previews::CallDetermineAllowedClientPreviewsState( &user_data, GURL("https://www.google.com"), is_reload, - is_redirect, is_data_saver_user, enabled_previews_decider(), - nullptr)); - + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); // Verify non-HTTP[S] URL has no previews enabled. EXPECT_EQ(content::PREVIEWS_UNSPECIFIED, - previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("data://someblob"), is_reload, is_redirect, - is_data_saver_user, enabled_previews_decider(), nullptr)); + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("data://someblob"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr)); // Other checks are performed in browser tests due to the nature of needing // fully initialized browser state. @@ -286,20 +314,24 @@ PreviewsUserData user_data(1); bool is_reload = false; - bool is_redirect = false; + bool previews_triggering_logic_already_ran = false; bool is_data_saver_user = true; // Verify Lite Page Redirect enabled for host without page hints. - content::PreviewsState ps1 = previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("https://www.google.com"), is_reload, is_redirect, - is_data_saver_user, enabled_previews_decider(), nullptr); + content::PreviewsState ps1 = + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("https://www.google.com"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr); EXPECT_TRUE(ps1 & content::LITE_PAGE_REDIRECT_ON); EXPECT_TRUE(ps1 & content::RESOURCE_LOADING_HINTS_ON); EXPECT_TRUE(ps1 & content::NOSCRIPT_ON); // Verify only page hint client previews enabled with known page hints. - content::PreviewsState ps2 = previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("https://www.hintcachedhost.com"), is_reload, - is_redirect, is_data_saver_user, enabled_previews_decider(), nullptr); + content::PreviewsState ps2 = + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("https://www.hintcachedhost.com"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr); EXPECT_FALSE(ps2 & content::LITE_PAGE_REDIRECT_ON); EXPECT_TRUE(ps2 & content::RESOURCE_LOADING_HINTS_ON); EXPECT_TRUE(ps2 & content::NOSCRIPT_ON); @@ -313,9 +345,11 @@ features::kLitePageServerPreviews, parameters); // Verify Lite Page Redirect now enabled for host with page hints. - content::PreviewsState ps = previews::DetermineAllowedClientPreviewsState( - &user_data, GURL("https://www.hintcachedhost.com"), is_reload, - is_redirect, is_data_saver_user, enabled_previews_decider(), nullptr); + content::PreviewsState ps = + previews::CallDetermineAllowedClientPreviewsState( + &user_data, GURL("https://www.hintcachedhost.com"), is_reload, + previews_triggering_logic_already_ran, is_data_saver_user, + enabled_previews_decider(), nullptr); EXPECT_TRUE(ps & content::LITE_PAGE_REDIRECT_ON); EXPECT_TRUE(ps & content::RESOURCE_LOADING_HINTS_ON); EXPECT_TRUE(ps & content::NOSCRIPT_ON);
diff --git a/chrome/browser/previews/previews_lite_page_redirect_url_loader.cc b/chrome/browser/previews/previews_lite_page_redirect_url_loader.cc index c049eb0..a5de7c6 100644 --- a/chrome/browser/previews/previews_lite_page_redirect_url_loader.cc +++ b/chrome/browser/previews/previews_lite_page_redirect_url_loader.cc
@@ -161,11 +161,8 @@ net::HTTP_TEMPORARY_REDIRECT, modified_resource_request_.url.spec().c_str()); - scoped_refptr<net::HttpResponseHeaders> fake_headers_for_redirect = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - header_string.c_str(), header_string.length())); - - response_head_.headers = fake_headers_for_redirect; + response_head_.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(header_string)); response_head_.encoded_data_length = 0; StartHandlingRedirect(resource_request, std::move(request),
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc index 6d82d6e..d353e12c 100644 --- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc +++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -767,7 +767,7 @@ network::ResourceResponseHead head; std::string headers("HTTP/1.1 200 OK\nContent-type: text/xml\n\n"); head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + net::HttpUtil::AssembleRawHeaders(headers)); head.mime_type = "text/xml"; network::URLLoaderCompletionStatus status; status.decoded_body_length = xml_config.size();
diff --git a/chrome/browser/profiling_host/profiling_process_host.cc b/chrome/browser/profiling_host/profiling_process_host.cc index 48af3cf..5e1b3ef 100644 --- a/chrome/browser/profiling_host/profiling_process_host.cc +++ b/chrome/browser/profiling_host/profiling_process_host.cc
@@ -51,8 +51,7 @@ void OnTraceUploadComplete(TraceCrashServiceUploader* uploader, bool success, const std::string& feedback) { - UMA_HISTOGRAM_BOOLEAN("OutOfProcessHeapProfiling.UploadTrace.Success", - success); + UMA_HISTOGRAM_BOOLEAN("HeapProfiling.UploadTrace.Success", success); if (!success) { LOG(ERROR) << "Cannot upload trace file: " << feedback; @@ -71,7 +70,7 @@ // account for all potentially too-small traces, we set the lower bounds to // 512 bytes. The upper bounds is set to 300MB as an extra-high threshold, // just in case something goes wrong. - UMA_HISTOGRAM_CUSTOM_COUNTS("OutOfProcessHeapProfiling.UploadTrace.Size", + UMA_HISTOGRAM_CUSTOM_COUNTS("HeapProfiling.UploadTrace.Size", file_contents.size(), 512, 300 * 1024 * 1024, 50); base::Value rules_list(base::Value::Type::LIST); @@ -167,8 +166,7 @@ auto finish_report_callback = base::BindOnce( [](std::string upload_url, std::string trigger_name, uint32_t sampling_rate, bool success, std::string trace) { - UMA_HISTOGRAM_BOOLEAN("OutOfProcessHeapProfiling.RecordTrace.Success", - success); + UMA_HISTOGRAM_BOOLEAN("HeapProfiling.RecordTrace.Success", success); if (success) { UploadTraceToCrashServer(std::move(upload_url), std::move(trace), std::move(trigger_name), sampling_rate); @@ -212,7 +210,7 @@ } void ProfilingProcessHost::ReportMetrics() { - UMA_HISTOGRAM_ENUMERATION("OutOfProcessHeapProfiling.ProfilingMode", + UMA_HISTOGRAM_ENUMERATION("HeapProfiling.ProfilingMode", Supervisor::GetInstance()->GetMode(), Mode::kCount); }
diff --git a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc index 3ef89aa..3ddb35d0 100644 --- a/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc +++ b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
@@ -17,6 +17,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/memory/memory_pressure_monitor_chromeos.h" +#include "base/memory/memory_pressure_monitor_notifying_chromeos.h" #include "base/metrics/histogram_macros.h" #include "base/process/memory.h" #include "base/process/process_handle.h" // kNullProcessHandle. @@ -223,11 +224,17 @@ // static int TabManagerDelegate::MemoryStat::LowMemoryMarginKB() { - static const int kDefaultLowMemoryMarginMb = 50; - static const char kLowMemoryMarginConfig[] = - "/sys/kernel/mm/chromeos-low_mem/margin"; - return ReadIntFromFile(kLowMemoryMarginConfig, kDefaultLowMemoryMarginMb) * - 1024; + constexpr int kDefaultLowMemoryMarginMb = 50; + + // A margin file can contain multiple values but the first one + // represents the critical memory threshold. + std::vector<int> margin_parts = + base::chromeos::MemoryPressureMonitorNotifying::GetMarginFileParts(); + if (!margin_parts.empty()) { + return margin_parts[0] * 1024; + } + + return kDefaultLowMemoryMarginMb * 1024; } // Target memory to free is the amount which brings available @@ -431,10 +438,23 @@ // driven MemoryPressureMonitor will continue to produce timed events // on top. So the longer the cleanup phase takes, the more tabs will // get discarded in parallel. - base::chromeos::MemoryPressureMonitor* monitor = - base::chromeos::MemoryPressureMonitor::Get(); - if (monitor) - monitor->ScheduleEarlyCheck(); + + // TODO(bgeffon): Once the notifying version has become the standard + // this can be removed, the reason the check is here and the type safe + // versions exist is because a FakeMemoryPressureMonitor can be used on + // chromeos for testing and ScheduleEarlyCheck() is not part of the + // base::MemoryPressureMonitor interface. + auto* monitor_legacy = base::chromeos::MemoryPressureMonitor::Get(); + if (monitor_legacy) { + monitor_legacy->ScheduleEarlyCheck(); + } else { + auto* monitor_notifying = + base::chromeos::MemoryPressureMonitorNotifying::Get(); + if (monitor_notifying) { + monitor_notifying->ScheduleEarlyCheck(); + } + } + break; } case content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED: {
diff --git a/chrome/browser/resources/settings/about_page/about_page.html b/chrome/browser/resources/settings/about_page/about_page.html index bb87585..9c777d1 100644 --- a/chrome/browser/resources/settings/about_page/about_page.html +++ b/chrome/browser/resources/settings/about_page/about_page.html
@@ -90,7 +90,7 @@ <settings-animated-pages id="pages" section="about" focus-config="[[focusConfig_]]"> <div route-path="default"> - <div class="settings-box two-line"> + <div class="settings-box two-line first"> <img id="product-logo" on-click="onProductLogoTap_" srcset="chrome://theme/current-channel-logo@1x 1x, chrome://theme/current-channel-logo@2x 2x" @@ -240,7 +240,7 @@ </settings-section> <settings-section> - <div class="settings-box padded block"> + <div class="settings-box padded block first"> <div class="info-section"> <div class="secondary">$i18n{aboutProductTitle}</div> <div class="secondary">$i18n{aboutProductCopyright}</div>
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn index ae79929..b5e2446 100644 --- a/chrome/browser/resources/settings/chromeos/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -62,9 +62,11 @@ group("closure_compile") { deps = [ + "os_privacy_page:closure_compile", "os_settings_main:closure_compile", "os_settings_menu:closure_compile", "os_settings_page:closure_compile", "os_settings_ui:closure_compile", + "personalization_page:closure_compile", ] }
diff --git a/chrome/browser/resources/settings/chromeos/lazy_load.html b/chrome/browser/resources/settings/chromeos/lazy_load.html index 0505fc5..278048b7 100644 --- a/chrome/browser/resources/settings/chromeos/lazy_load.html +++ b/chrome/browser/resources/settings/chromeos/lazy_load.html
@@ -2,12 +2,11 @@ <head></head> <body> <link rel="import" href="../a11y_page/a11y_page.html"> + <link rel="import" href="../date_time_page/date_time_page.html"> <link rel="import" href="../downloads_page/downloads_page.html"> <link rel="import" href="../languages_page/languages_page.html"> <link rel="import" href="../printing_page/printing_page.html"> - <link rel="import" href="../privacy_page/privacy_page.html"> <link rel="import" href="../reset_page/reset_page.html"> - - <link rel="import" href="../date_time_page/date_time_page.html"> + <link rel="import" href="os_privacy_page/os_privacy_page.html"> </body> </html>
diff --git a/chrome/browser/resources/settings/chromeos/os_privacy_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_privacy_page/BUILD.gn new file mode 100644 index 0000000..c4ae127b --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_privacy_page/BUILD.gn
@@ -0,0 +1,17 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/closure_compiler/compile_js.gni") + +js_type_check("closure_compile") { + deps = [ + ":os_privacy_page", + ] +} + +js_library("os_privacy_page") { + deps = [ + "//chrome/browser/resources/settings/controls:settings_toggle_button", + ] +}
diff --git a/chrome/browser/resources/settings/chromeos/os_privacy_page/os_privacy_page.html b/chrome/browser/resources/settings/chromeos/os_privacy_page/os_privacy_page.html new file mode 100644 index 0000000..027f4331 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_privacy_page/os_privacy_page.html
@@ -0,0 +1,25 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="../../controls/settings_toggle_button.html"> +<link rel="import" href="../../settings_shared_css.html"> + +<dom-module id="os-settings-privacy-page"> + <template> + <style include="settings-shared"></style> +<if expr="_google_chrome"> + <settings-toggle-button pref="{{prefs.cros.metrics.reportingEnabled}}" + label="$i18n{enableLogging}" + sub-label="$i18n{enableLoggingDesc}"> + </settings-toggle-button> +</if> + <settings-toggle-button + pref="{{prefs.cros.device.attestation_for_content_protection_enabled}}" + label="$i18n{enableContentProtectionAttestation}"> + </settings-toggle-button> + <settings-toggle-button + pref="{{prefs.settings.internet.wake_on_wifi_darkconnect}}" + label="$i18n{wakeOnWifi}"> + </settings-toggle-button> + </template> + <script src="os_privacy_page.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/chromeos/os_privacy_page/os_privacy_page.js b/chrome/browser/resources/settings/chromeos/os_privacy_page/os_privacy_page.js new file mode 100644 index 0000000..6bb9302 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_privacy_page/os_privacy_page.js
@@ -0,0 +1,27 @@ +// Copyright 2019 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. + +/** + * @fileoverview + * 'os-settings-privacy-page' is the settings page containing privacy and + * security settings. + */ +(function() { +'use strict'; + +Polymer({ + is: 'os-settings-privacy-page', + + properties: { + /** + * Preferences state. + */ + prefs: { + type: Object, + notify: true, + }, + }, + +}); +})();
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html index 4756ccd..344e1755 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html +++ b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
@@ -105,10 +105,9 @@ <iron-icon icon="cr:person"></iron-icon> $i18n{peoplePageTitle} </a> - <a id="appearance" href="/appearance" - hidden="[[!pageVisibility.appearance]]"> + <a id="personalization" href="/personalization"> <iron-icon icon="settings:palette"></iron-icon> - $i18n{appearancePageTitle} + $i18n{personalizationPageTitle} </a> <a href="/device"> <iron-icon icon="settings:laptop-chromebook"></iron-icon>
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.html b/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.html index 7464f6c..bf3476e 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.html +++ b/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.html
@@ -3,7 +3,7 @@ <link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> -<link rel="import" href="../../appearance_page/appearance_page.html"> +<link rel="import" href="../personalization_page/personalization_page.html"> <link rel="import" href="../../change_password_page/change_password_page.html"> <link rel="import" href="../../controls/settings_idle_load.html"> <link rel="import" href="../../people_page/people_page.html"> @@ -128,13 +128,15 @@ </settings-people-page> </settings-section> </template> + <!-- TODO(hsuregan): Change from appearance to personalization once + pageVisibility is forked for OS Settings.--> <template is="dom-if" if="[[showPage_(pageVisibility.appearance)]]" restamp> - <settings-section page-title="$i18n{appearancePageTitle}" - section="appearance"> - <settings-appearance-page prefs="{{prefs}}" + <settings-section page-title="$i18n{personalizationPageTitle}" + section="personalization"> + <settings-personalization-page page-visibility="[[pageVisibility.appearance]]"> - </settings-appearance-page> + </settings-personalization-page> </settings-section> </template> <template is="dom-if" if="[[showPage_(pageVisibility.device)]]" restamp> @@ -224,9 +226,8 @@ restamp> <settings-section page-title="$i18n{privacyPageTitle}" section="privacy"> - <settings-privacy-page prefs="{{prefs}}" - page-visibility="[[pageVisibility.privacy]]"> - </settings-privacy-page> + <os-settings-privacy-page prefs="{{prefs}}"> + </os-settings-privacy-page> </settings-section> </template> <template is="dom-if" if="[[showPage_(pageVisibility.languages)]]"
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn new file mode 100644 index 0000000..7e68a16 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn
@@ -0,0 +1,27 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/closure_compiler/compile_js.gni") + +js_type_check("closure_compile") { + deps = [ + ":personalization_browser_proxy", + ":personalization_page", + ] +} + +js_library("personalization_browser_proxy") { + deps = [ + "//ui/webui/resources/js:cr", + ] + externs_list = [ "$externs_path/chrome_send.js" ] +} + +js_library("personalization_page") { + deps = [ + ":personalization_browser_proxy", + "../../settings_page:settings_animated_pages", + "//ui/webui/resources/js:cr", + ] +}
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_browser_proxy.html b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_browser_proxy.html new file mode 100644 index 0000000..2061065 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_browser_proxy.html
@@ -0,0 +1,2 @@ +<link rel="href" src="chrome://resources/html/cr.html"> +<script src="personalization_browser_proxy.js"></script>
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_browser_proxy.js b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_browser_proxy.js new file mode 100644 index 0000000..d8e26a95 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_browser_proxy.js
@@ -0,0 +1,48 @@ +// Copyright 2019 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. + +cr.define('settings', function() { + /** @interface */ + class PersonalizationBrowserProxy { + /** + * @return {!Promise<boolean>} Whether the wallpaper setting row should be + * visible. + */ + isWallpaperSettingVisible() {} + + /** + * @return {!Promise<boolean>} Whether the wallpaper is policy controlled. + */ + isWallpaperPolicyControlled() {} + + openWallpaperManager() {} + } + + /** + * @implements {settings.PersonalizationBrowserProxy} + */ + class PersonalizationBrowserProxyImpl { + /** @override */ + isWallpaperSettingVisible() { + return cr.sendWithPromise('isWallpaperSettingVisible'); + } + + /** @override */ + isWallpaperPolicyControlled() { + return cr.sendWithPromise('isWallpaperPolicyControlled'); + } + + /** @override */ + openWallpaperManager() { + chrome.send('openWallpaperManager'); + } + } + + cr.addSingletonGetter(PersonalizationBrowserProxyImpl); + + return { + PersonalizationBrowserProxy: PersonalizationBrowserProxy, + PersonalizationBrowserProxyImpl: PersonalizationBrowserProxyImpl, + }; +});
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html new file mode 100644 index 0000000..914c34ae --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html
@@ -0,0 +1,26 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html"> +<link rel="import" href="personalization_browser_proxy.html"> +<link rel="import" href="../../settings_page/settings_animated_pages.html"> + +<dom-module id="settings-personalization-page"> + <template> + <settings-animated-pages id="pages" section="personalization"> + <div route-path="default"> + <cr-link-row id="wallpaperButton" + hidden="[[!pageVisibility.setWallpaper]]" + on-click="openWallpaperManager_" label="$i18n{setWallpaper}" + sub-label="$i18n{openWallpaperApp}" + disabled="[[isWallpaperPolicyControlled_]]" external> + <template is="dom-if" if="[[isWallpaperPolicyControlled_]]"> + <cr-policy-indicator id="wallpaperPolicyIndicator" + indicator-type="devicePolicy"> + </cr-policy-indicator> + </template> + </cr-link-row> + </div> + </settings-animated-pages> + </template> + <script src="personalization_page.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js new file mode 100644 index 0000000..d4deba3 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js
@@ -0,0 +1,56 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +(function() { +'use strict'; + +/** + * 'settings-personalization-page' is the settings page containing + * personalization settings. + */ +Polymer({ + is: 'settings-personalization-page', + + properties: { + /** + * Dictionary defining page visibility. + * @type {!AppearancePageVisibility} + */ + pageVisibility: Object, + + /** @private */ + isWallpaperPolicyControlled_: {type: Boolean, value: true}, + }, + + /** @private {?settings.PersonalizationBrowserProxy} */ + browserProxy_: null, + + /** @override */ + created: function() { + this.browserProxy_ = settings.PersonalizationBrowserProxyImpl.getInstance(); + }, + + /** @override */ + ready: function() { + this.browserProxy_.isWallpaperSettingVisible().then( + isWallpaperSettingVisible => { + // TODO(hsuregan): Uncomment after forking new pageVisibility for + // OS settings. + // assert(this.pageVisibility); + // this.pageVisibility.setWallpaper = isWallpaperSettingVisible; + }); + this.browserProxy_.isWallpaperPolicyControlled().then( + isPolicyControlled => { + this.isWallpaperPolicyControlled_ = isPolicyControlled; + }); + }, + + /** + * @private + */ + openWallpaperManager_: function() { + this.browserProxy_.openWallpaperManager(); + }, +}); +})();
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd index 39041108..382032d 100644 --- a/chrome/browser/resources/settings/os_settings_resources.grd +++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -121,35 +121,22 @@ file="settings_page/settings_animated_pages.js" type="chrome_html" preprocess="true" /> - <structure name="IDR_OS_SETTINGS_APPEARANCE_BROWSER_PROXY_HTML" - file="appearance_page/appearance_browser_proxy.html" + <structure name="IDR_OS_SETTINGS_PERSONALIZATION_BROWSER_PROXY_HTML" + file="chromeos/personalization_page/personalization_browser_proxy.html" type="chrome_html" /> - <structure name="IDR_OS_SETTINGS_APPEARANCE_BROWSER_PROXY_JS" - file="appearance_page/appearance_browser_proxy.js" + <structure name="IDR_OS_SETTINGS_PERSONALIZATION_BROWSER_PROXY_JS" + file="chromeos/personalization_page/personalization_browser_proxy.js" type="chrome_html" preprocess="true" /> - <structure name="IDR_OS_SETTINGS_APPEARANCE_FONTS_PAGE_HTML" - file="appearance_page/appearance_fonts_page.html" - type="chrome_html" - allowexternalscript="true" /> - <structure name="IDR_OS_SETTINGS_APPEARANCE_FONTS_PAGE_JS" - file="appearance_page/appearance_fonts_page.js" - type="chrome_html" /> - <structure name="IDR_OS_SETTINGS_APPEARANCE_PAGE_HTML" - file="appearance_page/appearance_page.html" + <structure name="IDR_OS_SETTINGS_PERSONALIZATION_PAGE_HTML" + file="chromeos/personalization_page/personalization_page.html" type="chrome_html" preprocess="true" allowexternalscript="true" /> - <structure name="IDR_OS_SETTINGS_APPEARANCE_PAGE_JS" - file="appearance_page/appearance_page.js" + <structure name="IDR_OS_SETTINGS_PERSONALIZATION_PAGE_JS" + file="chromeos/personalization_page/personalization_page.js" type="chrome_html" preprocess="true" /> - <structure name="IDR_OS_SETTINGS_APPEARANCE_HOME_URL_INPUT_HTML" - file="appearance_page/home_url_input.html" - type="chrome_html" /> - <structure name="IDR_OS_SETTINGS_APPEARANCE_HOME_URL_INPUT_JS" - file="appearance_page/home_url_input.js" - type="chrome_html" /> <structure name="IDR_OS_SETTINGS_OS_SETTINGS_PAGE_JS" file="chromeos/os_settings_page/os_settings_page.js" preprocess="true" @@ -171,12 +158,6 @@ <structure name="IDR_OS_SETTINGS_EXTENSION_CONTROL_BROWSER_PROXY_HTML" file="extension_control_browser_proxy.html" type="chrome_html" /> - <structure name="IDR_OS_SETTINGS_FONTS_BROWSER_PROXY_HTML" - file="appearance_page/fonts_browser_proxy.html" - type="chrome_html" /> - <structure name="IDR_OS_SETTINGS_FONTS_BROWSER_PROXY_JS" - file="appearance_page/fonts_browser_proxy.js" - type="chrome_html" /> <structure name="IDR_OS_SETTINGS_LIFETIME_BROWSER_PROXY_HTML" file="lifetime_browser_proxy.html" type="chrome_html" /> @@ -283,30 +264,6 @@ <structure name="IDR_OS_SETTINGS_HISTORY_DELETION_DIALOG_JS" file="clear_browsing_data_dialog/history_deletion_dialog.js" type="chrome_html" /> - <structure name="IDR_OS_SETTINGS_SECURITY_KEYS_PAGE_HTML" - file="privacy_page/security_keys_subpage.html" - type="chrome_html" /> - <structure name="IDR_OS_SETTINGS_SECURITY_KEYS_PAGE_JS" - file="privacy_page/security_keys_subpage.js" - type="chrome_html"/> - <structure name="IDR_OS_SETTINGS_SECURITY_KEYS_SET_PIN_DIALOG_HTML" - file="privacy_page/security_keys_set_pin_dialog.html" - type="chrome_html" /> - <structure name="IDR_OS_SETTINGS_SECURITY_KEYS_SET_PIN_DIALOG_JS" - file="privacy_page/security_keys_set_pin_dialog.js" - type="chrome_html"/> - <structure name="IDR_OS_SETTINGS_SECURITY_KEYS_RESET_DIALOG_HTML" - file="privacy_page/security_keys_reset_dialog.html" - type="chrome_html" /> - <structure name="IDR_OS_SETTINGS_SECURITY_KEYS_RESET_DIALOG_JS" - file="privacy_page/security_keys_reset_dialog.js" - type="chrome_html"/> - <structure name="IDR_OS_SETTINGS_SECURITY_KEYS_DIALOG_BROWSER_PROXY_HTML" - file="privacy_page/security_keys_browser_proxy.html" - type="chrome_html" /> - <structure name="IDR_OS_SETTINGS_SECURITY_KEYS_DIALOG_BROWSER_PROXY_JS" - file="privacy_page/security_keys_browser_proxy.js" - type="chrome_html" /> <structure name="IDR_OS_SETTINGS_CONTROLS_BOOLEAN_CONTROL_BEHAVIOR_HTML" file="controls/settings_boolean_control_behavior.html" type="chrome_html" /> @@ -729,6 +686,7 @@ <structure name="IDR_OS_SETTINGS_PDF_DOCUMENTS_JS" file="site_settings/pdf_documents.js" type="chrome_html" /> + <!-- TODO(jamescook): Remove after sync settings is forked. --> <structure name="IDR_OS_SETTINGS_PERSONALIZATION_OPTIONS_HTML" file="privacy_page/personalization_options.html" type="chrome_html" @@ -738,6 +696,7 @@ file="privacy_page/personalization_options.js" preprocess="true" type="chrome_html" /> + <!-- TODO(jamescook): Remove after sync settings is forked. --> <structure name="IDR_OS_SETTINGS_PRIVACY_PAGE_HTML" file="privacy_page/privacy_page.html" type="chrome_html" @@ -747,6 +706,7 @@ file="privacy_page/privacy_page.js" preprocess="true" type="chrome_html" /> + <!-- TODO(jamescook): Remove after sync settings is forked. --> <structure name="IDR_OS_SETTINGS_PRIVACY_PAGE_BROWSER_PROXY_HTML" file="privacy_page/privacy_page_browser_proxy.html" type="chrome_html" /> @@ -754,6 +714,15 @@ file="privacy_page/privacy_page_browser_proxy.js" preprocess="true" type="chrome_html" /> + <structure name="IDR_OS_SETTINGS_OS_PRIVACY_PAGE_HTML" + file="chromeos/os_privacy_page/os_privacy_page.html" + type="chrome_html" + flattenhtml="true" + allowexternalscript="true" /> + <structure name="IDR_OS_SETTINGS_OS_PRIVACY_PAGE_JS" + file="chromeos/os_privacy_page/os_privacy_page.js" + preprocess="true" + type="chrome_html" /> <structure name="IDR_OS_SETTINGS_PROTOCOL_HANDLERS_HTML" file="site_settings/protocol_handlers.html" preprocess="true"
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js b/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js index dc1a8e9..0352988 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js
@@ -51,6 +51,10 @@ }, }, + hostAttributes: { + role: 'main', + }, + listeners: { 'default-browser-change': 'onDefaultBrowserChange_', },
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc index 84f3fc4..4b21c607 100644 --- a/chrome/browser/safe_browsing/threat_details_unittest.cc +++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -375,8 +375,8 @@ const std::string& headers, const std::string& content) { network::ResourceResponseHead head; - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); head.remote_endpoint = net::IPEndPoint(net::IPAddress(1, 2, 3, 4), 80); head.mime_type = "text/html"; network::URLLoaderCompletionStatus status;
diff --git a/chrome/browser/speech/tts_chromeos.cc b/chrome/browser/speech/tts_chromeos.cc index 65ac711c..ade09024 100644 --- a/chrome/browser/speech/tts_chromeos.cc +++ b/chrome/browser/speech/tts_chromeos.cc
@@ -35,6 +35,20 @@ const content::UtteranceContinuousParameters& params, base::OnceCallback<void(bool)> on_speak_finished) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + // Insert call to strip SSML. + + ProcessSpeech(utterance_id, utterance, lang, voice, params, + std::move(on_speak_finished)); +} + +void TtsPlatformImplChromeOs::ProcessSpeech( + int utterance_id, + const std::string& utterance, + const std::string& lang, + const content::VoiceData& voice, + const content::UtteranceContinuousParameters& params, + base::OnceCallback<void(bool)> on_speak_finished) { auto* const arc_service_manager = arc::ArcServiceManager::Get(); if (!arc_service_manager) { std::move(on_speak_finished).Run(false);
diff --git a/chrome/browser/speech/tts_chromeos.h b/chrome/browser/speech/tts_chromeos.h index bf8fe9a..c624cc8 100644 --- a/chrome/browser/speech/tts_chromeos.h +++ b/chrome/browser/speech/tts_chromeos.h
@@ -42,6 +42,13 @@ TtsPlatformImplChromeOs() {} virtual ~TtsPlatformImplChromeOs() {} + void ProcessSpeech(int utterance_id, + const std::string& utterance, + const std::string& lang, + const content::VoiceData& voice, + const content::UtteranceContinuousParameters& params, + base::OnceCallback<void(bool)> on_speak_finished); + friend struct base::DefaultSingletonTraits<TtsPlatformImplChromeOs>; std::string error_;
diff --git a/chrome/browser/spellchecker/spelling_service_client_unittest.cc b/chrome/browser/spellchecker/spelling_service_client_unittest.cc index 6c0a57d..c94a5e21 100644 --- a/chrome/browser/spellchecker/spelling_service_client_unittest.cc +++ b/chrome/browser/spellchecker/spelling_service_client_unittest.cc
@@ -170,8 +170,8 @@ std::string headers(base::StringPrintf( "HTTP/1.1 %d %s\nContent-type: application/json\n\n", static_cast<int>(http_status), net::GetHttpReasonPhrase(http_status))); - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); head.mime_type = "application/json"; network::URLLoaderCompletionStatus status;
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc index e7c53f4..27a2d5e4 100644 --- a/chrome/browser/ssl/ssl_browsertest.cc +++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -4080,17 +4080,10 @@ // This test checks that all mixed content requests from a dedicated worker are // blocked regardless of the settings in WebPreferences when -// block-all-mixed-content CSP is set. -// TODO(crbug.com/890372): This test is flaky. -#if defined(OS_WIN) && !defined(NDEBUG) -#define MAYBE_MixedContentSettingsWithBlockingCSP \ - DISABLED_MixedContentSettingsWithBlockingCSP -#else -#define MAYBE_MixedContentSettingsWithBlockingCSP \ - MixedContentSettingsWithBlockingCSP -#endif -IN_PROC_BROWSER_TEST_P(SSLUIWorkerFetchTest, - MAYBE_MixedContentSettingsWithBlockingCSP) { +// block-all-mixed-content CSP is set with allow_running_insecure_content=true. +IN_PROC_BROWSER_TEST_P( + SSLUIWorkerFetchTest, + MixedContentSettingsWithBlockingCSP_AllowRunningInsecureContent) { ChromeContentBrowserClientForMixedContentTest browser_client; content::ContentBrowserClient* old_browser_client = content::SetBrowserClientForTesting(&browser_client); @@ -4105,20 +4098,51 @@ "HTTP/1.1 200 OK\n" "Content-Type: text/html\n" "Content-Security-Policy: block-all-mixed-content;"); + for (bool strict_mixed_content_checking : {true, false}) { + for (bool strictly_block_blockable_mixed_content : {true, false}) { + RunMixedContentSettingsTest( + &browser_client, true /* allow_running_insecure_content */, + strict_mixed_content_checking, strictly_block_blockable_mixed_content, + false /* expected_load */, false /* expected_show_blocked */, + false /* expected_show_dangerous */, + false /* expected_load_after_allow */, + false /* expected_show_blocked_after_allow */, + false /* expected_show_dangerous_after_allow */); + } + } + content::SetBrowserClientForTesting(old_browser_client); +} - for (bool allow_running_insecure_content : {true, false}) { - for (bool strict_mixed_content_checking : {true, false}) { - for (bool strictly_block_blockable_mixed_content : {true, false}) { - RunMixedContentSettingsTest( - &browser_client, allow_running_insecure_content, - strict_mixed_content_checking, - strictly_block_blockable_mixed_content, false /* expected_load */, - false /* expected_show_blocked */, - false /* expected_show_dangerous */, - false /* expected_load_after_allow */, - false /* expected_show_blocked_after_allow */, - false /* expected_show_dangerous_after_allow */); - } +// This test checks that all mixed content requests from a dedicated worker are +// blocked regardless of the settings in WebPreferences when +// block-all-mixed-content CSP is set with allow_running_insecure_content=false. +IN_PROC_BROWSER_TEST_P( + SSLUIWorkerFetchTest, + MixedContentSettingsWithBlockingCSP_DisallowRunningInsecureContent) { + ChromeContentBrowserClientForMixedContentTest browser_client; + content::ContentBrowserClient* old_browser_client = + content::SetBrowserClientForTesting(&browser_client); + + https_server_.ServeFilesFromDirectory(tmp_dir_.GetPath()); + embedded_test_server()->ServeFilesFromDirectory(tmp_dir_.GetPath()); + ASSERT_TRUE(https_server_.Start()); + ASSERT_TRUE(embedded_test_server()->Start()); + + WriteTestFiles(*embedded_test_server(), "example.com"); + WriteFile(FILE_PATH_LITERAL("worker_test.html.mock-http-headers"), + "HTTP/1.1 200 OK\n" + "Content-Type: text/html\n" + "Content-Security-Policy: block-all-mixed-content;"); + for (bool strict_mixed_content_checking : {true, false}) { + for (bool strictly_block_blockable_mixed_content : {true, false}) { + RunMixedContentSettingsTest( + &browser_client, false /* allow_running_insecure_content */, + strict_mixed_content_checking, strictly_block_blockable_mixed_content, + false /* expected_load */, false /* expected_show_blocked */, + false /* expected_show_dangerous */, + false /* expected_load_after_allow */, + false /* expected_show_blocked_after_allow */, + false /* expected_show_dangerous_after_allow */); } } content::SetBrowserClientForTesting(old_browser_client); @@ -4128,7 +4152,6 @@ // which is started from a subframe are blocked if // allow_running_insecure_content setting is false or // strict_mixed_content_checking setting is true. -// TODO(crbug.com/890372): This test is flaky. IN_PROC_BROWSER_TEST_P(SSLUIWorkerFetchTest, MixedContentSubFrame) { // TODO(carlosil): Reenable tests once confirmed not flaky for committed // interstitials.
diff --git a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc index d766c9f..1435ff0 100644 --- a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc +++ b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc
@@ -67,7 +67,7 @@ network::ResourceResponseHead head; std::string headers("HTTP/1.1 200 OK\n\n"); head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + net::HttpUtil::AssembleRawHeaders(headers)); network::URLLoaderCompletionStatus status(error); status.decoded_body_length = response.size(); test_url_loader_factory_.AddResponse(permission_creator_->GetApiUrl(), head,
diff --git a/chrome/browser/supervised_user/experimental/safe_search_url_reporter_unittest.cc b/chrome/browser/supervised_user/experimental/safe_search_url_reporter_unittest.cc index e00ed7b9..5bbec988 100644 --- a/chrome/browser/supervised_user/experimental/safe_search_url_reporter_unittest.cc +++ b/chrome/browser/supervised_user/experimental/safe_search_url_reporter_unittest.cc
@@ -56,7 +56,7 @@ network::ResourceResponseHead head; std::string headers("HTTP/1.1 200 OK\n\n"); head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + net::HttpUtil::AssembleRawHeaders(headers)); network::URLLoaderCompletionStatus status(error); test_url_loader_factory_.AddResponse(GURL(kSafeSearchReportApiUrl), head, std::string(), status);
diff --git a/chrome/browser/ui/android/tab_model/tab_model_observer_jni_bridge.cc b/chrome/browser/ui/android/tab_model/tab_model_observer_jni_bridge.cc index 3f09554..f46ff84 100644 --- a/chrome/browser/ui/android/tab_model/tab_model_observer_jni_bridge.cc +++ b/chrome/browser/ui/android/tab_model/tab_model_observer_jni_bridge.cc
@@ -11,6 +11,7 @@ #include "jni/TabModelObserverJniBridge_jni.h" using base::android::AttachCurrentThread; +using base::android::JavaObjectArrayReader; using base::android::JavaParamRef; using base::android::JavaRef; using base::android::ScopedJavaLocalRef; @@ -145,12 +146,10 @@ // |jtabs| is actually a Tab[]. Iterate over the array and convert it to // a vector of TabAndroid*. - jint size = env->GetArrayLength(jtabs.obj()); - tabs.reserve(size); - for (jint i = 0; i < size; ++i) { - jobject jtab = env->GetObjectArrayElement(jtabs.obj(), 0); - TabAndroid* tab = - TabAndroid::GetNativeTab(env, JavaParamRef<jobject>(env, jtab)); + JavaObjectArrayReader<jobject> jtabs_array(jtabs); + tabs.reserve(jtabs_array.size()); + for (auto jtab : jtabs_array) { + TabAndroid* tab = TabAndroid::GetNativeTab(env, jtab); CHECK(tab); tabs.push_back(tab); }
diff --git a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc index 74509e7..91344bb7 100644 --- a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc +++ b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
@@ -87,9 +87,9 @@ // |location| is relative to |web_contents|. // Returns true upon success. bool SimulateDragEnter(gfx::Point location, const std::string& text) { - ui::OSExchangeData data; - data.SetString(base::UTF8ToUTF16(text)); - return SimulateDragEnter(location, data); + os_exchange_data_ = std::make_unique<ui::OSExchangeData>(); + os_exchange_data_->SetString(base::UTF8ToUTF16(text)); + return SimulateDragEnter(location, *os_exchange_data_); } // Simulates dropping of the drag-and-dropped item. @@ -168,6 +168,7 @@ content::WebContents* web_contents_; std::unique_ptr<ui::DropTargetEvent> active_drag_event_; + std::unique_ptr<ui::OSExchangeData> os_exchange_data_; DISALLOW_COPY_AND_ASSIGN(DragAndDropSimulator); }; @@ -542,6 +543,11 @@ drag_simulator_.reset(new DragAndDropSimulator(web_contents())); } + void TearDownOnMainThread() override { + // For X11 need to tear down before UI goes away. + drag_simulator_.reset(); + } + bool use_cross_site_subframe() { // This is controlled by gtest's test param from INSTANTIATE_TEST_SUITE_P. return GetParam();
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc index b880021..69d1e0a1 100644 --- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc +++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
@@ -188,7 +188,9 @@ ui::NativeTheme::kColorId_SeparatorColor)); } -PaymentHandlerWebFlowViewController::~PaymentHandlerWebFlowViewController() {} +PaymentHandlerWebFlowViewController::~PaymentHandlerWebFlowViewController() { + state()->OnPaymentAppWindowClosed(); +} base::string16 PaymentHandlerWebFlowViewController::GetSheetTitle() { return GetPaymentHandlerDialogTitle(web_contents(), https_prefix_);
diff --git a/chrome/browser/ui/views/webauthn/hover_list_view.cc b/chrome/browser/ui/views/webauthn/hover_list_view.cc index ff69516..84e693a3 100644 --- a/chrome/browser/ui/views/webauthn/hover_list_view.cc +++ b/chrome/browser/ui/views/webauthn/hover_list_view.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/views/webauthn/hover_list_view.h" +#include <algorithm> #include <utility> #include "base/logging.h" @@ -245,6 +246,8 @@ } int HoverListView::GetPreferredViewHeight() const { + constexpr int kMaxViewHeight = 300; + // |item_container_| has one separator at the top and list items which // contain one separator and one hover button. const auto separator_height = views::Separator().GetPreferredSize().height(); @@ -264,5 +267,5 @@ separator_height + dummy_hover_button->GetPreferredSize().height(); size += list_item_height * reserved_items; } - return size; + return std::min(kMaxViewHeight, size); }
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc index 03050df..bc06bb0a 100644 --- a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc +++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
@@ -14,7 +14,6 @@ #include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h" #include "base/metrics/histogram_macros.h" #include "build/build_config.h" -#include "chrome/browser/ui/webui/certificates_handler.h" #include "chrome/browser/ui/webui/dark_mode_handler.h" #include "chrome/browser/ui/webui/managed_ui_handler.h" #include "chrome/browser/ui/webui/metrics_handler.h" @@ -31,14 +30,11 @@ #include "chrome/browser/ui/webui/settings/protocol_handlers_handler.h" #include "chrome/browser/ui/webui/settings/reset_settings_handler.h" #include "chrome/browser/ui/webui/settings/search_engines_handler.h" -#include "chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h" #include "chrome/browser/ui/webui/settings/settings_cookies_view_handler.h" #include "chrome/browser/ui/webui/settings/settings_import_data_handler.h" #include "chrome/browser/ui/webui/settings/settings_localized_strings_provider.h" #include "chrome/browser/ui/webui/settings/settings_media_devices_selection_handler.h" -#include "chrome/browser/ui/webui/settings/settings_security_key_handler.h" #include "chrome/browser/ui/webui/settings/settings_ui.h" -#include "chrome/browser/ui/webui/settings/site_settings_handler.h" #include "chrome/browser/web_applications/system_web_app_manager.h" #include "chrome/common/webui_url_constants.h" #include "chrome/grit/browser_resources.h" @@ -76,19 +72,10 @@ AddSettingsPageUIHandler( std::make_unique<::settings::AppearanceHandler>(web_ui)); -#if defined(USE_NSS_CERTS) - AddSettingsPageUIHandler( - std::make_unique<certificate_manager::CertificatesHandler>()); -#elif defined(OS_WIN) || defined(OS_MACOSX) - AddSettingsPageUIHandler(std::make_unique<NativeCertificatesHandler>()); -#endif // defined(USE_NSS_CERTS) - AddSettingsPageUIHandler( std::make_unique<::settings::AccessibilityMainHandler>()); AddSettingsPageUIHandler( std::make_unique<::settings::BrowserLifetimeHandler>()); - AddSettingsPageUIHandler( - std::make_unique<::settings::ClearBrowsingDataHandler>(web_ui)); AddSettingsPageUIHandler(std::make_unique<::settings::CookiesViewHandler>()); AddSettingsPageUIHandler( std::make_unique<::settings::DownloadsHandler>(profile)); @@ -108,9 +95,6 @@ std::make_unique<::settings::ProtocolHandlersHandler>()); AddSettingsPageUIHandler( std::make_unique<::settings::SearchEnginesHandler>(profile)); - AddSettingsPageUIHandler( - std::make_unique<::settings::SiteSettingsHandler>(profile)); - AddSettingsPageUIHandler(std::make_unique<::settings::SecurityKeysHandler>()); bool password_protection_available = false; #if defined(FULL_SAFE_BROWSING)
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index 184e4d5..0660a14 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -590,8 +590,9 @@ {"themesGalleryUrl", IDS_THEMES_GALLERY_URL}, {"chooseFromWebStore", IDS_SETTINGS_WEB_STORE}, #if defined(OS_CHROMEOS) - {"openWallpaperApp", IDS_SETTINGS_OPEN_WALLPAPER_APP}, - {"setWallpaper", IDS_SETTINGS_SET_WALLPAPER}, + {"personalizationPageTitle", IDS_OS_SETTINGS_PERSONALIZATION}, + {"openWallpaperApp", IDS_OS_SETTINGS_OPEN_WALLPAPER_APP}, + {"setWallpaper", IDS_OS_SETTINGS_SET_WALLPAPER}, #endif #if defined(OS_LINUX) && !defined(OS_CHROMEOS) {"showWindowDecorations", IDS_SHOW_WINDOW_DECORATIONS},
diff --git a/chrome/chrome_cleaner/components/system_report_component.cc b/chrome/chrome_cleaner/components/system_report_component.cc index 14912f6..54a733e2 100644 --- a/chrome/chrome_cleaner/components/system_report_component.cc +++ b/chrome/chrome_cleaner/components/system_report_component.cc
@@ -41,6 +41,7 @@ #include "base/win/scoped_bstr.h" #include "base/win/scoped_handle.h" #include "base/win/scoped_variant.h" +#include "base/win/win_util.h" #include "base/win/windows_version.h" #include "chrome/chrome_cleaner/chrome_utils/chrome_util.h" #include "chrome/chrome_cleaner/chrome_utils/extension_file_logger.h" @@ -593,9 +594,7 @@ const std::set<GUID, GUIDLess>& guids = provider->second; for (std::set<GUID, GUIDLess>::const_iterator guid = guids.begin(); guid != guids.end(); ++guid) { - base::string16 guid_str; - GUIDToString(*guid, &guid_str); - logged_guids.push_back(guid_str); + logged_guids.push_back(base::win::String16FromGUID(*guid)); } LoggingServiceAPI::GetInstance()->AddLayeredServiceProvider( logged_guids, file_information);
diff --git a/chrome/chrome_cleaner/os/disk_util.cc b/chrome/chrome_cleaner/os/disk_util.cc index 3d042c80..37a54b4e 100644 --- a/chrome/chrome_cleaner/os/disk_util.cc +++ b/chrome/chrome_cleaner/os/disk_util.cc
@@ -29,6 +29,7 @@ #include "base/win/current_module.h" #include "base/win/registry.h" #include "base/win/shortcut.h" +#include "base/win/win_util.h" #include "base/win/windows_version.h" #include "chrome/chrome_cleaner/constants/version.h" #include "chrome/chrome_cleaner/os/file_path_sanitization.h" @@ -658,9 +659,9 @@ providers->emplace(base::FilePath(path), std::set<GUID, GUIDLess>()); inserted.first->second.insert(service_providers[i].ProviderId); } else { - base::string16 guid; - GUIDToString(service_providers[i].ProviderId, &guid); - LOG(ERROR) << "Couldn't get path for provider: " << guid; + LOG(ERROR) << "Couldn't get path for provider: " + << base::win::String16FromGUID( + service_providers[i].ProviderId); } } }
diff --git a/chrome/chrome_cleaner/os/system_util.cc b/chrome/chrome_cleaner/os/system_util.cc index d3b919d0..55b8e57 100644 --- a/chrome/chrome_cleaner/os/system_util.cc +++ b/chrome/chrome_cleaner/os/system_util.cc
@@ -72,14 +72,6 @@ return true; } -void GUIDToString(const GUID& guid, base::string16* output) { - DCHECK(output); - static const size_t kGUIDStringSize = 39; - int result = ::StringFromGUID2(guid, base::WriteInto(output, kGUIDStringSize), - kGUIDStringSize); - DCHECK(result == kGUIDStringSize); -} - void SetBackgroundMode() { // Get the process working set size and flags, so that we can reset them // after setting the process to background mode. For some reason Windows sets
diff --git a/chrome/chrome_cleaner/os/system_util.h b/chrome/chrome_cleaner/os/system_util.h index f275c001..88d2e82 100644 --- a/chrome/chrome_cleaner/os/system_util.h +++ b/chrome/chrome_cleaner/os/system_util.h
@@ -53,10 +53,6 @@ // running on a Windows version before Vista. bool GetMediumIntegrityToken(base::win::ScopedHandle* medium_integrity_token); -// Convert a GUID to its textual representation. |output| receives the textual -// representation. -void GUIDToString(const GUID&, base::string16* output); - // Set the current process to background mode. void SetBackgroundMode();
diff --git a/chrome/chrome_cleaner/os/system_util_unittest.cc b/chrome/chrome_cleaner/os/system_util_unittest.cc index 82d4e77..fcf80df0 100644 --- a/chrome/chrome_cleaner/os/system_util_unittest.cc +++ b/chrome/chrome_cleaner/os/system_util_unittest.cc
@@ -34,16 +34,4 @@ EXPECT_LT(integrity_level, SECURITY_MANDATORY_HIGH_RID); } -TEST(SystemUtilTests, GUIDToString) { - base::string16 provider1; - base::string16 provider2; - base::string16 provider3; - GUIDToString(kGUID1, &provider1); - GUIDToString(kGUID2, &provider2); - GUIDToString(kGUID3, &provider3); - EXPECT_STREQ(provider1.c_str(), kGUID1Str); - EXPECT_STREQ(provider2.c_str(), kGUID2Str); - EXPECT_STREQ(provider3.c_str(), kGUID3Str); -} - } // namespace chrome_cleaner
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc b/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc index fc4215a0..c284b32 100644 --- a/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc +++ b/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc
@@ -8,6 +8,8 @@ #include "base/files/file_path.h" #include "base/logging.h" #include "base/macros.h" +#include "base/strings/string_util.h" +#include "base/win/win_util.h" #include "base/win/windows_version.h" #include "chrome/common/chrome_version.h" #include "chrome/credential_provider/eventlog/gcp_eventlog_messages.h" @@ -55,17 +57,15 @@ eventlog_path = eventlog_path.Append(FILE_PATH_LITERAL("gcp_eventlog_provider.dll")); - wchar_t provider_guid_in_wchar[64]; - StringFromGUID2(CLSID_GaiaCredentialProvider, provider_guid_in_wchar, - base::size(provider_guid_in_wchar)); + auto provider_guid_string = + base::win::String16FromGUID(CLSID_GaiaCredentialProvider); - wchar_t filter_guid_in_wchar[64]; - StringFromGUID2(__uuidof(CGaiaCredentialProviderFilter), filter_guid_in_wchar, - base::size(filter_guid_in_wchar)); + auto filter_guid_string = + base::win::String16FromGUID(__uuidof(CGaiaCredentialProviderFilter)); ATL::_ATL_REGMAP_ENTRY regmap[] = { - {L"CP_CLASS_GUID", provider_guid_in_wchar}, - {L"CP_FILTER_CLASS_GUID", filter_guid_in_wchar}, + {L"CP_CLASS_GUID", base::as_wcstr(provider_guid_string.c_str())}, + {L"CP_FILTER_CLASS_GUID", base::as_wcstr(filter_guid_string.c_str())}, {L"VERSION", TEXT(CHROME_VERSION_STRING)}, {L"EVENTLOG_PATH", eventlog_path.value().c_str()}, {nullptr, nullptr},
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_provider_unittests.cc b/chrome/credential_provider/gaiacp/gaia_credential_provider_unittests.cc index 63e9bce..f69e873 100644 --- a/chrome/credential_provider/gaiacp/gaia_credential_provider_unittests.cc +++ b/chrome/credential_provider/gaiacp/gaia_credential_provider_unittests.cc
@@ -11,6 +11,7 @@ #include "base/synchronization/waitable_event.h" #include "base/win/registry.h" +#include "base/win/win_util.h" #include "chrome/credential_provider/common/gcp_strings.h" #include "chrome/credential_provider/gaiacp/associated_user_validator.h" #include "chrome/credential_provider/gaiacp/auth_utils.h" @@ -931,15 +932,14 @@ // In the case that a real CReauthCredential is created, we expect that this // credential will set the default credential provider for the user tile. - wchar_t guid_in_wchar[64]; - ::StringFromGUID2(CLSID_GaiaCredentialProvider, guid_in_wchar, - base::size(guid_in_wchar)); + auto guid_string = + base::win::String16FromGUID(CLSID_GaiaCredentialProvider); wchar_t guid_in_registry[64]; ULONG length = base::size(guid_in_registry); EXPECT_EQ(S_OK, GetMachineRegString(kLogonUiUserTileRegKey, sid, guid_in_registry, &length)); - EXPECT_EQ(base::string16(guid_in_wchar), base::string16(guid_in_registry)); + EXPECT_EQ(guid_string, base::string16(guid_in_registry)); ::CoTaskMemFree(sid); }
diff --git a/chrome/credential_provider/gaiacp/reg_utils.cc b/chrome/credential_provider/gaiacp/reg_utils.cc index 95ca300..98956654 100644 --- a/chrome/credential_provider/gaiacp/reg_utils.cc +++ b/chrome/credential_provider/gaiacp/reg_utils.cc
@@ -11,6 +11,7 @@ #include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/win/registry.h" +#include "base/win/win_util.h" #include "chrome/credential_provider/common/gcp_strings.h" namespace credential_provider { @@ -317,10 +318,8 @@ } HRESULT SetLogonUiUserTileEntry(const base::string16& sid, CLSID cp_guid) { - wchar_t guid_in_wchar[64]; - ::StringFromGUID2(cp_guid, guid_in_wchar, base::size(guid_in_wchar)); - return SetMachineRegString(kLogonUiUserTileRegKey, sid.c_str(), - guid_in_wchar); + return SetMachineRegString(kLogonUiUserTileRegKey, sid, + base::win::String16FromGUID(cp_guid)); } } // namespace credential_provider
diff --git a/chrome/credential_provider/setup/BUILD.gn b/chrome/credential_provider/setup/BUILD.gn index 4c7aed8..010504901 100644 --- a/chrome/credential_provider/setup/BUILD.gn +++ b/chrome/credential_provider/setup/BUILD.gn
@@ -27,7 +27,6 @@ "//base:base", ] deps = [ - ":version", "../gaiacp:common", "//chrome/installer/util:with_no_strings", ] @@ -69,6 +68,7 @@ deps = [ ":common", ":setup_resources", + ":version", "../eventlog:gcp_eventlog_messages", "../gaiacp:common", "//chrome/common:version_header",
diff --git a/chrome/credential_provider/test/gcp_setup_unittests.cc b/chrome/credential_provider/test/gcp_setup_unittests.cc index f5c6604..16ef99a 100644 --- a/chrome/credential_provider/test/gcp_setup_unittests.cc +++ b/chrome/credential_provider/test/gcp_setup_unittests.cc
@@ -27,6 +27,7 @@ #include "base/test/scoped_path_override.h" #include "base/test/test_reg_util_win.h" #include "base/win/registry.h" +#include "base/win/win_util.h" #include "build/build_config.h" #include "chrome/credential_provider/common/gcp_strings.h" #include "chrome/credential_provider/gaiacp/gaia_credential_provider.h" @@ -128,13 +129,11 @@ void GcpSetupTest::ExpectCredentialProviderToBeRegistered( bool registered, const base::string16& product_version) { - wchar_t guid_in_wchar[64]; - StringFromGUID2(CLSID_GaiaCredentialProvider, guid_in_wchar, - base::size(guid_in_wchar)); + auto guid_string = base::win::String16FromGUID(CLSID_GaiaCredentialProvider); // Make sure COM object is registered. base::string16 register_key_path = - base::StringPrintf(L"CLSID\\%ls\\InprocServer32", guid_in_wchar); + base::StringPrintf(L"CLSID\\%ls\\InprocServer32", guid_string.c_str()); base::win::RegKey clsid_key(HKEY_CLASSES_ROOT, register_key_path.c_str(), KEY_READ); EXPECT_EQ(registered, clsid_key.Valid()); @@ -149,7 +148,8 @@ base::string16 cp_key_path = base::StringPrintf( L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" - L"Authentication\\Credential Providers\\%ls", guid_in_wchar); + L"Authentication\\Credential Providers\\%ls", + guid_string.c_str()); // Make sure credential provider is registered. base::win::RegKey cp_key(HKEY_LOCAL_MACHINE, cp_key_path.c_str(), KEY_READ);
diff --git a/chrome/install_static/install_util_unittest.cc b/chrome/install_static/install_util_unittest.cc index a057946..e363cd1 100644 --- a/chrome/install_static/install_util_unittest.cc +++ b/chrome/install_static/install_util_unittest.cc
@@ -9,7 +9,9 @@ #include <tuple> #include "base/stl_util.h" +#include "base/strings/string_util.h" #include "base/test/test_reg_util_win.h" +#include "base/win/win_util.h" #include "chrome/install_static/install_details.h" #include "chrome/install_static/install_modes.h" #include "chrome/install_static/test/scoped_install_details.h" @@ -519,11 +521,8 @@ EXPECT_EQ(GetToastActivatorClsid(), kToastActivatorClsids[std::get<0>(GetParam())]); - const int kCLSIDSize = 39; - wchar_t clsid_str[kCLSIDSize]; - ASSERT_EQ(::StringFromGUID2(GetToastActivatorClsid(), clsid_str, kCLSIDSize), - kCLSIDSize); - EXPECT_THAT(clsid_str, + auto clsid_str = base::win::String16FromGUID(GetToastActivatorClsid()); + EXPECT_THAT(base::as_wcstr(clsid_str.c_str()), StrCaseEq(kToastActivatorClsidsString[std::get<0>(GetParam())])); } @@ -576,11 +575,8 @@ EXPECT_EQ(GetElevatorClsid(), kElevatorClsids[std::get<0>(GetParam())]); - constexpr int kCLSIDSize = 39; - wchar_t clsid_str[kCLSIDSize] = {}; - ASSERT_EQ(::StringFromGUID2(GetElevatorClsid(), clsid_str, kCLSIDSize), - kCLSIDSize); - EXPECT_THAT(clsid_str, + auto clsid_str = base::win::String16FromGUID(GetElevatorClsid()); + EXPECT_THAT(base::as_wcstr(clsid_str.c_str()), StrCaseEq(kElevatorClsidsString[std::get<0>(GetParam())])); } @@ -645,10 +641,9 @@ EXPECT_EQ(GetElevatorIid(), kElevatorIids[std::get<0>(GetParam())]); - constexpr int kIIDSize = 39; - wchar_t iid_str[kIIDSize] = {}; - ASSERT_EQ(::StringFromGUID2(GetElevatorIid(), iid_str, kIIDSize), kIIDSize); - EXPECT_THAT(iid_str, StrCaseEq(kElevatorIidsString[std::get<0>(GetParam())])); + auto iid_str = base::win::String16FromGUID(GetElevatorIid()); + EXPECT_THAT(base::as_wcstr(iid_str.c_str()), + StrCaseEq(kElevatorIidsString[std::get<0>(GetParam())])); } TEST_P(InstallStaticUtilTest, UsageStatsAbsent) {
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc index 447a4829..3b3710b 100644 --- a/chrome/installer/setup/setup_util.cc +++ b/chrome/installer/setup/setup_util.cc
@@ -38,6 +38,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/version.h" #include "base/win/registry.h" +#include "base/win/win_util.h" #include "base/win/windows_version.h" #include "build/build_config.h" #include "chrome/install_static/install_details.h" @@ -912,8 +913,7 @@ } base::string16 GetElevationServiceGuid(base::StringPiece16 prefix) { - base::string16 result = - InstallUtil::String16FromGUID(install_static::GetElevatorClsid()); + auto result = base::win::String16FromGUID(install_static::GetElevatorClsid()); result.insert(0, prefix.data(), prefix.size()); return result; } @@ -927,8 +927,7 @@ } base::string16 GetElevationServiceIid(base::StringPiece16 prefix) { - base::string16 result = - InstallUtil::String16FromGUID(install_static::GetElevatorIid()); + auto result = base::win::String16FromGUID(install_static::GetElevatorIid()); result.insert(0, prefix.data(), prefix.size()); return result; }
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc index 8d65d1fe..33295f1 100644 --- a/chrome/installer/util/install_util.cc +++ b/chrome/installer/util/install_util.cc
@@ -27,6 +27,7 @@ #include "base/win/registry.h" #include "base/win/shlwapi.h" #include "base/win/shortcut.h" +#include "base/win/win_util.h" #include "base/win/windows_version.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" @@ -348,23 +349,9 @@ } // static -base::string16 InstallUtil::String16FromGUID(const GUID& guid) { - // A GUID has a string format of "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}", - // which contains 38 characters. The length is 39 inclusive of the string - // terminator. - constexpr int kGuidLength = 39; - base::string16 guid_string; - - const int length_with_terminator = ::StringFromGUID2( - guid, base::WriteInto(&guid_string, kGuidLength), kGuidLength); - DCHECK_EQ(length_with_terminator, kGuidLength); - return guid_string; -} - -// static base::string16 InstallUtil::GetToastActivatorRegistryPath() { - return L"Software\\Classes\\CLSID\\" + - String16FromGUID(install_static::GetToastActivatorClsid()); + return STRING16_LITERAL("Software\\Classes\\CLSID\\") + + base::win::String16FromGUID(install_static::GetToastActivatorClsid()); } // static
diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h index 5aa98f7..79c14995 100644 --- a/chrome/installer/util/install_util.h +++ b/chrome/installer/util/install_util.h
@@ -81,9 +81,6 @@ // CLSID registered. static bool IsStartMenuShortcutWithActivatorGuidInstalled(); - // Returns a string representation of |guid|. - static base::string16 String16FromGUID(const GUID& guid); - // Returns the toast activator registry path. static base::string16 GetToastActivatorRegistryPath();
diff --git a/chrome/test/chromedriver/net/websocket.cc b/chrome/test/chromedriver/net/websocket.cc index 5fb9034..8b9e774 100644 --- a/chrome/test/chromedriver/net/websocket.cc +++ b/chrome/test/chromedriver/net/websocket.cc
@@ -256,10 +256,9 @@ std::string websocket_accept; base::Base64Encode(base::SHA1HashString(sec_key_ + kMagicKey), &websocket_accept); - scoped_refptr<net::HttpResponseHeaders> headers( - new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders( - handshake_response_.data(), headers_end))); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders( + base::StringPiece(handshake_response_.data(), headers_end))); if (headers->response_code() != 101 || !headers->HasHeaderValue("Upgrade", "WebSocket") || !headers->HasHeaderValue("Connection", "Upgrade") ||
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index 5e36f00..2871ba5e 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -109,6 +109,7 @@ "settings/a11y/sign_out_a11y_test.js", "signin/signin_browsertest.js", "user_manager/user_manager_browsertest.js", + "welcome/a11y_tests.js", "welcome/onboarding_welcome_browsertest.js", ] }
diff --git a/chrome/test/data/webui/welcome/a11y_tests.js b/chrome/test/data/webui/welcome/a11y_tests.js new file mode 100644 index 0000000..0477bbc3 --- /dev/null +++ b/chrome/test/data/webui/welcome/a11y_tests.js
@@ -0,0 +1,43 @@ +// Copyright 2019 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. + +// Polymer BrowserTest fixture and aXe-core accessibility audit. +GEN_INCLUDE([ + '//chrome/test/data/webui/a11y/accessibility_test.js', + '//chrome/test/data/webui/polymer_browser_test_base.js', +]); +GEN('#include "chrome/browser/ui/webui/welcome/nux_helper.h"'); + +OnboardingA11y = class extends PolymerTest { + /** @override */ + get browsePreload() { + return 'chrome://welcome/'; + } + + /** @override */ + get featureList() { + return ['nux::kNuxOnboardingForceEnabled', '']; + } +}; + +AccessibilityTest.define('OnboardingA11y', { + // Must be unique within the test fixture and cannot have spaces. + name: 'OnboardingFlow', + + // Optional. Configuration for axe-core. Can be used to disable a test. + axeOptions: {}, + + // Optional. Filter on failures. Use this for individual false positives. + violationFilter: {}, + + // Optional. Any setup required for all tests. This will run before each one. + setup: function() {}, + + tests: { + 'Landing Page': function() { + // Make sure we're in the right page. + assertEquals('Make Chrome your own', getDeepActiveElement().textContent); + }, + }, +});
diff --git a/chrome/test/logging/win/log_file_printer.cc b/chrome/test/logging/win/log_file_printer.cc index 7842b2c..e39f509 100644 --- a/chrome/test/logging/win/log_file_printer.cc +++ b/chrome/test/logging/win/log_file_printer.cc
@@ -20,6 +20,7 @@ #include "base/strings/string_piece.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" +#include "base/win/win_util.h" #include "chrome/test/logging/win/log_file_reader.h" namespace { @@ -143,10 +144,9 @@ // Prints a useful message for events that can't be otherwise printed. void EventPrinter::PrintBadEvent(const EVENT_TRACE* event, const base::StringPiece& error) { - wchar_t guid[64]; - StringFromGUID2(event->Header.Guid, &guid[0], base::size(guid)); - *out_ << error << " (class=" << guid << ", type=" - << static_cast<int>(event->Header.Class.Type) << ")"; + *out_ << error + << " (class=" << base::win::String16FromGUID(event->Header.Guid) + << ", type=" << static_cast<int>(event->Header.Class.Type) << ")"; } void EventPrinter::OnUnknownEvent(const EVENT_TRACE* event) {
diff --git a/chromeos/services/assistant/public/features.cc b/chromeos/services/assistant/public/features.cc index 76ce471..54e8e57 100644 --- a/chromeos/services/assistant/public/features.cc +++ b/chromeos/services/assistant/public/features.cc
@@ -66,7 +66,8 @@ base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kEnableMediaSessionIntegration{ - "AssistantEnableMediaSessionIntegration", base::FEATURE_ENABLED_BY_DEFAULT}; + "AssistantEnableMediaSessionIntegration", + base::FEATURE_DISABLED_BY_DEFAULT}; bool IsAlarmTimerManagerEnabled() { return base::FeatureList::IsEnabled(kEnableAssistantAlarmTimerManager);
diff --git a/chromeos/services/device_sync/cryptauth_enrollment_manager.h b/chromeos/services/device_sync/cryptauth_enrollment_manager.h index 3106d19..8e6c3a6 100644 --- a/chromeos/services/device_sync/cryptauth_enrollment_manager.h +++ b/chromeos/services/device_sync/cryptauth_enrollment_manager.h
@@ -6,9 +6,11 @@ #define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_ENROLLMENT_MANAGER_H_ #include <memory> +#include <string> #include "base/macros.h" #include "base/observer_list.h" +#include "base/optional.h" #include "base/time/time.h" #include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" @@ -45,13 +47,18 @@ // Skips the waiting period and forces an enrollment immediately. If an // enrollment is already in progress, this function does nothing. - // |invocation_reason| specifies the reason that the enrollment was triggered, - // which is upload to the server. + // |invocation_reason|: Specifies the reason that the enrollment was + // triggered, which is upload to the server. + // |session_id|: The session ID sent by CryptAuth v2 in a GCM message + // requesting enrollment. Null if enrollment was not triggered + // by a GCM message or if no session ID was included in the GCM + // message. // TODO(nohle): Change cryptauth::InvocationReason to // cryptauthv2::ClientMetadata::InvocationReason when CryptAuth v1 is // obsolete. virtual void ForceEnrollmentNow( - cryptauth::InvocationReason invocation_reason) = 0; + cryptauth::InvocationReason invocation_reason, + const base::Optional<std::string>& session_id) = 0; // Returns true if a successful enrollment has been recorded and this // enrollment has not expired.
diff --git a/chromeos/services/device_sync/cryptauth_enrollment_manager_impl.cc b/chromeos/services/device_sync/cryptauth_enrollment_manager_impl.cc index 8f11947..1391da3 100644 --- a/chromeos/services/device_sync/cryptauth_enrollment_manager_impl.cc +++ b/chromeos/services/device_sync/cryptauth_enrollment_manager_impl.cc
@@ -172,7 +172,8 @@ } void CryptAuthEnrollmentManagerImpl::ForceEnrollmentNow( - cryptauth::InvocationReason invocation_reason) { + cryptauth::InvocationReason invocation_reason, + const base::Optional<std::string>& session_id) { // We store the invocation reason in a preference so that it can persist // across browser restarts. If the sync fails, the next retry should still use // this original reason instead of @@ -293,7 +294,8 @@ void CryptAuthEnrollmentManagerImpl::OnReenrollMessage( const base::Optional<std::string>& session_id, const base::Optional<CryptAuthFeatureType>& feature_type) { - ForceEnrollmentNow(cryptauth::INVOCATION_REASON_SERVER_INITIATED); + ForceEnrollmentNow(cryptauth::INVOCATION_REASON_SERVER_INITIATED, + base::nullopt /* session_id */); } void CryptAuthEnrollmentManagerImpl::OnSyncRequested(
diff --git a/chromeos/services/device_sync/cryptauth_enrollment_manager_impl.h b/chromeos/services/device_sync/cryptauth_enrollment_manager_impl.h index 860af7c5..6020a6f 100644 --- a/chromeos/services/device_sync/cryptauth_enrollment_manager_impl.h +++ b/chromeos/services/device_sync/cryptauth_enrollment_manager_impl.h
@@ -6,10 +6,12 @@ #define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_ENROLLMENT_MANAGER_IMPL_H_ #include <memory> +#include <string> #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "base/optional.h" #include "base/time/time.h" #include "chromeos/services/device_sync/cryptauth_enrollment_manager.h" #include "chromeos/services/device_sync/cryptauth_feature_type.h" @@ -92,7 +94,8 @@ // CryptAuthEnrollmentManager: void Start() override; void ForceEnrollmentNow( - cryptauth::InvocationReason invocation_reason) override; + cryptauth::InvocationReason invocation_reason, + const base::Optional<std::string>& session_id) override; bool IsEnrollmentValid() const override; base::Time GetLastEnrollmentTime() const override; base::TimeDelta GetTimeToNextAttempt() const override;
diff --git a/chromeos/services/device_sync/cryptauth_enrollment_manager_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_enrollment_manager_impl_unittest.cc index ad3881fc..3645bda 100644 --- a/chromeos/services/device_sync/cryptauth_enrollment_manager_impl_unittest.cc +++ b/chromeos/services/device_sync/cryptauth_enrollment_manager_impl_unittest.cc
@@ -354,7 +354,8 @@ EXPECT_CALL(*sync_scheduler(), ForceSync()); enrollment_manager_.ForceEnrollmentNow( - cryptauth::INVOCATION_REASON_SERVER_INITIATED); + cryptauth::INVOCATION_REASON_SERVER_INITIATED, + base::nullopt /* session_id */); auto completion_callback = FireSchedulerForEnrollment(cryptauth::INVOCATION_REASON_SERVER_INITIATED);
diff --git a/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl.cc b/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl.cc index 5cb0e13e..b492c63 100644 --- a/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl.cc +++ b/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl.cc
@@ -151,6 +151,8 @@ registry->RegisterIntegerPref( prefs::kCryptAuthEnrollmentFailureRecoveryInvocationReason, cryptauthv2::ClientMetadata::INVOCATION_REASON_UNSPECIFIED); + registry->RegisterStringPref( + prefs::kCryptAuthEnrollmentFailureRecoverySessionId, std::string()); // TODO(nohle): Remove when v1 Enrollment is deprecated. registry->RegisterStringPref(prefs::kCryptAuthEnrollmentUserPublicKey, @@ -240,15 +242,19 @@ } void CryptAuthV2EnrollmentManagerImpl::ForceEnrollmentNow( - cryptauth::InvocationReason invocation_reason) { + cryptauth::InvocationReason invocation_reason, + const base::Optional<std::string>& session_id) { if (state_ != State::kIdle) { - PA_LOG(WARNING) << "ForceEnrollmentNow() called while an enrollment is in " + PA_LOG(WARNING) << "Forced enrollment requested while an enrollment is in " << "progress. No action taken."; return; } - current_enrollment_invocation_reason_ = - ConvertInvocationReasonV1ToV2(invocation_reason); + current_client_metadata_ = cryptauthv2::ClientMetadata(); + current_client_metadata_->set_invocation_reason( + ConvertInvocationReasonV1ToV2(invocation_reason)); + if (session_id) + current_client_metadata_->set_session_id(*session_id); scheduler_->RequestEnrollmentNow(); } @@ -328,29 +334,39 @@ client_directive_policy_reference_ = client_directive_policy_reference; - base::Optional<cryptauthv2::ClientMetadata::InvocationReason> - failure_recovery_invocation_reason = - GetFailureRecoveryInvocationReasonFromPref(); + // Build the ClientMetadata if it hasn't already been built by + // ForceEnrollmentNow(). + if (!current_client_metadata_) { + current_client_metadata_ = cryptauthv2::ClientMetadata(); + base::Optional<cryptauthv2::ClientMetadata::InvocationReason> + failure_recovery_invocation_reason = + GetFailureRecoveryInvocationReasonFromPref(); + if (failure_recovery_invocation_reason) { + DCHECK(IsRecoveringFromFailure()); + current_client_metadata_->set_invocation_reason( + *failure_recovery_invocation_reason); + } else if (GetLastEnrollmentTime().is_null()) { + current_client_metadata_->set_invocation_reason( + cryptauthv2::ClientMetadata::INITIALIZATION); + } else if (!IsEnrollmentValid()) { + current_client_metadata_->set_invocation_reason( + cryptauthv2::ClientMetadata::PERIODIC); + } else { + current_client_metadata_->set_invocation_reason( + cryptauthv2::ClientMetadata::INVOCATION_REASON_UNSPECIFIED); + } - if (current_enrollment_invocation_reason_) { - // The invocation reason has already been set by ForceEnrollmentNow(). - } else if (failure_recovery_invocation_reason) { - DCHECK(IsRecoveringFromFailure()); - current_enrollment_invocation_reason_ = *failure_recovery_invocation_reason; - } else if (GetLastEnrollmentTime().is_null()) { - current_enrollment_invocation_reason_ = - cryptauthv2::ClientMetadata::INITIALIZATION; - } else if (!IsEnrollmentValid()) { - current_enrollment_invocation_reason_ = - cryptauthv2::ClientMetadata::PERIODIC; - } else { - current_enrollment_invocation_reason_ = - cryptauthv2::ClientMetadata::INVOCATION_REASON_UNSPECIFIED; + base::Optional<std::string> failure_recovery_session_id = + GetFailureRecoverySessionIdFromPref(); + if (failure_recovery_session_id) { + DCHECK(IsRecoveringFromFailure()); + current_client_metadata_->set_session_id(*failure_recovery_session_id); + } } base::UmaHistogramExactLinear( "CryptAuth.EnrollmentV2.InvocationReason", - *current_enrollment_invocation_reason_, + current_client_metadata_->invocation_reason(), cryptauthv2::ClientMetadata::InvocationReason_ARRAYSIZE); AttemptEnrollment(); @@ -370,11 +386,10 @@ AttemptEnrollment(); } -// TODO(nohle): Route session_id to ClientMetadata. void CryptAuthV2EnrollmentManagerImpl::OnReenrollMessage( const base::Optional<std::string>& session_id, const base::Optional<CryptAuthFeatureType>& feature_type) { - ForceEnrollmentNow(cryptauth::INVOCATION_REASON_SERVER_INITIATED); + ForceEnrollmentNow(cryptauth::INVOCATION_REASON_SERVER_INITIATED, session_id); } void CryptAuthV2EnrollmentManagerImpl::OnClientAppMetadataFetched( @@ -415,9 +430,12 @@ } void CryptAuthV2EnrollmentManagerImpl::Enroll() { - cryptauthv2::ClientMetadata client_metadata; - client_metadata.set_retry_count(scheduler_->GetNumConsecutiveFailures()); - client_metadata.set_invocation_reason(*current_enrollment_invocation_reason_); + // The invocation reason and session ID were set in ForceEnrollmentNow() for a + // forced enrollment and OnEnrollmentRequested() otherwise. Populate the other + // ClientMetadata fields here. + DCHECK(current_client_metadata_); + current_client_metadata_->set_retry_count( + scheduler_->GetNumConsecutiveFailures()); enroller_ = CryptAuthV2EnrollerImpl::Factory::Get()->BuildInstance( key_registry_, client_factory_); @@ -425,7 +443,7 @@ SetState(State::kWaitingForEnrollment); enroller_->Enroll( - client_metadata, *client_app_metadata_, + *current_client_metadata_, *client_app_metadata_, client_directive_policy_reference_, base::BindOnce(&CryptAuthV2EnrollmentManagerImpl::OnEnrollmentFinished, base::Unretained(this))); @@ -440,26 +458,30 @@ if (enrollment_result.IsSuccess()) { PA_LOG(INFO) << "Enrollment attempt with invocation reason " - << *current_enrollment_invocation_reason_ + << current_client_metadata_->invocation_reason() << " succeeded with result code " << enrollment_result.result_code(); pref_service_->SetInteger( prefs::kCryptAuthEnrollmentFailureRecoveryInvocationReason, cryptauthv2::ClientMetadata::INVOCATION_REASON_UNSPECIFIED); - + pref_service_->SetString( + prefs::kCryptAuthEnrollmentFailureRecoverySessionId, std::string()); } else { PA_LOG(WARNING) << "Enrollment attempt with invocation reason " - << *current_enrollment_invocation_reason_ + << current_client_metadata_->invocation_reason() << " failed with result code " << enrollment_result.result_code(); pref_service_->SetInteger( prefs::kCryptAuthEnrollmentFailureRecoveryInvocationReason, - *current_enrollment_invocation_reason_); + current_client_metadata_->invocation_reason()); + pref_service_->SetString( + prefs::kCryptAuthEnrollmentFailureRecoverySessionId, + current_client_metadata_->session_id()); } - current_enrollment_invocation_reason_.reset(); + current_client_metadata_.reset(); RecordEnrollmentResult(enrollment_result); @@ -528,6 +550,17 @@ reason_stored_in_prefs); } +base::Optional<std::string> +CryptAuthV2EnrollmentManagerImpl::GetFailureRecoverySessionIdFromPref() const { + std::string session_id_stored_in_prefs = pref_service_->GetString( + prefs::kCryptAuthEnrollmentFailureRecoverySessionId); + + if (session_id_stored_in_prefs.empty()) + return base::nullopt; + + return session_id_stored_in_prefs; +} + std::string CryptAuthV2EnrollmentManagerImpl::GetV1UserPublicKey() const { std::string public_key; if (!base::Base64UrlDecode(
diff --git a/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl.h b/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl.h index e410451..cde22c2 100644 --- a/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl.h +++ b/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl.h
@@ -124,7 +124,8 @@ // CryptAuthEnrollmentManager: void Start() override; void ForceEnrollmentNow( - cryptauth::InvocationReason invocation_reason) override; + cryptauth::InvocationReason invocation_reason, + const base::Optional<std::string>& session_id) override; bool IsEnrollmentValid() const override; base::Time GetLastEnrollmentTime() const override; base::TimeDelta GetTimeToNextAttempt() const override; @@ -161,6 +162,7 @@ // enrollment attempt. If no valid reason is stored, returns null. base::Optional<cryptauthv2::ClientMetadata::InvocationReason> GetFailureRecoveryInvocationReasonFromPref() const; + base::Optional<std::string> GetFailureRecoverySessionIdFromPref() const; std::string GetV1UserPublicKey() const; std::string GetV1UserPrivateKey() const; @@ -181,9 +183,11 @@ std::unique_ptr<CryptAuthEnrollmentScheduler> scheduler_; std::unique_ptr<CryptAuthV2Enroller> enroller_; - // Only non-null while an enrollment attempt is active. - base::Optional<cryptauthv2::ClientMetadata::InvocationReason> - current_enrollment_invocation_reason_; + // Only non-null while an enrollment attempt is active. The invocation reason + // and session ID are set in ForceEnrollmentNow() for forced enrollments and + // OnEnrollmentRequested() otherwise. The other ClientMetadata fields are + // populated in Enroll(). + base::Optional<cryptauthv2::ClientMetadata> current_client_metadata_; base::Optional<cryptauthv2::ClientAppMetadata> client_app_metadata_; base::Optional<cryptauthv2::PolicyReference>
diff --git a/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl_unittest.cc index 1234014..e07068e 100644 --- a/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl_unittest.cc +++ b/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl_unittest.cc
@@ -54,6 +54,7 @@ const char kFakeV1PrivateKey[] = "private_key_v1"; const char kFakeV2PublicKey[] = "public_key_v2"; const char kFakeV2PrivateKey[] = "private_key_v2"; +const char kFakeSessionId[] = "session_id"; constexpr base::TimeDelta kFakeRefreshPeriod = base::TimeDelta::FromMilliseconds(2592000000); @@ -289,8 +290,9 @@ enrollment_manager_->AddObserver(this); } - void RequestEnrollmentThroughGcm() { - fake_gcm_manager_.PushReenrollMessage(base::nullopt /* session_id */, + void RequestEnrollmentThroughGcm( + const base::Optional<std::string>& session_id) { + fake_gcm_manager_.PushReenrollMessage(session_id, base::nullopt /* feature_type */); } @@ -338,6 +340,7 @@ size_t expected_enroller_instance_index, const cryptauthv2::ClientMetadata::InvocationReason& expected_invocation_reason, + const base::Optional<std::string>& expected_session_id, const CryptAuthEnrollmentResult& enrollment_result) { EXPECT_TRUE(enrollment_manager_->IsEnrollmentInProgress()); @@ -355,7 +358,8 @@ fake_enroller_factory_ ->created_instances()[expected_enroller_instance_index]; - VerifyEnrollerData(enroller, expected_invocation_reason); + VerifyEnrollerData(enroller, expected_invocation_reason, + expected_session_id); enroller->FinishAttempt(enrollment_result); @@ -366,6 +370,12 @@ ? expected_invocation_reason : cryptauthv2::ClientMetadata::INVOCATION_REASON_UNSPECIFIED; VerifyPersistedFailureRecoveryInvocationReason(expected_persisted_reason); + + std::string expected_persisted_session_id = + enrollment_manager_->IsRecoveringFromFailure() + ? expected_session_id.value_or(std::string()) + : std::string(); + VerifyPersistedFailureRecoverySessionId(expected_persisted_session_id); } void VerifyEnrollmentResults( @@ -416,15 +426,17 @@ } private: - void VerifyEnrollerData(FakeCryptAuthV2Enroller* enroller, - const cryptauthv2::ClientMetadata::InvocationReason& - expected_invocation_reason) { + void VerifyEnrollerData( + FakeCryptAuthV2Enroller* enroller, + const cryptauthv2::ClientMetadata::InvocationReason& + expected_invocation_reason, + const base::Optional<std::string>& expected_session_id) { EXPECT_TRUE(enroller->was_enroll_called()); EXPECT_EQ(cryptauthv2::BuildClientMetadata( fake_enrollment_scheduler() ->GetNumConsecutiveFailures() /* retry_count */, - expected_invocation_reason) + expected_invocation_reason, expected_session_id) .SerializeAsString(), enroller->client_metadata()->SerializeAsString()); @@ -465,6 +477,13 @@ prefs::kCryptAuthEnrollmentFailureRecoveryInvocationReason))); } + void VerifyPersistedFailureRecoverySessionId( + const std::string& expected_persisted_session_id) { + EXPECT_EQ(expected_persisted_session_id, + test_pref_service_.GetString( + prefs::kCryptAuthEnrollmentFailureRecoverySessionId)); + } + void VerifyEnrollmentResultHistograms( const std::vector<CryptAuthEnrollmentResult> expected_enrollment_results) { @@ -546,6 +565,7 @@ FinishEnrollmentAttempt(0u /* expected_enroller_instance_index */, cryptauthv2::ClientMetadata:: INITIALIZATION /* expected_invocation_reason */, + base::nullopt /* expected_session_id */, expected_enrollment_result); VerifyEnrollmentResults({expected_enrollment_result}); @@ -613,7 +633,8 @@ enrollment_manager()->Start(); enrollment_manager()->ForceEnrollmentNow( - cryptauth::InvocationReason::INVOCATION_REASON_FEATURE_TOGGLED); + cryptauth::InvocationReason::INVOCATION_REASON_FEATURE_TOGGLED, + base::nullopt /* session_id */); EXPECT_TRUE(enrollment_manager()->IsEnrollmentInProgress()); VerifyEnrollmentManagerObserversNotifiedOfStart( 1 /* expected_num_enrollment_started_notifications */); @@ -627,6 +648,7 @@ FinishEnrollmentAttempt(0u /* expected_enroller_instance_index */, cryptauthv2::ClientMetadata:: FEATURE_TOGGLED /* expected_invocation_reason */, + base::nullopt /* expected_session_id */, expected_enrollment_result); VerifyEnrollmentResults({expected_enrollment_result}); @@ -678,6 +700,7 @@ FinishEnrollmentAttempt(0u /* expected_enroller_instance_index */, expected_invocation_reason, + base::nullopt /* expected_session_id */, first_expected_enrollment_result); EXPECT_EQ(kFakeRetryPeriod, enrollment_manager()->GetTimeToNextAttempt()); @@ -697,6 +720,7 @@ FinishEnrollmentAttempt(1u /* expected_enroller_instance_index */, expected_invocation_reason, + base::nullopt /* expected_session_id */, second_expected_enrollment_result); VerifyEnrollmentResults( @@ -709,12 +733,49 @@ } TEST_F(DeviceSyncCryptAuthV2EnrollmentManagerImplTest, - EnrollmentTriggeredByGcmMessage) { + EnrollmentTriggeredByGcmMessage_Success) { CreateEnrollmentManager(); enrollment_manager()->Start(); - RequestEnrollmentThroughGcm(); + RequestEnrollmentThroughGcm(kFakeSessionId); + EXPECT_TRUE(enrollment_manager()->IsEnrollmentInProgress()); + VerifyEnrollmentManagerObserversNotifiedOfStart( + 1 /* expected_num_enrollment_started_notifications */); + CompleteGcmRegistration(true /* success */); + HandleGetClientAppMetadataRequest(true /* success */); + CryptAuthEnrollmentResult expected_enrollment_result( + CryptAuthEnrollmentResult::ResultCode::kSuccessNoNewKeysNeeded, + cryptauthv2::GetClientDirectiveForTest()); + FinishEnrollmentAttempt(0u /* expected_enroller_instance_index */, + cryptauthv2::ClientMetadata:: + SERVER_INITIATED /* expected_invocation_reason */, + kFakeSessionId /* expected_session_id */, + expected_enrollment_result); + VerifyEnrollmentResults({expected_enrollment_result}); +} + +TEST_F(DeviceSyncCryptAuthV2EnrollmentManagerImplTest, + EnrollmentTriggeredByGcmMessage_Failure) { + CreateEnrollmentManager(); + enrollment_manager()->Start(); + + RequestEnrollmentThroughGcm(kFakeSessionId); + + EXPECT_TRUE(enrollment_manager()->IsEnrollmentInProgress()); + VerifyEnrollmentManagerObserversNotifiedOfStart( + 1 /* expected_num_enrollment_started_notifications */); + CompleteGcmRegistration(true /* success */); + HandleGetClientAppMetadataRequest(true /* success */); + CryptAuthEnrollmentResult expected_enrollment_result( + CryptAuthEnrollmentResult::ResultCode::kErrorCryptAuthServerOverloaded, + base::nullopt /* client_directive */); + FinishEnrollmentAttempt(0u /* expected_enroller_instance_index */, + cryptauthv2::ClientMetadata:: + SERVER_INITIATED /* expected_invocation_reason */, + kFakeSessionId /* expected_session_id */, + expected_enrollment_result); + VerifyEnrollmentResults({expected_enrollment_result}); } TEST_F(DeviceSyncCryptAuthV2EnrollmentManagerImplTest, @@ -803,6 +864,7 @@ HandleGetClientAppMetadataRequest(true /* success */); FinishEnrollmentAttempt(0u /* expected_enroller_instance_index */, expected_invocation_reasons.back(), + base::nullopt /* expected_session_id */, expected_enrollment_results.back()); // Fail periodic refresh twice due to overloaded CryptAuth server. @@ -817,6 +879,7 @@ 2 /* expected_num_enrollment_started_notifications */); FinishEnrollmentAttempt(1u /* expected_enroller_instance_index */, expected_invocation_reasons.back(), + base::nullopt /* expected_session_id */, expected_enrollment_results.back()); expected_invocation_reasons.push_back(cryptauthv2::ClientMetadata::PERIODIC); @@ -828,6 +891,7 @@ 3 /* expected_num_enrollment_started_notifications */); FinishEnrollmentAttempt(2u /* expected_enroller_instance_index */, expected_invocation_reasons.back(), + base::nullopt /* expected_session_id */, expected_enrollment_results.back()); // While waiting for retry, force a manual enrollment that succeeds. @@ -835,11 +899,13 @@ expected_enrollment_results.emplace_back( CryptAuthEnrollmentResult::ResultCode::kSuccessNoNewKeysNeeded, base::nullopt /* client_directive */); - enrollment_manager()->ForceEnrollmentNow(cryptauth::INVOCATION_REASON_MANUAL); + enrollment_manager()->ForceEnrollmentNow(cryptauth::INVOCATION_REASON_MANUAL, + base::nullopt /* session_id */); VerifyEnrollmentManagerObserversNotifiedOfStart( 4 /* expected_num_enrollment_started_notifications */); FinishEnrollmentAttempt(3u /* expected_enroller_instance_index */, expected_invocation_reasons.back(), + base::nullopt /* expected_session_id */, expected_enrollment_results.back()); VerifyInvocationReasonHistogram(expected_invocation_reasons);
diff --git a/chromeos/services/device_sync/device_sync_impl.cc b/chromeos/services/device_sync/device_sync_impl.cc index 177b5f4..611810c3 100644 --- a/chromeos/services/device_sync/device_sync_impl.cc +++ b/chromeos/services/device_sync/device_sync_impl.cc
@@ -344,7 +344,7 @@ } cryptauth_enrollment_manager_->ForceEnrollmentNow( - cryptauth::INVOCATION_REASON_MANUAL); + cryptauth::INVOCATION_REASON_MANUAL, base::nullopt /* session_id */); std::move(callback).Run(true /* success */); RecordForceEnrollmentNowResult( ForceCryptAuthOperationResult::kSuccess /* result */);
diff --git a/chromeos/services/device_sync/fake_cryptauth_enrollment_manager.cc b/chromeos/services/device_sync/fake_cryptauth_enrollment_manager.cc index 72b0fc0..e3a8a2b 100644 --- a/chromeos/services/device_sync/fake_cryptauth_enrollment_manager.cc +++ b/chromeos/services/device_sync/fake_cryptauth_enrollment_manager.cc
@@ -34,7 +34,8 @@ } void FakeCryptAuthEnrollmentManager::ForceEnrollmentNow( - cryptauth::InvocationReason invocation_reason) { + cryptauth::InvocationReason invocation_reason, + const base::Optional<std::string>& session_id) { is_enrollment_in_progress_ = true; last_invocation_reason_ = invocation_reason; NotifyEnrollmentStarted();
diff --git a/chromeos/services/device_sync/fake_cryptauth_enrollment_manager.h b/chromeos/services/device_sync/fake_cryptauth_enrollment_manager.h index 21e3238..0179959 100644 --- a/chromeos/services/device_sync/fake_cryptauth_enrollment_manager.h +++ b/chromeos/services/device_sync/fake_cryptauth_enrollment_manager.h
@@ -6,6 +6,7 @@ #define CHROMEOS_SERVICES_DEVICE_SYNC_FAKE_CRYPTAUTH_ENROLLMENT_MANAGER_H_ #include <memory> +#include <string> #include "base/macros.h" #include "base/optional.h" @@ -71,7 +72,8 @@ // CryptAuthEnrollmentManager: void Start() override; void ForceEnrollmentNow( - cryptauth::InvocationReason invocation_reason) override; + cryptauth::InvocationReason invocation_reason, + const base::Optional<std::string>& session_id = base::nullopt) override; bool IsEnrollmentValid() const override; base::Time GetLastEnrollmentTime() const override; base::TimeDelta GetTimeToNextAttempt() const override;
diff --git a/chromeos/services/device_sync/pref_names.cc b/chromeos/services/device_sync/pref_names.cc index 9be44a8..d149af01 100644 --- a/chromeos/services/device_sync/pref_names.cc +++ b/chromeos/services/device_sync/pref_names.cc
@@ -37,6 +37,11 @@ const char kCryptAuthEnrollmentFailureRecoveryInvocationReason[] = "cryptauth.enrollment.failure_recovery_invocation_reason"; +// The session ID, sent via a GCM message, to use when retrying a failed +// enrollment attempt. +const char kCryptAuthEnrollmentFailureRecoverySessionId[] = + "cryptauth.enrollment.failure_recovery_session_id"; + // Whether the system is scheduling enrollments more aggressively to recover // from the previous enrollment failure. const char kCryptAuthEnrollmentIsRecoveringFromFailure[] =
diff --git a/chromeos/services/device_sync/pref_names.h b/chromeos/services/device_sync/pref_names.h index f5c5d55..2043848 100644 --- a/chromeos/services/device_sync/pref_names.h +++ b/chromeos/services/device_sync/pref_names.h
@@ -16,6 +16,7 @@ extern const char kCryptAuthDeviceSyncReason[]; extern const char kCryptAuthDeviceSyncUnlockKeys[]; extern const char kCryptAuthEnrollmentFailureRecoveryInvocationReason[]; +extern const char kCryptAuthEnrollmentFailureRecoverySessionId[]; extern const char kCryptAuthEnrollmentIsRecoveringFromFailure[]; extern const char kCryptAuthEnrollmentLastEnrollmentTimeSeconds[]; extern const char kCryptAuthEnrollmentReason[];
diff --git a/chromeos/services/device_sync/proto/cryptauth_v2_test_util.cc b/chromeos/services/device_sync/proto/cryptauth_v2_test_util.cc index 1364c38..c516cd5a 100644 --- a/chromeos/services/device_sync/proto/cryptauth_v2_test_util.cc +++ b/chromeos/services/device_sync/proto/cryptauth_v2_test_util.cc
@@ -30,10 +30,13 @@ ClientMetadata BuildClientMetadata( int32_t retry_count, - const ClientMetadata::InvocationReason& invocation_reason) { + const ClientMetadata::InvocationReason& invocation_reason, + const base::Optional<std::string>& session_id) { ClientMetadata client_metadata; client_metadata.set_retry_count(retry_count); client_metadata.set_invocation_reason(invocation_reason); + if (session_id) + client_metadata.set_session_id(*session_id); return client_metadata; }
diff --git a/chromeos/services/device_sync/proto/cryptauth_v2_test_util.h b/chromeos/services/device_sync/proto/cryptauth_v2_test_util.h index 75590baa..47ddf8b 100644 --- a/chromeos/services/device_sync/proto/cryptauth_v2_test_util.h +++ b/chromeos/services/device_sync/proto/cryptauth_v2_test_util.h
@@ -9,6 +9,7 @@ #include <utility> #include <vector> +#include "base/optional.h" #include "chromeos/services/device_sync/proto/cryptauth_better_together_feature_metadata.pb.h" #include "chromeos/services/device_sync/proto/cryptauth_client_app_metadata.pb.h" #include "chromeos/services/device_sync/proto/cryptauth_common.pb.h" @@ -35,14 +36,19 @@ ClientMetadata BuildClientMetadata( int32_t retry_count, - const ClientMetadata::InvocationReason& invocation_reason); + const ClientMetadata::InvocationReason& invocation_reason, + const base::Optional<std::string>& session_id = base::nullopt); + PolicyReference BuildPolicyReference(const std::string& name, int64_t version); + KeyDirective BuildKeyDirective(const PolicyReference& policy_reference, int64_t enroll_time_millis); + RequestContext BuildRequestContext(const std::string& group, const ClientMetadata& client_metadata, const std::string& device_id, const std::string& device_id_token); + DeviceFeatureStatus BuildDeviceFeatureStatus( const std::string& device_id, const std::vector<std::pair<std::string /* feature_type */,
diff --git a/components/arc/DEPS b/components/arc/DEPS index 781b1c8c..86e6332 100644 --- a/components/arc/DEPS +++ b/components/arc/DEPS
@@ -11,7 +11,9 @@ "+components/session_manager/core", "+components/timers", "+components/user_manager", + "+components/user_prefs", "+components/version_info", + "+content/public/browser", "+media/base/video_codecs.h", "+media/video/video_encode_accelerator.h", "+mojo",
diff --git a/components/arc/arc_prefs.cc b/components/arc/arc_prefs.cc index 3620062..caf5df57 100644 --- a/components/arc/arc_prefs.cc +++ b/components/arc/arc_prefs.cc
@@ -39,6 +39,9 @@ // utility methods (IsArcPlayStoreEnabledForProfile() and // SetArcPlayStoreEnabledForProfile()) in chrome/browser/chromeos/arc/arc_util. const char kArcEnabled[] = "arc.enabled"; +// A preference to control if ARC can access removable media on the host side. +const char kArcHasAccessToRemovableMedia[] = + "arc.has_access_to_removable_media"; // A preference that indicates that initial settings need to be applied. Initial // settings are applied only once per new OptIn once mojo settings instance is // ready. Each OptOut resets this preference. Note, its sense is close to @@ -177,6 +180,7 @@ registry->RegisterStringPref(kAlwaysOnVpnPackage, std::string()); registry->RegisterBooleanPref(kArcDataRemoveRequested, false); registry->RegisterBooleanPref(kArcEnabled, false); + registry->RegisterBooleanPref(kArcHasAccessToRemovableMedia, false); registry->RegisterBooleanPref(kArcInitialSettingsPending, false); registry->RegisterBooleanPref(kArcPaiStarted, false); registry->RegisterBooleanPref(kArcFastAppReinstallStarted, false);
diff --git a/components/arc/arc_prefs.h b/components/arc/arc_prefs.h index 1e0dc0a..6c34a5d 100644 --- a/components/arc/arc_prefs.h +++ b/components/arc/arc_prefs.h
@@ -23,6 +23,7 @@ ARC_EXPORT extern const char kArcEnabled[]; ARC_EXPORT extern const char kArcFastAppReinstallPackages[]; ARC_EXPORT extern const char kArcFastAppReinstallStarted[]; +ARC_EXPORT extern const char kArcHasAccessToRemovableMedia[]; ARC_EXPORT extern const char kArcInitialSettingsPending[]; ARC_EXPORT extern const char kArcLocationServiceEnabled[]; ARC_EXPORT extern const char kArcPackages[];
diff --git a/components/arc/metrics/DEPS b/components/arc/metrics/DEPS index 83bdfd1e..ce83197d 100644 --- a/components/arc/metrics/DEPS +++ b/components/arc/metrics/DEPS
@@ -1,6 +1,4 @@ include_rules = [ - "+components/user_prefs", - "+content/public/browser", "+ui/aura", "+ui/wm/public", ]
diff --git a/components/arc/test/DEPS b/components/arc/test/DEPS index 461938c..cc564af 100644 --- a/components/arc/test/DEPS +++ b/components/arc/test/DEPS
@@ -1,9 +1,6 @@ specific_include_rules = { "test_browser_context.h": [ "+content/public/test/test_browser_context.h", - ], - "test_browser_context.cc": [ - "+components/user_prefs/user_prefs.h", ] }
diff --git a/components/arc/volume_mounter/arc_volume_mounter_bridge.cc b/components/arc/volume_mounter/arc_volume_mounter_bridge.cc index 4869246f..7346202 100644 --- a/components/arc/volume_mounter/arc_volume_mounter_bridge.cc +++ b/components/arc/volume_mounter/arc_volume_mounter_bridge.cc
@@ -12,7 +12,11 @@ #include "chromeos/disks/disk.h" #include "chromeos/disks/disk_mount_manager.h" #include "components/arc/arc_browser_context_keyed_service_factory_base.h" +#include "components/arc/arc_prefs.h" #include "components/arc/session/arc_bridge_service.h" +#include "components/prefs/pref_service.h" +#include "components/user_prefs/user_prefs.h" +#include "content/public/browser/browser_context.h" #include "third_party/re2/src/re2/re2.h" #include "ui/base/l10n/l10n_util.h" #include "ui/chromeos/strings/grit/ui_chromeos_strings.h" @@ -59,11 +63,22 @@ ArcVolumeMounterBridge::ArcVolumeMounterBridge(content::BrowserContext* context, ArcBridgeService* bridge_service) - : arc_bridge_service_(bridge_service), weak_ptr_factory_(this) { + : arc_bridge_service_(bridge_service), + pref_service_(user_prefs::UserPrefs::Get(context)), + weak_ptr_factory_(this) { + DCHECK(pref_service_); arc_bridge_service_->volume_mounter()->AddObserver(this); arc_bridge_service_->volume_mounter()->SetHost(this); DCHECK(DiskMountManager::GetInstance()); DiskMountManager::GetInstance()->AddObserver(this); + + change_registerar_.Init(pref_service_); + // Start monitoring |kArcHasAccessToRemovableMedia| changes. Note that the + // registerar automatically stops monitoring the pref in its dtor. + change_registerar_.Add( + prefs::kArcHasAccessToRemovableMedia, + base::BindRepeating(&ArcVolumeMounterBridge::OnPrefChanged, + weak_ptr_factory_.GetWeakPtr())); } ArcVolumeMounterBridge::~ArcVolumeMounterBridge() { @@ -103,6 +118,28 @@ device_label, device_type)); } +bool ArcVolumeMounterBridge::HasAccessToRemovableMedia() const { + DCHECK(pref_service_); + return pref_service_->GetBoolean(prefs::kArcHasAccessToRemovableMedia) + // TODO(yusukes): Once the UI for controlling the pref is ready, remove + // the condition below. + || true; +} + +void ArcVolumeMounterBridge::OnPrefChanged() { + if (HasAccessToRemovableMedia()) { + // Mount everything again. Mounting the same disk (e.g. MyFiles) again is + // allowed and is no-op. + SendAllMountEvents(); + return; + } + // Unmount everything except for MyFiles. + for (const auto& keyValue : DiskMountManager::GetInstance()->mount_points()) { + OnMountEvent(DiskMountManager::MountEvent::UNMOUNTING, + chromeos::MountError::MOUNT_ERROR_NONE, keyValue.second); + } +} + void ArcVolumeMounterBridge::OnConnectionReady() { // Deferring the SendAllMountEvents as a task to current thread to not // block the mojo request since SendAllMountEvents might take non trivial @@ -129,6 +166,15 @@ return; } + // Do not propagate MOUNTING event to ARC when the media sharing setting is + // turned off. The other event (i.e. UNMOUNTING) should still go through. + if (event == DiskMountManager::MountEvent::MOUNTING && + !HasAccessToRemovableMedia()) { + VLOG(2) << "Disk at " << mount_info.source_path + << " is not allowed to be shared with ARC"; + return; + } + // Get disks informations that are needed by Android MountService. const chromeos::disks::Disk* disk = DiskMountManager::GetInstance()->FindDiskBySourcePath(
diff --git a/components/arc/volume_mounter/arc_volume_mounter_bridge.h b/components/arc/volume_mounter/arc_volume_mounter_bridge.h index a7d04abe..75d91a3c 100644 --- a/components/arc/volume_mounter/arc_volume_mounter_bridge.h +++ b/components/arc/volume_mounter/arc_volume_mounter_bridge.h
@@ -13,6 +13,7 @@ #include "components/arc/common/volume_mounter.mojom.h" #include "components/arc/session/connection_observer.h" #include "components/keyed_service/core/keyed_service.h" +#include "components/prefs/pref_change_registrar.h" #include "mojo/public/cpp/bindings/binding.h" namespace content { @@ -57,8 +58,14 @@ void SendMountEventForMyFiles(); + bool HasAccessToRemovableMedia() const; + void OnPrefChanged(); + ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. + PrefService* const pref_service_; + PrefChangeRegistrar change_registerar_; + base::WeakPtrFactory<ArcVolumeMounterBridge> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ArcVolumeMounterBridge);
diff --git a/components/autofill/core/browser/autofill_data_util.cc b/components/autofill/core/browser/autofill_data_util.cc index 2dff299..a13de4a 100644 --- a/components/autofill/core/browser/autofill_data_util.cc +++ b/components/autofill/core/browser/autofill_data_util.cc
@@ -15,6 +15,7 @@ #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_country.h" #include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/webdata/autofill_table.h" @@ -26,7 +27,13 @@ namespace autofill { namespace data_util { +using bit_field_type_groups::kAddress; +using bit_field_type_groups::kEmail; +using bit_field_type_groups::kName; +using bit_field_type_groups::kPhone; + namespace { + // Mappings from Chrome card networks to Payment Request API basic card payment // spec networks and icons. Note that "generic" is not in the spec. // https://w3c.github.io/webpayments-methods-card/#method-id @@ -244,6 +251,47 @@ } // namespace +bool ContainsName(uint32_t groups) { + return groups & kName; +} + +bool ContainsAddress(uint32_t groups) { + return groups & kAddress; +} + +bool ContainsEmail(uint32_t groups) { + return groups & kEmail; +} + +bool ContainsPhone(uint32_t groups) { + return groups & kPhone; +} + +uint32_t DetermineGroups(const std::vector<ServerFieldType>& types) { + uint32_t group_bitmask = 0; + for (const ServerFieldType& type : types) { + const FieldTypeGroup group = + AutofillType(AutofillType(type).GetStorableType()).group(); + switch (group) { + case autofill::NAME: + group_bitmask |= kName; + break; + case autofill::ADDRESS_HOME: + group_bitmask |= kAddress; + break; + case autofill::EMAIL: + group_bitmask |= kEmail; + break; + case autofill::PHONE_HOME: + group_bitmask |= kPhone; + break; + default: + break; + } + } + return group_bitmask; +} + std::string TruncateUTF8(const std::string& data) { std::string trimmed_value; base::TruncateUTF8ToByteSize(data, AutofillTable::kMaxDataLength,
diff --git a/components/autofill/core/browser/autofill_data_util.h b/components/autofill/core/browser/autofill_data_util.h index ee3ede76..ba8f55f 100644 --- a/components/autofill/core/browser/autofill_data_util.h +++ b/components/autofill/core/browser/autofill_data_util.h
@@ -6,6 +6,7 @@ #define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_DATA_UTIL_H_ #include <string> +#include <vector> #include "base/strings/string16.h" #include "base/strings/string_piece_forward.h" @@ -23,6 +24,39 @@ base::string16 family; }; +namespace bit_field_type_groups { + +// Bits for FieldTypeGroup options. +// The form has a field associated with the NAME_HOME or NAME_BILLING +// FieldTypeGroups. +constexpr uint32_t kName = 1 << 0; +// The form has a field associated with the ADDRESS_HOME or ADDRESS_BILLING +// FieldTypeGroups. +constexpr uint32_t kAddress = 1 << 1; +// The form has a field associated with the EMAIL FieldTypeGroup. +constexpr uint32_t kEmail = 1 << 2; +// The form has a field associated with the PHONE_HOME or PHONE_BILLING +// FieldTypeGroups. +constexpr uint32_t kPhone = 1 << 3; + +} // namespace bit_field_type_groups + +// Returns true if kName is set in |groups|. +bool ContainsName(uint32_t groups); + +// Returns true if kAddress is set in |groups|. +bool ContainsAddress(uint32_t groups); + +// Returns true if kEmail is set in |groups|. +bool ContainsEmail(uint32_t groups); + +// Returns true if kPhone is set in |groups|. +bool ContainsPhone(uint32_t groups); + +// Returns a bitmask indicating whether the NAME, ADDRESS_HOME, EMAIL, and +// PHONE_HOME FieldTypeGroups are associated with the given |field_types|. +uint32_t DetermineGroups(const std::vector<ServerFieldType>& types); + // Truncates a string to the nearest UTF-8 character that will leave // the string less than or equal to the specified byte size. std::string TruncateUTF8(const std::string& data);
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc index 3dc8cf20..e04a175 100644 --- a/components/autofill/core/browser/autofill_manager_unittest.cc +++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -6293,6 +6293,270 @@ HasSubstr("Autofill.FormEvents.CreditCard")))); } +TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_AddressOnly) { + // Create a form with name and address fields. + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.button_titles = {std::make_pair( + ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; + form.url = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + form.main_frame_origin = + url::Origin::Create(GURL("https://myform_root.com/form.html")); + form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + FormFieldData field; + test::CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Last Name", "lastname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field); + form.fields.push_back(field); + + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form, + form.fields[0]); + histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.AddressOnly", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.AddressOnly", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + + // Logging is not done for other types of address forms. + const std::string histograms = histogram_tester.GetAllHistogramsRecorded(); + EXPECT_THAT(histograms, + Not(AnyOf("Autofill.FormEvents.Address.AddressPlusContact", + "Autofill.FormEvents.Address.AddressPlusEmail", + "Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + "Autofill.FormEvents.Address.AddressPlusPhone", + "Autofill.FormEvents.Address.ContactOnly", + "Autofill.FormEvents.Address.Other"))); +} + +TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_ContactOnly) { + // Create a form with name and contact fields. + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.button_titles = {std::make_pair( + ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; + form.url = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + form.main_frame_origin = + url::Origin::Create(GURL("https://myform_root.com/form.html")); + form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + FormFieldData field; + test::CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Last Name", "lastname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Email", "email", "", "email", &field); + form.fields.push_back(field); + + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form, + form.fields[0]); + histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.ContactOnly", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.ContactOnly", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + + // Logging is not done for other types of address forms. + const std::string histograms = histogram_tester.GetAllHistogramsRecorded(); + EXPECT_THAT(histograms, + Not(AnyOf("Autofill.FormEvents.Address.AddressPlusContact", + "Autofill.FormEvents.Address.AddressPlusEmail", + "Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + "Autofill.FormEvents.Address.AddressPlusPhone", + "Autofill.FormEvents.Address.AddressOnly", + "Autofill.FormEvents.Address.Other"))); +} + +TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_Other) { + // Create a form with name fields. + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.button_titles = {std::make_pair( + ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; + form.url = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + form.main_frame_origin = + url::Origin::Create(GURL("https://myform_root.com/form.html")); + form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + FormFieldData field; + test::CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Middle Name", "middlename", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Last Name", "lastname", "", "text", &field); + form.fields.push_back(field); + + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form, + form.fields[0]); + histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.Other", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.Other", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + + // Logging is not done for other types of address forms. + const std::string histograms = histogram_tester.GetAllHistogramsRecorded(); + EXPECT_THAT(histograms, + Not(AnyOf("Autofill.FormEvents.Address.AddressPlusContact", + "Autofill.FormEvents.Address.AddressPlusEmail", + "Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + "Autofill.FormEvents.Address.AddressPlusPhone", + "Autofill.FormEvents.Address.AddressOnly", + "Autofill.FormEvents.Address.ContactOnly"))); +} + +TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_AddressPlusEmail) { + // Create a form with name fields. + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.button_titles = {std::make_pair( + ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; + form.url = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + form.main_frame_origin = + url::Origin::Create(GURL("https://myform_root.com/form.html")); + form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + FormFieldData field; + test::CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Last Name", "lastname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Email", "email", "", "email", &field); + form.fields.push_back(field); + + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form, + form.fields[0]); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusEmail", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusEmail", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusContact", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusContact", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + + // Logging is not done for other types of address forms. + const std::string histograms = histogram_tester.GetAllHistogramsRecorded(); + EXPECT_THAT(histograms, + Not(AnyOf("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + "Autofill.FormEvents.Address.AddressPlusPhone", + "Autofill.FormEvents.Address.AddressOnly", + "Autofill.FormEvents.Address.ContactOnly", + "Autofill.FormEvents.Address.Other"))); +} + +TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_AddressPlusPhone) { + // Create a form with name fields. + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.button_titles = {std::make_pair( + ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; + form.url = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + form.main_frame_origin = + url::Origin::Create(GURL("https://myform_root.com/form.html")); + form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + FormFieldData field; + test::CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Last Name", "lastname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field); + form.fields.push_back(field); + + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form, + form.fields[0]); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusPhone", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusPhone", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusContact", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusContact", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + + // Logging is not done for other types of address forms. + const std::string histograms = histogram_tester.GetAllHistogramsRecorded(); + EXPECT_THAT(histograms, + Not(AnyOf("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + "Autofill.FormEvents.Address.AddressPlusEmail", + "Autofill.FormEvents.Address.AddressOnly", + "Autofill.FormEvents.Address.ContactOnly", + "Autofill.FormEvents.Address.Other"))); +} + +TEST_F(AutofillManagerTest, + DidShowSuggestions_LogByType_AddressPlusEmailPlusPhone) { + // Create a form with name fields. + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.button_titles = {std::make_pair( + ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; + form.url = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + form.main_frame_origin = + url::Origin::Create(GURL("https://myform_root.com/form.html")); + form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + FormFieldData field; + test::CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Last Name", "lastname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field); + form.fields.push_back(field); + test::CreateTestFormField("Email", "email", "", "email", &field); + form.fields.push_back(field); + + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form, + form.fields[0]); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusContact", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusContact", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + + // Logging is not done for other types of address forms. + const std::string histograms = histogram_tester.GetAllHistogramsRecorded(); + EXPECT_THAT(histograms, + Not(AnyOf("Autofill.FormEvents.Address.AddressPlusPhone", + "Autofill.FormEvents.Address.AddressPlusEmail", + "Autofill.FormEvents.Address.AddressOnly", + "Autofill.FormEvents.Address.ContactOnly", + "Autofill.FormEvents.Address.Other"))); +} + TEST_F(AutofillManagerTest, DidShowSuggestions_LogAutofillCreditCardShownMetric) { FormData form;
diff --git a/components/autofill/core/browser/autofill_metrics.h b/components/autofill/core/browser/autofill_metrics.h index cfdc034..3688ad1 100644 --- a/components/autofill/core/browser/autofill_metrics.h +++ b/components/autofill/core/browser/autofill_metrics.h
@@ -749,7 +749,7 @@ NUM_WALLET_REQUIRED_ACTIONS }; - // For mesuring how wallet addresses are converted to local profiles. + // For measuring how wallet addresses are converted to local profiles. enum WalletAddressConversionType : int { // The converted wallet address was merged into an existing local profile. CONVERTED_ADDRESS_MERGED, @@ -758,11 +758,11 @@ NUM_CONVERTED_ADDRESS_CONVERSION_TYPES }; - // To record whether or not the upload event was sent, + // To record whether the upload event was sent. enum class UploadEventStatus { kNotSent, kSent, kMaxValue = kSent }; - // Log all the scenarios that lead to making the decision whether card upload - // is enabled or not. + // Log all the scenarios that contribute to the decision of whether card + // upload is enabled or not. enum class CardUploadEnabledMetric { SYNC_SERVICE_NULL = 0, SYNC_SERVICE_PERSISTENT_AUTH_ERROR = 1,
diff --git a/components/autofill/core/browser/contact_form_label_formatter.cc b/components/autofill/core/browser/contact_form_label_formatter.cc index a375da5..48feb02 100644 --- a/components/autofill/core/browser/contact_form_label_formatter.cc +++ b/components/autofill/core/browser/contact_form_label_formatter.cc
@@ -4,6 +4,7 @@ #include "components/autofill/core/browser/contact_form_label_formatter.h" +#include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/label_formatter_utils.h" namespace autofill { @@ -41,14 +42,16 @@ base::string16 ContactFormLabelFormatter::MaybeGetEmail( const AutofillProfile& profile) const { - return ContainsEmail(groups()) ? GetLabelEmail(profile, app_locale()) - : base::string16(); + return data_util::ContainsEmail(groups()) + ? GetLabelEmail(profile, app_locale()) + : base::string16(); } base::string16 ContactFormLabelFormatter::MaybeGetPhone( const AutofillProfile& profile) const { - return ContainsPhone(groups()) ? GetLabelPhone(profile, app_locale()) - : base::string16(); + return data_util::ContainsPhone(groups()) + ? GetLabelPhone(profile, app_locale()) + : base::string16(); } } // namespace autofill
diff --git a/components/autofill/core/browser/label_formatter.cc b/components/autofill/core/browser/label_formatter.cc index 4e28c9e..5fa3b42 100644 --- a/components/autofill/core/browser/label_formatter.cc +++ b/components/autofill/core/browser/label_formatter.cc
@@ -12,15 +12,17 @@ #include "components/autofill/core/browser/address_email_form_label_formatter.h" #include "components/autofill/core/browser/address_form_label_formatter.h" #include "components/autofill/core/browser/address_phone_form_label_formatter.h" +#include "components/autofill/core/browser/autofill_data_util.h" +#include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/contact_form_label_formatter.h" #include "components/autofill/core/browser/label_formatter_utils.h" namespace autofill { -using label_formatter_groups::kAddress; -using label_formatter_groups::kEmail; -using label_formatter_groups::kName; -using label_formatter_groups::kPhone; +using data_util::bit_field_type_groups::kAddress; +using data_util::bit_field_type_groups::kEmail; +using data_util::bit_field_type_groups::kName; +using data_util::bit_field_type_groups::kPhone; LabelFormatter::LabelFormatter(const std::string& app_locale, ServerFieldType focused_field_type, @@ -78,7 +80,7 @@ ServerFieldType focused_field_type, const std::vector<ServerFieldType>& field_types, const std::vector<AutofillProfile*>& profiles) { - const uint32_t groups = DetermineGroups(field_types); + const uint32_t groups = data_util::DetermineGroups(field_types); switch (groups) { case kName | kAddress | kEmail | kPhone:
diff --git a/components/autofill/core/browser/label_formatter_utils.cc b/components/autofill/core/browser/label_formatter_utils.cc index 36df5c5..42bd1a10 100644 --- a/components/autofill/core/browser/label_formatter_utils.cc +++ b/components/autofill/core/browser/label_formatter_utils.cc
@@ -29,47 +29,6 @@ ADDRESS_HOME_STREET_ADDRESS, ADDRESS_BILLING_STREET_ADDRESS, ADDRESS_HOME_LINE3, ADDRESS_BILLING_LINE3}; -bool ContainsName(uint32_t groups) { - return groups & label_formatter_groups::kName; -} - -bool ContainsAddress(uint32_t groups) { - return groups & label_formatter_groups::kAddress; -} - -bool ContainsEmail(uint32_t groups) { - return groups & label_formatter_groups::kEmail; -} - -bool ContainsPhone(uint32_t groups) { - return groups & label_formatter_groups::kPhone; -} - -uint32_t DetermineGroups(const std::vector<ServerFieldType>& types) { - uint32_t group_bitmask = 0; - for (const ServerFieldType& type : types) { - const FieldTypeGroup group = - AutofillType(AutofillType(type).GetStorableType()).group(); - switch (group) { - case autofill::NAME: - group_bitmask |= label_formatter_groups::kName; - break; - case autofill::ADDRESS_HOME: - group_bitmask |= label_formatter_groups::kAddress; - break; - case autofill::EMAIL: - group_bitmask |= label_formatter_groups::kEmail; - break; - case autofill::PHONE_HOME: - group_bitmask |= label_formatter_groups::kPhone; - break; - default: - break; - } - } - return group_bitmask; -} - bool IsStreetAddressPart(ServerFieldType type) { return std::find(std::begin(kStreetAddressFieldTypes), std::end(kStreetAddressFieldTypes),
diff --git a/components/autofill/core/browser/label_formatter_utils.h b/components/autofill/core/browser/label_formatter_utils.h index 6db87afd..c12d589 100644 --- a/components/autofill/core/browser/label_formatter_utils.h +++ b/components/autofill/core/browser/label_formatter_utils.h
@@ -13,22 +13,6 @@ #include "components/autofill/core/browser/field_types.h" namespace autofill { -namespace label_formatter_groups { - -// Bits for FieldTypeGroup options. -// The form has a field associated with the NAME_HOME or NAME_BILLING -// FieldTypeGroups. -constexpr uint32_t kName = 1 << 0; -// The form has a field associated with the ADDRESS_HOME or ADDRESS_BILLING -// FieldTypeGroups. -constexpr uint32_t kAddress = 1 << 1; -// The form has a field associated with the EMAIL FieldTypeGroup. -constexpr uint32_t kEmail = 1 << 2; -// The form has a field associated with the PHONE_HOME or PHONE_BILLING -// FieldTypeGroups. -constexpr uint32_t kPhone = 1 << 3; - -} // namespace label_formatter_groups // Returns true if kName is set in |groups|. bool ContainsName(uint32_t groups);
diff --git a/components/autofill/core/browser/label_formatter_utils_unittest.cc b/components/autofill/core/browser/label_formatter_utils_unittest.cc index 0bd4931..237ec3c 100644 --- a/components/autofill/core/browser/label_formatter_utils_unittest.cc +++ b/components/autofill/core/browser/label_formatter_utils_unittest.cc
@@ -8,6 +8,7 @@ #include "base/strings/string16.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/grit/components_scaled_resources.h" @@ -18,10 +19,10 @@ namespace autofill { namespace { -using label_formatter_groups::kAddress; -using label_formatter_groups::kEmail; -using label_formatter_groups::kName; -using label_formatter_groups::kPhone; +using data_util::bit_field_type_groups::kAddress; +using data_util::bit_field_type_groups::kEmail; +using data_util::bit_field_type_groups::kName; +using data_util::bit_field_type_groups::kPhone; TEST(LabelFormatterUtilsTest, DetermineGroupsForHomeNameAndAddress) { const std::vector<ServerFieldType> field_types{ @@ -29,7 +30,7 @@ ADDRESS_HOME_CITY, ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP}; const uint32_t expected_group_bitmask = kName | kAddress; - const uint32_t group_bitmask = DetermineGroups(field_types); + const uint32_t group_bitmask = data_util::DetermineGroups(field_types); EXPECT_EQ(expected_group_bitmask, group_bitmask); } @@ -39,7 +40,7 @@ ADDRESS_BILLING_STATE, ADDRESS_BILLING_ZIP}; const uint32_t expected_group_bitmask = kName | kAddress; - const uint32_t group_bitmask = DetermineGroups(field_types); + const uint32_t group_bitmask = data_util::DetermineGroups(field_types); EXPECT_EQ(expected_group_bitmask, group_bitmask); } @@ -48,7 +49,7 @@ NAME_FULL, PHONE_HOME_CITY_AND_NUMBER, EMAIL_ADDRESS}; const uint32_t expected_group_bitmask = kName | kPhone | kEmail; - const uint32_t group_bitmask = DetermineGroups(field_types); + const uint32_t group_bitmask = data_util::DetermineGroups(field_types); EXPECT_EQ(expected_group_bitmask, group_bitmask); } @@ -57,7 +58,7 @@ NAME_BILLING_FULL, PHONE_BILLING_WHOLE_NUMBER, EMAIL_ADDRESS}; const uint32_t expected_group_bitmask = kName | kPhone | kEmail; - const uint32_t group_bitmask = DetermineGroups(field_types); + const uint32_t group_bitmask = data_util::DetermineGroups(field_types); EXPECT_EQ(expected_group_bitmask, group_bitmask); } @@ -66,7 +67,7 @@ ADDRESS_HOME_ZIP}; const uint32_t expected_group_bitmask = kName | kAddress; - const uint32_t group_bitmask = DetermineGroups(field_types); + const uint32_t group_bitmask = data_util::DetermineGroups(field_types); EXPECT_EQ(expected_group_bitmask, group_bitmask); } @@ -74,7 +75,7 @@ const std::vector<ServerFieldType> field_types = std::vector<ServerFieldType>(); const uint32_t expected_group_bitmask = 0; - const uint32_t group_bitmask = DetermineGroups(field_types); + const uint32_t group_bitmask = data_util::DetermineGroups(field_types); EXPECT_EQ(expected_group_bitmask, group_bitmask); }
diff --git a/components/autofill/core/browser/metrics/address_form_event_logger.cc b/components/autofill/core/browser/metrics/address_form_event_logger.cc index 06674d12..129918d6 100644 --- a/components/autofill/core/browser/metrics/address_form_event_logger.cc +++ b/components/autofill/core/browser/metrics/address_form_event_logger.cc
@@ -4,14 +4,47 @@ #include "components/autofill/core/browser/metrics/address_form_event_logger.h" +#include <algorithm> +#include <iterator> +#include <memory> +#include <vector> + +#include "base/metrics/histogram_functions.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" -#include "components/autofill/core/browser/autofill_data_model.h" -#include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/autofill_profile.h" -#include "components/autofill/core/browser/metrics/form_events.h" +#include "components/autofill/core/browser/autofill_data_util.h" +#include "components/autofill/core/browser/autofill_type.h" +#include "components/autofill/core/browser/field_types.h" namespace autofill { +namespace { + +using data_util::bit_field_type_groups::kAddress; +using data_util::bit_field_type_groups::kEmail; +using data_util::bit_field_type_groups::kName; +using data_util::bit_field_type_groups::kPhone; + +// Returns the histogram suffix corresponding to the given |bitmask|. +std::string GetSuffixForFormType(uint32_t bitmask) { + switch (bitmask) { + case kName | kAddress | kEmail | kPhone: + return ".AddressPlusEmailPlusPhone"; + case kName | kAddress | kPhone: + return ".AddressPlusPhone"; + case kName | kAddress | kEmail: + return ".AddressPlusEmail"; + case kName | kAddress: + return ".AddressOnly"; + case kName | kEmail | kPhone: + case kName | kEmail: + case kName | kPhone: + return ".ContactOnly"; + default: + return ".Other"; + } +} + +} // namespace AddressFormEventLogger::AddressFormEventLogger( bool is_in_main_frame, @@ -74,6 +107,26 @@ Log(FORM_EVENT_DYNAMIC_CHANGE_AFTER_REFILL, form); } +void AddressFormEventLogger::OnLog(const std::string& name, + FormEvent event, + const FormStructure& form) const { + std::vector<ServerFieldType> types; + std::transform( + form.begin(), form.end(), std::back_inserter(types), + [&](const std::unique_ptr<AutofillField>& field) -> ServerFieldType { + return field->Type().GetStorableType(); + }); + + uint32_t groups = data_util::DetermineGroups(types); + base::UmaHistogramEnumeration(name + GetSuffixForFormType(groups), event, + NUM_FORM_EVENTS); + if (data_util::ContainsName(groups) && data_util::ContainsAddress(groups) && + (data_util::ContainsPhone(groups) || data_util::ContainsEmail(groups))) { + base::UmaHistogramEnumeration(name + ".AddressPlusContact", event, + NUM_FORM_EVENTS); + } +} + void AddressFormEventLogger::RecordPollSuggestions() { base::RecordAction( base::UserMetricsAction("Autofill_PolledProfileSuggestions"));
diff --git a/components/autofill/core/browser/metrics/address_form_event_logger.h b/components/autofill/core/browser/metrics/address_form_event_logger.h index a115ffb..52d467d 100644 --- a/components/autofill/core/browser/metrics/address_form_event_logger.h +++ b/components/autofill/core/browser/metrics/address_form_event_logger.h
@@ -5,10 +5,15 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_ADDRESS_FORM_EVENT_LOGGER_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_ADDRESS_FORM_EVENT_LOGGER_H_ -#include "components/autofill/core/browser/autofill_data_model.h" +#include <string> + +#include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_metrics.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/metrics/form_event_logger_base.h" #include "components/autofill/core/browser/metrics/form_events.h" +#include "components/autofill/core/browser/sync_utils.h" namespace autofill { @@ -38,6 +43,9 @@ void RecordPollSuggestions() override; void RecordParseForm() override; void RecordShowSuggestions() override; + void OnLog(const std::string& name, + FormEvent event, + const FormStructure& form) const override; }; } // namespace autofill
diff --git a/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc b/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc index ea19e73..03aea4f 100644 --- a/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc +++ b/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc
@@ -9,13 +9,8 @@ #include "base/metrics/histogram_functions.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" -#include "components/autofill/core/browser/autofill_client.h" -#include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/credit_card.h" +#include "base/strings/string16.h" #include "components/autofill/core/browser/form_data_importer.h" -#include "components/autofill/core/browser/form_structure.h" -#include "components/autofill/core/browser/metrics/form_events.h" -#include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/validation.h" namespace autofill { @@ -155,7 +150,8 @@ } void CreditCardFormEventLogger::OnLog(const std::string& name, - FormEvent event) const { + FormEvent event, + const FormStructure& form) const { // Log in a different histogram for credit card forms on nonsecure pages so // that form interactions on nonsecure pages can be analyzed on their own. if (!is_context_secure_) {
diff --git a/components/autofill/core/browser/metrics/credit_card_form_event_logger.h b/components/autofill/core/browser/metrics/credit_card_form_event_logger.h index 67a1632..05c64a9 100644 --- a/components/autofill/core/browser/metrics/credit_card_form_event_logger.h +++ b/components/autofill/core/browser/metrics/credit_card_form_event_logger.h
@@ -8,12 +8,15 @@ #include <string> #include "components/autofill/core/browser/autofill_client.h" -#include "components/autofill/core/browser/autofill_data_model.h" +#include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/metrics/form_event_logger_base.h" #include "components/autofill/core/browser/metrics/form_events.h" #include "components/autofill/core/browser/personal_data_manager.h" +#include "components/autofill/core/browser/sync_utils.h" +#include "components/autofill/core/common/signatures_util.h" namespace autofill { @@ -67,7 +70,9 @@ void LogUkmInteractedWithForm(FormSignature form_signature) override; void OnSuggestionsShownOnce() override; void OnSuggestionsShownSubmittedOnce(const FormStructure& form) override; - void OnLog(const std::string& name, FormEvent event) const override; + void OnLog(const std::string& name, + FormEvent event, + const FormStructure& form) const override; // Bringing base class' Log function into scope to allow overloading. using FormEventLoggerBase::Log;
diff --git a/components/autofill/core/browser/metrics/form_event_logger_base.cc b/components/autofill/core/browser/metrics/form_event_logger_base.cc index 99025b5..7a7edfc 100644 --- a/components/autofill/core/browser/metrics/form_event_logger_base.cc +++ b/components/autofill/core/browser/metrics/form_event_logger_base.cc
@@ -4,22 +4,10 @@ #include "components/autofill/core/browser/metrics/form_event_logger_base.h" -#include <string> - #include "base/metrics/histogram_functions.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "base/time/time.h" -#include "components/autofill/core/browser/autofill_data_model.h" -#include "components/autofill/core/browser/autofill_field.h" -#include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/autofill_profile.h" -#include "components/autofill/core/browser/credit_card.h" -#include "components/autofill/core/browser/form_structure.h" -#include "components/autofill/core/browser/metrics/form_events.h" -#include "components/autofill/core/browser/sync_utils.h" -#include "components/autofill/core/common/form_field_data.h" -#include "components/autofill/core/common/signatures_util.h" namespace autofill { @@ -151,8 +139,8 @@ name + (is_in_main_frame_ ? ".IsInMainFrame" : ".IsInIFrame"), event, NUM_FORM_EVENTS); - // Allow specialized type of logging. - OnLog(name, event); + // Allow specialized types of logging, e.g. splitting metrics in useful ways. + OnLog(name, event, form); // Logging again in a different histogram for segmentation purposes. if (server_record_type_count_ == 0 && local_record_type_count_ == 0)
diff --git a/components/autofill/core/browser/metrics/form_event_logger_base.h b/components/autofill/core/browser/metrics/form_event_logger_base.h index 173df3b..f07e6950 100644 --- a/components/autofill/core/browser/metrics/form_event_logger_base.h +++ b/components/autofill/core/browser/metrics/form_event_logger_base.h
@@ -7,15 +7,13 @@ #include <string> -#include "components/autofill/core/browser/autofill_data_model.h" #include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/autofill_profile.h" -#include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/metrics/form_events.h" #include "components/autofill/core/browser/sync_utils.h" #include "components/autofill/core/common/form_field_data.h" +#include "components/autofill/core/common/signatures_util.h" namespace autofill { @@ -77,7 +75,14 @@ virtual void OnSuggestionsShownOnce() {} virtual void OnSuggestionsShownSubmittedOnce(const FormStructure& form) {} - virtual void OnLog(const std::string& name, FormEvent event) const {} + + // Logs |event| in a histogram prefixed with |name| according to the + // FormEventLogger type and |form|. For example, in the address context, it + // may be useful to analyze metrics for forms (A) with only name and address + // fields and (B) with only name and phone fields separately. + virtual void OnLog(const std::string& name, + FormEvent event, + const FormStructure& form) const {} // Constructor parameters. std::string form_type_name_;
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc index 21c247d..e4795380 100644 --- a/components/autofill/core/browser/personal_data_manager.cc +++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -28,6 +28,7 @@ #include "components/autofill/core/browser/address_i18n.h" #include "components/autofill/core/browser/autofill-inl.h" #include "components/autofill/core/browser/autofill_country.h" +#include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/autofill_download_manager.h" #include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_field.h" @@ -1187,7 +1188,7 @@ } suggestion_selection::PrepareSuggestions( - formatter && ContainsAddress(formatter->groups()), labels, + formatter && data_util::ContainsAddress(formatter->groups()), labels, &unique_suggestions); return unique_suggestions; }
diff --git a/components/captive_portal/captive_portal_testing_utils.cc b/components/captive_portal/captive_portal_testing_utils.cc index 60b88454..52b4536 100644 --- a/components/captive_portal/captive_portal_testing_utils.cc +++ b/components/captive_portal/captive_portal_testing_utils.cc
@@ -6,6 +6,7 @@ #include "base/logging.h" #include "base/memory/ref_counted.h" +#include "base/strings/string_piece.h" #include "net/base/net_errors.h" #include "net/http/http_response_headers.h" #include "net/http/http_util.h" @@ -13,10 +14,9 @@ namespace { scoped_refptr<net::HttpResponseHeaders> CreateResponseHeaders( - const std::string& response_headers) { - std::string raw_headers = net::HttpUtil::AssembleRawHeaders( - response_headers.c_str(), static_cast<int>(response_headers.length())); - return new net::HttpResponseHeaders(raw_headers); + base::StringPiece response_headers) { + std::string raw_headers = net::HttpUtil::AssembleRawHeaders(response_headers); + return base::MakeRefCounted<net::HttpResponseHeaders>(raw_headers); } } // namespace
diff --git a/components/cronet/native/test/url_request_test.cc b/components/cronet/native/test/url_request_test.cc index 49b9a4c..043371b1 100644 --- a/components/cronet/native/test/url_request_test.cc +++ b/components/cronet/native/test/url_request_test.cc
@@ -120,7 +120,7 @@ Cronet_RequestFinishedInfoListener_Destroy(request_finished_listener_); } - void SetUp() override { cronet::TestServer::Start(); } + void SetUp() override { EXPECT_TRUE(cronet::TestServer::Start()); } void TearDown() override { cronet::TestServer::Shutdown(); }
diff --git a/components/cronet/stale_host_resolver.cc b/components/cronet/stale_host_resolver.cc index e2ccbaa1..06ce3ae31 100644 --- a/components/cronet/stale_host_resolver.cc +++ b/components/cronet/stale_host_resolver.cc
@@ -463,6 +463,10 @@ secure_out); } +void StaleHostResolver::SetDnsClientEnabled(bool enabled) { + inner_resolver_->SetDnsClientEnabled(enabled); +} + net::HostCache* StaleHostResolver::GetHostCache() { return inner_resolver_->GetHostCache(); }
diff --git a/components/cronet/stale_host_resolver.h b/components/cronet/stale_host_resolver.h index fa122002..b54d1008 100644 --- a/components/cronet/stale_host_resolver.h +++ b/components/cronet/stale_host_resolver.h
@@ -84,6 +84,7 @@ // The remaining public methods pass through to the inner resolver: + void SetDnsClientEnabled(bool enabled) override; net::HostCache* GetHostCache() override; bool HasCached(base::StringPiece hostname, net::HostCache::Entry::Source* source_out,
diff --git a/components/cronet/stale_host_resolver_unittest.cc b/components/cronet/stale_host_resolver_unittest.cc index 72090e4..8287e14 100644 --- a/components/cronet/stale_host_resolver_unittest.cc +++ b/components/cronet/stale_host_resolver_unittest.cc
@@ -35,7 +35,6 @@ #include "net/dns/dns_hosts.h" #include "net/dns/dns_test_util.h" #include "net/dns/host_cache.h" -#include "net/dns/host_resolver_manager.h" #include "net/dns/host_resolver_proc.h" #include "net/dns/public/dns_protocol.h" #include "net/http/http_network_session.h" @@ -181,12 +180,7 @@ net::ProcTaskParams proc_params(mock_proc_.get(), 1u); inner_resolver->SetProcParamsForTesting(proc_params); - if (dns_client) { - inner_resolver->GetManagerForTesting()->SetDnsClientForTesting( - std::move(dns_client)); - } else { - inner_resolver->GetManagerForTesting()->SetDnsClientEnabled(false); - } + inner_resolver->SetDnsClientForTesting(std::move(dns_client)); return inner_resolver; }
diff --git a/components/cronet/url_request_context_config.cc b/components/cronet/url_request_context_config.cc index bcfc2be..aebd97a 100644 --- a/components/cronet/url_request_context_config.cc +++ b/components/cronet/url_request_context_config.cc
@@ -672,22 +672,20 @@ disable_ipv6_on_wifi) { CHECK(net_log) << "All DNS-related experiments require NetLog."; std::unique_ptr<net::HostResolver> host_resolver; - net::HostResolver::ManagerOptions host_resolver_manager_options; - host_resolver_manager_options.dns_client_enabled = async_dns_enable; // TODO(crbug.com/934402): Consider using a shared HostResolverManager for // Cronet HostResolvers. if (stale_dns_enable) { DCHECK(!disable_ipv6_on_wifi); host_resolver.reset(new StaleHostResolver( - net::HostResolver::CreateStandaloneContextResolver( - net_log, std::move(host_resolver_manager_options)), + net::HostResolver::CreateStandaloneContextResolver(net_log), stale_dns_options)); } else { - host_resolver = net::HostResolver::CreateStandaloneResolver( - net_log, std::move(host_resolver_manager_options)); + host_resolver = net::HostResolver::CreateStandaloneResolver(net_log); } if (disable_ipv6_on_wifi) host_resolver->SetNoIPv6OnWifi(true); + if (async_dns_enable) + host_resolver->SetDnsClientEnabled(true); if (host_resolver_rules_enable) { std::unique_ptr<net::MappedHostResolver> remapped_resolver( new net::MappedHostResolver(std::move(host_resolver)));
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc index c38b9c9..5aa2e50 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
@@ -678,8 +678,8 @@ EXPECT_EQ(request->GetTotalReceivedBytes(), total_received_bytes() - baseline_received_bytes); - const std::string raw_headers = net::HttpUtil::AssembleRawHeaders( - test.DrpResponseHeaders.c_str(), test.DrpResponseHeaders.size()); + const std::string raw_headers = + net::HttpUtil::AssembleRawHeaders(test.DrpResponseHeaders); EXPECT_EQ( static_cast<int64_t>(raw_headers.size() + 10000 /* original_response_body */), @@ -749,8 +749,8 @@ EXPECT_EQ(request->GetTotalReceivedBytes(), total_received_bytes() - baseline_received_bytes); - const std::string raw_headers = net::HttpUtil::AssembleRawHeaders( - test.DrpResponseHeaders.c_str(), test.DrpResponseHeaders.size()); + const std::string raw_headers = + net::HttpUtil::AssembleRawHeaders(test.DrpResponseHeaders); EXPECT_EQ( static_cast<int64_t>(raw_headers.size() + 10000 /* original_response_body */), @@ -908,9 +908,7 @@ base::RunLoop().RunUntilIdle(); int64_t expected_original_size = - net::HttpUtil::AssembleRawHeaders(test.response_headers.data(), - test.response_headers.size()) - .size() + + net::HttpUtil::AssembleRawHeaders(test.response_headers).size() + test.expected_original_content_length; EXPECT_EQ(request->GetTotalReceivedBytes(),
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc index 82a6bfa..2d65f55 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -1860,11 +1860,10 @@ // Since the Data Reduction Proxy is enabled, the length of the raw headers // should be used in the estimated original size. The X-OCL should be ignored. - EXPECT_EQ(static_cast<int64_t>(net::HttpUtil::AssembleRawHeaders( - kHeaders, sizeof(kHeaders) - 1) - .size() + - 10000 - request->GetTotalReceivedBytes()), - GetSavings()); + EXPECT_EQ( + static_cast<int64_t>(net::HttpUtil::AssembleRawHeaders(kHeaders).size() + + 10000 - request->GetTotalReceivedBytes()), + GetSavings()); } TEST_F(DataReductionProxyNetworkDelegateTest, TestAcceptTransformHistogram) {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc index 50822b1..ee29998a 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
@@ -180,8 +180,9 @@ network::ResourceResponseHead resource_response_head; std::string headers(test_case.response_headers); - resource_response_head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + resource_response_head.headers = + base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); test_url_loader_factory.SimulateResponseWithoutRemovingFromPendingList( test_url_loader_factory.GetPendingRequest(0), resource_response_head, test_case.response_body,
diff --git a/components/domain_reliability/monitor_unittest.cc b/components/domain_reliability/monitor_unittest.cc index cf32e1d7..92a216d 100644 --- a/components/domain_reliability/monitor_unittest.cc +++ b/components/domain_reliability/monitor_unittest.cc
@@ -13,6 +13,7 @@ #include <vector> #include "base/bind.h" +#include "base/strings/string_piece.h" #include "base/test/test_simple_task_runner.h" #include "components/domain_reliability/baked_in_configs.h" #include "components/domain_reliability/beacon.h" @@ -34,10 +35,9 @@ typedef std::vector<const DomainReliabilityBeacon*> BeaconVector; scoped_refptr<net::HttpResponseHeaders> MakeHttpResponseHeaders( - const std::string& headers) { - return scoped_refptr<net::HttpResponseHeaders>( - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - headers.c_str(), headers.length()))); + base::StringPiece headers) { + return base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); } size_t CountQueuedBeacons(DomainReliabilityContext* context) {
diff --git a/components/domain_reliability/uploader_unittest.cc b/components/domain_reliability/uploader_unittest.cc index 60f9491..374f2fe 100644 --- a/components/domain_reliability/uploader_unittest.cc +++ b/components/domain_reliability/uploader_unittest.cc
@@ -134,8 +134,8 @@ void ExpectRequestAndReturnResponseHeaders(const char* headers) { MockUploadResult result; result.net_error = net::OK; - result.response_headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers, strlen(headers))); + result.response_headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); results_.push_back(result); }
diff --git a/components/feedback/feedback_uploader_dispatch_unittest.cc b/components/feedback/feedback_uploader_dispatch_unittest.cc index 00977f6..ab1a8b0e 100644 --- a/components/feedback/feedback_uploader_dispatch_unittest.cc +++ b/components/feedback/feedback_uploader_dispatch_unittest.cc
@@ -119,7 +119,7 @@ network::ResourceResponseHead head; std::string headers("HTTP/1.1 204 No Content\n\n"); head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + net::HttpUtil::AssembleRawHeaders(headers)); network::URLLoaderCompletionStatus status; test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl), head, "", status); @@ -142,7 +142,7 @@ network::ResourceResponseHead head; std::string headers("HTTP/1.1 400 Bad Request\n\n"); head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + net::HttpUtil::AssembleRawHeaders(headers)); network::URLLoaderCompletionStatus status; test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl), head, "", status); @@ -164,7 +164,7 @@ network::ResourceResponseHead head; std::string headers("HTTP/1.1 500 Server Error\n\n"); head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + net::HttpUtil::AssembleRawHeaders(headers)); network::URLLoaderCompletionStatus status; test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl), head, "", status);
diff --git a/components/image_fetcher/core/image_data_fetcher_unittest.cc b/components/image_fetcher/core/image_data_fetcher_unittest.cc index 1af0ccc..26581ae 100644 --- a/components/image_fetcher/core/image_data_fetcher_unittest.cc +++ b/components/image_fetcher/core/image_data_fetcher_unittest.cc
@@ -88,8 +88,8 @@ std::string raw_header = "HTTP/1.1 200 OK\n" "Content-type: image/png\n\n"; - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(raw_header.c_str(), raw_header.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_header)); head.mime_type = "image/png"; network::URLLoaderCompletionStatus status; status.decoded_body_length = content.size(); @@ -121,8 +121,8 @@ std::string raw_header = "HTTP/1.1 200 OK\n" "Content-type: image/png\n\n"; - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(raw_header.c_str(), raw_header.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_header)); head.mime_type = "image/png"; network::URLLoaderCompletionStatus status; status.decoded_body_length = content.size(); @@ -152,8 +152,8 @@ std::string raw_header = "HTTP/1.1 404 Not Found\n" "Content-type: image/png\n\n"; - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(raw_header.c_str(), raw_header.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_header)); head.mime_type = "image/png"; network::URLLoaderCompletionStatus status; status.decoded_body_length = content.size(); @@ -185,8 +185,8 @@ "HTTP/1.1 404 Not Found\n" "Content-type: image/png\n" "Content-location: http://test-location/image.png\n\n"; - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(raw_header.c_str(), raw_header.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_header)); head.mime_type = "image/png"; network::URLLoaderCompletionStatus status; status.decoded_body_length = content.size();
diff --git a/components/journey/journey_info_fetcher_unittest.cc b/components/journey/journey_info_fetcher_unittest.cc index 00d21495..773cc7793 100644 --- a/components/journey/journey_info_fetcher_unittest.cc +++ b/components/journey/journey_info_fetcher_unittest.cc
@@ -110,7 +110,7 @@ "HTTP/1.1 %d %s\nContent-type: application/json\n\n", static_cast<int>(response_code), GetHttpReasonPhrase(response_code))); head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + net::HttpUtil::AssembleRawHeaders(headers)); head.mime_type = "application/json"; network::URLLoaderCompletionStatus status(error); status.decoded_body_length = response_data.size();
diff --git a/components/network_session_configurator/browser/network_session_configurator.cc b/components/network_session_configurator/browser/network_session_configurator.cc index e9d0aac..3b00fa2f 100644 --- a/components/network_session_configurator/browser/network_session_configurator.cc +++ b/components/network_session_configurator/browser/network_session_configurator.cc
@@ -399,6 +399,18 @@ GetVariationParam(quic_trial_params, "allow_server_migration"), "true"); } +int GetQuicInitialRttForHandshakeMilliseconds( + const VariationParameters& quic_trial_params) { + int value; + if (base::StringToInt( + GetVariationParam(quic_trial_params, + "initial_rtt_for_handshake_milliseconds"), + &value)) { + return value; + } + return 0; +} + base::flat_set<std::string> GetQuicHostWhitelist( const VariationParameters& quic_trial_params) { std::string host_whitelist = @@ -500,6 +512,12 @@ ShouldQuicRetryOnAlternateNetworkBeforeHandshake(quic_trial_params); params->quic_go_away_on_path_degrading = ShouldQuicGoawayOnPathDegrading(quic_trial_params); + int initial_rtt_for_handshake_milliseconds = + GetQuicInitialRttForHandshakeMilliseconds(quic_trial_params); + if (initial_rtt_for_handshake_milliseconds > 0) { + params->quic_initial_rtt_for_handshake_milliseconds = + initial_rtt_for_handshake_milliseconds; + } int retransmittable_on_wire_timeout_milliseconds = GetQuicRetransmittableOnWireTimeoutMilliseconds(quic_trial_params); if (retransmittable_on_wire_timeout_milliseconds > 0) {
diff --git a/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/components/network_session_configurator/browser/network_session_configurator_unittest.cc index 1cd82bd..002628a 100644 --- a/components/network_session_configurator/browser/network_session_configurator_unittest.cc +++ b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -124,6 +124,7 @@ EXPECT_FALSE(params_.quic_retry_on_alternate_network_before_handshake); EXPECT_FALSE(params_.quic_migrate_idle_sessions); EXPECT_FALSE(params_.quic_go_away_on_path_degrading); + EXPECT_EQ(0, params_.quic_initial_rtt_for_handshake_milliseconds); EXPECT_FALSE(params_.quic_allow_server_migration); EXPECT_TRUE(params_.quic_host_whitelist.empty()); EXPECT_EQ(net::kDefaultRetransmittableOnWireTimeoutMillisecs, @@ -839,4 +840,16 @@ EXPECT_TRUE(params_.enable_websocket_over_http2); } +TEST_F(NetworkSessionConfiguratorTest, + QuicInitialRttForHandshakeFromFieldTrailParams) { + std::map<std::string, std::string> field_trial_params; + field_trial_params["initial_rtt_for_handshake_milliseconds"] = "500"; + variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params); + base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled"); + + ParseFieldTrials(); + + EXPECT_EQ(500, params_.quic_initial_rtt_for_handshake_milliseconds); +} + } // namespace network_session_configurator
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc index f0a0e56..121b464 100644 --- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc +++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
@@ -248,8 +248,8 @@ std::string headers(base::StringPrintf( "HTTP/1.1 %d %s\nContent-type: application/json\n\n", static_cast<int>(response_code), GetHttpReasonPhrase(response_code))); - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); head.mime_type = "application/json"; network::URLLoaderCompletionStatus status(error); status.decoded_body_length = response_data.size();
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc index c1a9f48..fad316fc 100644 --- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc +++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
@@ -125,9 +125,7 @@ task_queue_.AddTask( std::make_unique<StaleEntryFinalizerTask>(this, prefetch_store)); - // Second, move FINISHED to ZOMBIE. This also just needs to run regularly to - // report various prefetch item metrics. Note that we're not running this in - // the background task due to crbug.com/944615. + // Second, move FINISHED to ZOMBIE. task_queue_.AddTask( std::make_unique<MetricsFinalizationTask>(prefetch_store)); @@ -216,6 +214,13 @@ task_queue_.AddTask(std::make_unique<ImportCleanupTask>( service_->GetPrefetchStore(), service_->GetPrefetchImporter())); + + // This task should be last, because it is least important for correct + // operation of the system, and because any reconciliation tasks might + // generate more entries in the FINISHED state that the finalization task + // could pick up. + task_queue_.AddTask( + std::make_unique<MetricsFinalizationTask>(service_->GetPrefetchStore())); } void PrefetchDispatcherImpl::QueueActionTasks() {
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc index 30df732..2007a27 100644 --- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc +++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
@@ -425,13 +425,6 @@ PrefetchService* prefetch_service() { return taco_->prefetch_service(); } TestDownloadService* download_service() { return taco_->download_service(); } - // Asserts that there exists a single item in the database, and returns it. - PrefetchItem GetSingleItem() { - std::set<PrefetchItem> items; - EXPECT_EQ(1ul, store_util_.GetAllItems(&items)); - return *items.begin(); - } - protected: // Owned by |taco_|. MockOfflinePageModel* offline_model_; @@ -979,6 +972,11 @@ TEST_F(PrefetchDispatcherTest, ZinePrefetchItemFlow) { Configure(PrefetchServiceTestTaco::kContentSuggestions); + auto get_item = [&]() { + std::set<PrefetchItem> items; + EXPECT_EQ(1ul, store_util_.GetAllItems(&items)); + return *items.begin(); + }; // The page should be added to the offline model. Return success through the // callback, and store the page to added_page. OfflinePageItem added_page; @@ -1002,17 +1000,13 @@ // Run the pipeline to completion. RunUntilIdle(); - PrefetchItem state1 = GetSingleItem(); + PrefetchItem state1 = get_item(); BeginBackgroundTask(); RunUntilIdle(); - PrefetchItem state2 = GetSingleItem(); + PrefetchItem state2 = get_item(); BeginBackgroundTask(); RunUntilIdle(); - PrefetchItem state3 = GetSingleItem(); - // Trigger MetricsFinalizationTask. - dispatcher()->AddCandidatePrefetchURLs(kSuggestedArticlesNamespace, {}); - RunUntilIdle(); - PrefetchItem state4 = GetSingleItem(); + PrefetchItem state3 = get_item(); // Check progression of item state. Log the states to help explain any failed // expectations. @@ -1033,11 +1027,8 @@ EXPECT_EQ(kBodyLength, state2.file_size); // State 3. - EXPECT_EQ(PrefetchItemState::FINISHED, state3.state); + EXPECT_EQ(PrefetchItemState::ZOMBIE, state3.state); EXPECT_EQ(PrefetchItemErrorCode::SUCCESS, state3.error_code); - - // State 4. - EXPECT_EQ(PrefetchItemState::ZOMBIE, state4.state); } // This is the same as PrefetchItemFlow, but with the Feed configuration. @@ -1066,21 +1057,16 @@ RunUntilIdle(); BeginBackgroundTask(); RunUntilIdle(); - const PrefetchItem item_state_1 = GetSingleItem(); - dispatcher()->AddCandidatePrefetchURLs(kSuggestedArticlesNamespace, {}); - RunUntilIdle(); - const PrefetchItem item_state_2 = GetSingleItem(); + std::set<PrefetchItem> items; + store_util_.GetAllItems(&items); + EXPECT_EQ(1ul, items.size()); + const PrefetchItem item = *items.begin(); - // State 1. - EXPECT_EQ(PrefetchItemState::FINISHED, item_state_1.state); - - // State 2. - EXPECT_EQ(base::UTF8ToUTF16(TestSuggestion1().article_title), - item_state_2.title); - EXPECT_EQ(TestSuggestion1().article_url, item_state_2.url); - EXPECT_EQ(PrefetchItemState::ZOMBIE, item_state_2.state); - EXPECT_EQ(PrefetchItemErrorCode::SUCCESS, item_state_2.error_code); + EXPECT_EQ(base::UTF8ToUTF16(TestSuggestion1().article_title), item.title); + EXPECT_EQ(TestSuggestion1().article_url, item.url); + EXPECT_EQ(PrefetchItemState::ZOMBIE, item.state); + EXPECT_EQ(PrefetchItemErrorCode::SUCCESS, item.error_code); } } // namespace offline_pages
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc index 93a39e0..26f8b78 100644 --- a/components/payments/content/payment_request_state.cc +++ b/components/payments/content/payment_request_state.cc
@@ -304,6 +304,12 @@ selected_shipping_profile_, selected_contact_profile_, this); } +void PaymentRequestState::OnPaymentAppWindowClosed() { + DCHECK(selected_instrument_); + response_helper_.reset(); + selected_instrument_->OnPaymentAppWindowClosed(); +} + void PaymentRequestState::RecordUseStats() { if (spec_->request_shipping()) { DCHECK(selected_shipping_profile_);
diff --git a/components/payments/content/payment_request_state.h b/components/payments/content/payment_request_state.h index 60c83e81..75aaec2 100644 --- a/components/payments/content/payment_request_state.h +++ b/components/payments/content/payment_request_state.h
@@ -126,6 +126,9 @@ // |is_ready_to_pay|, which is inexpensive. void GeneratePaymentResponse(); + // Cancels the generation of the PaymentResponse. + void OnPaymentAppWindowClosed(); + // Record the use of the data models that were used in the Payment Request. void RecordUseStats();
diff --git a/components/payments/content/service_worker_payment_instrument.cc b/components/payments/content/service_worker_payment_instrument.cc index d9315c3..1c08822 100644 --- a/components/payments/content/service_worker_payment_instrument.cc +++ b/components/payments/content/service_worker_payment_instrument.cc
@@ -244,6 +244,10 @@ payment_request_delegate_->ShowProcessingSpinner(); } +void ServiceWorkerPaymentInstrument::OnPaymentAppWindowClosed() { + delegate_ = nullptr; +} + mojom::PaymentRequestEventDataPtr ServiceWorkerPaymentInstrument::CreatePaymentRequestEventData() { mojom::PaymentRequestEventDataPtr event_data = @@ -283,8 +287,6 @@ void ServiceWorkerPaymentInstrument::OnPaymentAppInvoked( mojom::PaymentHandlerResponsePtr response) { - DCHECK(delegate_); - if (delegate_ != nullptr) { delegate_->OnInstrumentDetailsReady(response->method_name, response->stringified_details);
diff --git a/components/payments/content/service_worker_payment_instrument.h b/components/payments/content/service_worker_payment_instrument.h index 248b1964..7dbb9e47 100644 --- a/components/payments/content/service_worker_payment_instrument.h +++ b/components/payments/content/service_worker_payment_instrument.h
@@ -62,6 +62,7 @@ // PaymentInstrument: void InvokePaymentApp(Delegate* delegate) override; + void OnPaymentAppWindowClosed() override; bool IsCompleteForPayment() const override; bool IsExactlyMatchingMerchantRequest() const override; base::string16 GetMissingInfoLabel() const override;
diff --git a/components/payments/core/payment_instrument.h b/components/payments/core/payment_instrument.h index abe2ec5..d2a6863f 100644 --- a/components/payments/core/payment_instrument.h +++ b/components/payments/core/payment_instrument.h
@@ -40,6 +40,8 @@ // Will call into the |delegate| (can't be null) on success or error. virtual void InvokePaymentApp(Delegate* delegate) = 0; + // Called when the payment app window has closed. + virtual void OnPaymentAppWindowClosed() {} // Returns whether the instrument is complete to be used as a payment method // without further editing. virtual bool IsCompleteForPayment() const = 0;
diff --git a/components/rappor/log_uploader_unittest.cc b/components/rappor/log_uploader_unittest.cc index ab761a88..f8a53754 100644 --- a/components/rappor/log_uploader_unittest.cc +++ b/components/rappor/log_uploader_unittest.cc
@@ -93,7 +93,7 @@ network::ResourceResponseHead response_head; std::string headers("HTTP/1.1 400 Bad Request\nContent-type: text/html\n\n"); response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + net::HttpUtil::AssembleRawHeaders(headers)); response_head.mime_type = "text/html"; test_url_loader_factory_.AddResponse(GURL(kTestServerURL), response_head, "", network::URLLoaderCompletionStatus()); @@ -111,7 +111,7 @@ std::string headers( "HTTP/1.1 500 Internal Server Error\nContent-type: text/html\n\n"); response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + net::HttpUtil::AssembleRawHeaders(headers)); response_head.mime_type = "text/html"; test_url_loader_factory_.AddResponse(GURL(kTestServerURL), response_head, "", network::URLLoaderCompletionStatus());
diff --git a/components/safe_browsing/db/v4_local_database_manager.cc b/components/safe_browsing/db/v4_local_database_manager.cc index 7f46112..a42a052 100644 --- a/components/safe_browsing/db/v4_local_database_manager.cc +++ b/components/safe_browsing/db/v4_local_database_manager.cc
@@ -33,6 +33,9 @@ using CommandLineSwitchAndThreatType = std::pair<std::string, ThreatType>; +// The expiration time of the full hash stored in the artificial database. +const int64_t kFullHashExpiryTimeInMinutes = 60; + const ThreatSeverity kLeastSeverity = std::numeric_limits<ThreatSeverity>::max(); @@ -622,7 +625,7 @@ artificial_store_and_hash_prefix.hash_prefix; DCHECK_EQ(crypto::kSHA256Length, artificial_full_hash.size()); if (artificial_full_hash == full_hash) { - (check->full_hash_to_store_and_hash_prefixes)[full_hash] = { + (check->artificial_full_hash_to_store_and_hash_prefixes)[full_hash] = { artificial_store_and_hash_prefix}; } } @@ -733,9 +736,11 @@ GetPrefixMatches(check); GetArtificialPrefixMatches(check); - if (check->full_hash_to_store_and_hash_prefixes.empty()) { + if (check->full_hash_to_store_and_hash_prefixes.empty() && + check->artificial_full_hash_to_store_and_hash_prefixes.empty()) { return true; } + ScheduleFullHashCheck(std::move(check)); return false; } @@ -759,16 +764,38 @@ void V4LocalDatabaseManager::ScheduleFullHashCheck( std::unique_ptr<PendingCheck> check) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + // Add check to pending_checks_ before scheduling PerformFullHashCheck so that // even if the client calls CancelCheck before PerformFullHashCheck gets // called, the check can be found in pending_checks_. pending_checks_.insert(check.get()); - // Post on the IO thread to enforce async behavior. - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&V4LocalDatabaseManager::PerformFullHashCheck, - weak_factory_.GetWeakPtr(), std::move(check))); + // If the full hash matches one from the artificial list, don't send the + // request to the server. + if (!check->artificial_full_hash_to_store_and_hash_prefixes.empty()) { + std::vector<FullHashInfo> full_hash_infos; + for (const auto& entry : + check->artificial_full_hash_to_store_and_hash_prefixes) { + for (const auto& store_and_prefix : entry.second) { + ListIdentifier list_id = store_and_prefix.list_id; + base::Time next = base::Time::Now() + base::TimeDelta::FromMinutes( + kFullHashExpiryTimeInMinutes); + full_hash_infos.emplace_back(entry.first, list_id, next); + } + } + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&V4LocalDatabaseManager::OnFullHashResponse, + weak_factory_.GetWeakPtr(), std::move(check), + full_hash_infos)); + } else { + // Post on the IO thread to enforce async behavior. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&V4LocalDatabaseManager::PerformFullHashCheck, + weak_factory_.GetWeakPtr(), std::move(check))); + } } bool V4LocalDatabaseManager::HandleHashSynchronously(
diff --git a/components/safe_browsing/db/v4_local_database_manager.h b/components/safe_browsing/db/v4_local_database_manager.h index 78729402..0431b519 100644 --- a/components/safe_browsing/db/v4_local_database_manager.h +++ b/components/safe_browsing/db/v4_local_database_manager.h
@@ -181,6 +181,11 @@ // hash prefixes that match it in the local database. FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes; + // List of full hashes of urls we are checking and corresponding store and + // hash prefixes that match it in the artificial database. + FullHashToStoreAndHashPrefixesMap + artificial_full_hash_to_store_and_hash_prefixes; + // The metadata associated with the full hash of the severest match found // for that URL. ThreatMetadata url_metadata;
diff --git a/components/safe_browsing/db/v4_local_database_manager_unittest.cc b/components/safe_browsing/db/v4_local_database_manager_unittest.cc index 37961d88..539cba7a 100644 --- a/components/safe_browsing/db/v4_local_database_manager_unittest.cc +++ b/components/safe_browsing/db/v4_local_database_manager_unittest.cc
@@ -1138,7 +1138,7 @@ } TEST_F(V4LocalDatabaseManagerTest, FlagOneUrlAsPhishing) { - WaitForTasksOnTaskRunner(); + SetupFakeManager(); base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( "mark_as_phishing", "https://example.com/1/"); PopulateArtificialDatabase(); @@ -1146,16 +1146,20 @@ const GURL url_bad("https://example.com/1/"); EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl( url_bad, usual_threat_types_, nullptr)); + // PerformFullHashCheck will not be called if there is a match within the + // artificial database + EXPECT_FALSE(FakeV4LocalDatabaseManager::PerformFullHashCheckCalled( + v4_local_database_manager_)); + const GURL url_good("https://other.example.com"); EXPECT_TRUE(v4_local_database_manager_->CheckBrowseUrl( url_good, usual_threat_types_, nullptr)); - // Wait for PerformFullHashCheck to complete. - WaitForTasksOnTaskRunner(); + StopLocalDatabaseManager(); } TEST_F(V4LocalDatabaseManagerTest, FlagOneUrlAsMalware) { - WaitForTasksOnTaskRunner(); + SetupFakeManager(); base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( "mark_as_malware", "https://example.com/1/"); PopulateArtificialDatabase(); @@ -1163,16 +1167,20 @@ const GURL url_bad("https://example.com/1/"); EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl( url_bad, usual_threat_types_, nullptr)); + // PerformFullHashCheck will not be called if there is a match within the + // artificial database + EXPECT_FALSE(FakeV4LocalDatabaseManager::PerformFullHashCheckCalled( + v4_local_database_manager_)); + const GURL url_good("https://other.example.com"); EXPECT_TRUE(v4_local_database_manager_->CheckBrowseUrl( url_good, usual_threat_types_, nullptr)); - // Wait for PerformFullHashCheck to complete. - WaitForTasksOnTaskRunner(); + StopLocalDatabaseManager(); } TEST_F(V4LocalDatabaseManagerTest, FlagOneUrlAsUWS) { - WaitForTasksOnTaskRunner(); + SetupFakeManager(); base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( "mark_as_uws", "https://example.com/1/"); PopulateArtificialDatabase(); @@ -1180,16 +1188,20 @@ const GURL url_bad("https://example.com/1/"); EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl( url_bad, usual_threat_types_, nullptr)); + // PerformFullHashCheck will not be called if there is a match within the + // artificial database + EXPECT_FALSE(FakeV4LocalDatabaseManager::PerformFullHashCheckCalled( + v4_local_database_manager_)); + const GURL url_good("https://other.example.com"); EXPECT_TRUE(v4_local_database_manager_->CheckBrowseUrl( url_good, usual_threat_types_, nullptr)); - // Wait for PerformFullHashCheck to complete. - WaitForTasksOnTaskRunner(); + StopLocalDatabaseManager(); } TEST_F(V4LocalDatabaseManagerTest, FlagMultipleUrls) { - WaitForTasksOnTaskRunner(); + SetupFakeManager(); base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( "mark_as_phishing", "https://example.com/1/"); base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( @@ -1207,12 +1219,16 @@ const GURL url_uws("https://example.test.com"); EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl( url_uws, usual_threat_types_, nullptr)); + // PerformFullHashCheck will not be called if there is a match within the + // artificial database + EXPECT_FALSE(FakeV4LocalDatabaseManager::PerformFullHashCheckCalled( + v4_local_database_manager_)); + const GURL url_good("https://other.example.com"); EXPECT_TRUE(v4_local_database_manager_->CheckBrowseUrl( url_good, usual_threat_types_, nullptr)); - // Wait for PerformFullHashCheck to complete. - WaitForTasksOnTaskRunner(); + StopLocalDatabaseManager(); } } // namespace safe_browsing
diff --git a/components/search_provider_logos/logo_service_impl_unittest.cc b/components/search_provider_logos/logo_service_impl_unittest.cc index 19e4676..d22c695 100644 --- a/components/search_provider_logos/logo_service_impl_unittest.cc +++ b/components/search_provider_logos/logo_service_impl_unittest.cc
@@ -416,8 +416,8 @@ std::string headers(base::StringPrintf( "HTTP/1.1 %d %s\nContent-type: text/html\n\n", static_cast<int>(response_code), GetHttpReasonPhrase(response_code))); - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); head.mime_type = "text/html"; network::URLLoaderCompletionStatus status; status.error_code = error_code;
diff --git a/components/services/heap_profiling/connection_manager.cc b/components/services/heap_profiling/connection_manager.cc index 071c885..f2af464 100644 --- a/components/services/heap_profiling/connection_manager.cc +++ b/components/services/heap_profiling/connection_manager.cc
@@ -140,7 +140,7 @@ void ConnectionManager::ReportMetrics() { base::AutoLock lock(connections_lock_); for (auto& pair : connections_) { - UMA_HISTOGRAM_ENUMERATION("OutOfProcessHeapProfiling.ProfiledProcess.Type", + UMA_HISTOGRAM_ENUMERATION("HeapProfiling.ProfiledProcess.Type", pair.second->process_type, static_cast<int>(mojom::ProcessType::LAST) + 1); }
diff --git a/components/variations/service/variations_service_unittest.cc b/components/variations/service/variations_service_unittest.cc index b7cc43fa..ace3b64b 100644 --- a/components/variations/service/variations_service_unittest.cc +++ b/components/variations/service/variations_service_unittest.cc
@@ -557,8 +557,8 @@ std::string headers("HTTP/1.1 200 OK\n\n"); network::ResourceResponseHead head; - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); if (!cases[i].im.empty()) head.headers->AddHeader(cases[i].im); network::URLLoaderCompletionStatus status; @@ -587,8 +587,8 @@ std::string headers("HTTP/1.1 200 OK\n\n"); network::ResourceResponseHead head; - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); head.headers->AddHeader("X-Country: test"); network::URLLoaderCompletionStatus status; status.decoded_body_length = serialized_seed.size(); @@ -849,8 +849,8 @@ std::string headers("HTTP/1.1 200 OK\n\n"); network::ResourceResponseHead head; - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); head.headers->AddHeader(seed_signature_header); network::URLLoaderCompletionStatus status; status.decoded_body_length = response.size(); @@ -879,8 +879,8 @@ std::string headers("HTTP/1.1 304 Not Modified\n\n"); network::ResourceResponseHead head; - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); network::URLLoaderCompletionStatus status; service.test_url_loader_factory()->AddResponse(service.interception_url(), head, "", status); @@ -1019,8 +1019,8 @@ std::string headers("HTTP/1.1 200 OK\n\n"); network::ResourceResponseHead head; - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); EXPECT_EQ(net::HTTP_OK, head.headers->response_code()); head.headers->AddHeader(seed_signature_header); // Set ERR_FAILED status code despite the 200 response code.
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc index bf9e9514..078069a4 100644 --- a/components/viz/common/features.cc +++ b/components/viz/common/features.cc
@@ -66,11 +66,19 @@ } bool IsVizDisplayCompositorEnabled() { +#if defined(OS_MACOSX) || defined(OS_WIN) || \ + (defined(OS_LINUX) && !defined(OS_CHROMEOS)) + // We can't remove the feature switch yet because OOP-D isn't enabled on all + // platforms but turning it off on Mac, Windows and Linux is broken. Don't + // check the feature switch for these platforms anymore. + return true; +#else #if defined(OS_ANDROID) if (features::IsAndroidSurfaceControlEnabled()) return true; #endif return base::FeatureList::IsEnabled(kVizDisplayCompositor); +#endif } bool IsVizHitTestingDebugEnabled() {
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc index dd06416..50dec33 100644 --- a/components/viz/service/display/display.cc +++ b/components/viz/service/display/display.cc
@@ -47,7 +47,8 @@ // difficult to associate the trace-events with the particular displays. int64_t GetStartingTraceId() { static int64_t client = 0; - return ((++client & 0xffffffff) << 32); + // https://crbug.com/956695 + return ((++client & 0xffff) << 16); } gfx::PresentationFeedback SanitizePresentationFeedback(
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index b6ab725..eede6d1 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc
@@ -788,7 +788,7 @@ if (current_frame()->current_render_pass->has_transparent_background) { ClearCanvas(SkColorSetARGB(0, 0, 0, 0)); } else { -#ifndef NDEBUG +#if DCHECK_IS_ON() // On DEBUG builds, opaque render passes are cleared to blue // to easily see regions that were not drawn on the screen. ClearCanvas(SkColorSetARGB(255, 0, 0, 255));
diff --git a/components/viz/service/display_embedder/skia_output_device.cc b/components/viz/service/display_embedder/skia_output_device.cc index f32281d3..8693fbb3 100644 --- a/components/viz/service/display_embedder/skia_output_device.cc +++ b/components/viz/service/display_embedder/skia_output_device.cc
@@ -12,13 +12,16 @@ namespace viz { SkiaOutputDevice::SkiaOutputDevice( + bool need_swap_semaphore, DidSwapBufferCompleteCallback did_swap_buffer_complete_callback) - : did_swap_buffer_complete_callback_(did_swap_buffer_complete_callback) {} + : need_swap_semaphore_(need_swap_semaphore), + did_swap_buffer_complete_callback_(did_swap_buffer_complete_callback) {} SkiaOutputDevice::~SkiaOutputDevice() = default; gfx::SwapResponse SkiaOutputDevice::PostSubBuffer( const gfx::Rect& rect, + const GrBackendSemaphore& semaphore, BufferPresentedCallback feedback) { NOTREACHED(); StartSwapBuffers(std::move(feedback));
diff --git a/components/viz/service/display_embedder/skia_output_device.h b/components/viz/service/display_embedder/skia_output_device.h index 1165856da..a19cecc 100644 --- a/components/viz/service/display_embedder/skia_output_device.h +++ b/components/viz/service/display_embedder/skia_output_device.h
@@ -13,6 +13,7 @@ #include "third_party/skia/include/core/SkRefCnt.h" #include "ui/gfx/swap_result.h" +class GrBackendSemaphore; class SkSurface; namespace gfx { @@ -31,7 +32,8 @@ using DidSwapBufferCompleteCallback = base::RepeatingCallback<void(gpu::SwapBuffersCompleteParams, const gfx::Size& pixel_size)>; - explicit SkiaOutputDevice( + SkiaOutputDevice( + bool need_swap_semaphore, DidSwapBufferCompleteCallback did_swap_buffer_complete_callback); virtual ~SkiaOutputDevice(); @@ -45,8 +47,10 @@ bool has_alpha) = 0; // Presents DrawSurface. - virtual gfx::SwapResponse SwapBuffers(BufferPresentedCallback feedback) = 0; + virtual gfx::SwapResponse SwapBuffers(const GrBackendSemaphore& semaphore, + BufferPresentedCallback feedback) = 0; virtual gfx::SwapResponse PostSubBuffer(const gfx::Rect& rect, + const GrBackendSemaphore& semaphore, BufferPresentedCallback feedback); const OutputSurface::Capabilities& capabilities() const { return capabilities_; @@ -58,6 +62,8 @@ virtual void EnsureBackbuffer(); virtual void DiscardBackbuffer(); + bool need_swap_semaphore() const { return need_swap_semaphore_; } + protected: void StartSwapBuffers(base::Optional<BufferPresentedCallback> feedback); gfx::SwapResponse FinishSwapBuffers(gfx::SwapResult result); @@ -66,6 +72,7 @@ OutputSurface::Capabilities capabilities_; private: + const bool need_swap_semaphore_; uint64_t swap_id_ = 0; DidSwapBufferCompleteCallback did_swap_buffer_complete_callback_;
diff --git a/components/viz/service/display_embedder/skia_output_device_gl.cc b/components/viz/service/display_embedder/skia_output_device_gl.cc index e484e8f3..f7c162e0 100644 --- a/components/viz/service/display_embedder/skia_output_device_gl.cc +++ b/components/viz/service/display_embedder/skia_output_device_gl.cc
@@ -27,7 +27,8 @@ gpu::SurfaceHandle surface_handle, scoped_refptr<gpu::gles2::FeatureInfo> feature_info, const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback) - : SkiaOutputDevice(did_swap_buffer_complete_callback), + : SkiaOutputDevice(false /*need_swap_semaphore */, + did_swap_buffer_complete_callback), surface_handle_(surface_handle), feature_info_(feature_info) { DCHECK(surface_handle_); @@ -102,6 +103,7 @@ } gfx::SwapResponse SkiaOutputDeviceGL::SwapBuffers( + const GrBackendSemaphore& semaphore, BufferPresentedCallback feedback) { // TODO(backer): Support SwapBuffersAsync StartSwapBuffers({}); @@ -110,6 +112,7 @@ gfx::SwapResponse SkiaOutputDeviceGL::PostSubBuffer( const gfx::Rect& rect, + const GrBackendSemaphore& semaphore, BufferPresentedCallback feedback) { // TODO(backer): Support PostSubBufferAsync StartSwapBuffers({});
diff --git a/components/viz/service/display_embedder/skia_output_device_gl.h b/components/viz/service/display_embedder/skia_output_device_gl.h index 9d5f9941d..0c528d7 100644 --- a/components/viz/service/display_embedder/skia_output_device_gl.h +++ b/components/viz/service/display_embedder/skia_output_device_gl.h
@@ -48,8 +48,10 @@ float device_scale_factor, const gfx::ColorSpace& color_space, bool has_alpha) override; - gfx::SwapResponse SwapBuffers(BufferPresentedCallback feedback) override; + gfx::SwapResponse SwapBuffers(const GrBackendSemaphore& semaphore, + BufferPresentedCallback feedback) override; gfx::SwapResponse PostSubBuffer(const gfx::Rect& rect, + const GrBackendSemaphore& semaphore, BufferPresentedCallback feedback) override; void EnsureBackbuffer() override; void DiscardBackbuffer() override;
diff --git a/components/viz/service/display_embedder/skia_output_device_offscreen.cc b/components/viz/service/display_embedder/skia_output_device_offscreen.cc index 19779ec9..318f607 100644 --- a/components/viz/service/display_embedder/skia_output_device_offscreen.cc +++ b/components/viz/service/display_embedder/skia_output_device_offscreen.cc
@@ -15,7 +15,8 @@ bool flipped, bool has_alpha, DidSwapBufferCompleteCallback did_swap_buffer_complete_callback) - : SkiaOutputDevice(did_swap_buffer_complete_callback), + : SkiaOutputDevice(false /*need_swap_semaphore */, + did_swap_buffer_complete_callback), gr_context_(gr_context), has_alpha_(has_alpha) { capabilities_.flipped_output_surface = flipped; @@ -49,11 +50,13 @@ gfx::SwapResponse SkiaOutputDeviceOffscreen::PostSubBuffer( const gfx::Rect& rect, + const GrBackendSemaphore& semaphore, BufferPresentedCallback feedback) { - return SwapBuffers(std::move(feedback)); + return SwapBuffers(semaphore, std::move(feedback)); } gfx::SwapResponse SkiaOutputDeviceOffscreen::SwapBuffers( + const GrBackendSemaphore& semaphore, BufferPresentedCallback feedback) { // Reshape should have been called first. DCHECK(draw_surface_);
diff --git a/components/viz/service/display_embedder/skia_output_device_offscreen.h b/components/viz/service/display_embedder/skia_output_device_offscreen.h index fbec9fbb9..a1f38d7 100644 --- a/components/viz/service/display_embedder/skia_output_device_offscreen.h +++ b/components/viz/service/display_embedder/skia_output_device_offscreen.h
@@ -27,8 +27,11 @@ float device_scale_factor, const gfx::ColorSpace& color_space, bool has_alpha) override; - gfx::SwapResponse SwapBuffers(BufferPresentedCallback feedback) override; + gfx::SwapResponse SwapBuffers(const GrBackendSemaphore& semaphore, + BufferPresentedCallback feedback) override; gfx::SwapResponse PostSubBuffer(const gfx::Rect& rect, + const GrBackendSemaphore& semaphore, + BufferPresentedCallback feedback) override; void EnsureBackbuffer() override; void DiscardBackbuffer() override;
diff --git a/components/viz/service/display_embedder/skia_output_device_vulkan.cc b/components/viz/service/display_embedder/skia_output_device_vulkan.cc index 19aec32..a8a4bb4 100644 --- a/components/viz/service/display_embedder/skia_output_device_vulkan.cc +++ b/components/viz/service/display_embedder/skia_output_device_vulkan.cc
@@ -12,6 +12,7 @@ #include "gpu/vulkan/vulkan_implementation.h" #include "gpu/vulkan/vulkan_surface.h" #include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/include/gpu/GrBackendSemaphore.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/vk/GrVkTypes.h" @@ -21,7 +22,8 @@ VulkanContextProvider* context_provider, gpu::SurfaceHandle surface_handle, DidSwapBufferCompleteCallback did_swap_buffer_complete_callback) - : SkiaOutputDevice(did_swap_buffer_complete_callback), + : SkiaOutputDevice(true /*need_swap_semaphore */, + did_swap_buffer_complete_callback), context_provider_(context_provider), surface_handle_(surface_handle) { capabilities_.flipped_output_surface = true; @@ -29,6 +31,7 @@ } SkiaOutputDeviceVulkan::~SkiaOutputDeviceVulkan() { + scoped_write_.reset(); if (vulkan_surface_) vulkan_surface_->Destroy(); } @@ -40,6 +43,7 @@ if (!vulkan_surface_) CreateVulkanSurface(); + scoped_write_.reset(); auto old_size = vulkan_surface_->size(); vulkan_surface_->SetSize(size); if (vulkan_surface_->size() != old_size) { @@ -53,10 +57,12 @@ } gfx::SwapResponse SkiaOutputDeviceVulkan::SwapBuffers( + const GrBackendSemaphore& semaphore, BufferPresentedCallback feedback) { // Reshape should have been called first. DCHECK(vulkan_surface_); DCHECK(draw_surface_); + DCHECK(scoped_write_); StartSwapBuffers(std::move(feedback)); auto backend = draw_surface_->getBackendRenderTarget( @@ -64,10 +70,11 @@ GrVkImageInfo vk_image_info; if (!backend.getVkImageInfo(&vk_image_info)) NOTREACHED() << "Failed to get the image info."; - vulkan_surface_->GetSwapChain()->SetCurrentImageLayout( - vk_image_info.fImageLayout); - auto response = FinishSwapBuffers(vulkan_surface_->SwapBuffers()); + scoped_write_->set_image_layout(vk_image_info.fImageLayout); + scoped_write_->SetEndSemaphore(semaphore.vkSemaphore()); + scoped_write_.reset(); + auto response = FinishSwapBuffers(vulkan_surface_->SwapBuffers()); UpdateDrawSurface(); return response; @@ -97,20 +104,21 @@ void SkiaOutputDeviceVulkan::UpdateDrawSurface() { DCHECK(vulkan_surface_); - auto* swap_chain = vulkan_surface_->GetSwapChain(); - auto index = swap_chain->current_image(); - auto& sk_surface = sk_surfaces_[index]; + DCHECK(!scoped_write_); + + scoped_write_.emplace(vulkan_surface_->GetSwapChain()); + + auto& sk_surface = sk_surfaces_[scoped_write_->image_index()]; + if (!sk_surface) { SkSurfaceProps surface_props = SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType); - VkImage vk_image = swap_chain->GetCurrentImage(); - VkImageLayout vk_image_layout = swap_chain->GetCurrentImageLayout(); const auto surface_format = vulkan_surface_->surface_format().format; DCHECK(surface_format == VK_FORMAT_B8G8R8A8_UNORM || surface_format == VK_FORMAT_R8G8B8A8_UNORM); - GrVkImageInfo vk_image_info(vk_image, GrVkAlloc(), VK_IMAGE_TILING_OPTIMAL, - vk_image_layout, surface_format, - 1 /* level_count */); + GrVkImageInfo vk_image_info( + scoped_write_->image(), GrVkAlloc(), VK_IMAGE_TILING_OPTIMAL, + scoped_write_->image_layout(), surface_format, 1 /* level_count */); GrBackendRenderTarget render_target(vulkan_surface_->size().width(), vulkan_surface_->size().height(), 0 /* sample_cnt */, vk_image_info); @@ -125,9 +133,12 @@ } else { auto backend = sk_surface->getBackendRenderTarget( SkSurface::kFlushRead_BackendHandleAccess); - backend.setVkImageLayout(swap_chain->GetCurrentImageLayout()); + backend.setVkImageLayout(scoped_write_->image_layout()); } - + GrBackendSemaphore semaphore; + semaphore.initVulkan(scoped_write_->TakeBeginSemaphore()); + auto result = sk_surface->wait(1, &semaphore); + DCHECK(result); draw_surface_ = sk_surface; }
diff --git a/components/viz/service/display_embedder/skia_output_device_vulkan.h b/components/viz/service/display_embedder/skia_output_device_vulkan.h index 2d538ac..cc35ef7 100644 --- a/components/viz/service/display_embedder/skia_output_device_vulkan.h +++ b/components/viz/service/display_embedder/skia_output_device_vulkan.h
@@ -9,8 +9,10 @@ #include <vector> #include "base/macros.h" +#include "base/optional.h" #include "components/viz/service/display_embedder/skia_output_device.h" #include "gpu/ipc/common/surface_handle.h" +#include "gpu/vulkan/vulkan_swap_chain.h" namespace gpu { class VulkanSurface; @@ -33,7 +35,8 @@ float device_scale_factor, const gfx::ColorSpace& color_space, bool has_alpha) override; - gfx::SwapResponse SwapBuffers(BufferPresentedCallback feedback) override; + gfx::SwapResponse SwapBuffers(const GrBackendSemaphore& semaphore, + BufferPresentedCallback feedback) override; private: void CreateVulkanSurface(); @@ -44,6 +47,8 @@ const gpu::SurfaceHandle surface_handle_; std::unique_ptr<gpu::VulkanSurface> vulkan_surface_; + base::Optional<gpu::VulkanSwapChain::ScopedWrite> scoped_write_; + // SkSurfaces for swap chain images. std::vector<sk_sp<SkSurface>> sk_surfaces_;
diff --git a/components/viz/service/display_embedder/skia_output_device_x11.cc b/components/viz/service/display_embedder/skia_output_device_x11.cc index 76ed3d9..9f962db 100644 --- a/components/viz/service/display_embedder/skia_output_device_x11.cc +++ b/components/viz/service/display_embedder/skia_output_device_x11.cc
@@ -52,14 +52,16 @@ } gfx::SwapResponse SkiaOutputDeviceX11::SwapBuffers( + const GrBackendSemaphore& semaphore, BufferPresentedCallback feedback) { return PostSubBuffer( gfx::Rect(0, 0, draw_surface_->width(), draw_surface_->height()), - std::move(feedback)); + semaphore, std::move(feedback)); } gfx::SwapResponse SkiaOutputDeviceX11::PostSubBuffer( const gfx::Rect& rect, + const GrBackendSemaphore& semaphore, BufferPresentedCallback feedback) { StartSwapBuffers(std::move(feedback));
diff --git a/components/viz/service/display_embedder/skia_output_device_x11.h b/components/viz/service/display_embedder/skia_output_device_x11.h index a82d72e7..f599b7a 100644 --- a/components/viz/service/display_embedder/skia_output_device_x11.h +++ b/components/viz/service/display_embedder/skia_output_device_x11.h
@@ -27,8 +27,10 @@ float device_scale_factor, const gfx::ColorSpace& color_space, bool has_alpha) override; - gfx::SwapResponse SwapBuffers(BufferPresentedCallback feedback) override; + gfx::SwapResponse SwapBuffers(const GrBackendSemaphore& semaphore, + BufferPresentedCallback feedback) override; gfx::SwapResponse PostSubBuffer(const gfx::Rect& rect, + const GrBackendSemaphore& semaphore, BufferPresentedCallback feedback) override; private:
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc index d35f5d9..ff2e916 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -42,7 +42,6 @@ #include "gpu/vulkan/buildflags.h" #include "skia/ext/image_operations.h" #include "third_party/skia/include/core/SkPixelRef.h" -#include "third_party/skia/include/gpu/GrBackendSemaphore.h" #include "third_party/skia/include/private/SkDeferredDisplayList.h" #include "ui/gfx/color_space.h" #include "ui/gfx/skia_util.h" @@ -75,7 +74,8 @@ std::vector<ImageContext*> image_contexts) : impl_on_gpu_(impl_on_gpu), image_contexts_(std::move(image_contexts)) { begin_semaphores_.reserve(image_contexts_.size()); - end_semaphores_.reserve(image_contexts_.size()); + // We may need one more space for the swap buffer semaphore. + end_semaphores_.reserve(image_contexts_.size() + 1); // TODO(penghuang): gather begin read access semaphores from shared images. // https://crbug.com/944194 impl_on_gpu_->BeginAccessImages(image_contexts_, &begin_semaphores_, @@ -422,57 +422,71 @@ return; PullTextureUpdates(std::move(sync_tokens)); + { base::Optional<gpu::raster::GrShaderCache::ScopedCacheUse> cache_use; - if (gr_shader_cache_) { + if (gr_shader_cache_) cache_use.emplace(gr_shader_cache_, gpu::kInProcessCommandBufferClientId); - } + ScopedPromiseImageAccess scoped_promise_image_access( this, std::move(image_contexts)); - auto wait_result = output_sk_surface()->wait( - scoped_promise_image_access.begin_semaphores().size(), - scoped_promise_image_access.begin_semaphores().data()); - DCHECK(wait_result); + if (!scoped_promise_image_access.begin_semaphores().empty()) { + auto result = output_sk_surface()->wait( + scoped_promise_image_access.begin_semaphores().size(), + scoped_promise_image_access.begin_semaphores().data()); + DCHECK(result); + } + output_sk_surface()->draw(ddl.get()); + ddl = nullptr; + + if (overdraw_ddl) { + sk_sp<SkSurface> overdraw_surface = SkSurface::MakeRenderTarget( + gr_context(), overdraw_ddl->characterization(), SkBudgeted::kNo); + overdraw_surface->draw(overdraw_ddl.get()); + overdraw_ddl = nullptr; + + SkPaint paint; + sk_sp<SkImage> overdraw_image = overdraw_surface->makeImageSnapshot(); + + sk_sp<SkColorFilter> colorFilter = SkiaHelper::MakeOverdrawColorFilter(); + paint.setColorFilter(colorFilter); + // TODO(xing.xu): move below to the thread where skia record happens. + output_sk_surface()->getCanvas()->drawImage(overdraw_image.get(), 0, 0, + &paint); + } + + if (output_device_->need_swap_semaphore()) + scoped_promise_image_access.end_semaphores().emplace_back(); + GrFlushInfo flush_info = { .fFlags = kNone_GrFlushFlags, .fNumSemaphores = scoped_promise_image_access.end_semaphores().size(), .fSignalSemaphores = scoped_promise_image_access.end_semaphores().data(), }; - // TODO(penghuang): flush output_sk_surface() with kPresent. - if (gr_context()->flush(flush_info) != GrSemaphoresSubmitted::kYes) { + auto result = output_sk_surface()->flush( + SkSurface::BackendSurfaceAccess::kPresent, flush_info); + if (result != GrSemaphoresSubmitted::kYes && + !(scoped_promise_image_access.begin_semaphores().empty() && + scoped_promise_image_access.end_semaphores().empty())) { // TODO(penghuang): handle vulkan device lost. - DLOG(ERROR) << "GrContext::flush() failed."; + DLOG(ERROR) << "output_sk_surface()->flush() failed."; return; } - } - - // Note that the ScopedCacheUse for GrShaderCache is scoped until the - // ReleaseFenceSync call here since releasing the fence may schedule a - // different decoder's stream which also uses the shader cache. - ReleaseFenceSyncAndPushTextureUpdates(sync_fence_release); - - if (overdraw_ddl) { - base::Optional<gpu::raster::GrShaderCache::ScopedCacheUse> cache_use; - if (gr_shader_cache_) { - cache_use.emplace(gr_shader_cache_, gpu::kInProcessCommandBufferClientId); + if (output_device_->need_swap_semaphore()) { + DCHECK(!swap_buffers_semaphore_.isInitialized()); + swap_buffers_semaphore_ = + scoped_promise_image_access.end_semaphores().back(); + DCHECK(swap_buffers_semaphore_.isInitialized()); } - sk_sp<SkSurface> overdraw_surface = SkSurface::MakeRenderTarget( - gr_context(), overdraw_ddl->characterization(), SkBudgeted::kNo); - overdraw_surface->draw(overdraw_ddl.get()); - - SkPaint paint; - sk_sp<SkImage> overdraw_image = overdraw_surface->makeImageSnapshot(); - - sk_sp<SkColorFilter> colorFilter = SkiaHelper::MakeOverdrawColorFilter(); - paint.setColorFilter(colorFilter); - // TODO(xing.xu): move below to the thread where skia record happens. - output_sk_surface()->getCanvas()->drawImage(overdraw_image.get(), 0, 0, - &paint); + // Add an extra GrContext flush to workaround a skia crash + // TODO(penghuang): remove it when the crash is fixed. + // https://crbug.com/c/956177 gr_context()->flush(); } + ReleaseFenceSyncAndPushTextureUpdates(sync_fence_release); } void SkiaOutputSurfaceImplOnGpu::SwapBuffers(OutputSurfaceFrame frame) { @@ -490,10 +504,13 @@ frame.sub_buffer_rect->set_y(size_.height() - frame.sub_buffer_rect->y() - frame.sub_buffer_rect->height()); response = output_device_->PostSubBuffer(*frame.sub_buffer_rect, + swap_buffers_semaphore_, buffer_presented_callback_); } else { - response = output_device_->SwapBuffers(buffer_presented_callback_); + response = output_device_->SwapBuffers(swap_buffers_semaphore_, + buffer_presented_callback_); } + swap_buffers_semaphore_ = GrBackendSemaphore(); for (auto& latency : frame.latency_info) { latency.AddLatencyNumberWithTimestamp( @@ -533,10 +550,12 @@ cache_use.emplace(gr_shader_cache_, gpu::kInProcessCommandBufferClientId); ScopedPromiseImageAccess scoped_promise_image_access( this, std::move(image_contexts)); - auto wait_result = offscreen.surface()->wait( - scoped_promise_image_access.begin_semaphores().size(), - scoped_promise_image_access.begin_semaphores().data()); - DCHECK(wait_result); + if (!scoped_promise_image_access.begin_semaphores().empty()) { + auto result = offscreen.surface()->wait( + scoped_promise_image_access.begin_semaphores().size(), + scoped_promise_image_access.begin_semaphores().data()); + DCHECK(result); + } offscreen.surface()->draw(ddl.get()); GrFlushInfo flush_info = { .fFlags = kNone_GrFlushFlags, @@ -544,10 +563,14 @@ .fSignalSemaphores = scoped_promise_image_access.end_semaphores().data(), }; - // TODO(penghuang): flush offscreen.surface() only. - if (gr_context()->flush(flush_info) != GrSemaphoresSubmitted::kYes) { + + auto result = offscreen.surface()->flush( + SkSurface::BackendSurfaceAccess::kNoAccess, flush_info); + if (result != GrSemaphoresSubmitted::kYes && + !(scoped_promise_image_access.begin_semaphores().empty() && + scoped_promise_image_access.end_semaphores().empty())) { // TODO(penghuang): handle vulkan device lost. - DLOG(ERROR) << "GrContext::flush() failed."; + DLOG(ERROR) << "offscreen.surface()->flush() failed."; return; } } @@ -792,8 +815,6 @@ // and a fallback content has been used, in that case, we cannot change // the content, so we do nothing. if (context->representation) { - // TODO(penghuang): create gather read access semaphores and call - // skia flush() with them. https://crbug.com/944194 auto promise_image_texture = context->representation->BeginReadAccess( begin_semaphores, end_semaphores); // The image has been fulfilled and cached. It is too late to tell @@ -824,9 +845,8 @@ continue; } + DCHECK(representation->size() == context->size); context->representation = std::move(representation); - // TODO(penghuang): create gather read access semaphores and call - // skia flush() with them. https://crbug.com/944194 context->promise_image_texture = context->representation->BeginReadAccess( begin_semaphores, end_semaphores); if (!context->promise_image_texture) {
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h index 9318f1c..faad369 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -27,9 +27,9 @@ #include "gpu/ipc/service/image_transport_surface_delegate.h" #include "third_party/skia/include/core/SkPromiseImageTexture.h" #include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/include/gpu/GrBackendSemaphore.h" #include "ui/latency/latency_tracker.h" -class GrBackendSemaphore; class SkDeferredDisplayList; namespace base { @@ -214,6 +214,9 @@ std::unique_ptr<SkiaOutputDevice> output_device_; + // Semaphore for SkiaOutputDevice::SwapBuffers() to wait on. + GrBackendSemaphore swap_buffers_semaphore_; + // Offscreen surfaces for render passes. It can only be accessed on GPU // thread. class OffscreenSurface {
diff --git a/components/wifi/wifi_service_win.cc b/components/wifi/wifi_service_win.cc index 1a185839..3251ad7 100644 --- a/components/wifi/wifi_service_win.cc +++ b/components/wifi/wifi_service_win.cc
@@ -28,6 +28,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "base/win/registry.h" +#include "base/win/win_util.h" #include "components/onc/onc_constants.h" #include "components/wifi/network_properties.h" #include "third_party/libxml/chromium/libxml_utils.h" @@ -1137,10 +1138,7 @@ DWORD WiFiServiceImpl::FindAdapterIndexMapByGUID( const GUID& interface_guid, IP_ADAPTER_INDEX_MAP* adapter_index_map) { - base::string16 guid_string; - const int kGUIDSize = 39; - ::StringFromGUID2( - interface_guid, base::WriteInto(&guid_string, kGUIDSize), kGUIDSize); + const auto guid_string = base::win::String16FromGUID(interface_guid); ULONG buffer_length = 0; DWORD error = ::GetInterfaceInfo(nullptr, &buffer_length);
diff --git a/content/app/strings/content_strings.grd b/content/app/strings/content_strings.grd index 36c2864..c1ab358e 100644 --- a/content/app/strings/content_strings.grd +++ b/content/app/strings/content_strings.grd
@@ -961,9 +961,16 @@ Picture in picture </message> </if> - <message name="IDS_MEDIA_OVERFLOW_MENU_EXIT_PICTURE_IN_PICTURE" desc="Media controls overflow menu item label for a button to exit Picture-in-Picture."> - Exit picture-in-picture mode - </message> + <if expr="is_macosx"> + <message name="IDS_MEDIA_OVERFLOW_MENU_EXIT_PICTURE_IN_PICTURE" desc="Media controls overflow menu item label for a button to exit Picture-in-Picture."> + Exit Picture in Picture + </message> + </if> + <if expr="not is_macosx"> + <message name="IDS_MEDIA_OVERFLOW_MENU_EXIT_PICTURE_IN_PICTURE" desc="Media controls overflow menu item label for a button to exit Picture-in-Picture."> + Exit picture in picture + </message> + </if> <message name="IDS_MEDIA_PICTURE_IN_PICTURE_INTERSTITIAL_TEXT" desc="Text message shown to user when in picture in picture mode. When a video is in picture in picture mode, an interstitial with this text appears where the video player is positioned. The video continues to play back in another window that gives the experience that the video is 'popped out'."> Playing in picture-in-picture mode </message>
diff --git a/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc new file mode 100644 index 0000000..5210be9 --- /dev/null +++ b/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc
@@ -0,0 +1,198 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/accessibility/platform/ax_platform_node_textprovider_win.h" +#include "ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h" + +#include "base/win/scoped_bstr.h" +#include "base/win/scoped_safearray.h" +#include "base/win/scoped_variant.h" +#include "content/browser/accessibility/browser_accessibility.h" +#include "content/browser/accessibility/browser_accessibility_com_win.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/test/content_browser_test.h" +#include "content/public/test/content_browser_test_utils.h" +#include "content/shell/browser/shell.h" +#include "content/test/accessibility_browser_test_utils.h" +#include "net/base/escape.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "testing/gmock/include/gmock/gmock-matchers.h" + +using Microsoft::WRL::ComPtr; + +namespace content { + +#define ASSERT_UIA_SAFEARRAY_OF_TEXTRANGEPROVIDER(safearray, expected_size) \ + { \ + EXPECT_EQ(sizeof(CComPtr<ITextRangeProvider>), \ + ::SafeArrayGetElemsize(safearray)); \ + ASSERT_EQ(1u, SafeArrayGetDim(safearray)); \ + LONG array_lower_bound; \ + ASSERT_HRESULT_SUCCEEDED( \ + SafeArrayGetLBound(safearray, 1, &array_lower_bound)); \ + LONG array_upper_bound; \ + ASSERT_HRESULT_SUCCEEDED( \ + SafeArrayGetUBound(safearray, 1, &array_upper_bound)); \ + size_t count = array_upper_bound - array_lower_bound + 1; \ + ASSERT_EQ(expected_size, count); \ + } + +#define EXPECT_UIA_TEXTRANGE_EQ(provider, expected_content) \ + { \ + base::win::ScopedBstr provider_content; \ + ASSERT_HRESULT_SUCCEEDED( \ + provider->GetText(-1, provider_content.Receive())); \ + EXPECT_STREQ(expected_content, provider_content); \ + } + +class AXPlatformNodeTextProviderWinBrowserTest : public ContentBrowserTest { + protected: + void LoadInitialAccessibilityTreeFromUrl( + const GURL& url, + ui::AXMode accessibility_mode = ui::kAXModeComplete) { + AccessibilityNotificationWaiter waiter(shell()->web_contents(), + accessibility_mode, + ax::mojom::Event::kLoadComplete); + NavigateToURL(shell(), url); + waiter.WaitForNotification(); + } + + void LoadInitialAccessibilityTreeFromHtmlFilePath( + const std::string& html_file_path, + ui::AXMode accessibility_mode = ui::kAXModeComplete) { + if (!embedded_test_server()->Started()) + ASSERT_TRUE(embedded_test_server()->Start()); + ASSERT_TRUE(embedded_test_server()->Started()); + LoadInitialAccessibilityTreeFromUrl( + embedded_test_server()->GetURL(html_file_path), accessibility_mode); + } + + void LoadInitialAccessibilityTreeFromHtml( + const std::string& html, + ui::AXMode accessibility_mode = ui::kAXModeComplete) { + LoadInitialAccessibilityTreeFromUrl( + GURL("data:text/html," + net::EscapeQueryParamValue(html, false)), + accessibility_mode); + } + + BrowserAccessibilityManager* GetManagerAndAssertNonNull() { + auto GetManagerAndAssertNonNull = + [this](BrowserAccessibilityManager** result) { + WebContentsImpl* web_contents_impl = + static_cast<WebContentsImpl*>(shell()->web_contents()); + ASSERT_NE(nullptr, web_contents_impl); + BrowserAccessibilityManager* browser_accessibility_manager = + web_contents_impl->GetRootBrowserAccessibilityManager(); + ASSERT_NE(nullptr, browser_accessibility_manager); + *result = browser_accessibility_manager; + }; + + BrowserAccessibilityManager* browser_accessibility_manager; + GetManagerAndAssertNonNull(&browser_accessibility_manager); + return browser_accessibility_manager; + } + + BrowserAccessibility* GetRootAndAssertNonNull() { + auto GetRootAndAssertNonNull = [this](BrowserAccessibility** result) { + BrowserAccessibility* root_browser_accessibility = + GetManagerAndAssertNonNull()->GetRoot(); + ASSERT_NE(nullptr, result); + *result = root_browser_accessibility; + }; + + BrowserAccessibility* root_browser_accessibility; + GetRootAndAssertNonNull(&root_browser_accessibility); + return root_browser_accessibility; + } + + BrowserAccessibility* FindNode(ax::mojom::Role role, + const std::string& name_or_value) { + return FindNodeInSubtree(*GetRootAndAssertNonNull(), role, name_or_value); + } + + void GetTextProviderFromTextNode( + ComPtr<ITextProvider>& text_provider, + BrowserAccessibility* target_browser_accessibility) { + auto* provider_simple = + ToBrowserAccessibilityWin(target_browser_accessibility)->GetCOM(); + ASSERT_NE(nullptr, provider_simple); + + EXPECT_HRESULT_SUCCEEDED( + provider_simple->GetPatternProvider(UIA_TextPatternId, &text_provider)); + ASSERT_NE(nullptr, text_provider.Get()); + } + + private: + BrowserAccessibility* FindNodeInSubtree(BrowserAccessibility& node, + ax::mojom::Role role, + const std::string& name_or_value) { + const auto& name = + node.GetStringAttribute(ax::mojom::StringAttribute::kName); + const auto& value = + node.GetStringAttribute(ax::mojom::StringAttribute::kValue); + if (node.GetRole() == role && + (name == name_or_value || value == name_or_value)) { + return &node; + } + + for (unsigned int i = 0; i < node.PlatformChildCount(); ++i) { + BrowserAccessibility* result = + FindNodeInSubtree(*node.PlatformGetChild(i), role, name_or_value); + if (result) + return result; + } + + return nullptr; + } +}; + +IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextProviderWinBrowserTest, + GetVisibleBounds) { + LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML( + <!DOCTYPE html> + <html> + <head> + <style> + .overflow_y { + overflow-x: hidden; + overflow-y: visible; + } + </style> + </head> + <body> + <div class='overflow_y' style='width: 110px; height: 40px;'> + <span> + A B C D E F G H I J K L M N O P Q R S T U V W X Y Z + </span> + </div> + </body> + </html> + )HTML")); + + auto* node = FindNode(ax::mojom::Role::kStaticText, + "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"); + ASSERT_NE(nullptr, node); + EXPECT_TRUE(node->PlatformIsLeaf()); + EXPECT_EQ(0u, node->PlatformChildCount()); + + ComPtr<ITextProvider> text_provider; + GetTextProviderFromTextNode(text_provider, node); + + base::win::ScopedSafearray text_provider_ranges; + CComPtr<ITextRangeProvider>* array_data; + EXPECT_HRESULT_SUCCEEDED( + text_provider->GetVisibleRanges(text_provider_ranges.Receive())); + ASSERT_UIA_SAFEARRAY_OF_TEXTRANGEPROVIDER(text_provider_ranges.Get(), 2U); + + ASSERT_HRESULT_SUCCEEDED(::SafeArrayAccessData( + text_provider_ranges.Get(), reinterpret_cast<void**>(&array_data))); + + EXPECT_UIA_TEXTRANGE_EQ(array_data[0], L"A B C D E F "); + EXPECT_UIA_TEXTRANGE_EQ(array_data[1], L"G H I J K L "); + + ASSERT_HRESULT_SUCCEEDED(::SafeArrayUnaccessData(text_provider_ranges.Get())); + text_provider_ranges.Reset(); +} + +} // namespace content
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index 04659f6..8bd5733 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc
@@ -627,34 +627,44 @@ start_offset > end_offset) return gfx::Rect(); + return GetInnerTextRangeBoundsRectInSubtree( + start_offset, end_offset, coordinate_system, clipping_behavior, + offscreen_result); +} + +gfx::Rect BrowserAccessibility::GetInnerTextRangeBoundsRectInSubtree( + const int start_offset, + const int end_offset, + const ui::AXCoordinateSystem coordinate_system, + const ui::AXClippingBehavior clipping_behavior, + ui::AXOffscreenResult* offscreen_result) const { if (GetRole() == ax::mojom::Role::kInlineTextBox) { return RelativeToAbsoluteBounds( - GetInlineTextRect(start_offset, end_offset, inner_text_length), + GetInlineTextRect(start_offset, end_offset, GetInnerText().length()), coordinate_system, clipping_behavior, offscreen_result); } - if (IsPlainTextField() && InternalChildCount() == 1) { + const uint32_t internal_child_count = InternalChildCount(); + if (IsPlainTextField() && internal_child_count == 1) { return InternalGetChild(0)->RelativeToAbsoluteBounds( - GetInlineTextRect(start_offset, end_offset, inner_text_length), + GetInlineTextRect(start_offset, end_offset, GetInnerText().length()), coordinate_system, clipping_behavior, offscreen_result); } gfx::Rect bounds; - for (size_t i = 0, c = InternalChildCount(); i < c; ++i) { + int child_offset_in_parent = 0; + for (uint32_t i = 0; i < internal_child_count; ++i) { const BrowserAccessibility* browser_accessibility_child = InternalGetChild(i); const int child_inner_text_length = browser_accessibility_child->GetInnerText().length(); - const int child_offset_in_parent = - browser_accessibility_child->CreateTextPositionAt(0) - ->CreateParentPosition() - ->text_offset(); const gfx::Rect child_bounds = - browser_accessibility_child->GetInnerTextRangeBoundsRect( + browser_accessibility_child->GetInnerTextRangeBoundsRectInSubtree( std::max(start_offset - child_offset_in_parent, 0), std::min(end_offset - child_offset_in_parent, child_inner_text_length), coordinate_system, clipping_behavior, offscreen_result); + child_offset_in_parent += child_inner_text_length; if (bounds.IsEmpty()) bounds = child_bounds; else
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h index 31973a6..b664d573 100644 --- a/content/browser/accessibility/browser_accessibility.h +++ b/content/browser/accessibility/browser_accessibility.h
@@ -516,6 +516,14 @@ const int end_offset, const int max_length) const; + // Recursive helper function for GetInnerTextRangeBounds. + gfx::Rect GetInnerTextRangeBoundsRectInSubtree( + const int start_offset, + const int end_offset, + const ui::AXCoordinateSystem coordinate_system, + const ui::AXClippingBehavior clipping_behavior, + ui::AXOffscreenResult* offscreen_result) const; + // Given a set of node ids, return the nodes in this delegate's tree to // which they correspond. std::set<ui::AXPlatformNode*> GetNodesForNodeIdSet(
diff --git a/content/browser/appcache/appcache_request_handler_unittest.cc b/content/browser/appcache/appcache_request_handler_unittest.cc index 2e284bc..0cd4bfaf 100644 --- a/content/browser/appcache/appcache_request_handler_unittest.cc +++ b/content/browser/appcache/appcache_request_handler_unittest.cc
@@ -413,8 +413,8 @@ net::HttpResponseInfo info; std::string headers = base::StringPrintf("HTTP/1.1 %i Muffin\r\n\r\n", response_code); - info.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length())); + info.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); if (request_handler_type_ == URLREQUEST) { job_factory_->SetJob(std::make_unique<MockURLRequestJob>(
diff --git a/content/browser/appcache/appcache_update_job_unittest.cc b/content/browser/appcache/appcache_update_job_unittest.cc index b1b85de5..d6820b6 100644 --- a/content/browser/appcache/appcache_update_job_unittest.cc +++ b/content/browser/appcache/appcache_update_job_unittest.cc
@@ -618,8 +618,8 @@ } net::HttpResponseInfo info; - info.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length())); + info.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); network::ResourceResponseHead response; response.headers = info.headers;
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 7580d35..76a2d13 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -198,6 +198,7 @@ #if defined(OS_CHROMEOS) #include "base/memory/memory_pressure_monitor_chromeos.h" +#include "base/memory/memory_pressure_monitor_notifying_chromeos.h" #include "chromeos/constants/chromeos_switches.h" #endif @@ -409,6 +410,15 @@ // concrete class. #if defined(OS_CHROMEOS) if (chromeos::switches::MemoryPressureHandlingEnabled()) { + if (base::chromeos::MemoryPressureMonitorNotifying:: + SupportsKernelNotifications()) { + // We will use the MemoryPressureNotifying instance as our kernel supports + // notifications on memory level changes. + return std::make_unique<base::chromeos::MemoryPressureMonitorNotifying>(); + } + + // Our kernel does support notifications, so use the old 1s polling + // implementation. return std::make_unique<base::chromeos::MemoryPressureMonitor>( chromeos::switches::GetMemoryPressureThresholds()); }
diff --git a/content/browser/browsing_data/clear_site_data_throttle_unittest.cc b/content/browser/browsing_data/clear_site_data_throttle_unittest.cc index 7be8627..a2eaa62 100644 --- a/content/browser/browsing_data/clear_site_data_throttle_unittest.cc +++ b/content/browser/browsing_data/clear_site_data_throttle_unittest.cc
@@ -67,8 +67,8 @@ void SetResponseHeaders(const std::string& headers) { std::string headers_with_status_code = "HTTP/1.1 200\n" + headers; - headers_ = new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - headers_with_status_code.c_str(), headers_with_status_code.size())); + headers_ = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers_with_status_code)); } MOCK_METHOD4(ClearSiteData,
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc index bf9f376..5c196a34 100644 --- a/content/browser/devtools/protocol/network_handler.cc +++ b/content/browser/devtools/protocol/network_handler.cc
@@ -1984,8 +1984,8 @@ LOG(WARNING) << "Can't find headers in raw response"; header_size = 0; } else { - raw_headers = net::HttpUtil::AssembleRawHeaders( - reinterpret_cast<const char*>(raw.data()), header_size); + raw_headers = net::HttpUtil::AssembleRawHeaders(base::StringPiece( + reinterpret_cast<const char*>(raw.data()), header_size)); } CHECK_LE(header_size, raw.size()); response_headers =
diff --git a/content/browser/frame_host/origin_policy_throttle_unittest.cc b/content/browser/frame_host/origin_policy_throttle_unittest.cc index a7d968a..4f90af18 100644 --- a/content/browser/frame_host/origin_policy_throttle_unittest.cc +++ b/content/browser/frame_host/origin_policy_throttle_unittest.cc
@@ -123,9 +123,8 @@ // is deferred. const char* raw_headers = "HTTP/1.1 200 OK\nSec-Origin-Policy: policy=policy-1\n\n"; - scoped_refptr<net::HttpResponseHeaders> headers = - new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(raw_headers, strlen(raw_headers))); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_headers)); NavigationHandleImpl* nav_handle = static_cast<NavigationHandleImpl*>(navigation->GetNavigationHandle()); nav_handle->set_response_headers_for_testing(headers); @@ -186,9 +185,8 @@ // Fake a response with a policy header. const char* raw_headers = "HTTP/1.1 200 OK\nSec-Origin-Policy: policy=policy-1\n\n"; - scoped_refptr<net::HttpResponseHeaders> headers = - new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(raw_headers, strlen(raw_headers))); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_headers)); NavigationHandleImpl* nav_handle = static_cast<NavigationHandleImpl*>(navigation->GetNavigationHandle()); nav_handle->set_response_headers_for_testing(headers);
diff --git a/content/browser/renderer_host/input/fling_controller.cc b/content/browser/renderer_host/input/fling_controller.cc index 545fac1..771162e 100644 --- a/content/browser/renderer_host/input/fling_controller.cc +++ b/content/browser/renderer_host/input/fling_controller.cc
@@ -417,19 +417,14 @@ (last_fling_boost_event.GetType() == WebInputEvent::kGestureScrollBegin || last_fling_boost_event.GetType() == WebInputEvent::kGestureScrollUpdate)) { - WebGestureEvent scroll_begin_event = last_fling_boost_event; - scroll_begin_event.SetType(WebInputEvent::kGestureScrollBegin); - bool is_update = - last_fling_boost_event.GetType() == WebInputEvent::kGestureScrollUpdate; - float delta_x_hint = - is_update ? last_fling_boost_event.data.scroll_update.delta_x - : last_fling_boost_event.data.scroll_begin.delta_x_hint; - float delta_y_hint = - is_update ? last_fling_boost_event.data.scroll_update.delta_y - : last_fling_boost_event.data.scroll_begin.delta_y_hint; - scroll_begin_event.data.scroll_begin.delta_x_hint = delta_x_hint; - scroll_begin_event.data.scroll_begin.delta_y_hint = delta_y_hint; - + WebGestureEvent scroll_begin_event; + if (last_fling_boost_event.GetType() == + WebInputEvent::kGestureScrollUpdate) { + scroll_begin_event = + ui::ScrollBeginFromScrollUpdate(last_fling_boost_event); + } else { + scroll_begin_event = last_fling_boost_event; + } event_sender_client_->SendGeneratedGestureScrollEvents( GestureEventWithLatencyInfo( scroll_begin_event,
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue.cc b/content/browser/renderer_host/input/mouse_wheel_event_queue.cc index d0c25d8..3abbedab 100644 --- a/content/browser/renderer_host/input/mouse_wheel_event_queue.cc +++ b/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
@@ -330,18 +330,9 @@ bool synthetic) { DCHECK(!client_->IsWheelScrollInProgress()); - WebGestureEvent scroll_begin(gesture_update); - scroll_begin.SetType(WebInputEvent::kGestureScrollBegin); + WebGestureEvent scroll_begin = + ui::ScrollBeginFromScrollUpdate(gesture_update); scroll_begin.data.scroll_begin.synthetic = synthetic; - scroll_begin.data.scroll_begin.inertial_phase = - gesture_update.data.scroll_update.inertial_phase; - scroll_begin.data.scroll_begin.delta_x_hint = - gesture_update.data.scroll_update.delta_x; - scroll_begin.data.scroll_begin.delta_y_hint = - gesture_update.data.scroll_update.delta_y; - scroll_begin.data.scroll_begin.target_viewport = false; - scroll_begin.data.scroll_begin.delta_hint_units = - gesture_update.data.scroll_update.delta_units; client_->ForwardGestureEventWithLatencyInfo( scroll_begin, ui::LatencyInfo(ui::SourceEventType::WHEEL));
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index ca4ed765..183ec63 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -502,9 +502,6 @@ prefs.use_solid_color_scrollbars = false; - prefs.history_entry_requires_user_gesture = - command_line.HasSwitch(switches::kHistoryEntryRequiresUserGesture); - prefs.disable_ipc_flooding_protection = command_line.HasSwitch(switches::kDisableIpcFloodingProtection) || command_line.HasSwitch(switches::kDisablePushStateThrottle);
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc index 78c2d05c..5ebb41f 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.cc +++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -1222,6 +1222,7 @@ scroll_begin.data.scroll_begin.delta_y_hint = 0; scroll_begin.data.scroll_begin.delta_hint_units = blink::WebGestureEvent::kPrecisePixels; + scroll_begin.data.scroll_begin.scrollable_area_element_id = 0; view->ProcessGestureEvent( scroll_begin, ui::WebInputEventTraits::CreateLatencyInfoForWebGestureEvent(
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc index 28b8075..6f782e97 100644 --- a/content/browser/service_manager/service_manager_context.cc +++ b/content/browser/service_manager/service_manager_context.cc
@@ -807,6 +807,7 @@ auto service = device::CreateDeviceService( device_blocking_task_runner, service_manager_thread_task_runner_, base::MakeRefCounted<DeviceServiceURLLoaderFactory>(), + content::GetNetworkConnectionTracker(), GetContentClient()->browser()->GetGeolocationApiKey(), GetContentClient()->browser()->ShouldUseGmsCoreGeolocationProvider(), base::BindRepeating(&WakeLockContextHost::GetNativeViewForContext), @@ -818,6 +819,7 @@ auto service = device::CreateDeviceService( device_blocking_task_runner, service_manager_thread_task_runner_, base::MakeRefCounted<DeviceServiceURLLoaderFactory>(), + content::GetNetworkConnectionTracker(), GetContentClient()->browser()->GetGeolocationApiKey(), base::BindRepeating( &ContentBrowserClient::OverrideSystemLocationProvider,
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc index 85c0942f..976f85b2 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.cc +++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -41,8 +41,8 @@ traffic_annotation) override { std::string headers = "HTTP/1.1 200 OK\n\n"; net::HttpResponseInfo info; - info.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length())); + info.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); network::ResourceResponseHead response; response.headers = info.headers; response.headers->GetMimeType(&response.mime_type);
diff --git a/content/browser/service_worker/service_worker_new_script_loader_unittest.cc b/content/browser/service_worker/service_worker_new_script_loader_unittest.cc index 6a3f4f8..34a6a405 100644 --- a/content/browser/service_worker/service_worker_new_script_loader_unittest.cc +++ b/content/browser/service_worker/service_worker_new_script_loader_unittest.cc
@@ -93,8 +93,7 @@ // Pass the response header to the client. net::HttpResponseInfo info; info.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(response.headers.c_str(), - response.headers.size())); + net::HttpUtil::AssembleRawHeaders(response.headers)); network::ResourceResponseHead response_head; response_head.headers = info.headers; response_head.headers->GetMimeType(&response_head.mime_type);
diff --git a/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc b/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc index 0531290c..8da31c5 100644 --- a/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc +++ b/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc
@@ -45,8 +45,8 @@ "HTTP/1.1 200 OK\n" "Content-Type: application/javascript\n\n"; net::HttpResponseInfo info; - info.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length())); + info.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); network::ResourceResponseHead response; response.headers = info.headers; response.headers->GetMimeType(&response.mime_type);
diff --git a/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc b/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc index 38c55e6..3afd8184 100644 --- a/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc +++ b/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc
@@ -102,7 +102,7 @@ auto loader_factory = std::make_unique<network::TestURLLoaderFactory>(); network::ResourceResponseHead head; head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(header.c_str(), header.size())); + net::HttpUtil::AssembleRawHeaders(header)); network::URLLoaderCompletionStatus status(error); status.decoded_body_length = body.size(); loader_factory->AddResponse(url, head, body, status);
diff --git a/content/browser/speech/speech_recognition_engine_unittest.cc b/content/browser/speech/speech_recognition_engine_unittest.cc index b6479b9..a4062a1c 100644 --- a/content/browser/speech/speech_recognition_engine_unittest.cc +++ b/content/browser/speech/speech_recognition_engine_unittest.cc
@@ -563,8 +563,8 @@ network::ResourceResponseHead head; std::string headers("HTTP/1.1 200 OK\n\n"); - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); downstream_request->client->OnReceiveResponse(head); mojo::DataPipe data_pipe; @@ -631,8 +631,8 @@ ASSERT_TRUE(downstream_request); network::ResourceResponseHead head; std::string headers("HTTP/1.1 500 Server Sad\n\n"); - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); downstream_request->client->OnReceiveResponse(head); // Wait for the response to be handled. base::RunLoop().RunUntilIdle();
diff --git a/content/browser/speech/speech_recognizer_impl_unittest.cc b/content/browser/speech/speech_recognizer_impl_unittest.cc index 89a1ca0d..0c8ae64 100644 --- a/content/browser/speech/speech_recognizer_impl_unittest.cc +++ b/content/browser/speech/speech_recognizer_impl_unittest.cc
@@ -580,7 +580,7 @@ network::ResourceResponseHead response; const char kHeaders[] = "HTTP/1.0 500 Internal Server Error"; response.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(kHeaders, base::size(kHeaders))); + net::HttpUtil::AssembleRawHeaders(kHeaders)); url_loader_factory_.AddResponse(pending_request->request.url, response, "", network::URLLoaderCompletionStatus());
diff --git a/content/browser/speech/tts_android.cc b/content/browser/speech/tts_android.cc index 475d22e..7ee5ee30 100644 --- a/content/browser/speech/tts_android.cc +++ b/content/browser/speech/tts_android.cc
@@ -40,6 +40,18 @@ const VoiceData& voice, const UtteranceContinuousParameters& params, base::OnceCallback<void(bool)> on_speak_finished) { + // Insert call to ParseSSML. + ProcessSpeech(utterance_id, utterance, lang, voice, params, + std::move(on_speak_finished)); +} + +void TtsPlatformImplAndroid::ProcessSpeech( + int utterance_id, + const std::string& utterance, + const std::string& lang, + const VoiceData& voice, + const UtteranceContinuousParameters& params, + base::OnceCallback<void(bool)> on_speak_finished) { JNIEnv* env = AttachCurrentThread(); jboolean success = Java_TtsPlatformImpl_speak( env, java_ref_, utterance_id,
diff --git a/content/browser/speech/tts_android.h b/content/browser/speech/tts_android.h index 22769aa..052fcbc 100644 --- a/content/browser/speech/tts_android.h +++ b/content/browser/speech/tts_android.h
@@ -53,6 +53,13 @@ TtsEventType event_type, int char_index); + void ProcessSpeech(int utterance_id, + const std::string& utterance, + const std::string& lang, + const VoiceData& voice, + const UtteranceContinuousParameters& params, + base::OnceCallback<void(bool)> on_speak_finished); + base::android::ScopedJavaGlobalRef<jobject> java_ref_; int utterance_id_; std::string utterance_;
diff --git a/content/browser/speech/tts_linux.cc b/content/browser/speech/tts_linux.cc index 5ba5a23..7897c47 100644 --- a/content/browser/speech/tts_linux.cc +++ b/content/browser/speech/tts_linux.cc
@@ -74,6 +74,13 @@ SPDNotificationType state, char* index_mark); + void ProcessSpeech(int utterance_id, + const std::string& utterance, + const std::string& lang, + const VoiceData& voice, + const UtteranceContinuousParameters& params, + base::OnceCallback<void(bool)> on_speak_finished); + static SPDNotificationType current_notification_; base::Lock initialization_lock_; @@ -174,6 +181,18 @@ return; } + // Insert call to StripSSML. + ProcessSpeech(utterance_id, utterance, lang, voice, params, + std::move(on_speak_finished)); +} + +void TtsPlatformImplLinux::ProcessSpeech( + int utterance_id, + const std::string& utterance, + const std::string& lang, + const VoiceData& voice, + const UtteranceContinuousParameters& params, + base::OnceCallback<void(bool)> on_speak_finished) { // Speech dispatcher's speech params are around 3x at either limit. float rate = params.rate > 3 ? 3 : params.rate; rate = params.rate < 0.334 ? 0.334 : rate;
diff --git a/content/browser/speech/tts_mac.mm b/content/browser/speech/tts_mac.mm index b3d1c64..85bb283 100644 --- a/content/browser/speech/tts_mac.mm +++ b/content/browser/speech/tts_mac.mm
@@ -84,6 +84,13 @@ TtsPlatformImplMac(); ~TtsPlatformImplMac() override; + void ProcessSpeech(int utterance_id, + const std::string& utterance, + const std::string& lang, + const content::VoiceData& voice, + const content::UtteranceContinuousParameters& params, + base::OnceCallback<void(bool)> on_speak_finished); + base::scoped_nsobject<SingleUseSpeechSynthesizer> speech_synthesizer_; base::scoped_nsobject<ChromeTtsDelegate> delegate_; int utterance_id_; @@ -109,6 +116,19 @@ const content::UtteranceContinuousParameters& params, base::OnceCallback<void(bool)> on_speak_finished) { // TODO: convert SSML to SAPI xml. http://crbug.com/88072 + // Insert call to ParseSSML. + + ProcessSpeech(utterance_id, utterance, lang, voice, params, + std::move(on_speak_finished)); +} + +void TtsPlatformImplMac::ProcessSpeech( + int utterance_id, + const std::string& utterance, + const std::string& lang, + const content::VoiceData& voice, + const content::UtteranceContinuousParameters& params, + base::OnceCallback<void(bool)> on_speak_finished) { utterance_ = utterance; paused_ = false;
diff --git a/content/browser/speech/tts_win.cc b/content/browser/speech/tts_win.cc index 38fede51..0ee633c3 100644 --- a/content/browser/speech/tts_win.cc +++ b/content/browser/speech/tts_win.cc
@@ -63,6 +63,13 @@ void SetVoiceFromName(const std::string& name); + void ProcessSpeech(int utterance_id, + const std::string& utterance, + const std::string& lang, + const VoiceData& voice, + const UtteranceContinuousParameters& params, + base::OnceCallback<void(bool)> on_speak_finished); + Microsoft::WRL::ComPtr<ISpVoice> speech_synthesizer_; // These apply to the current utterance only. @@ -87,6 +94,18 @@ void TtsPlatformImplWin::Speak( int utterance_id, + const std::string& utterance, + const std::string& lang, + const VoiceData& voice, + const UtteranceContinuousParameters& params, + base::OnceCallback<void(bool)> on_speak_finished) { + // Insert call to ParseSSML. + ProcessSpeech(utterance_id, utterance, lang, voice, params, + std::move(on_speak_finished)); +} + +void TtsPlatformImplWin::ProcessSpeech( + int utterance_id, const std::string& src_utterance, const std::string& lang, const VoiceData& voice,
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc index 74f537d11..2ff912c1 100644 --- a/content/browser/web_contents/web_contents_view_aura.cc +++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -6,6 +6,8 @@ #include <stddef.h> #include <stdint.h> +#include <string> +#include <utility> #include "base/auto_reset.h" #include "base/command_line.h" @@ -34,6 +36,7 @@ #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/guest_mode.h" +#include "content/public/browser/navigation_handle.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_source.h" @@ -306,6 +309,13 @@ data.GetFilenames(&drop_data->filenames); +#if defined(OS_WIN) + // Get a list of virtual files for later retrieval when a drop is performed + // (will return empty vector if there are any non-virtual files in the data + // store). + data.GetVirtualFilenames(&drop_data->filenames); +#endif + base::Pickle pickle; std::vector<DropData::FileSystemFileInfo> file_system_files; if (data.GetPickledData(GetFileSystemFileFormatType(), &pickle) && @@ -357,6 +367,120 @@ } // namespace +#if defined(OS_WIN) +// A web contents observer that watches for navigations while an async drop +// operation is in progress during virtual file data retrieval and temp file +// creation. Navigations may cause completion of the drop to be disallowed. The +// class also serves to cache the drop parameters as they were at the beginning +// of the drop. This is needed for checking that the drop target is still valid +// when the async operation completes, and if so, passing the parameters on to +// the render widget host to complete the drop. +class WebContentsViewAura::AsyncDropNavigationObserver + : public WebContentsObserver { + public: + AsyncDropNavigationObserver(WebContents* watched_contents, + std::unique_ptr<DropData> drop_data, + RenderWidgetHostImpl* target_rwh, + const gfx::PointF& client_pt, + const gfx::PointF& screen_pt, + int key_modifiers); + + // WebContentsObserver: + void DidFinishNavigation(NavigationHandle* navigation_handle) override; + + // Was a navigation observed while the async drop was being processed that + // should disallow the drop? + bool drop_allowed() const { return drop_allowed_; } + + DropData* drop_data() const { return drop_data_.get(); } + RenderWidgetHostImpl* target_rwh() const { return target_rwh_.get(); } + const gfx::PointF& client_pt() const { return client_pt_; } + const gfx::PointF& screen_pt() const { return screen_pt_; } + int key_modifiers() const { return key_modifiers_; } + + private: + bool drop_allowed_; + + // Data cached at the start of the drop operation and needed to complete the + // drop. + std::unique_ptr<DropData> drop_data_; + base::WeakPtr<RenderWidgetHostImpl> target_rwh_; + const gfx::PointF client_pt_; + const gfx::PointF screen_pt_; + const int key_modifiers_; + + DISALLOW_COPY_AND_ASSIGN(AsyncDropNavigationObserver); +}; + +WebContentsViewAura::AsyncDropNavigationObserver::AsyncDropNavigationObserver( + WebContents* watched_contents, + std::unique_ptr<DropData> drop_data, + RenderWidgetHostImpl* target_rwh, + const gfx::PointF& client_pt, + const gfx::PointF& screen_pt, + int key_modifiers) + : WebContentsObserver(watched_contents), + drop_allowed_(true), + drop_data_(std::move(drop_data)), + target_rwh_(target_rwh->GetWeakPtr()), + client_pt_(client_pt), + screen_pt_(screen_pt), + key_modifiers_(key_modifiers) {} + +void WebContentsViewAura::AsyncDropNavigationObserver::DidFinishNavigation( + NavigationHandle* navigation_handle) { + // This method is called every time any navigation completes in the observed + // web contents, including subframe navigations. In the case of a subframe + // navigation, we can't readily determine on the browser process side if the + // navigated subframe is the intended drop target. Err on the side of security + // and disallow the drop if any navigation commits to a different url. + if (navigation_handle->HasCommitted() && + (navigation_handle->GetURL() != navigation_handle->GetPreviousURL())) { + drop_allowed_ = false; + } +} + +// Deletes registered temp files asynchronously when the object goes out of +// scope (when the WebContentsViewAura is deleted on tab closure). +class WebContentsViewAura::AsyncDropTempFileDeleter { + public: + AsyncDropTempFileDeleter() = default; + ~AsyncDropTempFileDeleter(); + void RegisterFile(const base::FilePath& path); + + private: + void DeleteAllFilesAsync() const; + void DeleteFileAsync(const base::FilePath& path) const; + + std::vector<base::FilePath> scoped_files_to_delete_; + DISALLOW_COPY_AND_ASSIGN(AsyncDropTempFileDeleter); +}; + +WebContentsViewAura::AsyncDropTempFileDeleter::~AsyncDropTempFileDeleter() { + DeleteAllFilesAsync(); +} + +void WebContentsViewAura::AsyncDropTempFileDeleter::RegisterFile( + const base::FilePath& path) { + scoped_files_to_delete_.push_back(path); +} + +void WebContentsViewAura::AsyncDropTempFileDeleter::DeleteAllFilesAsync() + const { + for (const auto& path : scoped_files_to_delete_) + DeleteFileAsync(path); +} + +void WebContentsViewAura::AsyncDropTempFileDeleter::DeleteFileAsync( + const base::FilePath& path) const { + base::PostTaskWithTraits(FROM_HERE, + {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::BLOCK_SHUTDOWN}, + base::BindOnce(base::IgnoreResult(&base::DeleteFile), + std::move(path), false)); +} +#endif + class WebContentsViewAura::WindowObserver : public aura::WindowObserver, public aura::WindowTreeHostObserver { public: @@ -1114,6 +1238,10 @@ // WebContentsViewAura, aura::client::DragDropDelegate implementation: void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) { +#if defined(OS_WIN) + async_drop_navigation_observer_.reset(); +#endif + gfx::PointF transformed_pt; RenderWidgetHostImpl* target_rwh = web_contents_->GetInputEventRouter()->GetRenderWidgetHostAtPoint( @@ -1240,16 +1368,122 @@ if (!current_drop_data_) return ui::DragDropTypes::DRAG_NONE; - target_rwh->DragTargetDrop( - *current_drop_data_, transformed_pt, - gfx::PointF(display::Screen::GetScreen()->GetCursorScreenPoint()), - ui::EventFlagsToWebEventModifiers(event.flags())); - if (drag_dest_delegate_) - drag_dest_delegate_->OnDrop(); + const int key_modifiers = ui::EventFlagsToWebEventModifiers(event.flags()); +#if defined(OS_WIN) + if (event.data().HasVirtualFilenames()) { + // Asynchronously retrieve the actual content of any virtual files now (this + // step is not needed for "real" files already on the file system, e.g. + // those dropped on Chromium from the desktop). When all content has been + // written to temporary files, the OnGotVirtualFilesAsTempFiles + // callback will be invoked and the drop communicated to the renderer + // process. + auto callback = + base::BindOnce(&WebContentsViewAura::OnGotVirtualFilesAsTempFiles, + weak_ptr_factory_.GetWeakPtr()); + + // GetVirtualFilesAsTempFiles will immediately return false if there are no + // virtual files to retrieve (all items are folders e.g.) and no callback + // will be received. + if (event.data().GetVirtualFilesAsTempFiles(std::move(callback))) { + // Cache the parameters as they were at the time of the drop. This is + // needed for checking that the drop target is still valid when the async + // operation completes. + async_drop_navigation_observer_ = + std::make_unique<AsyncDropNavigationObserver>( + web_contents_, std::move(current_drop_data_), target_rwh, + transformed_pt, screen_pt, key_modifiers); + + return ConvertFromWeb(current_drag_op_); + } + } + +#endif + CompleteDrop(target_rwh, *current_drop_data_, transformed_pt, screen_pt, + key_modifiers); current_drop_data_.reset(); return ConvertFromWeb(current_drag_op_); } +void WebContentsViewAura::CompleteDrop(RenderWidgetHostImpl* target_rwh, + const DropData& drop_data, + const gfx::PointF& client_pt, + const gfx::PointF& screen_pt, + int key_modifiers) { + target_rwh->DragTargetDrop(drop_data, client_pt, screen_pt, key_modifiers); + if (drag_dest_delegate_) + drag_dest_delegate_->OnDrop(); + + if (!drop_callback_for_testing_.is_null()) { + std::move(drop_callback_for_testing_) + .Run(target_rwh, drop_data, client_pt, screen_pt, key_modifiers, + /*drop_allowed*/ true); + } +} + +void WebContentsViewAura::RegisterDropCallbackForTesting( + DropCallbackForTesting callback) { + drop_callback_for_testing_ = std::move(callback); +} + +#if defined(OS_WIN) +void WebContentsViewAura::OnGotVirtualFilesAsTempFiles( + const std::vector<std::pair<base::FilePath, base::FilePath>>& + filepaths_and_names) { + DCHECK(!filepaths_and_names.empty()); + + if (!async_drop_navigation_observer_) + return; + + std::unique_ptr<AsyncDropNavigationObserver> drop_observer( + std::move(async_drop_navigation_observer_)); + + RenderWidgetHostImpl* target_rwh = drop_observer->target_rwh(); + DropData* drop_data = drop_observer->drop_data(); + + // Security check--don't allow the drop if a navigation occurred since the + // drop was initiated or the render widget host has changed or it is not a + // valid target. + if (!drop_observer->drop_allowed() || + !(target_rwh && target_rwh == current_rwh_for_drag_.get() && + IsValidDragTarget(target_rwh))) { + // Signal test code that the drop is disallowed + if (!drop_callback_for_testing_.is_null()) { + std::move(drop_callback_for_testing_) + .Run(target_rwh, *drop_data, drop_observer->client_pt(), + drop_observer->screen_pt(), drop_observer->key_modifiers(), + drop_observer->drop_allowed()); + } + + return; + } + + // The vector of filenames will still have items added during dragenter + // (script is allowed to enumerate the files in the data store but not + // retrieve the file contents in dragenter). But the temp file path in the + // FileInfo structs will just be a placeholder. Clear out the vector before + // replacing it with FileInfo structs that have the paths to the retrieved + // file contents. + drop_data->filenames.clear(); + + // Ensure we have temp file deleter. + if (!async_drop_temp_file_deleter_) { + async_drop_temp_file_deleter_ = + std::make_unique<AsyncDropTempFileDeleter>(); + } + + for (const auto& filepath_and_name : filepaths_and_names) { + drop_data->filenames.push_back( + ui::FileInfo(filepath_and_name.first, filepath_and_name.second)); + + // Make sure the temp file eventually gets cleaned up. + async_drop_temp_file_deleter_->RegisterFile(filepath_and_name.first); + } + + CompleteDrop(target_rwh, *drop_data, drop_observer->client_pt(), + drop_observer->screen_pt(), drop_observer->key_modifiers()); +} +#endif + int WebContentsViewAura::GetTopControlsHeight() const { WebContentsDelegate* delegate = web_contents_->GetDelegate(); if (!delegate)
diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h index a1395da..22d8ee98 100644 --- a/content/browser/web_contents/web_contents_view_aura.h +++ b/content/browser/web_contents/web_contents_view_aura.h
@@ -6,12 +6,14 @@ #define CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_VIEW_AURA_H_ #include <memory> +#include <utility> #include <vector> #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "build/build_config.h" #include "content/browser/renderer_host/render_view_host_delegate_view.h" #include "content/browser/web_contents/web_contents_view.h" #include "content/common/buildflags.h" @@ -62,6 +64,11 @@ RenderWidgetHostViewCreateFunction create_render_widget_host_view); private: + friend class WebContentsViewAuraTest; + FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest, EnableDisableOverscroll); + FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest, DragDropFiles); + FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest, DragDropVirtualFiles); + class WindowObserver; ~WebContentsViewAura() override; @@ -181,7 +188,39 @@ void OnDragExited() override; int OnPerformDrop(const ui::DropTargetEvent& event) override; - FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest, EnableDisableOverscroll); + // Completes a drop operation by communicating the drop data to the renderer + // process. + void CompleteDrop(RenderWidgetHostImpl* target_rwh, + const DropData& drop_data, + const gfx::PointF& client_pt, + const gfx::PointF& screen_pt, + int key_modifiers); + + // For unit testing, registers a callback for when a drop operation + // completes. + using DropCallbackForTesting = + base::OnceCallback<void(RenderWidgetHostImpl* target_rwh, + const DropData& drop_data, + const gfx::PointF& client_pt, + const gfx::PointF& screen_pt, + int key_modifiers, + bool drop_allowed)>; + void RegisterDropCallbackForTesting(DropCallbackForTesting callback); + +#if defined(OS_WIN) + // Callback for asynchronous retrieval of virtual files. + void OnGotVirtualFilesAsTempFiles( + const std::vector<std::pair</*temp path*/ base::FilePath, + /*display name*/ base::FilePath>>& + filepaths_and_names); + + class AsyncDropNavigationObserver; + std::unique_ptr<AsyncDropNavigationObserver> async_drop_navigation_observer_; + + class AsyncDropTempFileDeleter; + std::unique_ptr<AsyncDropTempFileDeleter> async_drop_temp_file_deleter_; +#endif + DropCallbackForTesting drop_callback_for_testing_; const bool is_mus_browser_plugin_guest_; @@ -229,6 +268,12 @@ bool init_rwhv_with_null_parent_for_testing_; +#if defined(OS_WIN) + // Used to ensure that the virtual files retrieval callback bound to this + // object is canceled when this object is destroyed. + base::WeakPtrFactory<WebContentsViewAura> weak_ptr_factory_{this}; +#endif + DISALLOW_COPY_AND_ASSIGN(WebContentsViewAura); };
diff --git a/content/browser/web_contents/web_contents_view_aura_unittest.cc b/content/browser/web_contents/web_contents_view_aura_unittest.cc index 426ffbfe..fb8f274 100644 --- a/content/browser/web_contents/web_contents_view_aura_unittest.cc +++ b/content/browser/web_contents/web_contents_view_aura_unittest.cc
@@ -5,11 +5,15 @@ #include "content/browser/web_contents/web_contents_view_aura.h" #include <memory> +#include <string> #include "base/command_line.h" +#include "base/files/file_util.h" #include "base/macros.h" +#include "base/run_loop.h" #include "base/test/scoped_command_line.h" #include "base/test/scoped_feature_list.h" +#include "build/build_config.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/common/content_features.h" #include "content/public/test/test_renderer_host.h" @@ -18,16 +22,40 @@ #include "ui/aura/test/test_windows.h" #include "ui/aura/test/window_test_api.h" #include "ui/aura/window.h" +#include "ui/base/dragdrop/drag_drop_types.h" +#include "ui/base/dragdrop/drop_target_event.h" +#include "ui/base/dragdrop/os_exchange_data.h" #include "ui/display/display_switches.h" #include "ui/gfx/geometry/rect.h" +#if defined(OS_WIN) +#include "ui/base/dragdrop/os_exchange_data_provider_win.h" +#endif + namespace content { namespace { constexpr gfx::Rect kBounds = gfx::Rect(0, 0, 20, 20); +constexpr gfx::PointF kClientPt = {5, 10}; +constexpr gfx::PointF kScreenPt = {17, 3}; } // namespace class WebContentsViewAuraTest : public RenderViewHostTestHarness { + public: + void OnDropComplete(RenderWidgetHostImpl* target_rwh, + const DropData& drop_data, + const gfx::PointF& client_pt, + const gfx::PointF& screen_pt, + int key_modifiers, + bool drop_allowed) { + // Cache the data for verification. + drop_complete_data_ = std::make_unique<DropCompleteData>( + target_rwh, drop_data, client_pt, screen_pt, key_modifiers, + drop_allowed); + + std::move(async_drop_closure_).Run(); + } + protected: WebContentsViewAuraTest() = default; ~WebContentsViewAuraTest() override = default; @@ -56,9 +84,47 @@ aura::Window* GetNativeView() { return web_contents()->GetNativeView(); } + void CheckDropData(WebContentsViewAura* wcva) const { + EXPECT_EQ(nullptr, wcva->current_drop_data_); + ASSERT_NE(nullptr, drop_complete_data_); + EXPECT_TRUE(drop_complete_data_->drop_allowed); + EXPECT_EQ(wcva->current_rwh_for_drag_.get(), + drop_complete_data_->target_rwh.get()); + EXPECT_EQ(kClientPt, drop_complete_data_->client_pt); + // Screen point of event is ignored, instead cursor position used. + EXPECT_EQ(gfx::PointF(), drop_complete_data_->screen_pt); + EXPECT_EQ(0, drop_complete_data_->key_modifiers); + } + // |occluding_window_| occludes |web_contents()| when it's shown. std::unique_ptr<aura::Window> occluding_window_; + // A closure indicating that async drop operation has completed. + base::OnceClosure async_drop_closure_; + + struct DropCompleteData { + DropCompleteData(RenderWidgetHostImpl* target_rwh, + const DropData& drop_data, + const gfx::PointF& client_pt, + const gfx::PointF& screen_pt, + int key_modifiers, + bool drop_allowed) + : target_rwh(target_rwh->GetWeakPtr()), + drop_data(drop_data), + client_pt(client_pt), + screen_pt(screen_pt), + key_modifiers(key_modifiers), + drop_allowed(drop_allowed) {} + + base::WeakPtr<RenderWidgetHostImpl> target_rwh; + const DropData drop_data; + const gfx::PointF client_pt; + const gfx::PointF screen_pt; + const int key_modifiers; + const bool drop_allowed; + }; + std::unique_ptr<DropCompleteData> drop_complete_data_; + private: DISALLOW_COPY_AND_ASSIGN(WebContentsViewAuraTest); }; @@ -90,4 +156,162 @@ EXPECT_EQ(web_contents()->GetVisibility(), Visibility::VISIBLE); } +TEST_F(WebContentsViewAuraTest, DragDropFiles) { + WebContentsViewAura* wcva = view(); + ui::OSExchangeData data; + + const base::string16 string_data = base::ASCIIToUTF16("Some string data"); + data.SetString(string_data); + +#if defined(OS_WIN) + const std::vector<ui::FileInfo> test_file_infos = { + {base::FilePath(FILE_PATH_LITERAL("C:\\tmp\\test_file1")), + base::FilePath()}, + {base::FilePath(FILE_PATH_LITERAL("C:\\tmp\\test_file2")), + base::FilePath()}, + { + base::FilePath(FILE_PATH_LITERAL("C:\\tmp\\test_file3")), + base::FilePath(), + }, + }; +#else + const std::vector<ui::FileInfo> test_file_infos = { + {base::FilePath(FILE_PATH_LITERAL("/tmp/test_file1")), base::FilePath()}, + {base::FilePath(FILE_PATH_LITERAL("/tmp/test_file2")), base::FilePath()}, + {base::FilePath(FILE_PATH_LITERAL("/tmp/test_file3")), base::FilePath()}, + }; +#endif + data.SetFilenames(test_file_infos); + + ui::DropTargetEvent event(data, kClientPt, kScreenPt, + ui::DragDropTypes::DRAG_COPY); + + // Simulate drag enter. + EXPECT_EQ(nullptr, wcva->current_drop_data_); + wcva->OnDragEntered(event); + ASSERT_NE(nullptr, wcva->current_drop_data_); + +#if defined(USE_X11) + // By design, OSExchangeDataProviderAuraX11::GetString returns an empty string + // if file data is also present. + EXPECT_TRUE(wcva->current_drop_data_->text.string().empty()); +#else + EXPECT_EQ(string_data, wcva->current_drop_data_->text.string()); +#endif + + std::vector<ui::FileInfo> retrieved_file_infos = + wcva->current_drop_data_->filenames; + ASSERT_EQ(test_file_infos.size(), retrieved_file_infos.size()); + for (size_t i = 0; i < retrieved_file_infos.size(); i++) { + EXPECT_EQ(test_file_infos[i].path, retrieved_file_infos[i].path); + EXPECT_EQ(test_file_infos[i].display_name, + retrieved_file_infos[i].display_name); + } + + // Simulate drop. + auto callback = base::BindOnce(&WebContentsViewAuraTest::OnDropComplete, + base::Unretained(this)); + wcva->RegisterDropCallbackForTesting(std::move(callback)); + + base::RunLoop run_loop; + async_drop_closure_ = run_loop.QuitClosure(); + + wcva->OnPerformDrop(event); + run_loop.Run(); + + CheckDropData(wcva); + +#if defined(USE_X11) + // By design, OSExchangeDataProviderAuraX11::GetString returns an empty string + // if file data is also present. + EXPECT_TRUE(drop_complete_data_->drop_data.text.string().empty()); +#else + EXPECT_EQ(string_data, drop_complete_data_->drop_data.text.string()); +#endif + + retrieved_file_infos = drop_complete_data_->drop_data.filenames; + ASSERT_EQ(test_file_infos.size(), retrieved_file_infos.size()); + for (size_t i = 0; i < retrieved_file_infos.size(); i++) { + EXPECT_EQ(test_file_infos[i].path, retrieved_file_infos[i].path); + EXPECT_EQ(test_file_infos[i].display_name, + retrieved_file_infos[i].display_name); + } +} + +#if defined(OS_WIN) +TEST_F(WebContentsViewAuraTest, DragDropVirtualFiles) { + WebContentsViewAura* wcva = view(); + ui::OSExchangeData data; + + const base::string16 string_data = base::ASCIIToUTF16("Some string data"); + data.SetString(string_data); + + const std::vector<std::pair<base::FilePath, std::string>> + test_filenames_and_contents = { + {base::FilePath(FILE_PATH_LITERAL("filename.txt")), + std::string("just some data")}, + {base::FilePath(FILE_PATH_LITERAL("another filename.txt")), + std::string("just some data\0with\0nulls", 25)}, + {base::FilePath(FILE_PATH_LITERAL("and another filename.txt")), + std::string("just some more data")}, + }; + + data.provider().SetVirtualFileContentsForTesting(test_filenames_and_contents, + TYMED_ISTREAM); + + ui::DropTargetEvent event(data, kClientPt, kScreenPt, + ui::DragDropTypes::DRAG_COPY); + + // Simulate drag enter. + EXPECT_EQ(nullptr, wcva->current_drop_data_); + wcva->OnDragEntered(event); + ASSERT_NE(nullptr, wcva->current_drop_data_); + + EXPECT_EQ(string_data, wcva->current_drop_data_->text.string()); + + const base::FilePath path_placeholder(FILE_PATH_LITERAL("temp.tmp")); + std::vector<ui::FileInfo> retrieved_file_infos = + wcva->current_drop_data_->filenames; + ASSERT_EQ(test_filenames_and_contents.size(), retrieved_file_infos.size()); + for (size_t i = 0; i < retrieved_file_infos.size(); i++) { + EXPECT_EQ(test_filenames_and_contents[i].first, + retrieved_file_infos[i].display_name); + EXPECT_EQ(path_placeholder, retrieved_file_infos[i].path); + } + + // Simulate drop (completes asynchronously since virtual file data is + // present). + auto callback = base::BindOnce(&WebContentsViewAuraTest::OnDropComplete, + base::Unretained(this)); + wcva->RegisterDropCallbackForTesting(std::move(callback)); + + base::RunLoop run_loop; + async_drop_closure_ = run_loop.QuitClosure(); + + wcva->OnPerformDrop(event); + run_loop.Run(); + + CheckDropData(wcva); + + EXPECT_EQ(string_data, drop_complete_data_->drop_data.text.string()); + + std::string read_contents; + base::FilePath temp_dir; + EXPECT_TRUE(base::GetTempDir(&temp_dir)); + + retrieved_file_infos = drop_complete_data_->drop_data.filenames; + ASSERT_EQ(test_filenames_and_contents.size(), retrieved_file_infos.size()); + for (size_t i = 0; i < retrieved_file_infos.size(); i++) { + EXPECT_EQ(test_filenames_and_contents[i].first, + retrieved_file_infos[i].display_name); + EXPECT_EQ(temp_dir, retrieved_file_infos[i].path.DirName()); + EXPECT_EQ(test_filenames_and_contents[i].first.Extension(), + retrieved_file_infos[i].path.Extension()); + EXPECT_TRUE( + base::ReadFileToString(retrieved_file_infos[i].path, &read_contents)); + EXPECT_EQ(test_filenames_and_contents[i].second, read_contents); + } +} +#endif + } // namespace content
diff --git a/content/browser/web_package/signed_exchange_envelope.cc b/content/browser/web_package/signed_exchange_envelope.cc index e090e5f..8200026 100644 --- a/content/browser/web_package/signed_exchange_envelope.cc +++ b/content/browser/web_package/signed_exchange_envelope.cc
@@ -361,7 +361,7 @@ } header_str.append("\r\n"); return base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(header_str.c_str(), header_str.size())); + net::HttpUtil::AssembleRawHeaders(header_str)); } void SignedExchangeEnvelope::set_cbor_header(base::span<const uint8_t> data) {
diff --git a/content/browser/web_package/signed_exchange_loader.cc b/content/browser/web_package/signed_exchange_loader.cc index d377c5d..1593702a 100644 --- a/content/browser/web_package/signed_exchange_loader.cc +++ b/content/browser/web_package/signed_exchange_loader.cc
@@ -109,8 +109,8 @@ "link: %s\r\n", 303, "See Other", link_header_.c_str()); } - response_head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(buf.c_str(), buf.size())); + response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(buf)); response_head.encoded_data_length = 0; response_head.request_start = request_start_; response_head.response_start = response_start_;
diff --git a/content/browser/web_package/signed_exchange_loader_unittest.cc b/content/browser/web_package/signed_exchange_loader_unittest.cc index 0aae537..9918ebb 100644 --- a/content/browser/web_package/signed_exchange_loader_unittest.cc +++ b/content/browser/web_package/signed_exchange_loader_unittest.cc
@@ -163,8 +163,8 @@ network::ResourceResponseHead response; std::string headers("HTTP/1.1 200 OK\nnContent-type: foo/bar\n\n"); - response.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + response.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); MockSignedExchangeHandlerFactory factory({MockSignedExchangeHandlerParams( resource_request.url, SignedExchangeLoadResult::kSuccess, net::OK,
diff --git a/content/browser/webkit_browsertest.cc b/content/browser/webkit_browsertest.cc index bde19649..eacc310b 100644 --- a/content/browser/webkit_browsertest.cc +++ b/content/browser/webkit_browsertest.cc
@@ -28,8 +28,8 @@ "HTTP/1.1 400 This is not OK\n" "Content-type: text/plain\n"; net::HttpResponseInfo info; - info.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length())); + info.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); network::ResourceResponseHead response; response.headers = info.headers; response.headers->GetMimeType(&response.mime_type);
diff --git a/content/browser/worker_host/worker_script_loader_factory_unittest.cc b/content/browser/worker_host/worker_script_loader_factory_unittest.cc index f298cafa..b716d66 100644 --- a/content/browser/worker_host/worker_script_loader_factory_unittest.cc +++ b/content/browser/worker_host/worker_script_loader_factory_unittest.cc
@@ -44,8 +44,8 @@ "HTTP/1.1 200 OK\n" "Content-Type: application/javascript\n\n"; net::HttpResponseInfo info; - info.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length())); + info.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); network::ResourceResponseHead response; response.headers = info.headers; response.headers->GetMimeType(&response.mime_type);
diff --git a/content/common/service_worker/service_worker_loader_helpers.cc b/content/common/service_worker/service_worker_loader_helpers.cc index 7001578..f9beb85 100644 --- a/content/common/service_worker/service_worker_loader_helpers.cc +++ b/content/common/service_worker/service_worker_loader_helpers.cc
@@ -65,8 +65,8 @@ } buf.append("\r\n"); - out_head->headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(buf.c_str(), buf.size())); + out_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(buf)); // Populate |out_head|'s MIME type with the value from the HTTP response // headers.
diff --git a/content/common/throttling_url_loader.cc b/content/common/throttling_url_loader.cc index 9943363a..9f1714e 100644 --- a/content/common/throttling_url_loader.cc +++ b/content/common/throttling_url_loader.cc
@@ -390,9 +390,8 @@ "Location: %s\n", net::HTTP_TEMPORARY_REDIRECT, throttle_will_start_redirect_url_.spec().c_str()); - response_head.headers = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - header_string.c_str(), header_string.length())); + response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(header_string)); response_head.encoded_data_length = header_string.size(); OnReceiveRedirect(redirect_info, response_head); return;
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/captioning/CaptioningChangeDelegate.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/captioning/CaptioningChangeDelegate.java index e1411aef..9530114 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/captioning/CaptioningChangeDelegate.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/captioning/CaptioningChangeDelegate.java
@@ -13,7 +13,6 @@ import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; -import java.util.EnumSet; import java.util.Locale; import java.util.Map; import java.util.WeakHashMap; @@ -77,15 +76,11 @@ mTextTrackTextColor = androidColorToCssColor(userStyle.getForegroundColor()); mTextTrackBackgroundColor = androidColorToCssColor(userStyle.getBackgroundColor()); - final ClosedCaptionEdgeAttribute edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute( - userStyle.getEdgeType(), - androidColorToCssColor(userStyle.getEdgeColor())); - - mTextTrackTextShadow = edge.getTextShadow(); + mTextTrackTextShadow = getShadowFromColorAndSystemEdge( + androidColorToCssColor(userStyle.getEdgeColor()), userStyle.getEdgeType()); final Typeface typeFace = userStyle.getTypeface(); - final ClosedCaptionFont font = ClosedCaptionFont.fromSystemFont(typeFace); - mTextTrackFontFamily = font.getFontFamily(); + mTextTrackFontFamily = getFontFromSystemFont(typeFace); if (typeFace != null && typeFace.isItalic()) { mTextTrackFontStyle = FONT_STYLE_ITALIC; } else { @@ -104,167 +99,65 @@ } /** - * Describes a character edge attribute for closed captioning + * Get the formatted Text Shadow CSS property from the edge and color attribute. + * + * @return the CSS-friendly String representation of the + * edge attribute. */ - public static enum ClosedCaptionEdgeAttribute { - NONE (""), - OUTLINE ("%2$s %2$s 0 %1$s, -%2$s -%2$s 0 %1$s, %2$s -%2$s 0 %1$s, -%2$s %2$s 0 %1$s"), - DROP_SHADOW ("%1$s %2$s %2$s 0.1em"), - RAISED ("-%2$s -%2$s 0 %1$s"), - DEPRESSED ("%2$s %2$s 0 %1$s"); - - private static String sDefaultEdgeColor = "silver"; - private static String sShadowOffset = "0.05em"; - private static String sEdgeColor; - private final String mTextShadow; - - private ClosedCaptionEdgeAttribute(String textShadow) { - mTextShadow = textShadow; - } - - /** - * Create a {@link ClosedCaptionEdgeAttribute} object based on the type number. - * - * @param type The edge type value specified by the user - * @param color The color of the edge (e.g. "red") - * @return The enum object - */ - public static ClosedCaptionEdgeAttribute fromSystemEdgeAttribute(Integer type, - String color) { - if (type == null) { - return NONE; - } - if (color == null || color.isEmpty()) { - sEdgeColor = sDefaultEdgeColor; - } else { - sEdgeColor = color; - } + public static String getShadowFromColorAndSystemEdge(String color, Integer type) { + String edgeShadow = ""; + if (type != null) { // Lollipop adds support for EDGE_TYPE_DEPRESSED and EDGE_TYPE_RAISED. switch (type) { case CaptionStyle.EDGE_TYPE_OUTLINE: - return OUTLINE; + edgeShadow = + "%2$s %2$s 0 %1$s, -%2$s -%2$s 0 %1$s, %2$s -%2$s 0 %1$s, -%2$s %2$s 0 %1$s"; + break; case CaptionStyle.EDGE_TYPE_DROP_SHADOW: - return DROP_SHADOW; + edgeShadow = "%1$s %2$s %2$s 0.1em"; + break; case CaptionStyle.EDGE_TYPE_RAISED: - return RAISED; + edgeShadow = "-%2$s -%2$s 0 %1$s"; + break; case CaptionStyle.EDGE_TYPE_DEPRESSED: - return DEPRESSED; + edgeShadow = "%2$s %2$s 0 %1$s"; + break; default: // CaptionStyle.EDGE_TYPE_NONE // CaptionStyle.EDGE_TYPE_UNSPECIFIED - return NONE; + break; } } - /** - * Specify a new shadow offset for the edge attribute. This - * will be used as both the horizontal and vertical - * offset. - * - * @param shadowOffset the offset to be applied - */ - public static void setShadowOffset(String shadowOffset) { - sShadowOffset = shadowOffset; - } + String edgeColor = color; + if (edgeColor == null || edgeColor.isEmpty()) edgeColor = "silver"; - /** - * Default color to use if no color is specified when - * using this enumeration. "silver" is the initial default. - * - * @param color The Color to use if none is specified - * when calling fromSystemEdgeAttribute - */ - public static void setDefaultEdgeColor(String color) { - sDefaultEdgeColor = color; - } - - /** - * Get the Text Shadow CSS property from the edge attribute. - * - * @return the CSS-friendly String representation of the - * edge attribute. - */ - public String getTextShadow() { - return String.format(mTextShadow, sEdgeColor, sShadowOffset); - } + return String.format(edgeShadow, edgeColor, "0.05em"); } /** - * Describes a font available for Closed Captioning + * Create a font family name based on provided Typeface. + * + * @param typeFace a Typeface object. + * @return a string representation of the font family name. */ - public static enum ClosedCaptionFont { + public static String getFontFromSystemFont(Typeface typeFace) { + if (typeFace == null) return ""; + // The list of fonts are obtained from apps/Settings/res/values/arrays.xml // in Android settings app. - // Fonts in Lollipop and above - DEFAULT ("", EnumSet.noneOf(Flags.class)), - SANS_SERIF ("sans-serif", EnumSet.of(Flags.SANS_SERIF)), - SANS_SERIF_CONDENSED ("sans-serif-condensed", EnumSet.of(Flags.SANS_SERIF)), - SANS_SERIF_MONOSPACE ("sans-serif-monospace", - EnumSet.of(Flags.SANS_SERIF, Flags.MONOSPACE)), - SERIF ("serif", EnumSet.of(Flags.SERIF)), - SERIF_MONOSPACE ("serif-monospace", EnumSet.of(Flags.SERIF, Flags.MONOSPACE)), - CASUAL ("casual", EnumSet.noneOf(Flags.class)), - CURSIVE ("cursive", EnumSet.noneOf(Flags.class)), - SANS_SERIF_SMALLCAPS ("sans-serif-smallcaps", EnumSet.of(Flags.SANS_SERIF)), - // Fonts in KitKat - MONOSPACE("monospace", EnumSet.of(Flags.MONOSPACE)); - - /** - * Describes certain properties of a font, used to verify that captioning fonts - * with the correct properties are mapped to system typefaces. - */ - @VisibleForTesting - /* package */ enum Flags { - SANS_SERIF, SERIF, MONOSPACE + String fonts[] = {// Fonts in Lollipop and above + "", "sans-serif", "sans-serif-condensed", "sans-serif-monospace", "serif", + "serif-monospace", "casual", "cursive", "sans-serif-smallcaps", + // Fonts in KitKat + "monospace"}; + for (String font : fonts) { + if (Typeface.create(font, typeFace.getStyle()).equals(typeFace)) return font; } - private final String mFontFamily; - @VisibleForTesting - /* package */ final EnumSet<Flags> mFlags; - - private ClosedCaptionFont(String fontFamily, EnumSet<Flags> flags) { - mFontFamily = fontFamily; - mFlags = flags; - } - - /** - * Create a {@link ClosedCaptionFont} object based on provided Typeface. - * - * @param typeFace a Typeface object - * @return a string representation of the typeface - */ - public static ClosedCaptionFont fromSystemFont(Typeface typeFace) { - if (typeFace == null) return DEFAULT; - for (ClosedCaptionFont font : ClosedCaptionFont.values()) { - if (belongsToFontFamily(typeFace, font)) { - return font; - } - } - // This includes Typeface.DEFAULT_BOLD since font-weight - // is not yet supported as a WebKit setting for a VTTCue. - return DEFAULT; - } - - /** - * Check if the a Typeface belongs to the given font family. - * - * @param typeFace a Typeface object - * @param font Font family to be matched - * @return true if the Typeface belongs to the font family, or false otherwise. - */ - private static boolean belongsToFontFamily(Typeface typeFace, ClosedCaptionFont font) { - return Typeface.create(font.getFontFamily(), typeFace.getStyle()).equals(typeFace); - } - - /** - * Get the font family CSS property from the edge attribute. - * - * @return the CSS-friendly String representation of the - * typeFace. - */ - public String getFontFamily() { - return mFontFamily; - } + // This includes Typeface.DEFAULT_BOLD since font-weight + // is not yet supported as a WebKit setting for a VTTCue. + return ""; } /**
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/captioning/CaptioningChangeDelegateTest.java b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/captioning/CaptioningChangeDelegateTest.java index 2f25c265..5e51ea7 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/captioning/CaptioningChangeDelegateTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/captioning/CaptioningChangeDelegateTest.java
@@ -13,8 +13,6 @@ import org.junit.runner.RunWith; import org.chromium.base.test.BaseJUnit4ClassRunner; -import org.chromium.content.browser.accessibility.captioning.CaptioningChangeDelegate.ClosedCaptionEdgeAttribute; -import org.chromium.content.browser.accessibility.captioning.CaptioningChangeDelegate.ClosedCaptionFont; /** * Test suite to ensure that platform settings are translated to CSS appropriately @@ -84,46 +82,18 @@ @Test @SmallTest public void testClosedCaptionEdgeAttributeWithDefaults() { - ClosedCaptionEdgeAttribute edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute( - null, null); - Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow()); - - edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(null, "red"); - Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow()); - - edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(0, "red"); - Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow()); - - edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(2, null); - Assert.assertEquals("silver 0.05em 0.05em 0.1em", edge.getTextShadow()); - - edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(2, ""); - Assert.assertEquals("silver 0.05em 0.05em 0.1em", edge.getTextShadow()); - - edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(2, "red"); - Assert.assertEquals("red 0.05em 0.05em 0.1em", edge.getTextShadow()); - } - - @Test - @SmallTest - public void testClosedCaptionEdgeAttributeWithCustomDefaults() { - ClosedCaptionEdgeAttribute.setShadowOffset("0.00em"); - ClosedCaptionEdgeAttribute.setDefaultEdgeColor("red"); - ClosedCaptionEdgeAttribute edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute( - null, null); - Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow()); - - edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(null, "red"); - Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow()); - - edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(0, "red"); - Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, edge.getTextShadow()); - - edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(2, null); - Assert.assertEquals("red 0.00em 0.00em 0.1em", edge.getTextShadow()); - - edge = ClosedCaptionEdgeAttribute.fromSystemEdgeAttribute(2, "silver"); - Assert.assertEquals("silver 0.00em 0.00em 0.1em", edge.getTextShadow()); + Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, + CaptioningChangeDelegate.getShadowFromColorAndSystemEdge(null, null)); + Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, + CaptioningChangeDelegate.getShadowFromColorAndSystemEdge("red", null)); + Assert.assertEquals(DEFAULT_CAPTIONING_PREF_VALUE, + CaptioningChangeDelegate.getShadowFromColorAndSystemEdge("red", 0)); + Assert.assertEquals("silver 0.05em 0.05em 0.1em", + CaptioningChangeDelegate.getShadowFromColorAndSystemEdge(null, 2)); + Assert.assertEquals("silver 0.05em 0.05em 0.1em", + CaptioningChangeDelegate.getShadowFromColorAndSystemEdge("", 2)); + Assert.assertEquals("red 0.05em 0.05em 0.1em", + CaptioningChangeDelegate.getShadowFromColorAndSystemEdge("red", 2)); } /** @@ -132,18 +102,17 @@ @Test @SmallTest public void testClosedCaptionDefaultFonts() { - final ClosedCaptionFont nullFont = ClosedCaptionFont.fromSystemFont(null); Assert.assertEquals("Null typeface should return the default font family.", - DEFAULT_CAPTIONING_PREF_VALUE, nullFont.getFontFamily()); + DEFAULT_CAPTIONING_PREF_VALUE, + CaptioningChangeDelegate.getFontFromSystemFont(null)); - final ClosedCaptionFont defaultFont = ClosedCaptionFont.fromSystemFont(Typeface.DEFAULT); Assert.assertEquals("Typeface.DEFAULT should return the default font family.", - DEFAULT_CAPTIONING_PREF_VALUE, defaultFont.getFontFamily()); + DEFAULT_CAPTIONING_PREF_VALUE, + CaptioningChangeDelegate.getFontFromSystemFont(Typeface.DEFAULT)); - final ClosedCaptionFont defaultBoldFont = ClosedCaptionFont.fromSystemFont( - Typeface.DEFAULT_BOLD); Assert.assertEquals("Typeface.BOLD should return the default font family.", - DEFAULT_CAPTIONING_PREF_VALUE, defaultBoldFont.getFontFamily()); + DEFAULT_CAPTIONING_PREF_VALUE, + CaptioningChangeDelegate.getFontFromSystemFont(Typeface.DEFAULT_BOLD)); } /** @@ -154,36 +123,25 @@ @Test @SmallTest public void testClosedCaptionNonDefaultFonts() { - final ClosedCaptionFont monospaceFont = ClosedCaptionFont.fromSystemFont( - Typeface.MONOSPACE); if (Typeface.MONOSPACE.equals(Typeface.DEFAULT)) { Assert.assertEquals( "Since the default font is monospace, the default family should be returned.", - DEFAULT_CAPTIONING_PREF_VALUE, monospaceFont.getFontFamily()); - } else { - Assert.assertTrue("Typeface.MONOSPACE should return a monospace font family.", - monospaceFont.mFlags.contains(ClosedCaptionFont.Flags.MONOSPACE)); + DEFAULT_CAPTIONING_PREF_VALUE, + CaptioningChangeDelegate.getFontFromSystemFont(Typeface.MONOSPACE)); } - final ClosedCaptionFont sansSerifFont = ClosedCaptionFont.fromSystemFont( - Typeface.SANS_SERIF); if (Typeface.SANS_SERIF.equals(Typeface.DEFAULT)) { Assert.assertEquals( "Since the default font is sans-serif, the default family should be returned.", - DEFAULT_CAPTIONING_PREF_VALUE, sansSerifFont.getFontFamily()); - } else { - Assert.assertTrue("Typeface.SANS_SERIF should return a sans-serif font family.", - sansSerifFont.mFlags.contains(ClosedCaptionFont.Flags.SANS_SERIF)); + DEFAULT_CAPTIONING_PREF_VALUE, + CaptioningChangeDelegate.getFontFromSystemFont(Typeface.SANS_SERIF)); } - final ClosedCaptionFont serifFont = ClosedCaptionFont.fromSystemFont(Typeface.SERIF); if (Typeface.SERIF.equals(Typeface.DEFAULT)) { Assert.assertEquals( "Since the default font is serif, the default font family should be returned.", - DEFAULT_CAPTIONING_PREF_VALUE, serifFont.getFontFamily()); - } else { - Assert.assertTrue("Typeface.SERIF should return a serif font family.", - serifFont.mFlags.contains(ClosedCaptionFont.Flags.SERIF)); + DEFAULT_CAPTIONING_PREF_VALUE, + CaptioningChangeDelegate.getFontFromSystemFont(Typeface.SANS_SERIF)); } } }
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h index 24bded9..94113ae5 100644 --- a/content/public/common/common_param_traits_macros.h +++ b/content/public/common/common_param_traits_macros.h
@@ -132,7 +132,6 @@ IPC_STRUCT_TRAITS_MEMBER(databases_enabled) IPC_STRUCT_TRAITS_MEMBER(application_cache_enabled) IPC_STRUCT_TRAITS_MEMBER(tabs_to_links) - IPC_STRUCT_TRAITS_MEMBER(history_entry_requires_user_gesture) IPC_STRUCT_TRAITS_MEMBER(disable_ipc_flooding_protection) IPC_STRUCT_TRAITS_MEMBER(hyperlink_auditing_enabled) IPC_STRUCT_TRAITS_MEMBER(allow_universal_access_from_file_urls)
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index 1075838..b770271 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc
@@ -524,11 +524,6 @@ // Causes the GPU process to display a dialog on launch. const char kGpuStartupDialog[] = "gpu-startup-dialog"; -// Don't allow content to arbitrarily append to the back/forward list. -// The page must prcoess a user gesture before an entry can be added. -const char kHistoryEntryRequiresUserGesture[] = - "history-entry-requires-user-gesture"; - // Start the renderer with an initial virtual time override specified in // seconds since the epoch. const char kInitialVirtualTime[] = "initial-virtual-time";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 57b89770..aa69b75 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h
@@ -159,7 +159,6 @@ CONTENT_EXPORT extern const char kGpuProcess[]; CONTENT_EXPORT extern const char kGpuSandboxStartEarly[]; CONTENT_EXPORT extern const char kGpuStartupDialog[]; -CONTENT_EXPORT extern const char kHistoryEntryRequiresUserGesture[]; CONTENT_EXPORT extern const char kInitialVirtualTime[]; CONTENT_EXPORT extern const char kInProcessGPU[]; CONTENT_EXPORT extern const char kIPCConnectionTimeout[];
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc index 1822036..65a18cd 100644 --- a/content/public/common/web_preferences.cc +++ b/content/public/common/web_preferences.cc
@@ -87,7 +87,6 @@ databases_enabled(false), application_cache_enabled(false), tabs_to_links(true), - history_entry_requires_user_gesture(false), disable_ipc_flooding_protection(false), hyperlink_auditing_enabled(true), allow_universal_access_from_file_urls(false),
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h index a83015f3..653f39410 100644 --- a/content/public/common/web_preferences.h +++ b/content/public/common/web_preferences.h
@@ -110,7 +110,6 @@ bool databases_enabled; bool application_cache_enabled; bool tabs_to_links; - bool history_entry_requires_user_gesture; bool disable_ipc_flooding_protection; bool hyperlink_auditing_enabled; bool allow_universal_access_from_file_urls;
diff --git a/content/public/test/mock_navigation_handle.h b/content/public/test/mock_navigation_handle.h index 73f5875..d4c35963 100644 --- a/content/public/test/mock_navigation_handle.h +++ b/content/public/test/mock_navigation_handle.h
@@ -43,7 +43,7 @@ MOCK_METHOD0(WasStartedFromContextMenu, bool()); MOCK_METHOD0(GetSearchableFormURL, const GURL&()); MOCK_METHOD0(GetSearchableFormEncoding, const std::string&()); - MOCK_METHOD0(GetReloadType, ReloadType()); + ReloadType GetReloadType() override { return reload_type_; } RestoreType GetRestoreType() override { return RestoreType::NONE; } const GURL& GetBaseURLForDataURL() override { return base_url_for_data_url_; } MOCK_METHOD0(IsPost, bool()); @@ -135,6 +135,7 @@ void set_proxy_server(const net::ProxyServer& proxy_server) { proxy_server_ = proxy_server; } + void set_reload_type(ReloadType reload_type) { reload_type_ = reload_type; } private: int64_t navigation_id_; @@ -157,6 +158,7 @@ bool was_response_cached_ = false; net::ProxyServer proxy_server_; base::Optional<url::Origin> initiator_origin_; + ReloadType reload_type_ = content::ReloadType::NONE; }; } // namespace content
diff --git a/content/public/test/url_loader_interceptor.cc b/content/public/test/url_loader_interceptor.cc index 7c6bf92..c40bc0a 100644 --- a/content/public/test/url_loader_interceptor.cc +++ b/content/public/test/url_loader_interceptor.cc
@@ -465,8 +465,8 @@ network::mojom::URLLoaderClient* client, base::Optional<net::SSLInfo> ssl_info) { net::HttpResponseInfo info; - info.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length())); + info.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); network::ResourceResponseHead response; response.headers = info.headers; response.headers->GetMimeType(&response.mime_type);
diff --git a/content/renderer/input/widget_input_handler_manager.cc b/content/renderer/input/widget_input_handler_manager.cc index 6d1c779..1b4e45a 100644 --- a/content/renderer/input/widget_input_handler_manager.cc +++ b/content/renderer/input/widget_input_handler_manager.cc
@@ -257,16 +257,8 @@ void WidgetInputHandlerManager::GenerateScrollBeginAndSendToMainThread( const blink::WebGestureEvent& update_event) { DCHECK_EQ(update_event.GetType(), blink::WebInputEvent::kGestureScrollUpdate); - blink::WebGestureEvent scroll_begin(update_event); - scroll_begin.SetType(blink::WebInputEvent::kGestureScrollBegin); - scroll_begin.data.scroll_begin.inertial_phase = - update_event.data.scroll_update.inertial_phase; - scroll_begin.data.scroll_begin.delta_x_hint = - update_event.data.scroll_update.delta_x; - scroll_begin.data.scroll_begin.delta_y_hint = - update_event.data.scroll_update.delta_y; - scroll_begin.data.scroll_begin.delta_hint_units = - update_event.data.scroll_update.delta_units; + blink::WebGestureEvent scroll_begin = + ui::ScrollBeginFromScrollUpdate(update_event); DispatchNonBlockingEventToMainThread( ui::WebInputEventTraits::Clone(scroll_begin), ui::LatencyInfo());
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc index 6de3884..7b9c89c 100644 --- a/content/renderer/render_view_browsertest.cc +++ b/content/renderer/render_view_browsertest.cc
@@ -2130,8 +2130,8 @@ network::ResourceResponseHead head; std::string headers( "HTTP/1.1 503 SERVICE UNAVAILABLE\nContent-type: text/html\n\n"); - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); TestRenderFrame* main_frame = static_cast<TestRenderFrame*>(frame()); main_frame->Navigate(head, common_params, CommitNavigationParams());
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 6f5469e..a950813 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -696,8 +696,6 @@ WebRuntimeFeatures::EnableDatabase(prefs.databases_enabled); settings->SetOfflineWebApplicationCacheEnabled( prefs.application_cache_enabled); - settings->SetHistoryEntryRequiresUserGesture( - prefs.history_entry_requires_user_gesture); settings->SetShouldProtectAgainstIpcFlooding( !prefs.disable_ipc_flooding_protection); settings->SetHyperlinkAuditingEnabled(prefs.hyperlink_auditing_enabled);
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc index 8396c0e0..c77e44c 100644 --- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc +++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -96,8 +96,8 @@ traffic_annotation) override { std::string headers = "HTTP/1.1 200 OK\n\n"; net::HttpResponseInfo info; - info.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length())); + info.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); network::ResourceResponseHead response; response.headers = info.headers; response.headers->GetMimeType(&response.mime_type); @@ -463,8 +463,8 @@ CreateResponseInfoFromServiceWorker() { auto head = std::make_unique<network::ResourceResponseHead>(); std::string headers = "HTTP/1.1 200 OK\n\n"; - head->headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length())); + head->headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); head->was_fetched_via_service_worker = true; head->was_fallback_required_by_service_worker = false; head->url_list_via_service_worker = std::vector<GURL>();
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 5a8ea7b..93a8a3b1 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1147,6 +1147,7 @@ "../browser/accessibility/accessibility_browsertest.cc", "../browser/accessibility/accessibility_browsertest.h", "../browser/accessibility/accessibility_win_browsertest.cc", + "../browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc", "../browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc", "../browser/accessibility/ax_platform_node_win_browsertest.cc", "../browser/renderer_host/accessibility_object_lifetime_win_browsertest.cc",
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py index d450e160..4ddef29 100644 --- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -431,6 +431,8 @@ ['win', 'passthrough', 'opengl', 'intel'], bug=602688) self.Fail('deqp/functional/gles3/shaderbuiltinvar.html', # ANGLE bug ['win', 'passthrough', 'opengl', 'intel'], bug=2880) + self.Fail('conformance2/rendering/element-index-uint.html', + ['win', 'passthrough', 'intel', 'opengl'], bug=957631) # Passthrough command decoder / Linux / OpenGL / NVIDIA self.Fail('conformance/textures/image_bitmap_from_video/' +
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py index 3f1d8b3..c7e34bc 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -524,6 +524,12 @@ ['win', 'passthrough', 'vulkan', 'amd'], bug=931016) self.Fail('conformance/glsl/bugs/assign-to-swizzled-twice-in-function.html', ['win', 'passthrough', 'vulkan', 'amd'], bug=3343) # ANGLE bug ID + self.Fail('conformance/glsl/samplers/glsl-function-texture2dproj.html', + ['win', 'passthrough', 'amd', 'vulkan'], bug=957644) + self.Fail('conformance/glsl/samplers/glsl-function-texture2dprojlod.html', + ['win', 'passthrough', 'amd', 'vulkan'], bug=957644) + self.Fail('conformance/textures/misc/texture-corner-case-videos.html', + ['win', 'passthrough', 'amd', 'vulkan'], bug=957644) # Mac failures self.Fail('conformance/glsl/misc/fragcolor-fragdata-invariant.html',
diff --git a/device/bluetooth/bluetooth_uuid.cc b/device/bluetooth/bluetooth_uuid.cc index 88e27363..0fbf22d4 100644 --- a/device/bluetooth/bluetooth_uuid.cc +++ b/device/bluetooth/bluetooth_uuid.cc
@@ -15,6 +15,7 @@ #include <objbase.h> #include "base/strings/string16.h" +#include "base/win/win_util.h" #endif // defined(OS_WIN) namespace device { @@ -79,16 +80,12 @@ #if defined(OS_WIN) BluetoothUUID::BluetoothUUID(GUID uuid) { - // 36 chars for UUID + 2 chars for braces + 1 char for null-terminator. - constexpr int kBufferSize = 39; - wchar_t buffer[kBufferSize]; - int result = ::StringFromGUID2(uuid, buffer, kBufferSize); - DCHECK_EQ(kBufferSize, result); + auto buffer = base::win::String16FromGUID(uuid); DCHECK_EQ('{', buffer[0]); DCHECK_EQ('}', buffer[37]); - GetCanonicalUuid(base::WideToUTF8(base::WStringPiece(buffer).substr(1, 36)), - &value_, &canonical_value_, &format_); + GetCanonicalUuid(base::WideToUTF8(buffer.substr(1, 36)), &value_, + &canonical_value_, &format_); DCHECK_EQ(kFormat128Bit, format_); } #endif // defined(OS_WIN)
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn index f63ef3ee..9f8616e 100644 --- a/device/fido/BUILD.gn +++ b/device/fido/BUILD.gn
@@ -289,6 +289,7 @@ deps = [ ":fido", "//base", + "//base/test:test_support", "//device/bluetooth:mocks", "//testing/gmock", "//testing/gtest",
diff --git a/device/fido/cable/fido_cable_handshake_handler_fuzzer.cc b/device/fido/cable/fido_cable_handshake_handler_fuzzer.cc index 5b0432e0..374022d 100644 --- a/device/fido/cable/fido_cable_handshake_handler_fuzzer.cc +++ b/device/fido/cable/fido_cable_handshake_handler_fuzzer.cc
@@ -9,6 +9,8 @@ #include "base/containers/span.h" #include "base/memory/ref_counted.h" +#include "base/no_destructor.h" +#include "base/test/scoped_task_environment.h" #include "device/bluetooth/test/mock_bluetooth_adapter.h" #include "device/fido/cable/fido_cable_device.h" #include "device/fido/cable/fido_cable_handshake_handler.h" @@ -33,6 +35,7 @@ } // namespace extern "C" int LLVMFuzzerTestOneInput(const uint8_t* raw_data, size_t size) { + static const base::NoDestructor<base::test::ScopedTaskEnvironment> task_env; auto data_span = base::make_span(raw_data, size); auto adapter = base::MakeRefCounted<::testing::NiceMock<device::MockBluetoothAdapter>>();
diff --git a/device/fido/ctap_get_assertion_request.cc b/device/fido/ctap_get_assertion_request.cc index 37ba8b9..2ee95ad 100644 --- a/device/fido/ctap_get_assertion_request.cc +++ b/device/fido/ctap_get_assertion_request.cc
@@ -44,9 +44,9 @@ cbor_map[cbor::Value(1)] = cbor::Value(request.rp_id); cbor_map[cbor::Value(2)] = cbor::Value(request.client_data_hash); - if (request.allow_list && !request.allow_list->empty()) { + if (!request.allow_list.empty()) { cbor::Value::ArrayValue allow_list_array; - for (const auto& descriptor : *request.allow_list) { + for (const auto& descriptor : request.allow_list) { allow_list_array.push_back(descriptor.ConvertToCBOR()); } cbor_map[cbor::Value(3)] = cbor::Value(std::move(allow_list_array));
diff --git a/device/fido/ctap_get_assertion_request.h b/device/fido/ctap_get_assertion_request.h index 95791e0..4a2c199 100644 --- a/device/fido/ctap_get_assertion_request.h +++ b/device/fido/ctap_get_assertion_request.h
@@ -53,7 +53,7 @@ UserVerificationRequirement::kDiscouraged; bool user_presence_required = true; - base::Optional<std::vector<PublicKeyCredentialDescriptor>> allow_list; + std::vector<PublicKeyCredentialDescriptor> allow_list; base::Optional<std::vector<uint8_t>> pin_auth; base::Optional<uint8_t> pin_protocol; base::Optional<std::vector<CableDiscoveryData>> cable_extension;
diff --git a/device/fido/ctap_request_unittest.cc b/device/fido/ctap_request_unittest.cc index 91ea179..a0ecf9ff 100644 --- a/device/fido/ctap_request_unittest.cc +++ b/device/fido/ctap_request_unittest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "components/cbor/reader.h" #include "device/fido/ctap_empty_authenticator_request.h" #include "device/fido/ctap_get_assertion_request.h" #include "device/fido/ctap_make_credential_request.h" @@ -86,8 +87,12 @@ } TEST(VirtualCtap2DeviceTest, ParseMakeCredentialRequestForVirtualCtapKey) { - const auto request_and_hash = ParseCtapMakeCredentialRequest( + const auto& cbor_request = cbor::Reader::Read( base::make_span(test_data::kCtapMakeCredentialRequest).subspan(1)); + ASSERT_TRUE(cbor_request); + ASSERT_TRUE(cbor_request->is_map()); + const auto request_and_hash = + ParseCtapMakeCredentialRequest(cbor_request->GetMap()); ASSERT_TRUE(request_and_hash); auto request = std::get<0>(*request_and_hash); auto client_data_hash = std::get<1>(*request_and_hash); @@ -133,9 +138,13 @@ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03}; - auto request_and_hash = ParseCtapGetAssertionRequest( + const auto& cbor_request = cbor::Reader::Read( base::make_span(test_data::kTestComplexCtapGetAssertionRequest) .subspan(1)); + ASSERT_TRUE(cbor_request); + ASSERT_TRUE(cbor_request->is_map()); + + auto request_and_hash = ParseCtapGetAssertionRequest(cbor_request->GetMap()); ASSERT_TRUE(request_and_hash); auto request = std::get<0>(*request_and_hash); auto client_data_hash = std::get<1>(*request_and_hash); @@ -144,12 +153,11 @@ EXPECT_EQ(test_data::kRelyingPartyId, request.rp_id); EXPECT_EQ(UserVerificationRequirement::kRequired, request.user_verification); EXPECT_FALSE(request.user_presence_required); - ASSERT_TRUE(request.allow_list); - ASSERT_EQ(2u, request.allow_list->size()); + ASSERT_EQ(2u, request.allow_list.size()); - EXPECT_THAT(request.allow_list->at(0).id(), + EXPECT_THAT(request.allow_list.at(0).id(), ::testing::ElementsAreArray(kAllowedCredentialOne)); - EXPECT_THAT(request.allow_list->at(1).id(), + EXPECT_THAT(request.allow_list.at(1).id(), ::testing::ElementsAreArray(kAllowedCredentialTwo)); } } // namespace device
diff --git a/device/fido/fido_device_authenticator.cc b/device/fido/fido_device_authenticator.cc index 7fcdbd4..8fb7b29 100644 --- a/device/fido/fido_device_authenticator.cc +++ b/device/fido/fido_device_authenticator.cc
@@ -275,8 +275,7 @@ // The PIN is effectively unavailable if there's no // UI support for collecting it. observer && observer->SupportsPIN(); - const bool resident_key_request = - !request.allow_list || request.allow_list->empty(); + const bool resident_key_request = request.allow_list.empty(); if (resident_key_request) { if (can_use_pin) {
diff --git a/device/fido/get_assertion_handler_unittest.cc b/device/fido/get_assertion_handler_unittest.cc index 1ab02844..c50d87c 100644 --- a/device/fido/get_assertion_handler_unittest.cc +++ b/device/fido/get_assertion_handler_unittest.cc
@@ -78,19 +78,19 @@ std::unique_ptr<GetAssertionRequestHandler> CreateGetAssertionHandlerU2f() { CtapGetAssertionRequest request(test_data::kRelyingPartyId, test_data::kClientDataJson); - request.allow_list.emplace({PublicKeyCredentialDescriptor( + request.allow_list = {PublicKeyCredentialDescriptor( CredentialType::kPublicKey, - fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle))}); + fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle))}; return CreateGetAssertionHandlerWithRequest(std::move(request)); } std::unique_ptr<GetAssertionRequestHandler> CreateGetAssertionHandlerCtap() { CtapGetAssertionRequest request(test_data::kRelyingPartyId, test_data::kClientDataJson); - request.allow_list.emplace({PublicKeyCredentialDescriptor( + request.allow_list = {PublicKeyCredentialDescriptor( CredentialType::kPublicKey, fido_parsing_utils::Materialize( - test_data::kTestGetAssertionCredentialId))}); + test_data::kTestGetAssertionCredentialId))}; return CreateGetAssertionHandlerWithRequest(std::move(request)); } @@ -258,9 +258,9 @@ TestU2fSignRequestWithUserVerificationRequired) { auto request = CtapGetAssertionRequest(test_data::kRelyingPartyId, test_data::kClientDataJson); - request.allow_list.emplace({PublicKeyCredentialDescriptor( + request.allow_list = {PublicKeyCredentialDescriptor( CredentialType::kPublicKey, - fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle))}); + fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle))}; request.user_verification = UserVerificationRequirement::kRequired; auto request_handler = CreateGetAssertionHandlerWithRequest(std::move(request)); @@ -299,9 +299,9 @@ TEST_F(FidoGetAssertionHandlerTest, InvalidCredential) { CtapGetAssertionRequest request(test_data::kRelyingPartyId, test_data::kClientDataJson); - request.allow_list.emplace({PublicKeyCredentialDescriptor( + request.allow_list = {PublicKeyCredentialDescriptor( CredentialType::kPublicKey, - fido_parsing_utils::Materialize(test_data::kKeyHandleAlpha))}); + fido_parsing_utils::Materialize(test_data::kKeyHandleAlpha))}; auto request_handler = CreateGetAssertionHandlerWithRequest(std::move(request)); discovery()->WaitForCallToStartAndSimulateSuccess(); @@ -421,7 +421,6 @@ TEST_F(FidoGetAssertionHandlerTest, AllTransportsAllowedIfAllowCredentialsListIsEmpty) { auto request = CreateTestRequestWithCableExtension(); - request.allow_list.emplace(); EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true)); auto request_handler = CreateGetAssertionHandlerWithRequest(std::move(request)); @@ -431,7 +430,7 @@ TEST_F(FidoGetAssertionHandlerTest, AllTransportsAllowedIfHasAllowedCredentialWithEmptyTransportsList) { auto request = CreateTestRequestWithCableExtension(); - request.allow_list.emplace({ + request.allow_list = { PublicKeyCredentialDescriptor( CredentialType::kPublicKey, fido_parsing_utils::Materialize( @@ -440,7 +439,7 @@ PublicKeyCredentialDescriptor( CredentialType::kPublicKey, fido_parsing_utils::Materialize(kBogusCredentialId)), - }); + }; EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true)); auto request_handler = @@ -451,7 +450,7 @@ TEST_F(FidoGetAssertionHandlerTest, AllowedTransportsAreUnionOfTransportsLists) { auto request = CreateTestRequestWithCableExtension(); - request.allow_list.emplace({ + request.allow_list = { PublicKeyCredentialDescriptor( CredentialType::kPublicKey, fido_parsing_utils::Materialize( @@ -462,7 +461,7 @@ fido_parsing_utils::Materialize(kBogusCredentialId), {FidoTransportProtocol::kInternal, FidoTransportProtocol::kNearFieldCommunication}), - }); + }; EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true)); auto request_handler = @@ -493,14 +492,14 @@ CtapGetAssertionRequest request(test_data::kRelyingPartyId, test_data::kClientDataJson); ASSERT_FALSE(!!request.cable_extension); - request.allow_list.emplace({ + request.allow_list = { PublicKeyCredentialDescriptor( CredentialType::kPublicKey, fido_parsing_utils::Materialize( test_data::kTestGetAssertionCredentialId), {FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy, FidoTransportProtocol::kUsbHumanInterfaceDevice}), - }); + }; auto request_handler = CreateGetAssertionHandlerWithRequest(std::move(request)); @@ -538,13 +537,13 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyUsbTransportAllowed) { auto request = CreateTestRequestWithCableExtension(); - request.allow_list.emplace({ + request.allow_list = { PublicKeyCredentialDescriptor( CredentialType::kPublicKey, fido_parsing_utils::Materialize( test_data::kTestGetAssertionCredentialId), {FidoTransportProtocol::kUsbHumanInterfaceDevice}), - }); + }; set_supported_transports({FidoTransportProtocol::kUsbHumanInterfaceDevice}); @@ -571,13 +570,13 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyBleTransportAllowed) { auto request = CreateTestRequestWithCableExtension(); - request.allow_list.emplace({ + request.allow_list = { PublicKeyCredentialDescriptor( CredentialType::kPublicKey, fido_parsing_utils::Materialize( test_data::kTestGetAssertionCredentialId), {FidoTransportProtocol::kBluetoothLowEnergy}), - }); + }; set_supported_transports({FidoTransportProtocol::kBluetoothLowEnergy}); EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true)); @@ -605,13 +604,13 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyNfcTransportAllowed) { auto request = CreateTestRequestWithCableExtension(); - request.allow_list.emplace({ + request.allow_list = { PublicKeyCredentialDescriptor( CredentialType::kPublicKey, fido_parsing_utils::Materialize( test_data::kTestGetAssertionCredentialId), {FidoTransportProtocol::kNearFieldCommunication}), - }); + }; set_supported_transports({FidoTransportProtocol::kNearFieldCommunication}); @@ -639,13 +638,13 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyInternalTransportAllowed) { auto request = CreateTestRequestWithCableExtension(); - request.allow_list.emplace({ + request.allow_list = { PublicKeyCredentialDescriptor( CredentialType::kPublicKey, fido_parsing_utils::Materialize( test_data::kTestGetAssertionCredentialId), {FidoTransportProtocol::kInternal}), - }); + }; set_supported_transports({FidoTransportProtocol::kInternal}); @@ -779,13 +778,13 @@ // Request the correct credential ID, but set a different transport hint. CtapGetAssertionRequest request(test_data::kRelyingPartyId, test_data::kClientDataJson); - request.allow_list.emplace({ + request.allow_list = { PublicKeyCredentialDescriptor( CredentialType::kPublicKey, fido_parsing_utils::Materialize( test_data::kTestGetAssertionCredentialId), {FidoTransportProtocol::kBluetoothLowEnergy}), - }); + }; TestGetAssertionRequestCallback cb; auto request_handler = std::make_unique<GetAssertionRequestHandler>(
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc index 864ab31..ddb685b0 100644 --- a/device/fido/get_assertion_request_handler.cc +++ b/device/fido/get_assertion_request_handler.cc
@@ -56,7 +56,7 @@ return false; } - if ((!request.allow_list || request.allow_list->empty()) && !user_entity) { + if (request.allow_list.empty() && !user_entity) { return false; } @@ -72,7 +72,7 @@ // TODO(hongjunchoi) : Add link to section of the CTAP spec once it is // published. const auto& allow_list = request.allow_list; - if (!allow_list || allow_list->empty()) { + if (allow_list.empty()) { if (authenticator.Options() && !authenticator.Options()->supports_resident_key) { // Allow list can't be empty for authenticators w/o resident key support. @@ -83,9 +83,9 @@ // allow list has size 1. Otherwise, it needs to match an entry from the // allow list const auto opt_transport_used = authenticator.AuthenticatorTransport(); - if ((!response.credential() && allow_list->size() != 1) || + if ((!response.credential() && allow_list.size() != 1) || (response.credential() && - !std::any_of(allow_list->cbegin(), allow_list->cend(), + !std::any_of(allow_list.cbegin(), allow_list.cend(), [&response, opt_transport_used](const auto& credential) { return credential.id() == response.raw_credential_id() && @@ -112,9 +112,8 @@ void SetCredentialIdForResponseWithEmptyCredential( const CtapGetAssertionRequest& request, AuthenticatorGetAssertionResponse& response) { - if (request.allow_list && request.allow_list->size() == 1 && - !response.credential()) { - response.SetCredential(request.allow_list->at(0)); + if (request.allow_list.size() == 1 && !response.credential()) { + response.SetCredential(request.allow_list.at(0)); } } @@ -151,15 +150,13 @@ FidoTransportProtocol::kBluetoothLowEnergy, FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy}; - // TODO(https://crbug.com/874479): |allowed_list| will |has_value| even if the - // WebAuthn request has `allowCredential` undefined. const auto& allowed_list = request.allow_list; - if (!allowed_list || allowed_list->empty()) { + if (allowed_list.empty()) { return kAllTransports; } base::flat_set<FidoTransportProtocol> transports; - for (const auto credential : *allowed_list) { + for (const auto credential : allowed_list) { if (credential.transports().empty()) return kAllTransports; transports.insert(credential.transports().begin(), @@ -368,8 +365,8 @@ SetCredentialIdForResponseWithEmptyCredential(request_, *response); const size_t num_responses = response->num_credentials().value_or(1); - if (num_responses == 0 || (num_responses > 1 && request_.allow_list && - !request_.allow_list->empty())) { + if (num_responses == 0 || + (num_responses > 1 && !request_.allow_list.empty())) { OnAuthenticatorResponse(authenticator, FidoReturnCode::kAuthenticatorResponseInvalid, base::nullopt);
diff --git a/device/fido/get_assertion_task.cc b/device/fido/get_assertion_task.cc index 54e7452..26e0ca0 100644 --- a/device/fido/get_assertion_task.cc +++ b/device/fido/get_assertion_task.cc
@@ -79,10 +79,9 @@ } CtapGetAssertionRequest GetAssertionTask::NextSilentRequest() { - DCHECK(request_.allow_list && - current_credential_ < request_.allow_list->size()); + DCHECK(current_credential_ < request_.allow_list.size()); CtapGetAssertionRequest request = request_; - request.allow_list = {{request_.allow_list->at(current_credential_)}}; + request.allow_list = {{request_.allow_list.at(current_credential_)}}; request.user_presence_required = false; request.user_verification = UserVerificationRequirement::kDiscouraged; return request; @@ -96,7 +95,7 @@ // support silent probing so don't do it with them.) if (device()->DeviceTransport() != FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy && - ((request_.allow_list && request_.allow_list->size() > 1) || + (request_.allow_list.size() > 1 || MayFallbackToU2fWithAppIdExtension(*device(), request_))) { sign_operation_ = std::make_unique<Ctap2DeviceOperation< CtapGetAssertionRequest, AuthenticatorGetAssertionResponse>>( @@ -157,7 +156,7 @@ void GetAssertionTask::HandleResponseToSilentRequest( CtapDeviceResponseCode response_code, base::Optional<AuthenticatorGetAssertionResponse> response_data) { - DCHECK(request_.allow_list && request_.allow_list->size() > 0); + DCHECK(request_.allow_list.size() > 0); if (canceled_) { return; @@ -169,7 +168,7 @@ // user verification configuration. if (response_code == CtapDeviceResponseCode::kSuccess) { CtapGetAssertionRequest request = request_; - request.allow_list = {{request_.allow_list->at(current_credential_)}}; + request.allow_list = {{request_.allow_list.at(current_credential_)}}; sign_operation_ = std::make_unique<Ctap2DeviceOperation< CtapGetAssertionRequest, AuthenticatorGetAssertionResponse>>( device(), std::move(request), @@ -183,7 +182,7 @@ // Credential was not recognized or an error occurred. Probe the next // credential. - if (++current_credential_ < request_.allow_list->size()) { + if (++current_credential_ < request_.allow_list.size()) { sign_operation_ = std::make_unique<Ctap2DeviceOperation< CtapGetAssertionRequest, AuthenticatorGetAssertionResponse>>( device(), NextSilentRequest(),
diff --git a/device/fido/get_assertion_task_unittest.cc b/device/fido/get_assertion_task_unittest.cc index 552d214a..7314a1d 100644 --- a/device/fido/get_assertion_task_unittest.cc +++ b/device/fido/get_assertion_task_unittest.cc
@@ -57,10 +57,10 @@ CtapGetAssertionRequest request_param(test_data::kRelyingPartyId, test_data::kClientDataJson); - request_param.allow_list.emplace({PublicKeyCredentialDescriptor( + request_param.allow_list.emplace_back(PublicKeyCredentialDescriptor( CredentialType::kPublicKey, fido_parsing_utils::Materialize( - test_data::kTestGetAssertionCredentialId))}); + test_data::kTestGetAssertionCredentialId))); auto task = std::make_unique<GetAssertionTask>( device.get(), std::move(request_param), @@ -80,9 +80,9 @@ CtapGetAssertionRequest request_param(test_data::kRelyingPartyId, test_data::kClientDataJson); - request_param.allow_list.emplace({PublicKeyCredentialDescriptor( + request_param.allow_list.emplace_back(PublicKeyCredentialDescriptor( CredentialType::kPublicKey, - fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle))}); + fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle))); auto task = std::make_unique<GetAssertionTask>( device.get(), std::move(request_param), @@ -102,8 +102,8 @@ std::vector<uint8_t> key_handle(hash.begin(), hash.end()); CtapGetAssertionRequest request_param(test_data::kRelyingPartyId, test_data::kClientDataJson); - request_param.allow_list.emplace( - {PublicKeyCredentialDescriptor(CredentialType::kPublicKey, key_handle)}); + request_param.allow_list.emplace_back( + PublicKeyCredentialDescriptor(CredentialType::kPublicKey, key_handle)); ; auto device = std::make_unique<VirtualCtap2Device>();
diff --git a/device/fido/mac/authenticator.mm b/device/fido/mac/authenticator.mm index e9e65b2..c5fce2a 100644 --- a/device/fido/mac/authenticator.mm +++ b/device/fido/mac/authenticator.mm
@@ -64,19 +64,16 @@ std::set<std::vector<uint8_t>> allow_list_credential_ids; // Extract applicable credential IDs from the allowList, if the request has // one. If not, any credential matching the RP works. - if (request.allow_list) { - for (const auto& credential_descriptor : *request.allow_list) { - if (credential_descriptor.credential_type() != - CredentialType::kPublicKey) - continue; + for (const auto& credential_descriptor : request.allow_list) { + if (credential_descriptor.credential_type() != CredentialType::kPublicKey) + continue; - if (!credential_descriptor.transports().empty() && - !base::ContainsKey(credential_descriptor.transports(), - FidoTransportProtocol::kInternal)) - continue; + if (!credential_descriptor.transports().empty() && + !base::ContainsKey(credential_descriptor.transports(), + FidoTransportProtocol::kInternal)) + continue; - allow_list_credential_ids.insert(credential_descriptor.id()); - } + allow_list_credential_ids.insert(credential_descriptor.id()); } return FindCredentialInKeychain(keychain_access_group_, metadata_secret_,
diff --git a/device/fido/mac/get_assertion_operation.mm b/device/fido/mac/get_assertion_operation.mm index 46fad38..30e6924 100644 --- a/device/fido/mac/get_assertion_operation.mm +++ b/device/fido/mac/get_assertion_operation.mm
@@ -67,18 +67,15 @@ // Collect the credential ids from allowList. If allowList is absent, we will // pick the first available credential for the RP. std::set<std::vector<uint8_t>> allowed_credential_ids; - if (request().allow_list) { - for (const PublicKeyCredentialDescriptor& desc : *request().allow_list) { - if (desc.credential_type() != CredentialType::kPublicKey) - continue; + for (const PublicKeyCredentialDescriptor& desc : request().allow_list) { + if (desc.credential_type() != CredentialType::kPublicKey) + continue; - if (!desc.transports().empty() && - !base::ContainsKey(desc.transports(), - FidoTransportProtocol::kInternal)) - continue; + if (!desc.transports().empty() && + !base::ContainsKey(desc.transports(), FidoTransportProtocol::kInternal)) + continue; - allowed_credential_ids.insert(desc.id()); - } + allowed_credential_ids.insert(desc.id()); } // Fetch credentials for RP from the request and current user profile.
diff --git a/device/fido/u2f_command_constructor.cc b/device/fido/u2f_command_constructor.cc index 0dae0a1..84d2e3f 100644 --- a/device/fido/u2f_command_constructor.cc +++ b/device/fido/u2f_command_constructor.cc
@@ -30,9 +30,8 @@ } bool IsConvertibleToU2fSignCommand(const CtapGetAssertionRequest& request) { - const auto& allow_list = request.allow_list; return request.user_verification != UserVerificationRequirement::kRequired && - allow_list && !allow_list->empty(); + !request.allow_list.empty(); } base::Optional<std::vector<uint8_t>> ConvertToU2fRegisterCommand(
diff --git a/device/fido/u2f_sign_operation.cc b/device/fido/u2f_sign_operation.cc index 4245d38d..05a250f 100644 --- a/device/fido/u2f_sign_operation.cc +++ b/device/fido/u2f_sign_operation.cc
@@ -27,8 +27,7 @@ U2fSignOperation::~U2fSignOperation() = default; void U2fSignOperation::Start() { - const auto& allow_list = request().allow_list; - if (allow_list && !allow_list->empty()) { + if (!request().allow_list.empty()) { if (request().alternative_application_parameter.has_value()) { // Try the alternative value first. This is because the U2F Zero // authenticator (at least) crashes if we try the wrong AppID first. @@ -103,7 +102,7 @@ // the primary value to try. app_param_type_ = ApplicationParameterType::kPrimary; TrySign(); - } else if (++current_key_handle_index_ < request().allow_list->size()) { + } else if (++current_key_handle_index_ < request().allow_list.size()) { // Key is not for this device. Try signing with the next key. if (request().alternative_application_parameter.has_value()) { app_param_type_ = ApplicationParameterType::kAlternative; @@ -179,8 +178,8 @@ } const std::vector<uint8_t>& U2fSignOperation::key_handle() const { - DCHECK_LT(current_key_handle_index_, request().allow_list->size()); - return request().allow_list->at(current_key_handle_index_).id(); + DCHECK_LT(current_key_handle_index_, request().allow_list.size()); + return request().allow_list.at(current_key_handle_index_).id(); } } // namespace device
diff --git a/device/fido/u2f_sign_operation_unittest.cc b/device/fido/u2f_sign_operation_unittest.cc index ec7223d..6203d8b 100644 --- a/device/fido/u2f_sign_operation_unittest.cc +++ b/device/fido/u2f_sign_operation_unittest.cc
@@ -40,10 +40,9 @@ CtapGetAssertionRequest request(test_data::kRelyingPartyId, test_data::kClientDataJson); - request.allow_list.emplace(); for (auto& key_handle : key_handles) { - request.allow_list->emplace_back(CredentialType::kPublicKey, - std::move(key_handle)); + request.allow_list.emplace_back(CredentialType::kPublicKey, + std::move(key_handle)); } return request; }
diff --git a/device/fido/virtual_ctap2_device.cc b/device/fido/virtual_ctap2_device.cc index a7dd629..287c7df 100644 --- a/device/fido/virtual_ctap2_device.cc +++ b/device/fido/virtual_ctap2_device.cc
@@ -571,7 +571,14 @@ CtapDeviceResponseCode VirtualCtap2Device::OnMakeCredential( base::span<const uint8_t> request_bytes, std::vector<uint8_t>* response) { - auto request_and_hash = ParseCtapMakeCredentialRequest(request_bytes); + const auto& cbor_request = cbor::Reader::Read(request_bytes); + if (!cbor_request || !cbor_request->is_map()) { + DLOG(ERROR) << "Incorrectly formatted MakeCredential request."; + return CtapDeviceResponseCode::kCtap2ErrOther; + } + + auto request_and_hash = + ParseCtapMakeCredentialRequest(cbor_request->GetMap()); if (!request_and_hash) { DLOG(ERROR) << "Incorrectly formatted MakeCredential request."; return CtapDeviceResponseCode::kCtap2ErrOther; @@ -715,7 +722,14 @@ std::vector<uint8_t>* response) { // Step numbers in this function refer to // https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorGetAssertion - auto request_and_hash = ParseCtapGetAssertionRequest(request_bytes); + const auto& cbor_request = cbor::Reader::Read(request_bytes); + if (!cbor_request || !cbor_request->is_map()) { + DLOG(ERROR) << "Incorrectly formatted MakeCredential request."; + return CtapDeviceResponseCode::kCtap2ErrOther; + } + + const auto& request_map = cbor_request->GetMap(); + auto request_and_hash = ParseCtapGetAssertionRequest(request_map); if (!request_and_hash) { DLOG(ERROR) << "Incorrectly formatted GetAssertion request."; return CtapDeviceResponseCode::kCtap2ErrOther; @@ -736,8 +750,7 @@ } // Resident keys are not supported. - if (!config_.resident_key_support && - (!request.allow_list || request.allow_list->empty())) { + if (!config_.resident_key_support && request.allow_list.empty()) { return CtapDeviceResponseCode::kCtap2ErrNoCredentials; } @@ -751,25 +764,25 @@ return CtapDeviceResponseCode::kCtap2ErrUnsupportedOption; } - if (request.allow_list) { - if (config_.reject_large_allow_and_exclude_lists && - request.allow_list->size() > 1) { - return CtapDeviceResponseCode::kCtap2ErrLimitExceeded; - } + if (config_.reject_large_allow_and_exclude_lists && + request.allow_list.size() > 1) { + return CtapDeviceResponseCode::kCtap2ErrLimitExceeded; + } - // An empty allow_list could be considered to be a resident-key request, but - // some authenticators in practice don't take it that way. Thus this code - // mirrors that to better reflect reality. CTAP 2.0 leaves it as undefined - // behaviour. - for (const auto& allowed_credential : *request.allow_list) { - RegistrationData* found = - FindRegistrationData(allowed_credential.id(), rp_id_hash); - if (found) { - found_registrations.emplace_back(allowed_credential.id(), found); - break; - } + // An empty allow_list could be considered to be a resident-key request, but + // some authenticators in practice don't take it that way. Thus this code + // mirrors that to better reflect reality. CTAP 2.0 leaves it as undefined + // behaviour. + for (const auto& allowed_credential : request.allow_list) { + RegistrationData* found = + FindRegistrationData(allowed_credential.id(), rp_id_hash); + if (found) { + found_registrations.emplace_back(allowed_credential.id(), found); + break; } - } else { + } + const auto allow_list_it = request_map.find(cbor::Value(3)); + if (allow_list_it == request_map.end()) { DCHECK(config_.resident_key_support); for (auto& registration : mutable_state()->registrations) { if (registration.second.is_resident && @@ -1343,12 +1356,7 @@ base::Optional<std::pair<CtapMakeCredentialRequest, CtapMakeCredentialRequest::ClientDataHash>> -ParseCtapMakeCredentialRequest(base::span<const uint8_t> request_bytes) { - const auto& cbor_request = cbor::Reader::Read(request_bytes); - if (!cbor_request || !cbor_request->is_map()) - return base::nullopt; - - const auto& request_map = cbor_request->GetMap(); +ParseCtapMakeCredentialRequest(const cbor::Value::MapValue& request_map) { if (!AreMakeCredentialRequestMapKeysCorrect(request_map)) return base::nullopt; @@ -1473,12 +1481,7 @@ base::Optional< std::pair<CtapGetAssertionRequest, CtapGetAssertionRequest::ClientDataHash>> -ParseCtapGetAssertionRequest(base::span<const uint8_t> request_bytes) { - const auto& cbor_request = cbor::Reader::Read(request_bytes); - if (!cbor_request || !cbor_request->is_map()) - return base::nullopt; - - const auto& request_map = cbor_request->GetMap(); +ParseCtapGetAssertionRequest(const cbor::Value::MapValue& request_map) { if (!AreGetAssertionRequestMapKeysCorrect(request_map)) return base::nullopt;
diff --git a/device/fido/virtual_ctap2_device.h b/device/fido/virtual_ctap2_device.h index 08b141c..7fe53ba8 100644 --- a/device/fido/virtual_ctap2_device.h +++ b/device/fido/virtual_ctap2_device.h
@@ -121,7 +121,7 @@ COMPONENT_EXPORT(DEVICE_FIDO) base::Optional<std::pair<CtapMakeCredentialRequest, CtapMakeCredentialRequest::ClientDataHash>> -ParseCtapMakeCredentialRequest(base::span<const uint8_t> request_bytes); +ParseCtapMakeCredentialRequest(const cbor::Value::MapValue& request_map); // Decodes a CBOR-encoded CTAP2 authenticatorGetAssertion request message. The // request's client_data_json() value will be empty, and the hashed client data @@ -129,7 +129,7 @@ COMPONENT_EXPORT(DEVICE_FIDO) base::Optional< std::pair<CtapGetAssertionRequest, CtapGetAssertionRequest::ClientDataHash>> -ParseCtapGetAssertionRequest(base::span<const uint8_t> request_bytes); +ParseCtapGetAssertionRequest(const cbor::Value::MapValue& request_map); } // namespace device
diff --git a/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc b/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc index 2d8ee94..7af9904 100644 --- a/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc +++ b/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc
@@ -38,20 +38,6 @@ using SourceKind = ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceKind; -using ABI::Windows::Foundation::ITypedEventHandler; -using ABI::Windows::UI::Input::Spatial::ISpatialInteractionManager; -using ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs; -using ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs2; -using ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceState; -using ABI::Windows::UI::Input::Spatial::SpatialInteractionManager; -using ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceEventArgs; -using Microsoft::WRL::Callback; -using Microsoft::WRL::ComPtr; - -typedef ITypedEventHandler<SpatialInteractionManager*, - SpatialInteractionSourceEventArgs*> - SpatialInteractionSourceEventHandler; - ParsedInputState::ParsedInputState() {} ParsedInputState::~ParsedInputState() {} ParsedInputState::ParsedInputState(ParsedInputState&& other) = default; @@ -319,16 +305,13 @@ } } // namespace -MixedRealityInputHelper::MixedRealityInputHelper(HWND hwnd) : hwnd_(hwnd) { - pressed_token_.value = 0; - released_token_.value = 0; -} +MixedRealityInputHelper::MixedRealityInputHelper(HWND hwnd) : hwnd_(hwnd) {} MixedRealityInputHelper::~MixedRealityInputHelper() { // Dispose must be called before destruction, which ensures that we're // unsubscribed from events. - DCHECK(pressed_token_.value == 0); - DCHECK(released_token_.value == 0); + DCHECK(pressed_subscription_ == nullptr); + DCHECK(released_subscription_ == nullptr); } void MixedRealityInputHelper::Dispose() { @@ -491,47 +474,34 @@ return input_state; } -HRESULT MixedRealityInputHelper::OnSourcePressed( - ISpatialInteractionManager* sender, - ISpatialInteractionSourceEventArgs* args) { - return ProcessSourceEvent(args, true /* is_pressed */); +void MixedRealityInputHelper::OnSourcePressed( + const WMRInputSourceEventArgs& args) { + ProcessSourceEvent(args, true /* is_pressed */); } -HRESULT MixedRealityInputHelper::OnSourceReleased( - ISpatialInteractionManager* sender, - ISpatialInteractionSourceEventArgs* args) { - return ProcessSourceEvent(args, false /* is_pressed */); +void MixedRealityInputHelper::OnSourceReleased( + const WMRInputSourceEventArgs& args) { + ProcessSourceEvent(args, false /* is_pressed */); } -HRESULT MixedRealityInputHelper::ProcessSourceEvent( - ISpatialInteractionSourceEventArgs* raw_args, +void MixedRealityInputHelper::ProcessSourceEvent( + const WMRInputSourceEventArgs& args, bool is_pressed) { base::AutoLock scoped_lock(lock_); - ComPtr<ISpatialInteractionSourceEventArgs> args(raw_args); - ComPtr<ISpatialInteractionSourceEventArgs2> args2; - HRESULT hr = args.As(&args2); - if (FAILED(hr)) - return S_OK; - PressKind press_kind; - hr = args2->get_PressKind(&press_kind); - DCHECK(SUCCEEDED(hr)); + PressKind press_kind = args.PressKind(); if (press_kind != PressKind::SpatialInteractionPressKind_Select) - return S_OK; + return; - ComPtr<ISpatialInteractionSourceState> source_state_wmr; - hr = args->get_State(&source_state_wmr); - DCHECK(SUCCEEDED(hr)); - - WMRInputSourceState state(source_state_wmr); + WMRInputSourceState state = args.State(); WMRInputSource source = state.GetSource(); SourceKind source_kind = source.Kind(); if (source_kind != SourceKind::SpatialInteractionSourceKind_Controller && source_kind != SourceKind::SpatialInteractionSourceKind_Voice) - return S_OK; + return; uint32_t id = GetSourceId(source); @@ -545,46 +515,26 @@ if (source_kind == SourceKind::SpatialInteractionSourceKind_Voice && !is_pressed) pending_voice_states_.push_back(std::move(state)); - return S_OK; } void MixedRealityInputHelper::SubscribeEvents() { DCHECK(input_manager_); - DCHECK(pressed_token_.value == 0); - DCHECK(released_token_.value == 0); + DCHECK(pressed_subscription_ == nullptr); + DCHECK(released_subscription_ == nullptr); - // The destructor ensures that we're unsubscribed so raw this is fine. - auto pressed_callback = Callback<SpatialInteractionSourceEventHandler>( - this, &MixedRealityInputHelper::OnSourcePressed); - HRESULT hr = input_manager_->GetComPtr()->add_SourcePressed( - pressed_callback.Get(), &pressed_token_); - DCHECK(SUCCEEDED(hr)); - - // The destructor ensures that we're unsubscribed so raw this is fine. - auto released_callback = Callback<SpatialInteractionSourceEventHandler>( - this, &MixedRealityInputHelper::OnSourceReleased); - hr = input_manager_->GetComPtr()->add_SourceReleased(released_callback.Get(), - &released_token_); - DCHECK(SUCCEEDED(hr)); + // Unretained is safe since we explicitly get disposed and unsubscribe before + // destruction + pressed_subscription_ = + input_manager_->AddPressedCallback(base::BindRepeating( + &MixedRealityInputHelper::OnSourcePressed, base::Unretained(this))); + released_subscription_ = + input_manager_->AddReleasedCallback(base::BindRepeating( + &MixedRealityInputHelper::OnSourceReleased, base::Unretained(this))); } void MixedRealityInputHelper::UnsubscribeEvents() { - base::AutoLock scoped_lock(lock_); - if (!input_manager_) - return; - - HRESULT hr = S_OK; - if (pressed_token_.value != 0) { - hr = input_manager_->GetComPtr()->remove_SourcePressed(pressed_token_); - pressed_token_.value = 0; - DCHECK(SUCCEEDED(hr)); - } - - if (released_token_.value != 0) { - hr = input_manager_->GetComPtr()->remove_SourceReleased(released_token_); - released_token_.value = 0; - DCHECK(SUCCEEDED(hr)); - } + pressed_subscription_ = nullptr; + released_subscription_ = nullptr; } } // namespace device
diff --git a/device/vr/windows_mixed_reality/mixed_reality_input_helper.h b/device/vr/windows_mixed_reality/mixed_reality_input_helper.h index c695ffa..c82d24c 100644 --- a/device/vr/windows_mixed_reality/mixed_reality_input_helper.h +++ b/device/vr/windows_mixed_reality/mixed_reality_input_helper.h
@@ -12,6 +12,7 @@ #include <unordered_map> #include <vector> +#include "base/callback_list.h" #include "base/synchronization/lock.h" #include "device/gamepad/public/cpp/gamepads.h" #include "device/vr/public/mojom/isolated_xr_service.mojom.h" @@ -46,6 +47,7 @@ class WMRCoordinateSystem; class WMRInputManager; class WMRInputSourceState; +class WMRInputSourceEventArgs; class WMRTimestamp; class MixedRealityInputHelper { public: @@ -67,25 +69,20 @@ const WMRInputSourceState& state, const WMRCoordinateSystem* origin); - HRESULT OnSourcePressed( - ABI::Windows::UI::Input::Spatial::ISpatialInteractionManager* sender, - ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs* - args); - HRESULT OnSourceReleased( - ABI::Windows::UI::Input::Spatial::ISpatialInteractionManager* sender, - ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs* - args); - HRESULT ProcessSourceEvent( - ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs* - raw_args, - bool is_pressed); + void OnSourcePressed(const WMRInputSourceEventArgs& args); + void OnSourceReleased(const WMRInputSourceEventArgs& args); + void ProcessSourceEvent(const WMRInputSourceEventArgs& args, bool is_pressed); void SubscribeEvents(); void UnsubscribeEvents(); std::unique_ptr<WMRInputManager> input_manager_; - EventRegistrationToken pressed_token_; - EventRegistrationToken released_token_; + std::unique_ptr< + base::CallbackList<void(const WMRInputSourceEventArgs&)>::Subscription> + pressed_subscription_; + std::unique_ptr< + base::CallbackList<void(const WMRInputSourceEventArgs&)>::Subscription> + released_subscription_; struct ControllerState { bool pressed;
diff --git a/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc b/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc index 25caf52..bf775ce 100644 --- a/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc +++ b/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc
@@ -38,8 +38,6 @@ using SpatialMovementRange = ABI::Windows::Perception::Spatial::SpatialMovementRange; using ABI::Windows::Foundation::DateTime; -using ABI::Windows::Foundation::IEventHandler; -using ABI::Windows::Foundation::IReference; using ABI::Windows::Foundation::TimeSpan; using ABI::Windows::Foundation::Numerics::Matrix4x4; using ABI::Windows::Graphics::Holographic::HolographicStereoTransform; @@ -126,7 +124,6 @@ : XRCompositorCommon(), on_display_info_changed_(std::move(on_display_info_changed)), weak_ptr_factory_(this) { - stage_changed_token_.value = 0; } MixedRealityRenderLoop::~MixedRealityRenderLoop() { @@ -308,44 +305,30 @@ if (!stage_statics_) return false; - auto weak_this = weak_ptr_factory_.GetWeakPtr(); - scoped_refptr<base::SingleThreadTaskRunner> thread_runner = task_runner(); - - auto callback = Microsoft::WRL::Callback<IEventHandler<IInspectable*>>( - [weak_this, thread_runner](IInspectable*, IInspectable*) { - thread_runner->PostTask( - FROM_HERE, - base::BindOnce(&MixedRealityRenderLoop::OnCurrentStageChanged, - weak_this)); - return S_OK; - }); - - DCHECK(stage_changed_token_.value == 0); - HRESULT hr = stage_statics_->GetComPtr()->add_CurrentChanged( - callback.Get(), &stage_changed_token_); - DCHECK(SUCCEEDED(hr)); + // Since we explicitly null out both the statics and the subscription during + // StopRuntime (which happens before destruction), base::Unretained is safe. + stage_changed_subscription_ = stage_statics_->AddStageChangedCallback( + base::BindRepeating(&MixedRealityRenderLoop::OnCurrentStageChanged, + base::Unretained(this))); return true; } void MixedRealityRenderLoop::ClearStageStatics() { - if (!stage_statics_) - return; - - HRESULT hr = S_OK; - if (stage_changed_token_.value != 0) { - hr = stage_statics_->GetComPtr()->remove_CurrentChanged( - stage_changed_token_); - stage_changed_token_.value = 0; - DCHECK(SUCCEEDED(hr)); - } - + stage_changed_subscription_ = nullptr; stage_statics_ = nullptr; } void MixedRealityRenderLoop::OnCurrentStageChanged() { - stage_origin_ = nullptr; - InitializeStageOrigin(); + // Unretained is safe here because the task_runner() gets invalidated + // during Stop() which happens before our destruction + task_runner()->PostTask(FROM_HERE, + base::BindOnce( + [](MixedRealityRenderLoop* render_loop) { + render_loop->stage_origin_ = nullptr; + render_loop->InitializeStageOrigin(); + }, + base::Unretained(this))); } void MixedRealityRenderLoop::EnsureStageBounds() {
diff --git a/device/vr/windows_mixed_reality/mixed_reality_renderloop.h b/device/vr/windows_mixed_reality/mixed_reality_renderloop.h index 68a6ffe..7f43e733 100644 --- a/device/vr/windows_mixed_reality/mixed_reality_renderloop.h +++ b/device/vr/windows_mixed_reality/mixed_reality_renderloop.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/callback.h" +#include "base/callback_list.h" #include "base/memory/scoped_refptr.h" #include "base/threading/thread.h" #include "base/time/time.h" @@ -111,7 +112,8 @@ std::unique_ptr<MixedRealityInputHelper> input_helper_; std::unique_ptr<WMRStageStatics> stage_statics_; - EventRegistrationToken stage_changed_token_; + std::unique_ptr<base::CallbackList<void()>::Subscription> + stage_changed_subscription_; std::vector<gfx::Point3F> bounds_; bool bounds_updated_ = false;
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.cc b/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.cc index 15db02d..a29616c 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.cc +++ b/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.cc
@@ -11,20 +11,58 @@ #include <memory> #include <vector> +#include "base/callback_list.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/win/core_winrt_util.h" #include "base/win/scoped_hstring.h" #include "device/vr/windows_mixed_reality/wrappers/wmr_input_source_state.h" +using ABI::Windows::Foundation::ITypedEventHandler; using ABI::Windows::Foundation::Collections::IVectorView; using ABI::Windows::Perception::IPerceptionTimestamp; using ABI::Windows::UI::Input::Spatial::ISpatialInteractionManager; +using ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs; +using ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs2; using ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceState; +using ABI::Windows::UI::Input::Spatial::SpatialInteractionManager; +using ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceEventArgs; using ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceState; +using Microsoft::WRL::Callback; using Microsoft::WRL::ComPtr; +using WMRPressKind = + ABI::Windows::UI::Input::Spatial::SpatialInteractionPressKind; + +typedef ITypedEventHandler<SpatialInteractionManager*, + SpatialInteractionSourceEventArgs*> + SpatialInteractionSourceEventHandler; + namespace device { +WMRInputSourceEventArgs::WMRInputSourceEventArgs( + ComPtr<ISpatialInteractionSourceEventArgs> args) + : args_(args) { + DCHECK(args_); + HRESULT hr = args_.As(&args2_); + DCHECK(SUCCEEDED(hr)); +} + +WMRInputSourceEventArgs::~WMRInputSourceEventArgs() = default; + +WMRPressKind WMRInputSourceEventArgs::PressKind() const { + WMRPressKind press_kind; + HRESULT hr = args2_->get_PressKind(&press_kind); + DCHECK(SUCCEEDED(hr)); + return press_kind; +} + +WMRInputSourceState WMRInputSourceEventArgs::State() const { + ComPtr<ISpatialInteractionSourceState> wmr_state; + HRESULT hr = args_->get_State(&wmr_state); + DCHECK(SUCCEEDED(hr)); + return WMRInputSourceState(wmr_state); +} + std::unique_ptr<WMRInputManager> WMRInputManager::GetForWindow(HWND hwnd) { if (!hwnd) return nullptr; @@ -50,9 +88,14 @@ WMRInputManager::WMRInputManager(ComPtr<ISpatialInteractionManager> manager) : manager_(manager) { DCHECK(manager_); + pressed_token_.value = 0; + released_token_.value = 0; + SubscribeEvents(); } -WMRInputManager::~WMRInputManager() = default; +WMRInputManager::~WMRInputManager() { + UnsubscribeEvents(); +} std::vector<WMRInputSourceState> WMRInputManager::GetDetectedSourcesAtTimestamp( ComPtr<IPerceptionTimestamp> timestamp) const { @@ -76,7 +119,69 @@ return input_states; } -ComPtr<ISpatialInteractionManager> WMRInputManager::GetComPtr() const { - return manager_; +std::unique_ptr<WMRInputManager::InputEventCallbackList::Subscription> +WMRInputManager::AddPressedCallback(const InputEventCallback& cb) { + return pressed_callback_list_.Add(cb); } + +std::unique_ptr<WMRInputManager::InputEventCallbackList::Subscription> +WMRInputManager::AddReleasedCallback(const InputEventCallback& cb) { + return released_callback_list_.Add(cb); +} + +HRESULT WMRInputManager::OnSourcePressed( + ISpatialInteractionManager* sender, + ISpatialInteractionSourceEventArgs* raw_args) { + ComPtr<ISpatialInteractionSourceEventArgs> wmr_args(raw_args); + WMRInputSourceEventArgs args(wmr_args); + pressed_callback_list_.Notify(args); + return S_OK; +} + +HRESULT WMRInputManager::OnSourceReleased( + ISpatialInteractionManager* sender, + ISpatialInteractionSourceEventArgs* raw_args) { + ComPtr<ISpatialInteractionSourceEventArgs> wmr_args(raw_args); + WMRInputSourceEventArgs args(wmr_args); + released_callback_list_.Notify(args); + return S_OK; +} + +void WMRInputManager::SubscribeEvents() { + DCHECK(manager_); + DCHECK(pressed_token_.value == 0); + DCHECK(released_token_.value == 0); + + // The destructor ensures that we're unsubscribed so raw this is fine. + auto pressed_callback = Callback<SpatialInteractionSourceEventHandler>( + this, &WMRInputManager::OnSourcePressed); + HRESULT hr = + manager_->add_SourcePressed(pressed_callback.Get(), &pressed_token_); + DCHECK(SUCCEEDED(hr)); + + // The destructor ensures that we're unsubscribed so raw this is fine. + auto released_callback = Callback<SpatialInteractionSourceEventHandler>( + this, &WMRInputManager::OnSourceReleased); + hr = manager_->add_SourceReleased(released_callback.Get(), &released_token_); + DCHECK(SUCCEEDED(hr)); +} + +void WMRInputManager::UnsubscribeEvents() { + if (!manager_) + return; + + HRESULT hr = S_OK; + if (pressed_token_.value != 0) { + hr = manager_->remove_SourcePressed(pressed_token_); + pressed_token_.value = 0; + DCHECK(SUCCEEDED(hr)); + } + + if (released_token_.value != 0) { + hr = manager_->remove_SourceReleased(released_token_); + released_token_.value = 0; + DCHECK(SUCCEEDED(hr)); + } +} + } // namespace device
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.h b/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.h index cd6fb72..be9b0b3 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.h +++ b/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.h
@@ -11,12 +11,39 @@ #include <memory> #include <vector> +#include "base/callback_list.h" #include "base/macros.h" namespace device { class WMRInputSourceState; +class WMRInputSourceEventArgs { + public: + explicit WMRInputSourceEventArgs( + Microsoft::WRL::ComPtr< + ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs> + args); + virtual ~WMRInputSourceEventArgs(); + + ABI::Windows::UI::Input::Spatial::SpatialInteractionPressKind PressKind() + const; + WMRInputSourceState State() const; + + private: + Microsoft::WRL::ComPtr< + ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs> + args_; + Microsoft::WRL::ComPtr< + ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs2> + args2_; +}; + class WMRInputManager { public: + using InputEventCallbackList = + base::CallbackList<void(const WMRInputSourceEventArgs&)>; + using InputEventCallback = + base::RepeatingCallback<void(const WMRInputSourceEventArgs&)>; + static std::unique_ptr<WMRInputManager> GetForWindow(HWND hwnd); explicit WMRInputManager( @@ -29,16 +56,34 @@ Microsoft::WRL::ComPtr<ABI::Windows::Perception::IPerceptionTimestamp> timestamp) const; - // TODO(954413): Remove this once the events that are used have been wrapped. - Microsoft::WRL::ComPtr< - ABI::Windows::UI::Input::Spatial::ISpatialInteractionManager> - GetComPtr() const; + std::unique_ptr<InputEventCallbackList::Subscription> AddPressedCallback( + const InputEventCallback& cb); + + std::unique_ptr<InputEventCallbackList::Subscription> AddReleasedCallback( + const InputEventCallback& cb); private: + void SubscribeEvents(); + void UnsubscribeEvents(); + + HRESULT OnSourcePressed( + ABI::Windows::UI::Input::Spatial::ISpatialInteractionManager* sender, + ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs* + args); + HRESULT OnSourceReleased( + ABI::Windows::UI::Input::Spatial::ISpatialInteractionManager* sender, + ABI::Windows::UI::Input::Spatial::ISpatialInteractionSourceEventArgs* + args); + Microsoft::WRL::ComPtr< ABI::Windows::UI::Input::Spatial::ISpatialInteractionManager> manager_; + EventRegistrationToken pressed_token_; + EventRegistrationToken released_token_; + InputEventCallbackList pressed_callback_list_; + InputEventCallbackList released_callback_list_; + DISALLOW_COPY_AND_ASSIGN(WMRInputManager); }; } // namespace device
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_origins.cc b/device/vr/windows_mixed_reality/wrappers/wmr_origins.cc index a9895b2..71c61d4 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_origins.cc +++ b/device/vr/windows_mixed_reality/wrappers/wmr_origins.cc
@@ -5,11 +5,13 @@ #include <windows.perception.spatial.h> #include <wrl.h> +#include <wrl/event.h> #include <cstdint> #include <memory> #include <vector> +#include "base/callback_list.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/win/core_winrt_util.h" @@ -21,6 +23,7 @@ namespace WFN = ABI::Windows::Foundation::Numerics; using SpatialMovementRange = ABI::Windows::Perception::Spatial::SpatialMovementRange; +using ABI::Windows::Foundation::IEventHandler; using ABI::Windows::Foundation::IReference; using ABI::Windows::Perception::Spatial::ISpatialCoordinateSystem; using ABI::Windows::Perception::Spatial::ISpatialLocator; @@ -220,9 +223,20 @@ ComPtr<ISpatialStageFrameOfReferenceStatics> stage_statics) : stage_statics_(stage_statics) { DCHECK(stage_statics_); + auto callback = Microsoft::WRL::Callback<IEventHandler<IInspectable*>>( + this, &WMRStageStatics::OnCurrentChanged); + HRESULT hr = + stage_statics_->add_CurrentChanged(callback.Get(), &stage_changed_token_); + DCHECK(SUCCEEDED(hr)); } -WMRStageStatics::~WMRStageStatics() = default; +WMRStageStatics::~WMRStageStatics() { + if (stage_changed_token_.value != 0) { + HRESULT hr = stage_statics_->remove_CurrentChanged(stage_changed_token_); + stage_changed_token_.value = 0; + DCHECK(SUCCEEDED(hr)); + } +} std::unique_ptr<WMRStageOrigin> WMRStageStatics::CurrentStage() { ComPtr<ISpatialStageFrameOfReference> stage_origin; @@ -235,8 +249,14 @@ return std::make_unique<WMRStageOrigin>(stage_origin); } -ComPtr<ISpatialStageFrameOfReferenceStatics> WMRStageStatics::GetComPtr() - const { - return stage_statics_; +std::unique_ptr<base::CallbackList<void()>::Subscription> +WMRStageStatics::AddStageChangedCallback( + const base::RepeatingCallback<void()>& cb) { + return callback_list_.Add(cb); +} + +HRESULT WMRStageStatics::OnCurrentChanged(IInspectable*, IInspectable*) { + callback_list_.Notify(); + return S_OK; } } // namespace device
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_origins.h b/device/vr/windows_mixed_reality/wrappers/wmr_origins.h index bb820e7..b7dedb9 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_origins.h +++ b/device/vr/windows_mixed_reality/wrappers/wmr_origins.h
@@ -10,6 +10,7 @@ #include <memory> #include <vector> +#include "base/callback_list.h" #include "base/macros.h" namespace device { @@ -112,16 +113,18 @@ std::unique_ptr<WMRStageOrigin> CurrentStage(); - // TODO(crbug.com/954413): Remove this once the events are exposed directly. - Microsoft::WRL::ComPtr< - ABI::Windows::Perception::Spatial::ISpatialStageFrameOfReferenceStatics> - GetComPtr() const; + std::unique_ptr<base::CallbackList<void()>::Subscription> + AddStageChangedCallback(const base::RepeatingCallback<void()>& cb); private: + HRESULT OnCurrentChanged(IInspectable* sender, IInspectable* args); Microsoft::WRL::ComPtr< ABI::Windows::Perception::Spatial::ISpatialStageFrameOfReferenceStatics> stage_statics_; + EventRegistrationToken stage_changed_token_; + base::CallbackList<void()> callback_list_; + DISALLOW_COPY_AND_ASSIGN(WMRStageStatics); }; } // namespace device
diff --git a/docs/linux_cert_management.md b/docs/linux_cert_management.md index bfc06277..7af877f 100644 --- a/docs/linux_cert_management.md +++ b/docs/linux_cert_management.md
@@ -1,11 +1,5 @@ # Linux Cert Management -*** note -**NOTE:** SSL client authentication with personal certificates does not work -completely in Linux, see [issue 16830](https://crbug.com/16830) and -[issue 25241](https://crbug.com/25241). -*** - The easy way to manage certificates is navigate to chrome://settings/search#ssl. Then click on the "Manage Certificates" button. This will load a built-in interface for managing certificates.
diff --git a/docs/threading_and_tasks.md b/docs/threading_and_tasks.md index 41847b7..840d5f30 100644 --- a/docs/threading_and_tasks.md +++ b/docs/threading_and_tasks.md
@@ -7,32 +7,87 @@ ## Overview -Chromium is a very multithreaded product. We try to keep the UI as responsive as -possible, and this means not blocking the UI thread with any blocking I/O or -other expensive operations. Our approach is to use message passing as the way of -communicating between threads. We discourage locking and threadsafe -objects. Instead, objects live on only one thread, we pass messages between -threads for communication, and we use callback interfaces (implemented by -message passing) for most cross-thread requests. +Chrome has a [multi-process +architecture](https://www.chromium.org/developers/design-documents/multi-process-architecture) +and each process is heavily multi-threaded. In this document we will go over the +basic threading system shared by each process. The main goal is to keep the main +thread (a.k.a. "UI" thread in the browser process) and IO thread (each process' +thread for handling +[IPC](https://en.wikipedia.org/wiki/Inter-process_communication)) responsive. +This means offloading any blocking I/O or other expensive operations to other +threads. Our approach is to use message passing as the way of communicating +between threads. We discourage locking and thread-safe objects. Instead, objects +live on only one (often virtual -- we'll get to that later!) thread and we pass +messages between those threads for communication. + +This documentation assumes familiarity with computer science +[threading concepts](https://en.wikipedia.org/wiki/Thread_(computing)). ### Nomenclature - * **Thread-unsafe**: The vast majority of types in Chromium are thread-unsafe - by design. Access to such types/methods must be synchronized, typically by - sequencing access through a single `base::SequencedTaskRunner` (this should - be enforced by a `SEQUENCE_CHECKER`) or via low-level synchronization (e.g. - locks -- but [prefer sequences](#Using-Sequences-Instead-of-Locks)). + +## Core Concepts + * **Task**: A unit of work to be processed. Effectively a function pointer with + optionally associated state. In Chrome this is `base::Callback` created via + `base::Bind` + ([documentation](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md)). + * **Task queue**: A queue of tasks to be processed. + * **Physical thread**: An operating system provided thread (e.g. pthread on + POSIX or CreateThread() on Windows). The Chrome cross-platform abstraction + is `base::PlatformThread`. You should pretty much never use this directly. + * **`base::Thread`**: A physical thread forever processing messages from a + dedicated task queue until Quit(). You should pretty much never be creating + your own `base::Thread`'s. + * **Thread pool**: A pool of physical threads with a shared task queue. In + Chrome, this is `base::ThreadPool`. There's exactly one instance per Chrome + process, it serves tasks posted through + [`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h) + and as such you should rarely need to use the `base::ThreadPool` API + directly (more on posting tasks later). + * **Sequence** or **Virtual thread**: A chrome-managed thread of execution. + Like a physical thread, only one task can run on a given sequence / virtual + thread at any given moment and each task sees the side-effects of the + preceding tasks. Tasks are executed sequentially but may hop physical + threads between each one. + * **Task runner**: An interface through which tasks can be posted. In Chrome + this is `base::TaskRunner`. + * **Sequenced task runner**: A task runner which guarantees that tasks posted + to it will run sequentially, in posted order. Each such task is guaranteed to + see the side-effects of the task preceding it. Tasks posted to a sequenced + task runner are typically processed by a single thread (virtual or physical). + In Chrome this is `base::SequencedTaskRunner` which is-a + `base::TaskRunner`. + * **Single-thread task runner**: A sequenced task runner which guarantees that + all tasks will be processed by the same physical thread. In Chrome this is + `base::SingleThreadTaskRunner` which is-a `base::SequencedTaskRunner`. We + [prefer sequences to threads](#prefer-sequences-to-physical-threads) whenever + possible. + +## Threading Lexicon +Note to the reader: the following terms are an attempt to bridge the gap between +common threading nomenclature and the way we use them in Chrome. It might be a +bit heavy if you're just getting started. Should this be hard to parse, consider +skipping to the more detailed sections below and referring back to this as +necessary. + + * **Thread-unsafe**: The vast majority of types in Chrome are thread-unsafe + (by design). Access to such types/methods must be externally synchronized. + Typically thread-unsafe types require that all tasks accessing their state be + posted to the same `base::SequencedTaskRunner` and they verify this in debug + builds with a `SEQUENCE_CHECKER` member. Locks are also an option to + synchronize access but in Chrome we strongly + [prefer sequences to locks](#Using-Sequences-Instead-of-Locks). * **Thread-affine**: Such types/methods need to be always accessed from the same physical thread (i.e. from the same `base::SingleThreadTaskRunner`) and - should use `THREAD_CHECKER` to verify that they are. Short of using a - third-party API or having a leaf dependency which is thread-affine: there's - pretty much no reason for a type to be thread-affine in Chromium. Note that - `base::SingleThreadTaskRunner` is-a `base::SequencedTaskRunner` so + typically have a `THREAD_CHECKER` member to verify that they are. Short of + using a third-party API or having a leaf dependency which is thread-affine: + there's pretty much no reason for a type to be thread-affine in Chrome. + Note that `base::SingleThreadTaskRunner` is-a `base::SequencedTaskRunner` so thread-affine is a subset of thread-unsafe. Thread-affine is also sometimes referred to as **thread-hostile**. * **Thread-safe**: Such types/methods can be safely accessed concurrently. * **Thread-compatible**: Such types provide safe concurrent access to const methods but require synchronization for non-const (or mixed const/non-const - access). Chromium doesn't expose reader-writer locks; as such, the only use + access). Chrome doesn't expose reader-writer locks; as such, the only use case for this is objects (typically globals) which are initialized once in a thread-safe manner (either in the single-threaded phase of startup or lazily through a thread-safe static-local-initialization paradigm a la @@ -43,18 +98,18 @@ support being invoked from a `base::SequencedTaskRunner`. Ideally this would be the case for all thread-unsafe types but legacy code sometimes has overzealous checks that enforce thread-affinity in mere thread-unsafe - scenarios. See [Prefer Sequences to Threads](#prefer-sequences-to-threads) - below for more details. + scenarios. See [Prefer Sequences to + Threads](#prefer-sequences-to-physical-threads) below for more details. ### Threads Every Chrome process has * a main thread - * in the browser process: updates the UI - * in renderer processes: runs most of Blink + * in the browser process (BrowserThread::UI): updates the UI + * in renderer processes (Blink main thread): runs most of Blink * an IO thread - * in the browser process: handles IPCs and network requests + * in the browser process (BrowserThread::IO): handles IPCs and network requests * in renderer processes: handles IPCs * a few more special-purpose threads * and a pool of general-purpose threads @@ -90,31 +145,24 @@ * [COM Single Threaded](#Posting-Tasks-to-a-COM-Single-Thread-Apartment-STA_Thread-Windows_): A variant of single threaded with COM initialized. -### Prefer Sequences to Threads +### Prefer Sequences to Physical Threads -**Sequenced execution mode is far preferred to Single Threaded** in scenarios -that require mere thread-safety as it opens up scheduling paradigms that -wouldn't be possible otherwise (sequences can hop threads instead of being stuck -behind unrelated work on a dedicated thread). Ability to hop threads also means -the thread count can dynamically adapt to the machine's true resource -availability (increased parallelism on bigger machines, avoids trashing -resources on smaller machines). +Sequenced execution (on virtual threads) is strongly preferred to +single-threaded execution (on physical threads). Except for types/methods bound +to the main thread (UI) or IO threads: thread-safety is better achieved via +`base::SequencedTaskRunner` than through managing your own physical threads +(ref. [Posting a Sequenced Task](#posting-a-sequenced-task) below). -Many core APIs were recently made sequence-friendly (classes are rarely -thread-affine -- i.e. only when using third-party APIs that are thread-affine; -even ThreadLocalStorage has a SequenceLocalStorage equivalent). But the codebase -has long evolved assuming single-threaded contexts... If your class could run on -a sequence but is blocked by an overzealous use of -ThreadChecker/ThreadTaskRunnerHandle/SingleThreadTaskRunner in a leaf -dependency, consider fixing that dependency for everyone's benefit (or at the -very least file a blocking bug against https://crbug.com/675631 and flag your -use of base::CreateSingleThreadTaskRunnerWithTraits() with a TODO against your -bug to use base::CreateSequencedTaskRunnerWithTraits() when fixed). +All APIs which are exposed for "current physical thread" have an equivalent for +"current sequence" +([mapping](threading_and_tasks_faq.md#How-to-migrate-from-SingleThreadTaskRunner-to-SequencedTaskRunner)). -Detailed documentation on how to migrate from single-threaded contexts to -sequenced contexts can be found [here](threading_and_tasks_faq.md#How-to-migrate-from-SingleThreadTaskRunner-to-SequencedTaskRunner). - -The discussion below covers all of these ways to execute tasks in details. +If you find yourself writing a sequence-friendly type and it fails +thread-affinity checks (e.g., `THREAD_CHECKER`) in a leaf dependency: consider +making that dependency sequence-friendly as well. Most core APIs in Chrome are +sequence-friendly, but some legacy types may still over-zealously use +ThreadChecker/ThreadTaskRunnerHandle/SingleThreadTaskRunner when they could +instead rely on the "current sequence" and no longer be thread-affine. ## Posting a Parallel Task @@ -144,29 +192,23 @@ ### Posting via a TaskRunner A parallel -[`TaskRunner`](https://cs.chromium.org/chromium/src/base/task_runner.h) is an -alternative to calling `base::PostTask*()` directly. This is mainly useful when -it isn’t known in advance whether tasks will be posted in parallel, in sequence, -or to a single-thread (ref. -[Posting a Sequenced Task](#Posting-a-Sequenced-Task), -[Posting Multiple Tasks to the Same Thread](#Posting-Multiple-Tasks-to-the-Same-Thread)). -Since `TaskRunner` is the base class of `SequencedTaskRunner` and -`SingleThreadTaskRunner`, a `scoped_refptr<TaskRunner>` member can hold a -`TaskRunner`, a `SequencedTaskRunner` or a `SingleThreadTaskRunner`. +[`base::TaskRunner`](https://cs.chromium.org/chromium/src/base/task_runner.h) is +an alternative to calling `base::PostTask*()` directly. This is mainly useful +when it isn’t known in advance whether tasks will be posted in parallel, in +sequence, or to a single-thread (ref. [Posting a Sequenced +Task](#Posting-a-Sequenced-Task), [Posting Multiple Tasks to the Same +Thread](#Posting-Multiple-Tasks-to-the-Same-Thread)). Since `base::TaskRunner` +is the base class of `base::SequencedTaskRunner` and +`base::SingleThreadTaskRunner`, a `scoped_refptr<TaskRunner>` member can hold a +`base::TaskRunner`, a `base::SequencedTaskRunner` or a +`base::SingleThreadTaskRunner`. ```cpp class A { public: A() = default; - void set_task_runner_for_testing( - scoped_refptr<base::TaskRunner> task_runner) { - task_runner_ = std::move(task_runner); - } - void DoSomething() { - // In production, A is always posted in parallel. In test, it is posted to - // the TaskRunner provided via set_task_runner_for_testing(). task_runner_->PostTask(FROM_HERE, base::BindOnce(&A)); } @@ -184,11 +226,11 @@ A sequence is a set of tasks that run one at a time in posting order (not necessarily on the same thread). To post tasks as part of a sequence, use a -[`SequencedTaskRunner`](https://cs.chromium.org/chromium/src/base/sequenced_task_runner.h). +[`base::SequencedTaskRunner`](https://cs.chromium.org/chromium/src/base/sequenced_task_runner.h). ### Posting to a New Sequence -A `SequencedTaskRunner` can be created by +A `base::SequencedTaskRunner` can be created by `base::CreateSequencedTaskRunnerWithTraits()`. ```cpp @@ -202,14 +244,14 @@ ### Posting to the Current Sequence -The `SequencedTaskRunner` to which the current task was posted can be obtained -via -[`SequencedTaskRunnerHandle::Get()`](https://cs.chromium.org/chromium/src/base/threading/sequenced_task_runner_handle.h). +The `base::SequencedTaskRunner` to which the current task was posted can be +obtained via +[`base::SequencedTaskRunnerHandle::Get()`](https://cs.chromium.org/chromium/src/base/threading/sequenced_task_runner_handle.h). *** note -**NOTE:** it is invalid to call `SequencedTaskRunnerHandle::Get()` from a +**NOTE:** it is invalid to call `base::SequencedTaskRunnerHandle::Get()` from a parallel task, but it is valid from a single-threaded task (a -`SingleThreadTaskRunner` is a `SequencedTaskRunner`). +`base::SingleThreadTaskRunner` is a `base::SequencedTaskRunner`). *** ```cpp @@ -271,13 +313,14 @@ Locks should only be used to swap in a shared data structure that can be accessed on multiple threads. If one thread updates it based on expensive computation or through disk access, then that slow work should be done without -holding on to the lock. Only when the result is available should the lock be -used to swap in the new data. An example of this is in PluginList::LoadPlugins -([`content/browser/plugin_list.cc`](https://cs.chromium.org/chromium/src/content/browser/plugin_list.cc)). If you must use locks, +holding the lock. Only when the result is available should the lock be used to +swap in the new data. An example of this is in PluginList::LoadPlugins +([`content/browser/plugin_list.cc`](https://cs.chromium.org/chromium/src/content/browser/plugin_list.cc). +If you must use locks, [here](https://www.chromium.org/developers/lock-and-condition-variable) are some best practices and pitfalls to avoid. -In order to write non-blocking code, many APIs in Chromium are asynchronous. +In order to write non-blocking code, many APIs in Chrome are asynchronous. Usually this means that they either need to be executed on a particular thread/sequence and will return results via a custom delegate interface, or they take a `base::Callback<>` object that is called when the requested operation is @@ -287,8 +330,8 @@ ## Posting Multiple Tasks to the Same Thread If multiple tasks need to run on the same thread, post them to a -[`SingleThreadTaskRunner`](https://cs.chromium.org/chromium/src/base/single_thread_task_runner.h). -All tasks posted to the same `SingleThreadTaskRunner` run on the same thread in +[`base::SingleThreadTaskRunner`](https://cs.chromium.org/chromium/src/base/single_thread_task_runner.h). +All tasks posted to the same `base::SingleThreadTaskRunner` run on the same thread in posting order. ### Posting to the Main Thread or to the IO Thread in the Browser Process @@ -322,7 +365,7 @@ ### Posting to a Custom SingleThreadTaskRunner If multiple tasks need to run on the same thread and that thread doesn’t have to -be the main thread or the IO thread, post them to a `SingleThreadTaskRunner` +be the main thread or the IO thread, post them to a `base::SingleThreadTaskRunner` created by `base::CreateSingleThreadTaskRunnerWithTraits`. ```cpp @@ -334,31 +377,25 @@ single_thread_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskB)); ``` -*** note -**IMPORTANT:** You should rarely need this, most classes in Chromium require -thread-safety (which sequences provide) not thread-affinity. If an API you’re -using is incorrectly thread-affine (i.e. using -[`base::ThreadChecker`](https://cs.chromium.org/chromium/src/base/threading/thread_checker.h) -when it’s merely thread-unsafe and should use -[`base::SequenceChecker`](https://cs.chromium.org/chromium/src/base/sequence_checker.h)), -please consider -[`fixing it`](threading_and_tasks_faq.md#How-to-migrate-from-SingleThreadTaskRunner-to-SequencedTaskRunner) -instead of making things worse by also making your API thread-affine. -*** +Remember that we [prefer sequences to physical +threads](#prefer-sequences-to-physical-threads) and that this thus should rarely +be necessary. ### Posting to the Current Thread *** note **IMPORTANT:** To post a task that needs mutual exclusion with the current sequence of tasks but doesn’t absolutely need to run on the current thread, use -`SequencedTaskRunnerHandle::Get()` instead of `ThreadTaskRunnerHandle::Get()` -(ref. [Posting to the Current Sequence](#Posting-to-the-Current-Sequence)). That -will better document the requirements of the posted task. In a single-thread -task, `SequencedTaskRunnerHandle::Get()` is equivalent to -`ThreadTaskRunnerHandle::Get()`. +`base::SequencedTaskRunnerHandle::Get()` instead of +`base::ThreadTaskRunnerHandle::Get()` (ref. [Posting to the Current +Sequence](#Posting-to-the-Current-Sequence)). That will better document the +requirements of the posted task and will avoid unnecessarily making your API +thread-affine. In a single-thread task, `base::SequencedTaskRunnerHandle::Get()` +is equivalent to `base::ThreadTaskRunnerHandle::Get()`. *** -To post a task to the current thread, use [`ThreadTaskRunnerHandle`](https://cs.chromium.org/chromium/src/base/threading/thread_task_runner_handle.h). +To post a task to the current thread, use +[`base::ThreadTaskRunnerHandle`](https://cs.chromium.org/chromium/src/base/threading/thread_task_runner_handle.h). ```cpp // The task will run on the current thread in the future. @@ -367,17 +404,18 @@ ``` *** note -**NOTE:** It is invalid to call `ThreadTaskRunnerHandle::Get()` from a parallel +**NOTE:** It is invalid to call `base::ThreadTaskRunnerHandle::Get()` from a parallel or a sequenced task. *** ## Posting Tasks to a COM Single-Thread Apartment (STA) Thread (Windows) Tasks that need to run on a COM Single-Thread Apartment (STA) thread must be -posted to a `SingleThreadTaskRunner` returned by -`CreateCOMSTATaskRunnerWithTraits()`. As mentioned in [Posting Multiple Tasks to -the Same Thread](#Posting-Multiple-Tasks-to-the-Same-Thread), all tasks posted -to the same `SingleThreadTaskRunner` run on the same thread in posting order. +posted to a `base::SingleThreadTaskRunner` returned by +`base::CreateCOMSTATaskRunnerWithTraits()`. As mentioned in [Posting Multiple +Tasks to the Same Thread](#Posting-Multiple-Tasks-to-the-Same-Thread), all tasks +posted to the same `base::SingleThreadTaskRunner` run on the same thread in +posting order. ```cpp // Task(A|B|C)UsingCOMSTA will run on the same COM STA thread. @@ -402,15 +440,15 @@ ## Annotating Tasks with TaskTraits -[`TaskTraits`](https://cs.chromium.org/chromium/src/base/task/task_traits.h) +[`base::TaskTraits`](https://cs.chromium.org/chromium/src/base/task/task_traits.h) encapsulate information about a task that helps the thread pool make better scheduling decisions. -All `PostTask*()` functions in +All `base::PostTask*()` functions in [`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h) -have an overload that takes `TaskTraits` as argument and one that doesn’t. The -overload that doesn’t take `TaskTraits` as argument is appropriate for tasks -that: +have an overload that takes `base::TaskTraits` as argument and one that doesn’t. +The overload that doesn’t take `base::TaskTraits` as argument is appropriate for +tasks that: - Don’t block (ref. MayBlock and WithBaseSyncPrimitives). - Prefer inheriting the current priority to specifying their own. - Can either block shutdown or be skipped on shutdown (thread pool is free to @@ -423,7 +461,7 @@ [`content/public/browser/browser_task_traits.h`](https://cs.chromium.org/chromium/src/content/public/browser/browser_task_traits.h) to facilitate posting a task onto a BrowserThread. -Below are some examples of how to specify `TaskTraits`. +Below are some examples of how to specify `base::TaskTraits`. ```cpp // This task has no explicit TaskTraits. It cannot block. Its priority @@ -461,8 +499,8 @@ Do not perform expensive work on the main thread, the IO thread or any sequence that is expected to run tasks with a low latency. Instead, perform expensive work asynchronously using `base::PostTaskAndReply*()` or -`SequencedTaskRunner::PostTaskAndReply()`. Note that asynchronous/overlapped -I/O on the IO thread are fine. +`base::SequencedTaskRunner::PostTaskAndReply()`. Note that +asynchronous/overlapped I/O on the IO thread are fine. Example: Running the code below on the main thread will prevent the browser from responding to user input for a long time. @@ -492,7 +530,7 @@ ### Posting a One-Off Task with a Delay To post a task that must run once after a delay expires, use -`base::PostDelayedTask*()` or `TaskRunner::PostDelayedTask()`. +`base::PostDelayedTask*()` or `base::TaskRunner::PostDelayedTask()`. ```cpp base::PostDelayedTaskWithTraits( @@ -593,13 +631,17 @@ To test code that uses `base::ThreadTaskRunnerHandle`, `base::SequencedTaskRunnerHandle` or a function in -[`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h), instantiate a +[`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h), +instantiate a [`base::test::ScopedTaskEnvironment`](https://cs.chromium.org/chromium/src/base/test/scoped_task_environment.h) -for the scope of the test. +for the scope of the test. If you need BrowserThreads, use +`content::TestBrowserThreadBundle` instead of +`base::test::ScopedTaskEnvironment`. -Tests can run the ScopedTaskEnvironment's message pump using a RunLoop, which -can be made to run until Quit, or to execute ready-to-run tasks and immediately -return. +Tests can run the `base::test::ScopedTaskEnvironment`'s message pump using a +`base::RunLoop`, which can be made to run until `Quit()` (explicitly or via +`RunLoop::QuitClosure()`), or to `RunUntilIdle()` ready-to-run tasks and +immediately return. ScopedTaskEnvironment configures RunLoop::Run() to LOG(FATAL) if it hasn't been explicitly quit after TestTimeouts::action_timeout(). This is preferable to @@ -703,16 +745,21 @@ directly from [`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h). -Dependency injection of TaskRunners can still seldomly be useful to unit test a -component when triggering a specific race in a specific way is essential to the -test. For such cases the preferred approach is the following: +As mentioned above, `base::test::ScopedTaskEnvironment` allows unit tests to +control tasks posted from underlying TaskRunners. In rare cases where a test +needs to more precisely control task ordering: dependency injection of +TaskRunners can be useful. For such cases the preferred approach is the +following: ```cpp -class FooWithCustomizableTaskRunnerForTesting { +class Foo { public: + // Overrides |background_task_runner_| in tests. void SetBackgroundTaskRunnerForTesting( - scoped_refptr<base::SequencedTaskRunner> background_task_runner); + scoped_refptr<base::SequencedTaskRunner> background_task_runner) { + background_task_runner_ = std::move(background_task_runner); + } private: scoped_refptr<base::SequencedTaskRunner> background_task_runner_ =
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc index d14153d0..c284ebf 100644 --- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc +++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -427,7 +427,7 @@ } } head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length())); + net::HttpUtil::AssembleRawHeaders(headers)); head.encoded_data_length = 0; current_response_ = head;
diff --git a/fuchsia/runners/BUILD.gn b/fuchsia/runners/BUILD.gn index 7595902..1da5594 100644 --- a/fuchsia/runners/BUILD.gn +++ b/fuchsia/runners/BUILD.gn
@@ -43,12 +43,15 @@ "cast/named_message_port_connector.h", "cast/queryable_data_bindings.cc", "cast/queryable_data_bindings.h", + "cast/touch_input_bindings.cc", + "cast/touch_input_bindings.h", ] data = [ "cast/cast_channel_bindings.js", "cast/named_message_port_connector.js", - "cast/queryable_data_bindings.js", "cast/not_implemented_api_bindings.js", + "cast/queryable_data_bindings.js", + "cast/touch_input_bindings.js", ] deps = [ "//base",
diff --git a/fuchsia/runners/cast/cast_component.cc b/fuchsia/runners/cast/cast_component.cc index 1ab17c5..a1dd03a 100644 --- a/fuchsia/runners/cast/cast_component.cc +++ b/fuchsia/runners/cast/cast_component.cc
@@ -25,19 +25,35 @@ constexpr char kStubBindingsPath[] = FILE_PATH_LITERAL("fuchsia/runners/cast/not_implemented_api_bindings.js"); +TouchInputPolicy TouchInputPolicyFromApplicationConfig( + const chromium::cast::ApplicationConfig& application_config) { + if (!application_config.has_touch_enabled_policy()) + return TouchInputPolicy::UNSPECIFIED; + + if (application_config.touch_enabled_policy()) + return TouchInputPolicy::FORCE_ENABLE; + + return TouchInputPolicy::FORCE_DISABLE; +} + } // namespace CastComponent::CastComponent( CastRunner* runner, + chromium::cast::ApplicationConfig application_config, std::unique_ptr<base::fuchsia::StartupContext> context, fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller_request, std::unique_ptr<cr_fuchsia::AgentManager> agent_manager) : WebComponent(runner, std::move(context), std::move(controller_request)), agent_manager_(std::move(agent_manager)), + application_config_(std::move(application_config)), + touch_input_policy_( + TouchInputPolicyFromApplicationConfig(application_config_)), navigation_listener_binding_(this) { base::AutoReset<bool> constructor_active_reset(&constructor_active_, true); + frame()->SetEnableInput(false); InitializeCastPlatformBindings(); frame()->SetNavigationEventListener( @@ -88,4 +104,6 @@ frame(), agent_manager_->ConnectToAgentService<chromium::cast::QueryableData>( CastRunner::kAgentComponentUrl)); + touch_input_ = std::make_unique<TouchInputBindings>(touch_input_policy_, + frame(), &connector_); }
diff --git a/fuchsia/runners/cast/cast_component.h b/fuchsia/runners/cast/cast_component.h index a9b37119..7b44f84 100644 --- a/fuchsia/runners/cast/cast_component.h +++ b/fuchsia/runners/cast/cast_component.h
@@ -15,6 +15,7 @@ #include "fuchsia/runners/cast/cast_channel_bindings.h" #include "fuchsia/runners/cast/named_message_port_connector.h" #include "fuchsia/runners/cast/queryable_data_bindings.h" +#include "fuchsia/runners/cast/touch_input_bindings.h" #include "fuchsia/runners/common/web_component.h" class CastRunner; @@ -24,6 +25,7 @@ public fuchsia::web::NavigationEventListener { public: CastComponent(CastRunner* runner, + chromium::cast::ApplicationConfig application_config, std::unique_ptr<base::fuchsia::StartupContext> startup_context, fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller_request, @@ -44,11 +46,14 @@ OnNavigationStateChangedCallback callback) override; std::unique_ptr<cr_fuchsia::AgentManager> agent_manager_; + chromium::cast::ApplicationConfig application_config_; bool constructor_active_ = false; + TouchInputPolicy touch_input_policy_; NamedMessagePortConnector connector_; std::unique_ptr<CastChannelBindings> cast_channel_; std::unique_ptr<QueryableDataBindings> queryable_data_; + std::unique_ptr<TouchInputBindings> touch_input_; fuchsia::sys::ServiceProviderPtr agent_services_; fuchsia::modular::AgentControllerPtr agent_controller_;
diff --git a/fuchsia/runners/cast/cast_platform_bindings_ids.h b/fuchsia/runners/cast/cast_platform_bindings_ids.h index 478658f7..bfbac4cf 100644 --- a/fuchsia/runners/cast/cast_platform_bindings_ids.h +++ b/fuchsia/runners/cast/cast_platform_bindings_ids.h
@@ -13,6 +13,7 @@ QUERYABLE_DATA, QUERYABLE_DATA_VALUES, NOT_IMPLEMENTED_API, + TOUCH_INPUT, }; #endif // FUCHSIA_RUNNERS_CAST_CAST_PLATFORM_BINDINGS_IDS_H_
diff --git a/fuchsia/runners/cast/cast_runner.cc b/fuchsia/runners/cast/cast_runner.cc index 86a6aeba..b161cd1 100644 --- a/fuchsia/runners/cast/cast_runner.cc +++ b/fuchsia/runners/cast/cast_runner.cc
@@ -101,14 +101,12 @@ // fields stashed in PendingComponent. GURL cast_app_url(app_config.web_url()); auto component = std::make_unique<CastComponent>( - this, std::move(pending_component->startup_context), + this, std::move(app_config), + std::move(pending_component->startup_context), std::move(pending_component->controller_request), std::move(pending_component->agent_manager)); pending_components_.erase(it); - // Disable input for the Frame by default. - component->frame()->SetEnableInput(false); - component->LoadUrl(std::move(cast_app_url)); RegisterComponent(std::move(component)); }
diff --git a/fuchsia/runners/cast/not_implemented_api_bindings.js b/fuchsia/runners/cast/not_implemented_api_bindings.js index db5ccea..f166281 100644 --- a/fuchsia/runners/cast/not_implemented_api_bindings.js +++ b/fuchsia/runners/cast/not_implemented_api_bindings.js
@@ -59,11 +59,6 @@ cast.__platform__.canDisplayType = cast.__platform__._notImplemented('canDisplayType', true); -cast.__platform__.setTouchInputSupport = - cast.__platform__._notImplemented('setTouchInputSupport', - {displayControls: true}, - cast.__platform__.ReturnType.PROMISE_RESOLVED); - cast.__platform__.setAssistantMessageHandler = cast.__platform__._notImplemented('setAssistantMessageHandler');
diff --git a/fuchsia/runners/cast/not_implemented_api_bindings_browsertest.cc b/fuchsia/runners/cast/not_implemented_api_bindings_browsertest.cc index fce56d0..7ba1ce9 100644 --- a/fuchsia/runners/cast/not_implemented_api_bindings_browsertest.cc +++ b/fuchsia/runners/cast/not_implemented_api_bindings_browsertest.cc
@@ -142,7 +142,6 @@ // expected output. const std::vector<StubExpectation> kExpectations = { {"canDisplayType", "true"}, - {"setTouchInputSupport", "promise {\"displayControls\":true}"}, {"setAssistantMessageHandler"}, {"sendAssistantRequest"}, {"setWindowRequestHandler"},
diff --git a/fuchsia/runners/cast/touch_input_bindings.cc b/fuchsia/runners/cast/touch_input_bindings.cc new file mode 100644 index 0000000..d8a1bcd5 --- /dev/null +++ b/fuchsia/runners/cast/touch_input_bindings.cc
@@ -0,0 +1,151 @@ +// Copyright 2019 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 "fuchsia/runners/cast/touch_input_bindings.h" + +#include <string> +#include <utility> + +#include "base/base_paths_fuchsia.h" +#include "base/bind.h" +#include "base/fuchsia/fuchsia_logging.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/path_service.h" +#include "fuchsia/base/mem_buffer_util.h" +#include "fuchsia/runners/cast/cast_platform_bindings_ids.h" + +namespace { + +constexpr char kMessagePortName[] = "cast.__platform__.__touchInput__"; +constexpr char kRequestId[] = "requestId"; +constexpr char kTouchEnabled[] = "touchEnabled"; +constexpr char kDisplayControls[] = "displayControls"; + +} // namespace + +TouchInputBindings::TouchInputBindings(TouchInputPolicy policy, + fuchsia::web::Frame* frame, + NamedMessagePortConnector* connector) + : policy_(policy), frame_(frame), connector_(connector) { + constexpr uint64_t kBindingsId = + static_cast<uint64_t>(CastPlatformBindingsId::TOUCH_INPUT); + + DCHECK(frame_); + DCHECK(connector_); + + connector_->Register(kMessagePortName, + base::BindRepeating(&TouchInputBindings::OnPortReceived, + base::Unretained(this)), + frame_); + + base::FilePath bindings_js_path; + CHECK(base::PathService::Get(base::DIR_ASSETS, &bindings_js_path)); + bindings_js_path = bindings_js_path.AppendASCII( + "fuchsia/runners/cast/touch_input_bindings.js"); + frame_->AddBeforeLoadJavaScript( + kBindingsId, {"*"}, + cr_fuchsia::MemBufferFromFile(base::File( + bindings_js_path, base::File::FLAG_OPEN | base::File::FLAG_READ)), + [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) { + CHECK(result.is_response()) << "JavaScript injection error."; + }); +} + +TouchInputBindings::~TouchInputBindings() { + connector_->Unregister(frame_, kMessagePortName); +} + +void TouchInputBindings::OnPortReceived(fuchsia::web::MessagePortPtr port) { + port_ = std::move(port); + ReadNextMessage(); +} + +void TouchInputBindings::ReadNextMessage() { + port_->ReceiveMessage( + fit::bind_member(this, &TouchInputBindings::OnControlMessageReceived)); +} + +void TouchInputBindings::OnControlMessageReceived( + fuchsia::web::WebMessage message) { + // Parse and validate the contents of |message|. + std::string message_data; + if (!cr_fuchsia::StringFromMemBuffer(message.data(), &message_data)) { + LOG(ERROR) << "Couldn't read payload from control message."; + port_.Unbind(); + return; + } + + base::Optional<base::Value> message_parsed; + message_parsed = base::JSONReader::Read(message_data); + if (!message_parsed || !message_parsed->is_dict()) { + LOG(ERROR) << "Invalid control message payload."; + port_.Unbind(); + return; + } + + base::Value* request_id_value = message_parsed->FindPath(kRequestId); + const base::Value* should_enable_touch_value = + message_parsed->FindPath(kTouchEnabled); + if (!request_id_value || !should_enable_touch_value) { + LOG(ERROR) << "Parameter dictionary missing required field(s)."; + port_.Unbind(); + return; + } + + if (!request_id_value->is_int()) { + LOG(ERROR) << "requestId is not a number."; + port_.Unbind(); + return; + } + if (!should_enable_touch_value->is_bool()) { + LOG(ERROR) << "touchEnabled is not a boolean."; + port_.Unbind(); + return; + } + + bool should_enable_touch; + base::Value response(base::Value::Type::DICTIONARY); + response.SetPath(kRequestId, std::move(*request_id_value)); + switch (policy_) { + case TouchInputPolicy::FORCE_ENABLE: + // Touch is always enabled for whitelisted applications, regardless of + // what they specified in "touchEnabled". + should_enable_touch = true; + + // Whitelisted applications should not show SDK-provided on-screen + // controls. + response.SetPath(kDisplayControls, base::Value(false)); + break; + + case TouchInputPolicy::FORCE_DISABLE: + // If the application is blacklisted, then reject the Promise by not + // setting a value in kDisplayControls. + should_enable_touch = false; + break; + + case TouchInputPolicy::UNSPECIFIED: + // If no policy is specified for the application, then apply its requested + // state. + should_enable_touch = should_enable_touch_value->GetBool(); + + response.SetPath(kDisplayControls, base::Value(true)); + break; + } + + frame_->SetEnableInput(should_enable_touch); + + // Send the acknowledgement message to JS. + std::string response_json; + CHECK(base::JSONWriter::Write(response, &response_json)); + fuchsia::web::WebMessage response_message = {}; + response_message.set_data(cr_fuchsia::MemBufferFromString(response_json)); + port_->PostMessage(std::move(response_message), + [](fuchsia::web::MessagePort_PostMessage_Result result) { + LOG_IF(ERROR, result.is_err()) + << "PostMessage failed, reason: " + << static_cast<int>(result.err()); + }); + ReadNextMessage(); +}
diff --git a/fuchsia/runners/cast/touch_input_bindings.h b/fuchsia/runners/cast/touch_input_bindings.h new file mode 100644 index 0000000..a436f4d3 --- /dev/null +++ b/fuchsia/runners/cast/touch_input_bindings.h
@@ -0,0 +1,51 @@ +// Copyright 2019 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 FUCHSIA_RUNNERS_CAST_TOUCH_INPUT_BINDINGS_H_ +#define FUCHSIA_RUNNERS_CAST_TOUCH_INPUT_BINDINGS_H_ + +#include <fuchsia/web/cpp/fidl.h> + +#include "base/macros.h" +#include "fuchsia/runners/cast/named_message_port_connector.h" + +enum class TouchInputPolicy { + UNSPECIFIED, + FORCE_ENABLE, + FORCE_DISABLE, +}; + +// Implements the native portions of the setTouchInputEnabled() Cast JS +// API. +class TouchInputBindings { + public: + // |policy|: Touch capabilities for the application declared by the + // ApplicationConfig service. + // |frame|: The Frame which is hosting the Cast application. + // Must outlive |this|. + // |connector|: Used to supply the messaging channel to the JS layer. + TouchInputBindings(TouchInputPolicy policy, + fuchsia::web::Frame* frame, + NamedMessagePortConnector* connector); + ~TouchInputBindings(); + + private: + // Receives a MessagePort from the API. + void OnPortReceived(fuchsia::web::MessagePortPtr port); + + // Processes setTouchInputEnabled() calls. + void OnControlMessageReceived(fuchsia::web::WebMessage message); + + void ReadNextMessage(); + + const TouchInputPolicy policy_; + fuchsia::web::Frame* const frame_; + NamedMessagePortConnector* const connector_; + + fuchsia::web::MessagePortPtr port_; + + DISALLOW_COPY_AND_ASSIGN(TouchInputBindings); +}; + +#endif // FUCHSIA_RUNNERS_CAST_TOUCH_INPUT_BINDINGS_H_
diff --git a/fuchsia/runners/cast/touch_input_bindings.js b/fuchsia/runners/cast/touch_input_bindings.js new file mode 100644 index 0000000..daee3fe --- /dev/null +++ b/fuchsia/runners/cast/touch_input_bindings.js
@@ -0,0 +1,70 @@ +// Copyright 2019 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. + +cast.__platform__.__touchInput__ = new class { + constructor() { + this.port_ = cast.__platform__.connector.bind( + 'cast.__platform__.__touchInput__', + function(response) { + var responseParsed = JSON.parse(response); + if (responseParsed) { + this.onAck(responseParsed.requestId, + responseParsed.displayControls); + } + }.bind(this)); + } + + // Receives an acknowledgement from the native bindings layer and relays the + // result to the Promise. + onAck(requestId, displayControls) { + if (!this.pendingRequests_.hasOwnProperty(requestId)) { + console.error('Received ack for unknown request ID: ' + requestId); + return; + } + + var request = this.pendingRequests_[requestId]; + delete this.pendingRequests_[requestId]; + + if (displayControls === undefined) { + request.reject(); + } else { + request.resolve({'displayControls': displayControls}); + } + } + + // Requests touch input support from the native bindings layer and returns a + // Promise with the result. + // If the request was successful, the Promise will be resolved with a + // dictionary indicating whether onscreen controls should be shown for the + // application. + // If the request was rejected, then the Promise will be rejected. + setTouchInputSupport(touchEnabled) { + return new Promise((resolve, reject) => { + var requestId = this.currentRequestId_++; + this.pendingRequests_[requestId] = { + 'resolve': resolve, + 'reject': reject, + }; + this.port_.sendMessage(JSON.stringify({ + 'requestId': requestId, + 'touchEnabled': touchEnabled, + })); + }); + } + + // Port for sending requests and receiving acknowledgements with the native + // bindings layer. + port_ = null; + + // A dictionary relating inflight request IDs to their Promise resolve/reject + // functions. + pendingRequests_ = {}; + + // Unique ID of the next request. + currentRequestId_ = 0; +}; + +cast.__platform__.setTouchInputSupport = + cast.__platform__.__touchInput__.setTouchInputSupport.bind( + cast.__platform__.__touchInput__);
diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc index f801bb4..03cf41b 100644 --- a/gpu/command_buffer/service/framebuffer_manager.cc +++ b/gpu/command_buffer/service/framebuffer_manager.cc
@@ -539,7 +539,8 @@ bool Framebuffer::ValidateAndAdjustDrawBuffers( uint32_t fragment_output_type_mask, uint32_t fragment_output_written_mask) { uint32_t mask = draw_buffer_bound_mask_ & fragment_output_written_mask; - if ((mask & fragment_output_type_mask) != (mask & draw_buffer_type_mask_)) + if (mask != draw_buffer_bound_mask_ || + (mask & fragment_output_type_mask) != (mask & draw_buffer_type_mask_)) return false; AdjustDrawBuffersImpl(mask);
diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc index a19ffa39..22be5a54 100644 --- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc +++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
@@ -1250,25 +1250,15 @@ // Test ValidateAndAdjustDrawBuffers(). // gl_FragColor situation. - EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_TRUE(framebuffer_->ValidateAndAdjustDrawBuffers(0x3u, 0x3u)); + EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _)).Times(0); + EXPECT_FALSE(framebuffer_->ValidateAndAdjustDrawBuffers(0x3u, 0x3u)); // gl_FragData situation. EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _)) .Times(0); EXPECT_FALSE( framebuffer_->ValidateAndAdjustDrawBuffers(0xFFFFFFFFu, 0xFFFFFFFFu)); // User defined output variables, fully match. - EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_TRUE( - framebuffer_->ValidateAndAdjustDrawBuffers(0x31Bu, 0x33Fu)); - // Call it a second time - this test is critical, making sure we don't - // call DrawBuffers() every draw call if program doesn't change. - EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _)) - .Times(0); + EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _)).Times(0); EXPECT_TRUE( framebuffer_->ValidateAndAdjustDrawBuffers(0x31Bu, 0x33Fu)); // User defined output variables, fully on, one type mismatch. @@ -1277,23 +1267,12 @@ EXPECT_FALSE( framebuffer_->ValidateAndAdjustDrawBuffers(0x32Bu, 0x33Fu)); // Empty output. - EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_TRUE( - framebuffer_->ValidateAndAdjustDrawBuffers(0u, 0u)); + EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _)).Times(0); + EXPECT_FALSE(framebuffer_->ValidateAndAdjustDrawBuffers(0u, 0u)); // User defined output variables, some active buffers have no corresponding // output variables, but if they do, types match. - EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_TRUE( - framebuffer_->ValidateAndAdjustDrawBuffers(0x310u, 0x330u)); - // Call it a second time - making sure DrawBuffers isn't triggered. - EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _)) - .Times(0); - EXPECT_TRUE( - framebuffer_->ValidateAndAdjustDrawBuffers(0x310u, 0x330u)); + EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _)).Times(0); + EXPECT_FALSE(framebuffer_->ValidateAndAdjustDrawBuffers(0x310u, 0x330u)); } class FramebufferInfoFloatTest : public FramebufferInfoTestBase {
diff --git a/gpu/command_buffer/service/wrapped_sk_image.cc b/gpu/command_buffer/service/wrapped_sk_image.cc index d92340e8..1d52e077 100644 --- a/gpu/command_buffer/service/wrapped_sk_image.cc +++ b/gpu/command_buffer/service/wrapped_sk_image.cc
@@ -79,7 +79,7 @@ GrBackendTexture gr_texture = image_->getBackendTexture(/*flushPendingGrContextIO=*/true); DCHECK(gr_texture.isValid()); - return SkSurface::MakeFromBackendTextureAsRenderTarget( + return SkSurface::MakeFromBackendTexture( context_state_->gr_context(), gr_texture, kTopLeft_GrSurfaceOrigin, final_msaa_count, color_type, color_space, &surface_props); } @@ -126,6 +126,11 @@ if (!surface) return false; +#if DCHECK_IS_ON() + auto* canvas = surface->getCanvas(); + canvas->clear(SK_ColorGREEN); +#endif + image_ = surface->makeImageSnapshot(); } else { SkBitmap bitmap;
diff --git a/gpu/vulkan/demo/vulkan_demo.cc b/gpu/vulkan/demo/vulkan_demo.cc index c75f0784..451ae9f5 100644 --- a/gpu/vulkan/demo/vulkan_demo.cc +++ b/gpu/vulkan/demo/vulkan_demo.cc
@@ -15,6 +15,7 @@ #include "third_party/skia/include/core/SkFont.h" #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/effects/SkGradientShader.h" +#include "third_party/skia/include/gpu/GrBackendSemaphore.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/GrContext.h" #include "ui/events/platform/platform_event_source.h" @@ -99,19 +100,16 @@ } void VulkanDemo::CreateSkSurface() { - auto* swap_chain = vulkan_surface_->GetSwapChain(); - auto index = swap_chain->current_image(); - auto& sk_surface = sk_surfaces_[index]; + scoped_write_.emplace(vulkan_surface_->GetSwapChain()); + auto& sk_surface = sk_surfaces_[scoped_write_->image_index()]; if (!sk_surface) { SkSurfaceProps surface_props = SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType); - VkImage vk_image = swap_chain->GetCurrentImage(); - VkImageLayout vk_image_layout = swap_chain->GetCurrentImageLayout(); GrVkImageInfo vk_image_info; - vk_image_info.fImage = vk_image; + vk_image_info.fImage = scoped_write_->image(); vk_image_info.fAlloc = {VK_NULL_HANDLE, 0, 0, 0}; - vk_image_info.fImageLayout = vk_image_layout; + vk_image_info.fImageLayout = scoped_write_->image_layout(); vk_image_info.fImageTiling = VK_IMAGE_TILING_OPTIMAL; vk_image_info.fFormat = VK_FORMAT_B8G8R8A8_UNORM; vk_image_info.fLevelCount = 1; @@ -125,9 +123,13 @@ } else { auto backend = sk_surface->getBackendRenderTarget( SkSurface::kFlushRead_BackendHandleAccess); - backend.setVkImageLayout(swap_chain->GetCurrentImageLayout()); + backend.setVkImageLayout(scoped_write_->image_layout()); } sk_surface_ = sk_surface; + GrBackendSemaphore semaphore; + semaphore.initVulkan(scoped_write_->TakeBeginSemaphore()); + auto result = sk_surface_->wait(1, &semaphore); + DCHECK(result); } void VulkanDemo::Draw(SkCanvas* canvas, float fraction) { @@ -182,7 +184,6 @@ canvas->drawString(message, 0, 0, font, paint); canvas->restore(); - canvas->flush(); } void VulkanDemo::RenderFrame() { @@ -190,13 +191,21 @@ return; CreateSkSurface(); Draw(sk_surface_->getCanvas(), 0.7); + GrBackendSemaphore semaphore; + GrFlushInfo flush_info = { + .fFlags = kNone_GrFlushFlags, + .fNumSemaphores = 1, + .fSignalSemaphores = &semaphore, + }; + sk_surface_->flush(SkSurface::BackendSurfaceAccess::kPresent, flush_info); auto backend = sk_surface_->getBackendRenderTarget( SkSurface::kFlushRead_BackendHandleAccess); GrVkImageInfo vk_image_info; if (!backend.getVkImageInfo(&vk_image_info)) NOTREACHED() << "Failed to get image info"; - vulkan_surface_->GetSwapChain()->SetCurrentImageLayout( - vk_image_info.fImageLayout); + scoped_write_->set_image_layout(vk_image_info.fImageLayout); + scoped_write_->SetEndSemaphore(semaphore.vkSemaphore()); + scoped_write_.reset(); vulkan_surface_->SwapBuffers(); base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/gpu/vulkan/demo/vulkan_demo.h b/gpu/vulkan/demo/vulkan_demo.h index 9e9ae12..577f8fc 100644 --- a/gpu/vulkan/demo/vulkan_demo.h +++ b/gpu/vulkan/demo/vulkan_demo.h
@@ -8,6 +8,8 @@ #include <memory> #include "base/memory/scoped_refptr.h" +#include "base/optional.h" +#include "gpu/vulkan/vulkan_swap_chain.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "ui/gfx/geometry/size.h" #include "ui/platform_window/platform_window_delegate.h" @@ -59,12 +61,13 @@ void Draw(SkCanvas* canvas, float fraction); void RenderFrame(); - std::unique_ptr<gpu::VulkanImplementation> vulkan_implementation_; + std::unique_ptr<VulkanImplementation> vulkan_implementation_; scoped_refptr<viz::VulkanContextProvider> vulkan_context_provider_; gfx::AcceleratedWidget accelerated_widget_ = gfx::kNullAcceleratedWidget; std::unique_ptr<ui::PlatformEventSource> event_source_; std::unique_ptr<ui::PlatformWindow> window_; - std::unique_ptr<gpu::VulkanSurface> vulkan_surface_; + std::unique_ptr<VulkanSurface> vulkan_surface_; + base::Optional<VulkanSwapChain::ScopedWrite> scoped_write_; sk_sp<SkSurface> sk_surface_; std::vector<sk_sp<SkSurface>> sk_surfaces_; float rotation_angle_ = 0;
diff --git a/gpu/vulkan/vulkan_device_queue.cc b/gpu/vulkan/vulkan_device_queue.cc index 4c327ac..a471cf9 100644 --- a/gpu/vulkan/vulkan_device_queue.cc +++ b/gpu/vulkan/vulkan_device_queue.cc
@@ -182,6 +182,7 @@ } void VulkanDeviceQueue::Destroy() { + cleanup_helper_->Destroy(); cleanup_helper_.reset(); if (VK_NULL_HANDLE != owned_vk_device_) {
diff --git a/gpu/vulkan/vulkan_fence_helper.cc b/gpu/vulkan/vulkan_fence_helper.cc index a423576..15df368 100644 --- a/gpu/vulkan/vulkan_fence_helper.cc +++ b/gpu/vulkan/vulkan_fence_helper.cc
@@ -22,6 +22,11 @@ : device_queue_(device_queue) {} VulkanFenceHelper::~VulkanFenceHelper() { + DCHECK(tasks_pending_fence_.empty()); + DCHECK(cleanup_tasks_.empty()); +} + +void VulkanFenceHelper::Destroy() { PerformImmediateCleanup(); } @@ -172,14 +177,12 @@ // recover from this. CHECK(result == VK_SUCCESS || result == VK_ERROR_DEVICE_LOST); bool device_lost = result == VK_ERROR_DEVICE_LOST; + if (!device_lost) + current_generation_ = next_generation_ - 1; // Run all cleanup tasks. Create a temporary vector of tasks to run to avoid // reentrancy issues. std::vector<CleanupTask> tasks_to_run; - tasks_to_run.insert(tasks_to_run.end(), - std::make_move_iterator(tasks_pending_fence_.begin()), - std::make_move_iterator(tasks_pending_fence_.end())); - tasks_pending_fence_.clear(); while (!cleanup_tasks_.empty()) { auto& tasks_for_fence = cleanup_tasks_.front(); vkDestroyFence(device_queue_->GetVulkanDevice(), @@ -189,6 +192,10 @@ std::make_move_iterator(tasks_for_fence.tasks.end())); cleanup_tasks_.pop(); } + tasks_to_run.insert(tasks_to_run.end(), + std::make_move_iterator(tasks_pending_fence_.begin()), + std::make_move_iterator(tasks_pending_fence_.end())); + tasks_pending_fence_.clear(); for (auto& task : tasks_to_run) std::move(task).Run(device_queue_, device_lost); }
diff --git a/gpu/vulkan/vulkan_fence_helper.h b/gpu/vulkan/vulkan_fence_helper.h index a4d5827..5d64eee 100644 --- a/gpu/vulkan/vulkan_fence_helper.h +++ b/gpu/vulkan/vulkan_fence_helper.h
@@ -21,6 +21,9 @@ explicit VulkanFenceHelper(VulkanDeviceQueue* device_queue); ~VulkanFenceHelper(); + // Destroy the fence helper. + void Destroy(); + // Class representing a fence registered with this system. Should be treated // as an opaque handle. class FenceHandle {
diff --git a/gpu/vulkan/vulkan_swap_chain.cc b/gpu/vulkan/vulkan_swap_chain.cc index 84c9d38..2e1e43d 100644 --- a/gpu/vulkan/vulkan_swap_chain.cc +++ b/gpu/vulkan/vulkan_swap_chain.cc
@@ -4,6 +4,7 @@ #include "gpu/vulkan/vulkan_swap_chain.h" +#include "base/bind.h" #include "gpu/vulkan/vulkan_command_buffer.h" #include "gpu/vulkan/vulkan_command_pool.h" #include "gpu/vulkan/vulkan_device_queue.h" @@ -100,6 +101,19 @@ 1, &image_memory_barrier); } +VkSemaphore CreateSemaphore(VkDevice vk_device) { + // Generic semaphore creation structure. + VkSemaphoreCreateInfo semaphore_create_info = { + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; + + VkSemaphore vk_semaphore; + auto result = vkCreateSemaphore(vk_device, &semaphore_create_info, nullptr, + &vk_semaphore); + DLOG_IF(FATAL, VK_SUCCESS != result) + << "vkCreateSemaphore() failed: " << result; + return vk_semaphore; +} + } // namespace VulkanSwapChain::VulkanSwapChain() {} @@ -107,7 +121,6 @@ VulkanSwapChain::~VulkanSwapChain() { DCHECK(images_.empty()); DCHECK_EQ(static_cast<VkSwapchainKHR>(VK_NULL_HANDLE), swap_chain_); - DCHECK_EQ(static_cast<VkSemaphore>(VK_NULL_HANDLE), next_present_semaphore_); } bool VulkanSwapChain::Initialize( @@ -118,43 +131,53 @@ std::unique_ptr<VulkanSwapChain> old_swap_chain) { DCHECK(device_queue); device_queue_ = device_queue; + device_queue_->GetFenceHelper()->ProcessCleanupTasks(); return InitializeSwapChain(surface, surface_caps, surface_format, std::move(old_swap_chain)) && InitializeSwapImages(surface_caps, surface_format); } void VulkanSwapChain::Destroy() { + DCHECK(!is_writing_); DestroySwapImages(); DestroySwapChain(); } gfx::SwapResult VulkanSwapChain::SwapBuffers() { - VkResult result = VK_SUCCESS; + DCHECK(end_write_semaphore_ != VK_NULL_HANDLE); + VkResult result = VK_SUCCESS; VkDevice device = device_queue_->GetVulkanDevice(); VkQueue queue = device_queue_->GetVulkanQueue(); + auto* fence_helper = device_queue_->GetFenceHelper(); auto& current_image_data = images_[current_image_]; + if (current_image_data.layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { + current_image_data.command_buffer->Clear(); + CmdSetImageLayout(current_image_data.command_buffer.get(), + current_image_data.image, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR /* layout */, + current_image_data.layout /* old_layout */); + current_image_data.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - current_image_data->post_raster_command_buffer->Clear(); - CmdSetImageLayout(current_image_data->post_raster_command_buffer.get(), - current_image_data->image, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR /* layout */, - current_image_data->layout /* old_layout */); - current_image_data->layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - // Submit our post_raster_command_buffer for the current buffer. It sets the - // image layout for presenting. - if (!current_image_data->post_raster_command_buffer->Submit( - 0, nullptr, 1, ¤t_image_data->render_semaphore)) { - return gfx::SwapResult::SWAP_FAILED; + VkSemaphore vk_semaphore = CreateSemaphore(device); + // Submit our command_buffer for the current buffer. It sets the image + // layout for presenting. + if (!current_image_data.command_buffer->Submit(1, &end_write_semaphore_, 1, + &vk_semaphore)) { + vkDestroySemaphore(device, vk_semaphore, nullptr /* pAllocator */); + return gfx::SwapResult::SWAP_FAILED; + } + current_image_data.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + fence_helper->EnqueueSemaphoreCleanupForSubmittedWork(end_write_semaphore_); + end_write_semaphore_ = vk_semaphore; } // Queue the present. VkPresentInfoKHR present_info = {}; present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; present_info.waitSemaphoreCount = 1; - present_info.pWaitSemaphores = ¤t_image_data->render_semaphore; + present_info.pWaitSemaphores = &end_write_semaphore_; present_info.swapchainCount = 1; present_info.pSwapchains = &swap_chain_; present_info.pImageIndices = ¤t_image_; @@ -163,38 +186,23 @@ if (VK_SUCCESS != result) { return gfx::SwapResult::SWAP_FAILED; } + fence_helper->EnqueueSemaphoreCleanupForSubmittedWork(end_write_semaphore_); + end_write_semaphore_ = VK_NULL_HANDLE; + VkSemaphore vk_semaphore = CreateSemaphore(device); uint32_t next_image = 0; // Acquire then next image. - result = vkAcquireNextImageKHR(device, swap_chain_, UINT64_MAX, - next_present_semaphore_, VK_NULL_HANDLE, - &next_image); + result = vkAcquireNextImageKHR(device, swap_chain_, UINT64_MAX, vk_semaphore, + VK_NULL_HANDLE, &next_image); if (VK_SUCCESS != result) { + vkDestroySemaphore(device, vk_semaphore, nullptr /* pAllocator */); DLOG(ERROR) << "vkAcquireNextImageKHR() failed: " << result; return gfx::SwapResult::SWAP_FAILED; } - auto& next_image_data = images_[next_image]; - // Swap in the "next_present_semaphore" into the newly acquired image. The - // old "present_semaphore" for the image becomes the place holder for the next - // present semaphore for the next image. - std::swap(next_image_data->present_semaphore, next_present_semaphore_); - - // Submit our pre_raster_command_buffer for the next buffer. It sets the image - // layout for rastering. - next_image_data->pre_raster_command_buffer->Clear(); - CmdSetImageLayout(next_image_data->pre_raster_command_buffer.get(), - next_image_data->image, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL /* layout */, - next_image_data->layout /* old_layout */); - next_image_data->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - if (!next_image_data->pre_raster_command_buffer->Submit( - 1, &next_image_data->present_semaphore, 0, nullptr)) { - return gfx::SwapResult::SWAP_FAILED; - } - current_image_ = next_image; + DCHECK(begin_write_semaphore_ == VK_NULL_HANDLE); + begin_write_semaphore_ = vk_semaphore; return gfx::SwapResult::SWAP_ACK; } @@ -229,13 +237,11 @@ &new_swap_chain); if (VK_SUCCESS != result) { DLOG(ERROR) << "vkCreateSwapchainKHR() failed: " << result; - return false; + result = vkCreateSwapchainKHR(device, &swap_chain_create_info, nullptr, + &new_swap_chain); } if (old_swap_chain) { - result = vkQueueWaitIdle(device_queue_->GetVulkanQueue()); - DLOG_IF(ERROR, VK_SUCCESS != result) - << "vkQueueWaitIdle failed: " << result; old_swap_chain->Destroy(); old_swap_chain = nullptr; } @@ -248,12 +254,18 @@ } void VulkanSwapChain::DestroySwapChain() { - VkDevice device = device_queue_->GetVulkanDevice(); + if (swap_chain_ == VK_NULL_HANDLE) + return; - if (swap_chain_ != VK_NULL_HANDLE) { - vkDestroySwapchainKHR(device, swap_chain_, nullptr); - swap_chain_ = VK_NULL_HANDLE; - } + device_queue_->GetFenceHelper()->EnqueueCleanupTaskForSubmittedWork( + base::BindOnce( + [](VkSwapchainKHR swapchain, VulkanDeviceQueue* device_queue, + bool /* is_lost */) { + VkDevice device = device_queue->GetVulkanDevice(); + vkDestroySwapchainKHR(device, swapchain, nullptr /* pAllocator */); + }, + swap_chain_)); + swap_chain_ = VK_NULL_HANDLE; } bool VulkanSwapChain::InitializeSwapImages( @@ -277,108 +289,121 @@ return false; } - // Generic semaphore creation structure. - VkSemaphoreCreateInfo semaphore_create_info = {}; - semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - command_pool_ = device_queue_->CreateCommandPool(); if (!command_pool_) return false; images_.resize(image_count); for (uint32_t i = 0; i < image_count; ++i) { - images_[i].reset(new ImageData); - std::unique_ptr<ImageData>& image_data = images_[i]; - image_data->image = images[i]; - - // Setup semaphores. - result = vkCreateSemaphore(device, &semaphore_create_info, nullptr, - &image_data->render_semaphore); - if (VK_SUCCESS != result) { - DLOG(ERROR) << "vkCreateSemaphore(render) failed: " << result; - return false; - } - - result = vkCreateSemaphore(device, &semaphore_create_info, nullptr, - &image_data->present_semaphore); - if (VK_SUCCESS != result) { - DLOG(ERROR) << "vkCreateSemaphore(present) failed: " << result; - return false; - } - + auto& image_data = images_[i]; + image_data.image = images[i]; // Initialize the command buffer for this buffer data. - image_data->pre_raster_command_buffer = - command_pool_->CreatePrimaryCommandBuffer(); - image_data->post_raster_command_buffer = - command_pool_->CreatePrimaryCommandBuffer(); + image_data.command_buffer = command_pool_->CreatePrimaryCommandBuffer(); } - result = vkCreateSemaphore(device, &semaphore_create_info, nullptr, - &next_present_semaphore_); - if (VK_SUCCESS != result) { - DLOG(ERROR) << "vkCreateSemaphore(next_present) failed: " << result; - return false; - } - + VkSemaphore vk_semaphore = CreateSemaphore(device); // Acquire the initial buffer. - result = vkAcquireNextImageKHR(device, swap_chain_, UINT64_MAX, - next_present_semaphore_, VK_NULL_HANDLE, - ¤t_image_); + result = vkAcquireNextImageKHR(device, swap_chain_, UINT64_MAX, vk_semaphore, + VK_NULL_HANDLE, ¤t_image_); if (VK_SUCCESS != result) { DLOG(ERROR) << "vkAcquireNextImageKHR() failed: " << result; return false; } - - std::swap(images_[current_image_]->present_semaphore, - next_present_semaphore_); - + begin_write_semaphore_ = vk_semaphore; return true; } void VulkanSwapChain::DestroySwapImages() { - VkDevice device = device_queue_->GetVulkanDevice(); - - if (VK_NULL_HANDLE != next_present_semaphore_) { - vkDestroySemaphore(device, next_present_semaphore_, nullptr); - next_present_semaphore_ = VK_NULL_HANDLE; - } - - for (const std::unique_ptr<ImageData>& image_data : images_) { - if (image_data->post_raster_command_buffer) { - // Make sure command buffer is done processing. - image_data->pre_raster_command_buffer->Wait(UINT64_MAX); - image_data->pre_raster_command_buffer->Destroy(); - image_data->pre_raster_command_buffer.reset(); - - // Make sure command buffer is done processing. - image_data->post_raster_command_buffer->Wait(UINT64_MAX); - image_data->post_raster_command_buffer->Destroy(); - image_data->post_raster_command_buffer.reset(); - } - - // Destroy Semaphores. - if (VK_NULL_HANDLE != image_data->present_semaphore) { - vkDestroySemaphore(device, image_data->present_semaphore, nullptr); - image_data->present_semaphore = VK_NULL_HANDLE; - } - - if (VK_NULL_HANDLE != image_data->render_semaphore) { - vkDestroySemaphore(device, image_data->render_semaphore, nullptr); - image_data->render_semaphore = VK_NULL_HANDLE; - } - - image_data->image = VK_NULL_HANDLE; - } + auto* fence_helper = device_queue_->GetFenceHelper(); + fence_helper->EnqueueCleanupTaskForSubmittedWork(base::BindOnce( + [](VkSemaphore begin_semaphore, VkSemaphore end_semaphore, + std::vector<ImageData> images, + std::unique_ptr<VulkanCommandPool> command_pool, + VulkanDeviceQueue* device_queue, bool /* is_lost */) { + auto* vk_device = device_queue->GetVulkanDevice(); + if (begin_semaphore) + vkDestroySemaphore(vk_device, begin_semaphore, + nullptr /* pAllocator */); + if (end_semaphore) + vkDestroySemaphore(vk_device, end_semaphore, + nullptr /* pAllocator */); + for (auto& image_data : images) { + if (!image_data.command_buffer) + continue; + image_data.command_buffer->Destroy(); + image_data.command_buffer = nullptr; + } + command_pool->Destroy(); + }, + begin_write_semaphore_, end_write_semaphore_, std::move(images_), + std::move(command_pool_))); + begin_write_semaphore_ = VK_NULL_HANDLE; + end_write_semaphore_ = VK_NULL_HANDLE; images_.clear(); - - if (command_pool_) { - command_pool_->Destroy(); - command_pool_.reset(); - } + fence_helper->GenerateCleanupFence(); } -VulkanSwapChain::ImageData::ImageData() {} +void VulkanSwapChain::BeginWriteCurrentImage(VkImage* image, + uint32_t* image_index, + VkImageLayout* image_layout, + VkSemaphore* semaphore) { + DCHECK(image); + DCHECK(image_index); + DCHECK(image_layout); + DCHECK(semaphore); + DCHECK(!is_writing_); + DCHECK(begin_write_semaphore_ != VK_NULL_HANDLE); + DCHECK(end_write_semaphore_ == VK_NULL_HANDLE); -VulkanSwapChain::ImageData::~ImageData() {} + auto& current_image_data = images_[current_image_]; + *image = current_image_data.image; + *image_index = current_image_; + *image_layout = current_image_data.layout; + *semaphore = begin_write_semaphore_; + begin_write_semaphore_ = VK_NULL_HANDLE; + is_writing_ = true; +} + +void VulkanSwapChain::EndWriteCurrentImage(VkImageLayout image_layout, + VkSemaphore semaphore) { + DCHECK(is_writing_); + DCHECK(begin_write_semaphore_ == VK_NULL_HANDLE); + DCHECK(end_write_semaphore_ == VK_NULL_HANDLE); + + auto& current_image_data = images_[current_image_]; + current_image_data.layout = image_layout; + end_write_semaphore_ = semaphore; + is_writing_ = false; +} + +VulkanSwapChain::ScopedWrite::ScopedWrite(VulkanSwapChain* swap_chain) + : swap_chain_(swap_chain) { + swap_chain_->BeginWriteCurrentImage(&image_, &image_index_, &image_layout_, + &begin_semaphore_); +} + +VulkanSwapChain::ScopedWrite::~ScopedWrite() { + DCHECK(begin_semaphore_ == VK_NULL_HANDLE); + swap_chain_->EndWriteCurrentImage(image_layout_, end_semaphore_); +} + +VkSemaphore VulkanSwapChain::ScopedWrite::TakeBeginSemaphore() { + DCHECK(begin_semaphore_ != VK_NULL_HANDLE); + VkSemaphore semaphore = begin_semaphore_; + begin_semaphore_ = VK_NULL_HANDLE; + return semaphore; +} + +void VulkanSwapChain::ScopedWrite::SetEndSemaphore(VkSemaphore semaphore) { + DCHECK(end_semaphore_ == VK_NULL_HANDLE); + DCHECK(semaphore != VK_NULL_HANDLE); + end_semaphore_ = semaphore; +} + +VulkanSwapChain::ImageData::ImageData() = default; +VulkanSwapChain::ImageData::ImageData(ImageData&& other) = default; +VulkanSwapChain::ImageData::~ImageData() = default; +VulkanSwapChain::ImageData& VulkanSwapChain::ImageData::operator=( + ImageData&& other) = default; } // namespace gpu
diff --git a/gpu/vulkan/vulkan_swap_chain.h b/gpu/vulkan/vulkan_swap_chain.h index 1823af7c..6abc635 100644 --- a/gpu/vulkan/vulkan_swap_chain.h +++ b/gpu/vulkan/vulkan_swap_chain.h
@@ -22,6 +22,35 @@ class VULKAN_EXPORT VulkanSwapChain { public: + class ScopedWrite { + public: + explicit ScopedWrite(VulkanSwapChain* swap_chain); + ~ScopedWrite(); + + VkImage image() const { return image_; } + uint32_t image_index() const { return image_index_; } + VkImageLayout image_layout() const { return image_layout_; } + void set_image_layout(VkImageLayout layout) { image_layout_ = layout; } + + // Take the begin write semaphore. The ownership of the semaphore will be + // transferred to the caller. + VkSemaphore TakeBeginSemaphore(); + + // Set the end write semaphore. The ownership of the semaphore will be + // transferred to ScopedWrite. + void SetEndSemaphore(VkSemaphore); + + private: + VulkanSwapChain* const swap_chain_; + VkImage image_ = VK_NULL_HANDLE; + uint32_t image_index_ = 0; + VkImageLayout image_layout_ = VK_IMAGE_LAYOUT_UNDEFINED; + VkSemaphore begin_semaphore_ = VK_NULL_HANDLE; + VkSemaphore end_semaphore_ = VK_NULL_HANDLE; + + DISALLOW_COPY_AND_ASSIGN(ScopedWrite); + }; + VulkanSwapChain(); ~VulkanSwapChain(); @@ -31,38 +60,12 @@ const VkSurfaceFormatKHR& surface_format, std::unique_ptr<VulkanSwapChain> old_swap_chain); void Destroy(); - gfx::SwapResult SwapBuffers(); uint32_t num_images() const { return static_cast<uint32_t>(images_.size()); } uint32_t current_image() const { return current_image_; } const gfx::Size& size() const { return size_; } - VulkanCommandBuffer* GetCurrentCommandBuffer() const { - DCHECK_LT(current_image_, images_.size()); - return images_[current_image_]->pre_raster_command_buffer.get(); - } - - VkImage GetImage(uint32_t index) const { - DCHECK_LT(index, images_.size()); - return images_[index]->image; - } - - VkImage GetCurrentImage() const { - DCHECK_LT(current_image_, images_.size()); - return images_[current_image_]->image; - } - - VkImageLayout GetCurrentImageLayout() const { - DCHECK_LT(current_image_, images_.size()); - return images_[current_image_]->layout; - } - - void SetCurrentImageLayout(VkImageLayout layout) { - DCHECK_LT(current_image_, images_.size()); - images_[current_image_]->layout = layout; - } - private: bool InitializeSwapChain(VkSurfaceKHR surface, const VkSurfaceCapabilitiesKHR& surface_caps, @@ -73,6 +76,11 @@ bool InitializeSwapImages(const VkSurfaceCapabilitiesKHR& surface_caps, const VkSurfaceFormatKHR& surface_format); void DestroySwapImages(); + void BeginWriteCurrentImage(VkImage* image, + uint32_t* image_index, + VkImageLayout* layout, + VkSemaphore* semaphore); + void EndWriteCurrentImage(VkImageLayout layout, VkSemaphore semaphore); VulkanDeviceQueue* device_queue_; VkSwapchainKHR swap_chain_ = VK_NULL_HANDLE; @@ -83,20 +91,22 @@ struct ImageData { ImageData(); + ImageData(ImageData&& other); ~ImageData(); + ImageData& operator=(ImageData&& other); + VkImage image = VK_NULL_HANDLE; VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; - std::unique_ptr<VulkanCommandBuffer> pre_raster_command_buffer; - std::unique_ptr<VulkanCommandBuffer> post_raster_command_buffer; - - VkSemaphore render_semaphore = VK_NULL_HANDLE; - VkSemaphore present_semaphore = VK_NULL_HANDLE; + std::unique_ptr<VulkanCommandBuffer> command_buffer; }; - std::vector<std::unique_ptr<ImageData>> images_; + std::vector<ImageData> images_; uint32_t current_image_ = 0; + bool is_writing_ = false; + VkSemaphore begin_write_semaphore_ = VK_NULL_HANDLE; + VkSemaphore end_write_semaphore_ = VK_NULL_HANDLE; - VkSemaphore next_present_semaphore_ = VK_NULL_HANDLE; + DISALLOW_COPY_AND_ASSIGN(VulkanSwapChain); }; } // namespace gpu
diff --git a/headless/test/test_network_interceptor.cc b/headless/test/test_network_interceptor.cc index 0d48acd..0d60a0de 100644 --- a/headless/test/test_network_interceptor.cc +++ b/headless/test/test_network_interceptor.cc
@@ -148,8 +148,7 @@ raw_headers = data.substr(0, end_of_headers); body = data.substr(end_of_headers + strlen(kHeaderDelimiter)); headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(raw_headers.c_str(), - raw_headers.size())); + net::HttpUtil::AssembleRawHeaders(raw_headers)); } TestNetworkInterceptor::Response::Response(const std::string body, @@ -157,8 +156,7 @@ : raw_headers("HTTP/1.1 200 OK\r\nContent-Type: " + mime_type), body(std::move(body)) { headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(raw_headers.c_str(), - raw_headers.size())); + net::HttpUtil::AssembleRawHeaders(raw_headers)); } TestNetworkInterceptor::Response::Response(const Response& r) = default;
diff --git a/ios/build/bots/scripts/xcodebuild_runner.py b/ios/build/bots/scripts/xcodebuild_runner.py index ea89518..a3f083d 100644 --- a/ios/build/bots/scripts/xcodebuild_runner.py +++ b/ios/build/bots/scripts/xcodebuild_runner.py
@@ -615,16 +615,16 @@ self.test_results['end_run'] = int(time.time()) # Gets passed tests - self.logs['passed'] = [] + self.logs['passed tests'] = [] for shard_attempts in attempts_results: for attempt in shard_attempts: - self.logs['passed'].extend(attempt['passed']) + self.logs['passed tests'].extend(attempt['passed']) # If the last attempt does not have failures, mark failed as empty - self.logs['failed'] = [] + self.logs['failed tests'] = [] for shard_attempts in attempts_results: if shard_attempts[-1]['failed']: - self.logs['failed'].extend(shard_attempts[-1]['failed'].keys()) + self.logs['failed tests'].extend(shard_attempts[-1]['failed'].keys()) # Gets all failures/flakes and lists them in bot summary all_failures = set() @@ -638,10 +638,11 @@ all_failures.add(failure) # Gets only flaky(not failed) tests. - self.logs['flaked'] = list(all_failures - set(self.logs['failed'])) + self.logs['flaked tests'] = list( + all_failures - set(self.logs['failed tests'])) # Test is failed if there are failures for the last run. - return not self.logs['failed'] + return not self.logs['failed tests'] def erase_all_simulators(self): """Erases all simulator devices.
diff --git a/ios/chrome/browser/ui/settings/settings_egtest.mm b/ios/chrome/browser/ui/settings/settings_egtest.mm index 3eb18b3..12da268 100644 --- a/ios/chrome/browser/ui/settings/settings_egtest.mm +++ b/ios/chrome/browser/ui/settings/settings_egtest.mm
@@ -545,16 +545,17 @@ // Verifies that Settings opens when signed-out and in Incognito mode. // This tests that crbug.com/607335 has not regressed. -- (void)testSettingsSignedOutIncognito { - CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGrey openNewIncognitoTab]); - [ChromeEarlGreyUI openSettingsMenu]; - [[EarlGrey selectElementWithMatcher:SettingsCollectionView()] - assertWithMatcher:grey_notNil()]; - - [[EarlGrey selectElementWithMatcher:SettingsDoneButton()] - performAction:grey_tap()]; - CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGrey closeAllIncognitoTabs]); -} +// DISABLED, see https://crbug.com/957687. +// - (void)testSettingsSignedOutIncognito { +// CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGrey openNewIncognitoTab]); +// [ChromeEarlGreyUI openSettingsMenu]; +// [[EarlGrey selectElementWithMatcher:SettingsCollectionView()] +// assertWithMatcher:grey_notNil()]; +// +// [[EarlGrey selectElementWithMatcher:SettingsDoneButton()] +// performAction:grey_tap()]; +// CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGrey closeAllIncognitoTabs]); +// } // Verifies the UI elements are accessible on the Settings page. - (void)testAccessibilityOnSettingsPage {
diff --git a/ios/chrome/browser/web/image_fetch_tab_helper_unittest.mm b/ios/chrome/browser/web/image_fetch_tab_helper_unittest.mm index 4ad6cf1a2..fa38abcdd 100644 --- a/ios/chrome/browser/web/image_fetch_tab_helper_unittest.mm +++ b/ios/chrome/browser/web/image_fetch_tab_helper_unittest.mm
@@ -53,8 +53,7 @@ "HTTP/1.1 200 OK\n" "Content-type: image/png\n\n"; head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(raw_header.c_str(), - raw_header.size())); + net::HttpUtil::AssembleRawHeaders(raw_header)); head.mime_type = "image/png"; network::URLLoaderCompletionStatus status; status.decoded_body_length = strlen(kImageData);
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm index 13c954b..c80075d 100644 --- a/ios/web/web_state/web_state_impl_unittest.mm +++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -126,16 +126,6 @@ MOCK_METHOD0(WebStateDestroyed, void()); }; -// Creates and returns an HttpResponseHeader using the string representation. -scoped_refptr<net::HttpResponseHeaders> HeadersFromString(const char* string) { - std::string raw_string(string); - std::string headers_string = net::HttpUtil::AssembleRawHeaders( - raw_string.c_str(), raw_string.length()); - scoped_refptr<net::HttpResponseHeaders> headers( - new net::HttpResponseHeaders(headers_string)); - return headers; -} - // Test callback for script commands. // Sets |is_called| to true if it is called, and checks that the parameters // match their expected values. @@ -222,16 +212,16 @@ TEST_P(WebStateImplTest, ResponseHeaders) { GURL real_url("http://foo.com/bar"); GURL frame_url("http://frames-r-us.com/"); - scoped_refptr<net::HttpResponseHeaders> real_headers(HeadersFromString( - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html\r\n" - "X-Should-Be-Here: yep\r\n" - "\r\n")); - scoped_refptr<net::HttpResponseHeaders> frame_headers(HeadersFromString( - "HTTP/1.1 200 OK\r\n" - "Content-Type: application/pdf\r\n" - "X-Should-Not-Be-Here: oops\r\n" - "\r\n")); + auto real_headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders("HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "X-Should-Be-Here: yep\r\n" + "\r\n")); + auto frame_headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders("HTTP/1.1 200 OK\r\n" + "Content-Type: application/pdf\r\n" + "X-Should-Not-Be-Here: oops\r\n" + "\r\n")); // Simulate a load of a page with a frame. web_state_->OnHttpResponseHeadersReceived(real_headers.get(), real_url); web_state_->OnHttpResponseHeadersReceived(frame_headers.get(), frame_url); @@ -252,10 +242,10 @@ TEST_P(WebStateImplTest, ResponseHeaderClearing) { GURL url("http://foo.com/"); - scoped_refptr<net::HttpResponseHeaders> headers(HeadersFromString( - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html\r\n" - "\r\n")); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders("HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "\r\n")); web_state_->OnHttpResponseHeadersReceived(headers.get(), url); // There should be no headers before loading.
diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc index d322bc6..599958e9 100644 --- a/media/audio/android/audio_manager_android.cc +++ b/media/audio/android/audio_manager_android.cc
@@ -113,11 +113,8 @@ // MODIFY_AUDIO_SETTINGS or RECORD_AUDIO permissions. return; } - jsize len = env->GetArrayLength(j_device_array.obj()); AudioDeviceName device; - for (jsize i = 0; i < len; ++i) { - ScopedJavaLocalRef<jobject> j_device( - env, env->GetObjectArrayElement(j_device_array.obj(), i)); + for (auto j_device : j_device_array.ReadElements<jobject>()) { ScopedJavaLocalRef<jstring> j_device_name = Java_AudioDeviceName_name(env, j_device); ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name);
diff --git a/media/base/android/media_codec_util.cc b/media/base/android/media_codec_util.cc index 51f3095..a6d6ee7 100644 --- a/media/base/android/media_codec_util.cc +++ b/media/base/android/media_codec_util.cc
@@ -263,10 +263,8 @@ JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobjectArray> j_codec_profile_levels( Java_MediaCodecUtil_getSupportedCodecProfileLevels(env)); - int java_array_length = env->GetArrayLength(j_codec_profile_levels.obj()); - for (int i = 0; i < java_array_length; ++i) { - ScopedJavaLocalRef<jobject> java_codec_profile_level( - env, env->GetObjectArrayElement(j_codec_profile_levels.obj(), i)); + for (auto java_codec_profile_level : + j_codec_profile_levels.ReadElements<jobject>()) { result->push_back(MediaCodecProfileLevelToChromiumProfileLevel( env, java_codec_profile_level)); }
diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc index 222e868..8d54dbe6 100644 --- a/media/base/android/media_drm_bridge.cc +++ b/media/base/android/media_drm_bridge.cc
@@ -38,10 +38,11 @@ #include "third_party/widevine/cdm/widevine_cdm_common.h" using base::android::AttachCurrentThread; -using base::android::ConvertUTF8ToJavaString; using base::android::ConvertJavaStringToUTF8; +using base::android::ConvertUTF8ToJavaString; using base::android::JavaByteArrayToByteVector; using base::android::JavaByteArrayToString; +using base::android::JavaObjectArrayReader; using base::android::JavaParamRef; using base::android::ScopedJavaGlobalRef; using base::android::ScopedJavaLocalRef; @@ -772,13 +773,10 @@ CdmKeysInfo cdm_keys_info; - size_t size = env->GetArrayLength(j_keys_info); - DCHECK_GT(size, 0u); + JavaObjectArrayReader<jobject> j_keys_info_array(j_keys_info); + DCHECK_GT(j_keys_info_array.size(), 0); - for (size_t i = 0; i < size; ++i) { - ScopedJavaLocalRef<jobject> j_key_status( - env, env->GetObjectArrayElement(j_keys_info, i)); - + for (auto j_key_status : j_keys_info_array) { ScopedJavaLocalRef<jbyteArray> j_key_id = Java_KeyStatus_getKeyId(env, j_key_status); std::vector<uint8_t> key_id;
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index c18ec680..184b38eb4 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -2646,7 +2646,7 @@ // If possible attempt to avoid decoder spool up until playback starts. Pipeline::StartType start_type = Pipeline::StartType::kNormal; if (!chunk_demuxer_ && preload_ == MultibufferDataSource::METADATA && - !client_->CouldPlayIfEnoughData()) { + !client_->CouldPlayIfEnoughData() && !IsStreaming()) { start_type = (has_poster_ || base::FeatureList::IsEnabled(kPreloadMetadataLazyLoad)) ? Pipeline::StartType::kSuspendAfterMetadata
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc index aba87ec1..f40e4d6 100644 --- a/media/blink/webmediaplayer_impl_unittest.cc +++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -575,9 +575,17 @@ return GetVideoStatsReporter()->codec_profile_; } - void Load(std::string data_file) { - // URL doesn't matter, it's value is unknown to the underlying demuxer. - const GURL kTestURL("file://example.com/sample.webm"); + enum class LoadType { kFullyBuffered, kStreaming }; + void Load(std::string data_file, + LoadType load_type = LoadType::kFullyBuffered) { + const bool is_streaming = load_type == LoadType::kStreaming; + + // The URL is used by MultibufferDataSource to determine if it should assume + // the resource is fully buffered locally. We can use a fake one here since + // we're injecting the response artificially. It's value is unknown to the + // underlying demuxer. + const GURL kTestURL(std::string(is_streaming ? "http" : "file") + + "://example.com/sample.webm"); // This block sets up a fetch context which ultimately provides us a pointer // to the WebAssociatedURLLoaderClient handed out by the DataSource after it @@ -603,19 +611,25 @@ scoped_refptr<DecoderBuffer> data = ReadTestDataFile(data_file); // "Serve" the file to the DataSource. Note: We respond with 200 okay, which - // will prevent range requests or partial responses from being used. + // will prevent range requests or partial responses from being used. For + // streaming responses, we'll pretend we don't know the content length. blink::WebURLResponse response(kTestURL); response.SetHttpHeaderField( blink::WebString::FromUTF8("Content-Length"), - blink::WebString::FromUTF8(base::NumberToString(data->data_size()))); - response.SetExpectedContentLength(data->data_size()); + blink::WebString::FromUTF8( + is_streaming ? "-1" : base::NumberToString(data->data_size()))); + response.SetExpectedContentLength(is_streaming ? -1 : data->data_size()); response.SetHttpStatusCode(200); client->DidReceiveResponse(response); - // Copy over the file data and indicate that's everything. + // Copy over the file data. client->DidReceiveData(reinterpret_cast<const char*>(data->data()), data->data_size()); - client->DidFinishLoading(); + + // If we're pretending to be a streaming resource, don't complete the load; + // otherwise the DataSource will not be marked as streaming. + if (!is_streaming) + client->DidFinishLoading(); } void LoadAndWaitForMetadata(std::string data_file) { @@ -828,6 +842,37 @@ EXPECT_EQ(reported_memory_ - data_source_size, 0); } +// Verify that preload=metadata suspend works properly for streaming sources. +TEST_F(WebMediaPlayerImplTest, LoadPreloadMetadataSuspendNoStreaming) { + InitializeWebMediaPlayerImpl(); + EXPECT_CALL(client_, CouldPlayIfEnoughData()).WillRepeatedly(Return(false)); + wmpi_->SetPreload(blink::WebMediaPlayer::kPreloadMetaData); + + // This test needs a file which is larger than the MultiBuffer block size; + // otherwise we'll never complete initialization of the MultiBufferDataSource. + constexpr char kLargeAudioOnlyTestFile[] = "bear_192kHz.wav"; + Load(kLargeAudioOnlyTestFile, LoadType::kStreaming); + + // This runs until we reach the have current data state. Attempting to wait + // for states < kReadyStateHaveCurrentData is unreliable due to asynchronous + // execution of tasks on the base::test:ScopedTaskEnvironment. + while (wmpi_->GetReadyState() < + blink::WebMediaPlayer::kReadyStateHaveCurrentData) { + base::RunLoop loop; + EXPECT_CALL(client_, ReadyStateChanged()) + .WillRepeatedly(RunClosure(loop.QuitClosure())); + loop.Run(); + + // Clear the mock so it doesn't have a stale QuitClosure. + testing::Mock::VerifyAndClearExpectations(&client_); + } + + testing::Mock::VerifyAndClearExpectations(&client_); + EXPECT_CALL(client_, ReadyStateChanged()).Times(AnyNumber()); + CycleThreads(); + EXPECT_FALSE(IsSuspended()); +} + // Verify that lazy load for preload=metadata works properly. TEST_F(WebMediaPlayerImplTest, LazyLoadPreloadMetadataSuspend) { base::test::ScopedFeatureList scoped_feature_list;
diff --git a/media/capture/video/android/video_capture_device_factory_android.cc b/media/capture/video/android/video_capture_device_factory_android.cc index 4a7e12c..b57ab05 100644 --- a/media/capture/video/android/video_capture_device_factory_android.cc +++ b/media/capture/video/android/video_capture_device_factory_android.cc
@@ -112,11 +112,7 @@ if (collected_formats.is_null()) return; - jsize num_formats = env->GetArrayLength(collected_formats.obj()); - for (int i = 0; i < num_formats; ++i) { - base::android::ScopedJavaLocalRef<jobject> format( - env, env->GetObjectArrayElement(collected_formats.obj(), i)); - + for (auto format : collected_formats.ReadElements<jobject>()) { VideoPixelFormat pixel_format = PIXEL_FORMAT_UNKNOWN; switch (Java_VideoCaptureFactory_getCaptureFormatPixelFormat(env, format)) { case VideoCaptureDeviceAndroid::ANDROID_IMAGE_FORMAT_YV12:
diff --git a/media/capture/video/win/sink_input_pin_win.cc b/media/capture/video/win/sink_input_pin_win.cc index ed40946a..92ae610 100644 --- a/media/capture/video/win/sink_input_pin_win.cc +++ b/media/capture/video/win/sink_input_pin_win.cc
@@ -13,6 +13,7 @@ #include "base/logging.h" #include "base/stl_util.h" +#include "base/win/win_util.h" #include "media/base/timestamp_constants.h" namespace media { @@ -111,11 +112,8 @@ return true; } -#ifndef NDEBUG - WCHAR guid_str[128]; - StringFromGUID2(sub_type, guid_str, base::size(guid_str)); - DVLOG(2) << __func__ << " unsupported media type: " << guid_str; -#endif + DVLOG(2) << __func__ << " unsupported media type: " + << base::win::String16FromGUID(sub_type); return false; }
diff --git a/media/capture/video/win/video_capture_device_win.cc b/media/capture/video/win/video_capture_device_win.cc index ee71ff53..db7ea55 100644 --- a/media/capture/video/win/video_capture_device_win.cc +++ b/media/capture/video/win/video_capture_device_win.cc
@@ -17,6 +17,7 @@ #include "base/strings/sys_string_conversions.h" #include "base/win/scoped_co_mem.h" #include "base/win/scoped_variant.h" +#include "base/win/win_util.h" #include "media/base/media_switches.h" #include "media/base/timestamp_constants.h" #include "media/capture/mojom/image_capture_types.h" @@ -338,11 +339,8 @@ if (sub_type == pixel_format.sub_type) return pixel_format.format; } -#ifndef NDEBUG - WCHAR guid_str[128]; - StringFromGUID2(sub_type, guid_str, base::size(guid_str)); - DVLOG(2) << "Device (also) supports an unknown media type " << guid_str; -#endif + DVLOG(2) << "Device (also) supports an unknown media type " + << base::win::String16FromGUID(sub_type); return PIXEL_FORMAT_UNKNOWN; }
diff --git a/media/midi/midi_device_android.cc b/media/midi/midi_device_android.cc index 26e8524..608c160 100644 --- a/media/midi/midi_device_android.cc +++ b/media/midi/midi_device_android.cc
@@ -32,21 +32,14 @@ : raw_device_(raw_device) { ScopedJavaLocalRef<jobjectArray> raw_input_ports = Java_MidiDeviceAndroid_getInputPorts(env, raw_device); - jsize num_input_ports = env->GetArrayLength(raw_input_ports.obj()); - - for (jsize i = 0; i < num_input_ports; ++i) { - ScopedJavaLocalRef<jobject> j_port( - env, env->GetObjectArrayElement(raw_input_ports.obj(), i)); + for (auto j_port : raw_input_ports.ReadElements<jobject>()) { input_ports_.push_back( std::make_unique<MidiInputPortAndroid>(env, j_port.obj(), delegate)); } ScopedJavaLocalRef<jobjectArray> raw_output_ports = Java_MidiDeviceAndroid_getOutputPorts(env, raw_device); - jsize num_output_ports = env->GetArrayLength(raw_output_ports.obj()); - for (jsize i = 0; i < num_output_ports; ++i) { - ScopedJavaLocalRef<jobject> j_port( - env, env->GetObjectArrayElement(raw_output_ports.obj(), i)); + for (auto j_port : raw_output_ports.ReadElements<jobject>()) { output_ports_.push_back( std::make_unique<MidiOutputPortAndroid>(env, j_port.obj())); }
diff --git a/media/midi/midi_manager_android.cc b/media/midi/midi_manager_android.cc index 5f6500a..662d026 100644 --- a/media/midi/midi_manager_android.cc +++ b/media/midi/midi_manager_android.cc
@@ -120,11 +120,7 @@ JNIEnv* env, const JavaParamRef<jobject>& caller, const JavaParamRef<jobjectArray>& devices) { - jsize length = env->GetArrayLength(devices); - - for (jsize i = 0; i < length; ++i) { - base::android::ScopedJavaLocalRef<jobject> raw_device( - env, env->GetObjectArrayElement(devices, i)); + for (auto raw_device : devices.ReadElements<jobject>()) { AddDevice(std::make_unique<MidiDeviceAndroid>(env, raw_device, this)); } service()->task_service()->PostBoundTask(
diff --git a/media/midi/usb_midi_device_factory_android.cc b/media/midi/usb_midi_device_factory_android.cc index 1d1e90c7..292874b4 100644 --- a/media/midi/usb_midi_device_factory_android.cc +++ b/media/midi/usb_midi_device_factory_android.cc
@@ -55,11 +55,8 @@ JNIEnv* env, const JavaParamRef<jobject>& caller, const JavaParamRef<jobjectArray>& devices) { - size_t size = env->GetArrayLength(devices); UsbMidiDevice::Devices devices_to_pass; - for (size_t i = 0; i < size; ++i) { - base::android::ScopedJavaLocalRef<jobject> raw_device( - env, env->GetObjectArrayElement(devices, i)); + for (auto raw_device : devices.ReadElements<jobject>()) { devices_to_pass.push_back( std::make_unique<UsbMidiDeviceAndroid>(raw_device, delegate_)); }
diff --git a/mojo/public/cpp/bindings/README.md b/mojo/public/cpp/bindings/README.md index 55a366c..36bbe87 100644 --- a/mojo/public/cpp/bindings/README.md +++ b/mojo/public/cpp/bindings/README.md
@@ -10,7 +10,7 @@ generated code from the [Mojom IDL and bindings generator](/mojo/public/tools/bindings/README.md), users can easily connect interface clients and implementations across arbitrary intra- -and inter-process bounaries. +and inter-process boundaries. This document provides a detailed guide to bindings API usage with example code snippets. For a detailed API references please consult the headers in @@ -384,7 +384,7 @@ incoming messages for an endpoint on disconnection, the connection error won't be triggered until the messages are drained. -Pipe disconnecition may be caused by: +Pipe disconnection may be caused by: * Mojo system-level causes: process terminated, resource exhausted, etc. * The bindings close the pipe due to a validation error when processing a received message. @@ -603,7 +603,7 @@ This allows struct values to be nullable and struct types to be potentially self-referential. -Every genereated struct class has a static `New()` method which returns a new +Every generated struct class has a static `New()` method which returns a new `mojo::StructPtr<T>` wrapping a new instance of the class constructed by forwarding the arguments from `New`. For example: @@ -1742,7 +1742,7 @@ ## Versioning Considerations For general documentation of versioning in the Mojom IDL see -[Versioning](/mojo/public/tools/bindings/README.md#Versiwoning). +[Versioning](/mojo/public/tools/bindings/README.md#Versioning). This section briefly discusses some C++-specific considerations relevant to versioned Mojom types.
diff --git a/net/base/network_interfaces_unittest.cc b/net/base/network_interfaces_unittest.cc index 843de293..b5c5a19 100644 --- a/net/base/network_interfaces_unittest.cc +++ b/net/base/network_interfaces_unittest.cc
@@ -18,6 +18,8 @@ #elif defined(OS_WIN) #include <iphlpapi.h> #include <objbase.h> +#include "base/strings/string_util.h" +#include "base/win/win_util.h" #endif namespace net { @@ -48,10 +50,8 @@ GUID guid; EXPECT_EQ(static_cast<DWORD>(NO_ERROR), ConvertInterfaceLuidToGuid(&luid, &guid)); - LPOLESTR name; - StringFromCLSID(guid, &name); - EXPECT_STREQ(base::UTF8ToWide(it->name).c_str(), name); - CoTaskMemFree(name); + auto name = base::win::String16FromGUID(guid); + EXPECT_EQ(base::as_u16cstr(base::UTF8ToWide(it->name)), name); if (it->type == NetworkChangeNotifier::CONNECTION_WIFI) { EXPECT_NE(WIFI_PHY_LAYER_PROTOCOL_NONE, GetWifiPHYLayerProtocol());
diff --git a/net/cookies/cookie_store_test_callbacks.h b/net/cookies/cookie_store_test_callbacks.h index ff9e2d2f6..77e41f5 100644 --- a/net/cookies/cookie_store_test_callbacks.h +++ b/net/cookies/cookie_store_test_callbacks.h
@@ -90,6 +90,12 @@ NoResultCookieCallback(); explicit NoResultCookieCallback(base::Thread* run_in_thread); + // Makes a callback that will invoke Run. Assumes that |this| will be kept + // alive till the time the callback is used. + base::OnceCallback<void()> MakeCallback() { + return base::BindOnce(&NoResultCookieCallback::Run, base::Unretained(this)); + } + void Run() { CallbackEpilogue(); }
diff --git a/net/dns/BUILD.gn b/net/dns/BUILD.gn index 71764bc..a3bdb220 100644 --- a/net/dns/BUILD.gn +++ b/net/dns/BUILD.gn
@@ -227,9 +227,6 @@ # URLRequestContext creation for chromecast. "//chromecast/browser", - # Tests and test support. - "//components/cronet:cronet_common_unittests", - # Network stack/service. "//net/*", "//services/network/*", @@ -447,8 +444,8 @@ source_set("fuzzer_test_support") { testonly = true sources = [ - "fuzzed_host_resolver_util.cc", - "fuzzed_host_resolver_util.h", + "fuzzed_context_host_resolver.cc", + "fuzzed_context_host_resolver.h", ] deps = [ "//base",
diff --git a/net/dns/context_host_resolver.cc b/net/dns/context_host_resolver.cc index 10e0fbee..0df2ef21 100644 --- a/net/dns/context_host_resolver.cc +++ b/net/dns/context_host_resolver.cc
@@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/strings/string_piece.h" #include "base/time/tick_clock.h" +#include "net/dns/dns_client.h" #include "net/dns/dns_config.h" #include "net/dns/host_cache.h" #include "net/dns/host_resolver_manager.h" @@ -131,6 +132,10 @@ return manager_->CreateMdnsListener(host, query_type); } +void ContextHostResolver::SetDnsClientEnabled(bool enabled) { + manager_->SetDnsClientEnabled(enabled); +} + HostCache* ContextHostResolver::GetHostCache() { return host_cache_.get(); } @@ -161,6 +166,11 @@ return manager_->GetNoIPv6OnWifi(); } +void ContextHostResolver::SetDnsConfigOverrides( + const DnsConfigOverrides& overrides) { + manager_->SetDnsConfigOverrides(overrides); +} + void ContextHostResolver::SetRequestContext( URLRequestContext* request_context) { DCHECK(request_context); @@ -195,6 +205,11 @@ manager_->set_proc_params_for_test(proc_params); } +void ContextHostResolver::SetDnsClientForTesting( + std::unique_ptr<DnsClient> dns_client) { + manager_->SetDnsClient(std::move(dns_client)); +} + void ContextHostResolver::SetBaseDnsConfigForTesting( const DnsConfig& base_config) { manager_->SetBaseDnsConfigForTesting(base_config);
diff --git a/net/dns/context_host_resolver.h b/net/dns/context_host_resolver.h index 32fba6c..f03a6a5 100644 --- a/net/dns/context_host_resolver.h +++ b/net/dns/context_host_resolver.h
@@ -19,6 +19,7 @@ namespace net { +class DnsClient; struct DnsConfig; class HostCache; class HostResolverManager; @@ -51,6 +52,7 @@ std::unique_ptr<MdnsListener> CreateMdnsListener( const HostPortPair& host, DnsQueryType query_type) override; + void SetDnsClientEnabled(bool enabled) override; HostCache* GetHostCache() override; bool HasCached(base::StringPiece hostname, HostCache::Entry::Source* source_out, @@ -59,6 +61,7 @@ std::unique_ptr<base::Value> GetDnsConfigAsValue() const override; void SetNoIPv6OnWifi(bool no_ipv6_on_wifi) override; bool GetNoIPv6OnWifi() override; + void SetDnsConfigOverrides(const DnsConfigOverrides& overrides) override; void SetRequestContext(URLRequestContext* request_context) override; const std::vector<DnsConfig::DnsOverHttpsServerConfig>* GetDnsOverHttpsServersForTesting() const override; @@ -72,6 +75,7 @@ size_t CacheSize() const; void SetProcParamsForTesting(const ProcTaskParams& proc_params); + void SetDnsClientForTesting(std::unique_ptr<DnsClient> dns_client); void SetBaseDnsConfigForTesting(const DnsConfig& base_config); void SetTickClockForTesting(const base::TickClock* tick_clock);
diff --git a/net/dns/context_host_resolver_unittest.cc b/net/dns/context_host_resolver_unittest.cc index ef2a1d6..29361ff 100644 --- a/net/dns/context_host_resolver_unittest.cc +++ b/net/dns/context_host_resolver_unittest.cc
@@ -50,7 +50,7 @@ auto dns_client = std::make_unique<MockDnsClient>(DnsConfig(), std::move(rules)); dns_client_ = dns_client.get(); - manager_->SetDnsClientForTesting(std::move(dns_client)); + manager_->SetDnsClient(std::move(dns_client)); scoped_refptr<HostResolverProc> proc = CreateCatchAllHostResolverProc(); manager_->set_proc_params_for_test(ProcTaskParams(proc.get(), 1u));
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc index a83ecfa..01ad86b 100644 --- a/net/dns/dns_transaction_unittest.cc +++ b/net/dns/dns_transaction_unittest.cc
@@ -514,9 +514,8 @@ raw_headers.append(base::StringPrintf("Content-Length: %1d\n", static_cast<int>(content_length_))); } - info->headers = - base::MakeRefCounted<HttpResponseHeaders>(HttpUtil::AssembleRawHeaders( - raw_headers.c_str(), static_cast<int>(raw_headers.length()))); + info->headers = base::MakeRefCounted<HttpResponseHeaders>( + HttpUtil::AssembleRawHeaders(raw_headers)); if (response_modifier_) response_modifier_.Run(request(), info); }
diff --git a/net/dns/fuzzed_host_resolver_util.cc b/net/dns/fuzzed_context_host_resolver.cc similarity index 89% rename from net/dns/fuzzed_host_resolver_util.cc rename to net/dns/fuzzed_context_host_resolver.cc index ab59eef4..17b064b 100644 --- a/net/dns/fuzzed_host_resolver_util.cc +++ b/net/dns/fuzzed_context_host_resolver.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/dns/fuzzed_host_resolver_util.h" +#include "net/dns/fuzzed_context_host_resolver.h" #include <stdint.h> #include <algorithm> @@ -26,7 +26,6 @@ #include "net/base/ip_address.h" #include "net/base/ip_endpoint.h" #include "net/base/net_errors.h" -#include "net/dns/context_host_resolver.h" #include "net/dns/dns_client.h" #include "net/dns/dns_config.h" #include "net/dns/dns_hosts.h" @@ -38,7 +37,6 @@ #include "net/log/net_log.h" #include "net/log/net_log_with_source.h" #include "net/socket/datagram_server_socket.h" -#include "net/socket/fuzzed_socket_factory.h" namespace net { @@ -309,12 +307,7 @@ : HostResolverManager(options, net_log), data_provider_(data_provider), is_ipv6_reachable_(data_provider->ConsumeBool()), - socket_factory_(data_provider_), - net_log_(net_log), data_provider_weak_factory_(data_provider) { - // Use SetDnsClientEnabled() to ensure fuzzed client is used. - DCHECK(!options.dns_client_enabled); - ProcTaskParams proc_task_params( new FuzzedHostResolverProc(data_provider_weak_factory_.GetWeakPtr()), // Retries are only used when the original request hangs, which this @@ -328,15 +321,6 @@ ~FuzzedHostResolverManager() override = default; - // Enable / disable the async resolver. When enabled, installs a - // DnsClient with fuzzed UDP and TCP sockets. - void SetDnsClientEnabled(bool enabled) override; - - void SetDnsClientForTesting(std::unique_ptr<DnsClient> dns_client) { - // Should only call SetDnsClientEnabled() to ensure a fuzzed client is used. - NOTREACHED(); - } - private: // HostResolverManager implementation: bool IsGloballyReachable(const IPAddress& dest, @@ -353,19 +337,32 @@ // Fixed value to be returned by IsIPv6Reachable. const bool is_ipv6_reachable_; - // Used for UDP and TCP sockets if the async resolver is enabled. - FuzzedSocketFactory socket_factory_; - - NetLog* const net_log_; - base::WeakPtrFactory<base::FuzzedDataProvider> data_provider_weak_factory_; DISALLOW_COPY_AND_ASSIGN(FuzzedHostResolverManager); }; -void FuzzedHostResolverManager::SetDnsClientEnabled(bool enabled) { +} // namespace + +FuzzedContextHostResolver::FuzzedContextHostResolver( + const ManagerOptions& options, + NetLog* net_log, + base::FuzzedDataProvider* data_provider, + bool enable_caching) + : ContextHostResolver( + std::make_unique<FuzzedHostResolverManager>(options, + net_log, + data_provider), + enable_caching ? HostCache::CreateDefaultCache() : nullptr), + data_provider_(data_provider), + socket_factory_(data_provider), + net_log_(net_log) {} + +FuzzedContextHostResolver::~FuzzedContextHostResolver() = default; + +void FuzzedContextHostResolver::SetDnsClientEnabled(bool enabled) { if (!enabled) { - HostResolverManager::SetDnsClientEnabled(false); + ContextHostResolver::SetDnsClientEnabled(false); return; } @@ -427,29 +424,7 @@ base::Bind(&base::FuzzedDataProvider::ConsumeIntegralInRange<int32_t>, base::Unretained(data_provider_))); dns_client->SetConfig(config); - HostResolverManager::SetDnsClientForTesting(std::move(dns_client)); -} - -} // namespace - -std::unique_ptr<ContextHostResolver> CreateFuzzedContextHostResolver( - const HostResolver::ManagerOptions& options, - NetLog* net_log, - base::FuzzedDataProvider* data_provider, - bool enable_caching) { - // FuzzedHostResolverManager only handles fuzzing DnsClient when enabled - // through SetDnsClientEnabled(). - bool enable_dns_client = options.dns_client_enabled; - HostResolver::ManagerOptions filtered_options(options); - filtered_options.dns_client_enabled = false; - - auto manager = std::make_unique<FuzzedHostResolverManager>( - filtered_options, net_log, data_provider); - manager->SetDnsClientEnabled(enable_dns_client); - - return std::make_unique<ContextHostResolver>( - std::move(manager), - enable_caching ? HostCache::CreateDefaultCache() : nullptr); + SetDnsClientForTesting(std::move(dns_client)); } } // namespace net
diff --git a/net/dns/fuzzed_context_host_resolver.h b/net/dns/fuzzed_context_host_resolver.h new file mode 100644 index 0000000..4fe68d1c --- /dev/null +++ b/net/dns/fuzzed_context_host_resolver.h
@@ -0,0 +1,67 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_DNS_FUZZED_CONTEXT_HOST_RESOLVER_H_ +#define NET_DNS_FUZZED_CONTEXT_HOST_RESOLVER_H_ + +#include <stdint.h> + +#include <memory> + +#include "base/macros.h" +#include "net/dns/context_host_resolver.h" +#include "net/dns/host_resolver.h" +#include "net/socket/fuzzed_socket_factory.h" + +namespace base { +class FuzzedDataProvider; +} + +namespace net { + +class NetLog; + +// HostResolver that uses a fuzzer to determine what results to return. It +// inherits from ContextHostResolver, unlike MockHostResolver, so more closely +// matches real behavior. +// +// By default uses a mocked out system resolver, though can be configured to +// use the built-in async resolver (Built in DNS stub resolver) with a fuzzed +// set of UDP/TCP sockets. +// +// To make behavior most deterministic, does not use the WorkerPool to run its +// simulated platform host resolver calls, instead runs them on the thread it is +// created on. +// +// Note that it does not attempt to sort the resulting AddressList when using +// the mock system resolver path. +// +// The async DNS client can make system calls in AddressSorterPosix, but other +// methods that make system calls are stubbed out. +class FuzzedContextHostResolver : public ContextHostResolver { + public: + FuzzedContextHostResolver(const ManagerOptions& options, + NetLog* net_log, + base::FuzzedDataProvider* data_provider, + bool enable_caching); + ~FuzzedContextHostResolver() override; + + // Enable / disable the async resolver. When enabled, installs a + // DnsClient with fuzzed UDP and TCP sockets. + void SetDnsClientEnabled(bool enabled) override; + + private: + base::FuzzedDataProvider* const data_provider_; + + // Used for UDP and TCP sockets if the async resolver is enabled. + FuzzedSocketFactory socket_factory_; + + NetLog* const net_log_; + + DISALLOW_COPY_AND_ASSIGN(FuzzedContextHostResolver); +}; + +} // namespace net + +#endif // NET_DNS_FUZZED_CONTEXT_HOST_RESOLVER_H_
diff --git a/net/dns/fuzzed_host_resolver_util.h b/net/dns/fuzzed_host_resolver_util.h deleted file mode 100644 index 5f6fbb1..0000000 --- a/net/dns/fuzzed_host_resolver_util.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_DNS_FUZZED_HOST_RESOLVER_UTIL_H_ -#define NET_DNS_FUZZED_HOST_RESOLVER_UTIL_H_ - -#include <memory> - -#include "net/dns/host_resolver.h" - -namespace base { -class FuzzedDataProvider; -} - -namespace net { - -class ContextHostResolver; -class NetLog; - -// Creates a ContextHostResolver that uses a fuzzer to determine what results to -// return. It inherits from ContextHostResolver, unlike MockHostResolver, so -// more closely matches real behavior. -// -// By default uses a mocked out system resolver, though can be configured (using -// SetDnsClientEnabled() on the underlying manager) to use the built-in async -// resolver (Built in DNS stub resolver) with a fuzzed set of UDP/TCP sockets. -// -// To make behavior most deterministic, does not use the WorkerPool to run its -// simulated platform host resolver calls, instead runs them on the thread it is -// created on. -// -// Note that it does not attempt to sort the resulting AddressList when using -// the mock system resolver path. -// -// The async DNS client can make system calls in AddressSorterPosix, but other -// methods that make system calls are stubbed out. -std::unique_ptr<ContextHostResolver> CreateFuzzedContextHostResolver( - const HostResolver::ManagerOptions& options, - NetLog* net_log, - base::FuzzedDataProvider* data_provider, - bool enable_caching); - -} // namespace net - -#endif // NET_DNS_FUZZED_HOST_RESOLVER_UTIL_H_
diff --git a/net/dns/host_resolver.cc b/net/dns/host_resolver.cc index edac29d..74857ba 100644 --- a/net/dns/host_resolver.cc +++ b/net/dns/host_resolver.cc
@@ -50,6 +50,8 @@ return nullptr; } +void HostResolver::SetDnsClientEnabled(bool enabled) {} + HostCache* HostResolver::GetHostCache() { return nullptr; } @@ -66,6 +68,12 @@ return false; } +void HostResolver::SetDnsConfigOverrides(const DnsConfigOverrides& overrides) { + // Should be overridden in any HostResolver implementation where this method + // may be called. + NOTREACHED(); +} + void HostResolver::SetRequestContext(URLRequestContext* request_context) { // Should be overridden in any HostResolver implementation where this method // may be called.
diff --git a/net/dns/host_resolver.h b/net/dns/host_resolver.h index e77e4b4..25e0490c 100644 --- a/net/dns/host_resolver.h +++ b/net/dns/host_resolver.h
@@ -20,7 +20,6 @@ #include "net/base/host_port_pair.h" #include "net/base/request_priority.h" #include "net/dns/dns_config.h" -#include "net/dns/dns_config_overrides.h" #include "net/dns/host_cache.h" #include "net/dns/host_resolver_source.h" #include "net/dns/public/dns_query_type.h" @@ -130,15 +129,6 @@ // system resolver. No effect when the system resolver is not used. // |kDefaultRetryAttempts| for the resolver to choose a default value. size_t max_system_retry_attempts = kDefaultRetryAttempts; - - // Initial setting for whether the built-in asynchronous DnsClient is - // enabled or disabled. See HostResolverManager::SetDnsClientEnabled() for - // details. - bool dns_client_enabled = false; - - // Initial configuration overrides for the built-in asynchronous DnsClient. - // See HostResolverManager::SetDnsConfigOverrides() for details. - DnsConfigOverrides dns_config_overrides; }; // Factory class. Useful for classes that need to inject and override resolver @@ -268,6 +258,9 @@ const HostPortPair& host, DnsQueryType query_type); + // Enable or disable the built-in asynchronous DnsClient. + virtual void SetDnsClientEnabled(bool enabled); + // Returns the HostResolverCache |this| uses, or NULL if there isn't one. // Used primarily to clear the cache and for getting debug information. virtual HostCache* GetHostCache(); @@ -293,6 +286,10 @@ virtual void SetNoIPv6OnWifi(bool no_ipv6_on_wifi); virtual bool GetNoIPv6OnWifi(); + // Sets overriding configuration that will replace or add to configuration + // read from the system for DnsClient resolution. + virtual void SetDnsConfigOverrides(const DnsConfigOverrides& overrides); + // Set the associated URLRequestContext, generally expected to be called by // URLRequestContextBuilder on passing ownership of |this| to a context. May // only be called once.
diff --git a/net/dns/host_resolver_manager.cc b/net/dns/host_resolver_manager.cc index 5d92642..9610355 100644 --- a/net/dns/host_resolver_manager.cc +++ b/net/dns/host_resolver_manager.cc
@@ -2315,7 +2315,6 @@ proc_params_(nullptr, options.max_system_retry_attempts), net_log_(net_log), received_dns_config_(false), - dns_config_overrides_(options.dns_config_overrides), num_dns_failures_(0), assume_ipv6_failure_on_wifi_(false), use_local_ipv6_(false), @@ -2377,6 +2376,27 @@ NetworkChangeNotifier::RemoveDNSObserver(this); } +void HostResolverManager::SetDnsClient(std::unique_ptr<DnsClient> dns_client) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + // DnsClient and config must be updated before aborting DnsTasks, since doing + // so may start new jobs. + dns_client_ = std::move(dns_client); + if (dns_client_ && !dns_client_->GetConfig() && + num_dns_failures_ < kMaximumDnsFailures) { + dns_client_->SetConfig(GetBaseDnsConfig(false)); + num_dns_failures_ = 0; + } + + AbortDnsTasks(ERR_NETWORK_CHANGED, false /* fallback_only */); + DnsConfig dns_config; + if (!HaveDnsConfig()) + // UpdateModeForHistogram() needs to know the DnsConfig when + // !HaveDnsConfig() + dns_config = GetBaseDnsConfig(false); + UpdateModeForHistogram(dns_config); +} + std::unique_ptr<HostResolverManager::CancellableRequest> HostResolverManager::CreateRequest( const HostPortPair& host, @@ -2424,13 +2444,10 @@ #if defined(ENABLE_BUILT_IN_DNS) if (enabled && !dns_client_) { SetDnsClient(DnsClient::CreateClient(net_log_)); - return; - } -#endif - - if (!enabled && dns_client_) { + } else if (!enabled && dns_client_) { SetDnsClient(nullptr); } +#endif } std::unique_ptr<base::Value> HostResolverManager::GetDnsConfigAsValue() const { @@ -2526,14 +2543,6 @@ UpdateDNSConfig(true); } -void HostResolverManager::SetDnsClientForTesting( - std::unique_ptr<DnsClient> dns_client) { - // Use SetDnsClientEnabled(false) to disable. - DCHECK(dns_client); - - SetDnsClient(std::move(dns_client)); -} - void HostResolverManager::SetTaskRunnerForTesting( scoped_refptr<base::TaskRunner> task_runner) { proc_task_runner_ = std::move(task_runner); @@ -3039,28 +3048,6 @@ dispatcher_->SetLimits(limits); } -void HostResolverManager::SetDnsClient(std::unique_ptr<DnsClient> dns_client) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - // DnsClient and config must be updated before aborting DnsTasks, since doing - // so may start new jobs. - dns_client_ = std::move(dns_client); - if (dns_client_ && !dns_client_->GetConfig() && - num_dns_failures_ < kMaximumDnsFailures) { - dns_client_->SetConfig(GetBaseDnsConfig(false)); - num_dns_failures_ = 0; - } - - AbortDnsTasks(ERR_NETWORK_CHANGED, false /* fallback_only */); - DnsConfig dns_config; - if (!HaveDnsConfig()) { - // UpdateModeForHistogram() needs to know the DnsConfig when - // !HaveDnsConfig() - dns_config = GetBaseDnsConfig(false); - } - UpdateModeForHistogram(dns_config); -} - void HostResolverManager::AbortDnsTasks(int error, bool fallback_only) { // Aborting jobs potentially modifies |jobs_| and may even delete some jobs. // Create safe closures of all current jobs.
diff --git a/net/dns/host_resolver_manager.h b/net/dns/host_resolver_manager.h index ad48f3a3..68f9bbc 100644 --- a/net/dns/host_resolver_manager.h +++ b/net/dns/host_resolver_manager.h
@@ -115,6 +115,12 @@ // be called. ~HostResolverManager() override; + // Set the DnsClient to be used for resolution. In case of failure, the + // HostResolverProc from ProcTaskParams will be queried. If the DnsClient is + // not pre-configured with a valid DnsConfig, a new config is fetched from + // NetworkChangeNotifier. + void SetDnsClient(std::unique_ptr<DnsClient> dns_client); + // If |host_cache| is non-null, its HostCache::Invalidator must have already // been added (via AddHostCacheInvalidator()). std::unique_ptr<CancellableRequest> CreateRequest( @@ -125,24 +131,13 @@ HostCache* host_cache); std::unique_ptr<MdnsListener> CreateMdnsListener(const HostPortPair& host, DnsQueryType query_type); - - // Enables or disables the built-in asynchronous DnsClient. If enabled, by - // default (when no |ResolveHostParameters::source| is specified), the - // DnsClient will be used for resolves and, in case of failure, resolution - // will fallback to the system resolver (HostResolverProc from - // ProcTaskParams). If the DnsClient is not pre-configured with a valid - // DnsConfig, a new config is fetched from NetworkChangeNotifier. - // - // Setting to |true| has no effect if |ENABLE_BUILT_IN_DNS| not defined. - virtual void SetDnsClientEnabled(bool enabled); + void SetDnsClientEnabled(bool enabled); std::unique_ptr<base::Value> GetDnsConfigAsValue() const; void SetNoIPv6OnWifi(bool no_ipv6_on_wifi); bool GetNoIPv6OnWifi(); - // Sets overriding configuration that will replace or add to configuration - // read from the system for DnsClient resolution. void SetDnsConfigOverrides(const DnsConfigOverrides& overrides); // Support for invalidating HostCaches on changes to network or DNS @@ -180,10 +175,6 @@ void SetBaseDnsConfigForTesting(const DnsConfig& base_config); - // Similar to SetDnsClientEnabled(true) except allows setting |dns_client| - // as the instance to be used. - void SetDnsClientForTesting(std::unique_ptr<DnsClient> dns_client); - // Allows the tests to catch slots leaking out of the dispatcher. One // HostResolverManager::Job could occupy multiple PrioritizedDispatcher job // slots. @@ -340,8 +331,6 @@ // requests. Might start new jobs. void AbortAllInProgressJobs(); - void SetDnsClient(std::unique_ptr<DnsClient> dns_client); - // Aborts all in progress DnsTasks. In-progress jobs will fall back to // ProcTasks if able and otherwise abort with |error|. Might start new jobs, // if any jobs were taking up two dispatcher slots.
diff --git a/net/dns/host_resolver_manager_fuzzer.cc b/net/dns/host_resolver_manager_fuzzer.cc index ca19d4f..8d8b0ce7 100644 --- a/net/dns/host_resolver_manager_fuzzer.cc +++ b/net/dns/host_resolver_manager_fuzzer.cc
@@ -17,8 +17,7 @@ #include "net/base/address_list.h" #include "net/base/net_errors.h" #include "net/base/request_priority.h" -#include "net/dns/context_host_resolver.h" -#include "net/dns/fuzzed_host_resolver_util.h" +#include "net/dns/fuzzed_context_host_resolver.h" #include "net/dns/host_resolver.h" #include "net/log/net_log_with_source.h" #include "net/log/test_net_log.h" @@ -205,11 +204,10 @@ net::HostResolver::ManagerOptions options; options.max_concurrent_resolves = data_provider.ConsumeIntegralInRange(1, 8); - options.dns_client_enabled = data_provider.ConsumeBool(); bool enable_caching = data_provider.ConsumeBool(); - std::unique_ptr<net::ContextHostResolver> host_resolver = - net::CreateFuzzedContextHostResolver(options, &net_log, &data_provider, - enable_caching); + net::FuzzedContextHostResolver host_resolver( + options, &net_log, &data_provider, enable_caching); + host_resolver.SetDnsClientEnabled(data_provider.ConsumeBool()); std::vector<std::unique_ptr<DnsRequest>> dns_requests; bool done = false; @@ -220,14 +218,14 @@ done = true; break; case 1: - DnsRequest::CreateRequest(host_resolver.get(), &data_provider, + DnsRequest::CreateRequest(&host_resolver, &data_provider, &dns_requests); break; case 2: DnsRequest::WaitForRequestComplete(&data_provider, &dns_requests); break; case 3: - DnsRequest::CancelRequest(host_resolver.get(), &data_provider, + DnsRequest::CancelRequest(&host_resolver, &data_provider, &dns_requests); break; }
diff --git a/net/dns/host_resolver_manager_unittest.cc b/net/dns/host_resolver_manager_unittest.cc index d912f85e..e74e5b46 100644 --- a/net/dns/host_resolver_manager_unittest.cc +++ b/net/dns/host_resolver_manager_unittest.cc
@@ -3385,7 +3385,7 @@ auto dns_client = std::make_unique<MockDnsClient>(DnsConfig(), std::move(rules)); dns_client_ = dns_client.get(); - resolver_->SetDnsClientForTesting(std::move(dns_client)); + resolver_->SetDnsClient(std::move(dns_client)); if (!config.Equals(DnsConfig())) ChangeDnsConfig(config); } @@ -3788,7 +3788,7 @@ // Simulate the case when the preference or policy has disabled the DNS client // causing AbortDnsTasks. - resolver_->SetDnsClientEnabled(false); + resolver_->SetDnsClient(nullptr); // All requests should fallback to proc resolver. EXPECT_THAT(response0.result_error(), IsError(ERR_NAME_NOT_RESOLVED)); @@ -3821,7 +3821,7 @@ // Simulate the case when the preference or policy has disabled the DNS client // causing AbortDnsTasks. - resolver_->SetDnsClientEnabled(false); + resolver_->SetDnsClient(nullptr); // No fallback expected. All requests should fail. EXPECT_THAT(response0.result_error(), IsError(ERR_NETWORK_CHANGED)); @@ -4240,7 +4240,7 @@ proc_->AddRuleForAllFamilies(std::string(), std::string()); // Try without DnsClient. - resolver_->SetDnsClientEnabled(false); + resolver_->SetDnsClient(nullptr); ResolveHostResponseHelper system_response(resolver_->CreateRequest( HostPortPair("localhost", 80), NetLogWithSource(), base::nullopt, request_context_.get(), host_cache_.get())); @@ -4922,7 +4922,7 @@ // Clear DnsClient. The two in-progress jobs should fall back to a ProcTask, // and the next one should be started with a ProcTask. - resolver_->SetDnsClientEnabled(false); + resolver_->SetDnsClient(std::unique_ptr<DnsClient>()); // All three in-progress requests should now be running a ProcTask. EXPECT_EQ(3u, num_running_dispatcher_jobs()); @@ -5758,7 +5758,7 @@ } // Test system resolver is detected. - resolver_->SetDnsClientEnabled(false); + resolver_->SetDnsClient(nullptr); ChangeDnsConfig(CreateValidDnsConfig()); EXPECT_EQ(resolver_->mode_for_histogram_, HostResolverManager::MODE_FOR_HISTOGRAM_SYSTEM);
diff --git a/net/dns/mapped_host_resolver.cc b/net/dns/mapped_host_resolver.cc index 53fba6d..04667430 100644 --- a/net/dns/mapped_host_resolver.cc +++ b/net/dns/mapped_host_resolver.cc
@@ -4,7 +4,6 @@ #include "net/dns/mapped_host_resolver.h" -#include <string> #include <utility> #include "base/no_destructor.h" @@ -71,6 +70,10 @@ return impl_->CreateRequest(rewritten, source_net_log, optional_parameters); } +void MappedHostResolver::SetDnsClientEnabled(bool enabled) { + impl_->SetDnsClientEnabled(enabled); +} + HostCache* MappedHostResolver::GetHostCache() { return impl_->GetHostCache(); } @@ -94,6 +97,11 @@ return impl_->GetNoIPv6OnWifi(); } +void MappedHostResolver::SetDnsConfigOverrides( + const DnsConfigOverrides& overrides) { + impl_->SetDnsConfigOverrides(overrides); +} + void MappedHostResolver::SetRequestContext(URLRequestContext* request_context) { impl_->SetRequestContext(request_context); }
diff --git a/net/dns/mapped_host_resolver.h b/net/dns/mapped_host_resolver.h index 7f46b49..8d619b1 100644 --- a/net/dns/mapped_host_resolver.h +++ b/net/dns/mapped_host_resolver.h
@@ -53,6 +53,7 @@ const NetLogWithSource& net_log, const base::Optional<ResolveHostParameters>& optional_parameters) override; + void SetDnsClientEnabled(bool enabled) override; HostCache* GetHostCache() override; bool HasCached(base::StringPiece hostname, HostCache::Entry::Source* source_out, @@ -61,6 +62,7 @@ std::unique_ptr<base::Value> GetDnsConfigAsValue() const override; void SetNoIPv6OnWifi(bool no_ipv6_on_wifi) override; bool GetNoIPv6OnWifi() override; + void SetDnsConfigOverrides(const DnsConfigOverrides& overrides) override; void SetRequestContext(URLRequestContext* request_context) override; const std::vector<DnsConfig::DnsOverHttpsServerConfig>* GetDnsOverHttpsServersForTesting() const override;
diff --git a/net/dns/mock_host_resolver.h b/net/dns/mock_host_resolver.h index c653bcf89..9fc59cd 100644 --- a/net/dns/mock_host_resolver.h +++ b/net/dns/mock_host_resolver.h
@@ -125,6 +125,7 @@ HostCache::Entry::Source* source_out, HostCache::EntryStaleness* stale_out, bool* secure_out) const override; + void SetDnsConfigOverrides(const DnsConfigOverrides& overrides) override {} void SetRequestContext(URLRequestContext* request_context) override {} // Preloads the cache with what would currently be the result of a request
diff --git a/net/http/http_auth_controller_unittest.cc b/net/http/http_auth_controller_unittest.cc index b2c9036..39b9c78 100644 --- a/net/http/http_auth_controller_unittest.cc +++ b/net/http/http_auth_controller_unittest.cc
@@ -36,12 +36,8 @@ }; scoped_refptr<HttpResponseHeaders> HeadersFromString(const char* string) { - std::string raw_string(string); - std::string headers_string = HttpUtil::AssembleRawHeaders( - raw_string.c_str(), raw_string.length()); - scoped_refptr<HttpResponseHeaders> headers( - new HttpResponseHeaders(headers_string)); - return headers; + return base::MakeRefCounted<HttpResponseHeaders>( + HttpUtil::AssembleRawHeaders(string)); } // Runs an HttpAuthController with a single round mock auth handler
diff --git a/net/http/http_auth_unittest.cc b/net/http/http_auth_unittest.cc index c4a0c32..39e32e5d 100644 --- a/net/http/http_auth_unittest.cc +++ b/net/http/http_auth_unittest.cc
@@ -49,8 +49,8 @@ scoped_refptr<HttpResponseHeaders> HeadersFromResponseText( const std::string& response) { - return scoped_refptr<HttpResponseHeaders>(new HttpResponseHeaders( - HttpUtil::AssembleRawHeaders(response.c_str(), response.length()))); + return base::MakeRefCounted<HttpResponseHeaders>( + HttpUtil::AssembleRawHeaders(response)); } HttpAuth::AuthorizationResult HandleChallengeResponse(
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index c429671..720abed 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc
@@ -555,10 +555,8 @@ // Verifies the response headers (|response|) match a partial content // response for the range starting at |start| and ending at |end|. void Verify206Response(const std::string& response, int start, int end) { - std::string raw_headers( - HttpUtil::AssembleRawHeaders(response.data(), response.size())); - scoped_refptr<HttpResponseHeaders> headers( - new HttpResponseHeaders(raw_headers)); + auto headers = base::MakeRefCounted<HttpResponseHeaders>( + HttpUtil::AssembleRawHeaders(response)); ASSERT_EQ(206, headers->response_code()); @@ -580,13 +578,11 @@ ASSERT_TRUE( cache->CreateBackendEntry(kRangeGET_TransactionOK.url, &entry, nullptr)); - raw_headers = - HttpUtil::AssembleRawHeaders(raw_headers.data(), raw_headers.size()); - HttpResponseInfo response; response.response_time = base::Time::Now(); response.request_time = base::Time::Now(); - response.headers = new HttpResponseHeaders(raw_headers); + response.headers = base::MakeRefCounted<HttpResponseHeaders>( + HttpUtil::AssembleRawHeaders(raw_headers)); // Set the last argument for this to be an incomplete request. EXPECT_TRUE(MockHttpCache::WriteResponseInfo(entry, &response, true, true)); @@ -7736,11 +7732,10 @@ std::string raw_headers(kRangeGET_TransactionOK.status); raw_headers.append("\n"); raw_headers.append(kRangeGET_TransactionOK.response_headers); - raw_headers = - HttpUtil::AssembleRawHeaders(raw_headers.data(), raw_headers.size()); HttpResponseInfo response; - response.headers = new HttpResponseHeaders(raw_headers); + response.headers = base::MakeRefCounted<HttpResponseHeaders>( + HttpUtil::AssembleRawHeaders(raw_headers)); EXPECT_TRUE(MockHttpCache::WriteResponseInfo(entry, &response, true, false)); scoped_refptr<IOBuffer> buf(base::MakeRefCounted<IOBuffer>(500)); @@ -7784,11 +7779,10 @@ std::string raw_headers(kRangeGET_TransactionOK.status); raw_headers.append("\n"); raw_headers.append(kRangeGET_TransactionOK.response_headers); - raw_headers = - HttpUtil::AssembleRawHeaders(raw_headers.data(), raw_headers.size()); HttpResponseInfo response; - response.headers = new HttpResponseHeaders(raw_headers); + response.headers = base::MakeRefCounted<HttpResponseHeaders>( + HttpUtil::AssembleRawHeaders(raw_headers)); EXPECT_TRUE(MockHttpCache::WriteResponseInfo(entry, &response, true, false)); scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(500); @@ -7826,11 +7820,10 @@ std::string raw_headers(kRangeGET_TransactionOK.status); raw_headers.append("\n"); raw_headers.append("Content-Length: 80\n"); - raw_headers = - HttpUtil::AssembleRawHeaders(raw_headers.data(), raw_headers.size()); HttpResponseInfo response; - response.headers = new HttpResponseHeaders(raw_headers); + response.headers = base::MakeRefCounted<HttpResponseHeaders>( + HttpUtil::AssembleRawHeaders(raw_headers)); EXPECT_TRUE(MockHttpCache::WriteResponseInfo(entry, &response, true, false)); scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(500); @@ -8459,10 +8452,9 @@ ASSERT_TRUE( cache.CreateBackendEntry("http://www.google.com", &entry, nullptr)); - std::string headers("HTTP/1.1 200 OK"); - headers = HttpUtil::AssembleRawHeaders(headers.data(), headers.size()); HttpResponseInfo response; - response.headers = new HttpResponseHeaders(headers); + response.headers = base::MakeRefCounted<HttpResponseHeaders>( + HttpUtil::AssembleRawHeaders("HTTP/1.1 200 OK")); // Set the last argument for this to be an incomplete request. EXPECT_TRUE(MockHttpCache::WriteResponseInfo(entry, &response, true, true));
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index 1c32ed9e..8ef12ea5 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc
@@ -134,6 +134,7 @@ quic_race_cert_verification(false), quic_estimate_initial_rtt(false), quic_headers_include_h2_stream_dependency(false), + quic_initial_rtt_for_handshake_milliseconds(0), http_09_on_non_default_ports_enabled(false), disable_idle_sockets_close_on_memory_pressure(false) { quic_supported_versions.push_back(quic::QUIC_VERSION_43); @@ -234,7 +235,8 @@ params.quic_headers_include_h2_stream_dependency, params.quic_connection_options, params.quic_client_connection_options, - params.quic_enable_socket_recv_optimization), + params.quic_enable_socket_recv_optimization, + params.quic_initial_rtt_for_handshake_milliseconds), spdy_session_pool_(context.host_resolver, context.ssl_config_service, context.http_server_properties, @@ -384,6 +386,8 @@ dict->SetBoolean("estimate_initial_rtt", params_.quic_estimate_initial_rtt); dict->SetBoolean("server_push_cancellation", params_.enable_server_push_cancellation); + dict->SetInteger("initial_rtt_for_handshake_milliseconds", + params_.quic_initial_rtt_for_handshake_milliseconds); return std::move(dict); }
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index 5852772..ead9752 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h
@@ -231,6 +231,10 @@ // If true, client headers will include HTTP/2 stream dependency info // derived from the request priority. bool quic_headers_include_h2_stream_dependency; + // The initial rtt that will be used in crypto handshake if no cached + // smoothed rtt is present. + int quic_initial_rtt_for_handshake_milliseconds; + // If non-empty, QUIC will only be spoken to hosts in this list. base::flat_set<std::string> quic_host_whitelist;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index d2d72e5..3aefbfc 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc
@@ -96,6 +96,7 @@ #include "net/spdy/spdy_session.h" #include "net/spdy/spdy_session_pool.h" #include "net/spdy/spdy_test_util_common.h" +#include "net/ssl/client_cert_identity_test_util.h" #include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_config_service.h" #include "net/ssl/ssl_info.h" @@ -734,6 +735,17 @@ return true; } +bool CheckBasicSecureServerAuth( + const base::Optional<AuthChallengeInfo>& auth_challenge) { + if (!auth_challenge) + return false; + EXPECT_FALSE(auth_challenge->is_proxy); + EXPECT_EQ("https://www.example.org", auth_challenge->challenger.Serialize()); + EXPECT_EQ("MyRealm1", auth_challenge->realm); + EXPECT_EQ(kBasicAuthScheme, auth_challenge->scheme); + return true; +} + bool CheckBasicProxyAuth( const base::Optional<AuthChallengeInfo>& auth_challenge) { if (!auth_challenge) @@ -19960,4 +19972,488 @@ session->CloseAllConnections(); } +// Test the proxy and origin server each requesting both TLS client certificates +// and HTTP auth. This is a regression test for https://crbug.com/946406. +TEST_F(HttpNetworkTransactionTest, AuthEverything) { + // Note these hosts must match the CheckBasic*Auth() functions. + session_deps_.proxy_resolution_service = ProxyResolutionService::CreateFixed( + "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS); + + auto cert_request_info_proxy = base::MakeRefCounted<SSLCertRequestInfo>(); + cert_request_info_proxy->host_and_port = HostPortPair("myproxy", 70); + + std::unique_ptr<FakeClientCertIdentity> identity_proxy = + FakeClientCertIdentity::CreateFromCertAndKeyFiles( + GetTestCertsDirectory(), "client_1.pem", "client_1.pk8"); + ASSERT_TRUE(identity_proxy); + + auto cert_request_info_origin = base::MakeRefCounted<SSLCertRequestInfo>(); + cert_request_info_origin->host_and_port = + HostPortPair("www.example.org", 443); + + std::unique_ptr<FakeClientCertIdentity> identity_origin = + FakeClientCertIdentity::CreateFromCertAndKeyFiles( + GetTestCertsDirectory(), "client_2.pem", "client_2.pk8"); + ASSERT_TRUE(identity_origin); + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.example.org/"); + request.traffic_annotation = + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + + // First, the client connects to the proxy, which requests a client + // certificate. + SSLSocketDataProvider ssl_proxy1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED); + ssl_proxy1.cert_request_info = cert_request_info_proxy.get(); + ssl_proxy1.expected_send_client_cert = false; + StaticSocketDataProvider data1; + session_deps_.socket_factory->AddSocketDataProvider(&data1); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1); + + // The client responds with a certificate on a new connection. The handshake + // succeeds. + SSLSocketDataProvider ssl_proxy2(ASYNC, OK); + ssl_proxy2.expected_send_client_cert = true; + ssl_proxy2.expected_client_cert = identity_proxy->certificate(); + // The client attempts an HTTP CONNECT, but the proxy requests basic auth. + std::vector<MockWrite> mock_writes2; + std::vector<MockRead> mock_reads2; + mock_writes2.emplace_back( + "CONNECT www.example.org:443 HTTP/1.1\r\n" + "Host: www.example.org:443\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"); + mock_reads2.emplace_back( + "HTTP/1.1 407 Proxy Authentication Required\r\n" + "Content-Length: 0\r\n" + "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n"); + // The client retries with credentials. + mock_writes2.emplace_back( + "CONNECT www.example.org:443 HTTP/1.1\r\n" + "Host: www.example.org:443\r\n" + "Proxy-Connection: keep-alive\r\n" + // Authenticate as proxyuser:proxypass. + "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n"); + mock_reads2.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n"); + // The origin requests client certificates. + SSLSocketDataProvider ssl_origin2(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED); + ssl_origin2.cert_request_info = cert_request_info_origin.get(); + StaticSocketDataProvider data2(mock_reads2, mock_writes2); + session_deps_.socket_factory->AddSocketDataProvider(&data2); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin2); + + // The client responds to the origin client certificate request on a new + // connection. + SSLSocketDataProvider ssl_proxy3(ASYNC, OK); + ssl_proxy3.expected_send_client_cert = true; + ssl_proxy3.expected_client_cert = identity_proxy->certificate(); + std::vector<MockWrite> mock_writes3; + std::vector<MockRead> mock_reads3; + mock_writes3.emplace_back( + "CONNECT www.example.org:443 HTTP/1.1\r\n" + "Host: www.example.org:443\r\n" + "Proxy-Connection: keep-alive\r\n" + // Authenticate as proxyuser:proxypass. + "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n"); + mock_reads3.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n"); + SSLSocketDataProvider ssl_origin3(ASYNC, OK); + ssl_origin3.expected_send_client_cert = true; + ssl_origin3.expected_client_cert = identity_origin->certificate(); + // The client sends the origin HTTP request, which results in another HTTP + // auth request. + mock_writes3.emplace_back( + "GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n\r\n"); + mock_reads3.emplace_back( + "HTTP/1.1 401 Unauthorized\r\n" + "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n" + "Content-Length: 0\r\n\r\n"); + // The client retries with credentials, and the request finally succeeds. + mock_writes3.emplace_back( + "GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n" + // Authenticate as user:pass. + "Authorization: Basic dXNlcjpwYXNz\r\n\r\n"); + mock_reads3.emplace_back( + "HTTP/1.1 200 OK\r\n" + "Content-Length: 0\r\n\r\n"); + StaticSocketDataProvider data3(mock_reads3, mock_writes3); + session_deps_.socket_factory->AddSocketDataProvider(&data3); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy3); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin3); + + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + + // Start the request. + TestCompletionCallback callback; + auto trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + int rv = callback.GetResult( + trans->Start(&request, callback.callback(), NetLogWithSource())); + + // Handle the proxy client certificate challenge. + ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED)); + SSLCertRequestInfo* cert_request_info = + trans->GetResponseInfo()->cert_request_info.get(); + ASSERT_TRUE(cert_request_info); + EXPECT_TRUE(cert_request_info->is_proxy); + EXPECT_EQ(cert_request_info->host_and_port, + cert_request_info_proxy->host_and_port); + rv = callback.GetResult(trans->RestartWithCertificate( + identity_proxy->certificate(), identity_proxy->ssl_private_key(), + callback.callback())); + + // Handle the proxy HTTP auth challenge. + ASSERT_THAT(rv, IsOk()); + EXPECT_EQ(407, trans->GetResponseInfo()->headers->response_code()); + EXPECT_TRUE( + CheckBasicSecureProxyAuth(trans->GetResponseInfo()->auth_challenge)); + rv = callback.GetResult(trans->RestartWithAuth( + AuthCredentials(ASCIIToUTF16("proxyuser"), ASCIIToUTF16("proxypass")), + callback.callback())); + + // Handle the origin client certificate challenge. + ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED)); + cert_request_info = trans->GetResponseInfo()->cert_request_info.get(); + ASSERT_TRUE(cert_request_info); + EXPECT_FALSE(cert_request_info->is_proxy); + EXPECT_EQ(cert_request_info->host_and_port, + cert_request_info_origin->host_and_port); + rv = callback.GetResult(trans->RestartWithCertificate( + identity_origin->certificate(), identity_origin->ssl_private_key(), + callback.callback())); + + // Handle the origin HTTP auth challenge. + ASSERT_THAT(rv, IsOk()); + EXPECT_EQ(401, trans->GetResponseInfo()->headers->response_code()); + EXPECT_TRUE( + CheckBasicSecureServerAuth(trans->GetResponseInfo()->auth_challenge)); + rv = callback.GetResult(trans->RestartWithAuth( + AuthCredentials(ASCIIToUTF16("user"), ASCIIToUTF16("pass")), + callback.callback())); + + // The request completes. + ASSERT_THAT(rv, IsOk()); + EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code()); +} + +// Test the proxy and origin server each requesting both TLS client certificates +// and HTTP auth and each HTTP auth closing the connection. This is a regression +// test for https://crbug.com/946406. +TEST_F(HttpNetworkTransactionTest, AuthEverythingWithConnectClose) { + // Note these hosts must match the CheckBasic*Auth() functions. + session_deps_.proxy_resolution_service = ProxyResolutionService::CreateFixed( + "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS); + + auto cert_request_info_proxy = base::MakeRefCounted<SSLCertRequestInfo>(); + cert_request_info_proxy->host_and_port = HostPortPair("myproxy", 70); + + std::unique_ptr<FakeClientCertIdentity> identity_proxy = + FakeClientCertIdentity::CreateFromCertAndKeyFiles( + GetTestCertsDirectory(), "client_1.pem", "client_1.pk8"); + ASSERT_TRUE(identity_proxy); + + auto cert_request_info_origin = base::MakeRefCounted<SSLCertRequestInfo>(); + cert_request_info_origin->host_and_port = + HostPortPair("www.example.org", 443); + + std::unique_ptr<FakeClientCertIdentity> identity_origin = + FakeClientCertIdentity::CreateFromCertAndKeyFiles( + GetTestCertsDirectory(), "client_2.pem", "client_2.pk8"); + ASSERT_TRUE(identity_origin); + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.example.org/"); + request.traffic_annotation = + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + + // First, the client connects to the proxy, which requests a client + // certificate. + SSLSocketDataProvider ssl_proxy1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED); + ssl_proxy1.cert_request_info = cert_request_info_proxy.get(); + ssl_proxy1.expected_send_client_cert = false; + StaticSocketDataProvider data1; + session_deps_.socket_factory->AddSocketDataProvider(&data1); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1); + + // The client responds with a certificate on a new connection. The handshake + // succeeds. + SSLSocketDataProvider ssl_proxy2(ASYNC, OK); + ssl_proxy2.expected_send_client_cert = true; + ssl_proxy2.expected_client_cert = identity_proxy->certificate(); + // The client attempts an HTTP CONNECT, but the proxy requests basic auth. + std::vector<MockWrite> mock_writes2; + std::vector<MockRead> mock_reads2; + mock_writes2.emplace_back( + "CONNECT www.example.org:443 HTTP/1.1\r\n" + "Host: www.example.org:443\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"); + mock_reads2.emplace_back( + "HTTP/1.1 407 Proxy Authentication Required\r\n" + "Content-Length: 0\r\n" + "Proxy-Connection: close\r\n" + "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n"); + StaticSocketDataProvider data2(mock_reads2, mock_writes2); + session_deps_.socket_factory->AddSocketDataProvider(&data2); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2); + + // The client retries with credentials on a new connection. + SSLSocketDataProvider ssl_proxy3(ASYNC, OK); + ssl_proxy3.expected_send_client_cert = true; + ssl_proxy3.expected_client_cert = identity_proxy->certificate(); + std::vector<MockWrite> mock_writes3; + std::vector<MockRead> mock_reads3; + mock_writes3.emplace_back( + "CONNECT www.example.org:443 HTTP/1.1\r\n" + "Host: www.example.org:443\r\n" + "Proxy-Connection: keep-alive\r\n" + // Authenticate as proxyuser:proxypass. + "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n"); + mock_reads3.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n"); + // The origin requests client certificates. + SSLSocketDataProvider ssl_origin3(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED); + ssl_origin3.cert_request_info = cert_request_info_origin.get(); + StaticSocketDataProvider data3(mock_reads3, mock_writes3); + session_deps_.socket_factory->AddSocketDataProvider(&data3); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy3); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin3); + + // The client responds to the origin client certificate request on a new + // connection. + SSLSocketDataProvider ssl_proxy4(ASYNC, OK); + ssl_proxy4.expected_send_client_cert = true; + ssl_proxy4.expected_client_cert = identity_proxy->certificate(); + std::vector<MockWrite> mock_writes4; + std::vector<MockRead> mock_reads4; + mock_writes4.emplace_back( + "CONNECT www.example.org:443 HTTP/1.1\r\n" + "Host: www.example.org:443\r\n" + "Proxy-Connection: keep-alive\r\n" + // Authenticate as proxyuser:proxypass. + "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n"); + mock_reads4.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n"); + SSLSocketDataProvider ssl_origin4(ASYNC, OK); + ssl_origin4.expected_send_client_cert = true; + ssl_origin4.expected_client_cert = identity_origin->certificate(); + // The client sends the origin HTTP request, which results in another HTTP + // auth request and closed connection. + mock_writes4.emplace_back( + "GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n\r\n"); + mock_reads4.emplace_back( + "HTTP/1.1 401 Unauthorized\r\n" + "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n" + "Connection: close\r\n" + "Content-Length: 0\r\n\r\n"); + StaticSocketDataProvider data4(mock_reads4, mock_writes4); + session_deps_.socket_factory->AddSocketDataProvider(&data4); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy4); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin4); + + // The client retries with credentials on a new connection, and the request + // finally succeeds. + SSLSocketDataProvider ssl_proxy5(ASYNC, OK); + ssl_proxy5.expected_send_client_cert = true; + ssl_proxy5.expected_client_cert = identity_proxy->certificate(); + std::vector<MockWrite> mock_writes5; + std::vector<MockRead> mock_reads5; + mock_writes5.emplace_back( + "CONNECT www.example.org:443 HTTP/1.1\r\n" + "Host: www.example.org:443\r\n" + "Proxy-Connection: keep-alive\r\n" + // Authenticate as proxyuser:proxypass. + "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n"); + mock_reads5.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n"); + SSLSocketDataProvider ssl_origin5(ASYNC, OK); + ssl_origin5.expected_send_client_cert = true; + ssl_origin5.expected_client_cert = identity_origin->certificate(); + mock_writes5.emplace_back( + "GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n" + // Authenticate as user:pass. + "Authorization: Basic dXNlcjpwYXNz\r\n\r\n"); + mock_reads5.emplace_back( + "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-Length: 0\r\n\r\n"); + StaticSocketDataProvider data5(mock_reads5, mock_writes5); + session_deps_.socket_factory->AddSocketDataProvider(&data5); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy5); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin5); + + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + + // Start the request. + TestCompletionCallback callback; + auto trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + int rv = callback.GetResult( + trans->Start(&request, callback.callback(), NetLogWithSource())); + + // Handle the proxy client certificate challenge. + ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED)); + SSLCertRequestInfo* cert_request_info = + trans->GetResponseInfo()->cert_request_info.get(); + ASSERT_TRUE(cert_request_info); + EXPECT_TRUE(cert_request_info->is_proxy); + EXPECT_EQ(cert_request_info->host_and_port, + cert_request_info_proxy->host_and_port); + rv = callback.GetResult(trans->RestartWithCertificate( + identity_proxy->certificate(), identity_proxy->ssl_private_key(), + callback.callback())); + + // Handle the proxy HTTP auth challenge. + ASSERT_THAT(rv, IsOk()); + EXPECT_EQ(407, trans->GetResponseInfo()->headers->response_code()); + EXPECT_TRUE( + CheckBasicSecureProxyAuth(trans->GetResponseInfo()->auth_challenge)); + rv = callback.GetResult(trans->RestartWithAuth( + AuthCredentials(ASCIIToUTF16("proxyuser"), ASCIIToUTF16("proxypass")), + callback.callback())); + + // Handle the origin client certificate challenge. + ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED)); + cert_request_info = trans->GetResponseInfo()->cert_request_info.get(); + ASSERT_TRUE(cert_request_info); + EXPECT_FALSE(cert_request_info->is_proxy); + EXPECT_EQ(cert_request_info->host_and_port, + cert_request_info_origin->host_and_port); + rv = callback.GetResult(trans->RestartWithCertificate( + identity_origin->certificate(), identity_origin->ssl_private_key(), + callback.callback())); + + // Handle the origin HTTP auth challenge. + ASSERT_THAT(rv, IsOk()); + EXPECT_EQ(401, trans->GetResponseInfo()->headers->response_code()); + EXPECT_TRUE( + CheckBasicSecureServerAuth(trans->GetResponseInfo()->auth_challenge)); + rv = callback.GetResult(trans->RestartWithAuth( + AuthCredentials(ASCIIToUTF16("user"), ASCIIToUTF16("pass")), + callback.callback())); + + // The request completes. + ASSERT_THAT(rv, IsOk()); + EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code()); +} + +// Test the proxy requesting HTTP auth and the server requesting TLS client +// certificates. This is a regression test for https://crbug.com/946406. +TEST_F(HttpNetworkTransactionTest, ProxyHTTPAndServerTLSAuth) { + // Note these hosts must match the CheckBasic*Auth() functions. + session_deps_.proxy_resolution_service = ProxyResolutionService::CreateFixed( + "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS); + + auto cert_request_info_origin = base::MakeRefCounted<SSLCertRequestInfo>(); + cert_request_info_origin->host_and_port = + HostPortPair("www.example.org", 443); + + std::unique_ptr<FakeClientCertIdentity> identity_origin = + FakeClientCertIdentity::CreateFromCertAndKeyFiles( + GetTestCertsDirectory(), "client_2.pem", "client_2.pk8"); + ASSERT_TRUE(identity_origin); + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.example.org/"); + request.traffic_annotation = + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + + // The client connects to the proxy. The handshake succeeds. + SSLSocketDataProvider ssl_proxy1(ASYNC, OK); + // The client attempts an HTTP CONNECT, but the proxy requests basic auth. + std::vector<MockWrite> mock_writes1; + std::vector<MockRead> mock_reads1; + mock_writes1.emplace_back( + "CONNECT www.example.org:443 HTTP/1.1\r\n" + "Host: www.example.org:443\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"); + mock_reads1.emplace_back( + "HTTP/1.1 407 Proxy Authentication Required\r\n" + "Content-Length: 0\r\n" + "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n"); + // The client retries with credentials, and the request finally succeeds. + mock_writes1.emplace_back( + "CONNECT www.example.org:443 HTTP/1.1\r\n" + "Host: www.example.org:443\r\n" + "Proxy-Connection: keep-alive\r\n" + // Authenticate as proxyuser:proxypass. + "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n"); + mock_reads1.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n"); + // The origin requests client certificates. + SSLSocketDataProvider ssl_origin1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED); + ssl_origin1.cert_request_info = cert_request_info_origin.get(); + StaticSocketDataProvider data1(mock_reads1, mock_writes1); + session_deps_.socket_factory->AddSocketDataProvider(&data1); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin1); + + // The client responds to the origin client certificate request on a new + // connection. + SSLSocketDataProvider ssl_proxy2(ASYNC, OK); + std::vector<MockWrite> mock_writes2; + std::vector<MockRead> mock_reads2; + mock_writes2.emplace_back( + "CONNECT www.example.org:443 HTTP/1.1\r\n" + "Host: www.example.org:443\r\n" + "Proxy-Connection: keep-alive\r\n" + // Authenticate as proxyuser:proxypass. + "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n"); + mock_reads2.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n"); + SSLSocketDataProvider ssl_origin2(ASYNC, OK); + ssl_origin2.expected_send_client_cert = true; + ssl_origin2.expected_client_cert = identity_origin->certificate(); + // The client sends the origin HTTP request, which succeeds. + mock_writes2.emplace_back( + "GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n\r\n"); + mock_reads2.emplace_back( + "HTTP/1.1 200 OK\r\n" + "Content-Length: 0\r\n\r\n"); + StaticSocketDataProvider data2(mock_reads2, mock_writes2); + session_deps_.socket_factory->AddSocketDataProvider(&data2); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin2); + + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + + // Start the request. + TestCompletionCallback callback; + auto trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + int rv = callback.GetResult( + trans->Start(&request, callback.callback(), NetLogWithSource())); + + // Handle the proxy HTTP auth challenge. + ASSERT_THAT(rv, IsOk()); + EXPECT_EQ(407, trans->GetResponseInfo()->headers->response_code()); + EXPECT_TRUE( + CheckBasicSecureProxyAuth(trans->GetResponseInfo()->auth_challenge)); + rv = callback.GetResult(trans->RestartWithAuth( + AuthCredentials(ASCIIToUTF16("proxyuser"), ASCIIToUTF16("proxypass")), + callback.callback())); + + // Handle the origin client certificate challenge. + ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED)); + SSLCertRequestInfo* cert_request_info = + trans->GetResponseInfo()->cert_request_info.get(); + ASSERT_TRUE(cert_request_info); + EXPECT_FALSE(cert_request_info->is_proxy); + EXPECT_EQ(cert_request_info->host_and_port, + cert_request_info_origin->host_and_port); + rv = callback.GetResult(trans->RestartWithCertificate( + identity_origin->certificate(), identity_origin->ssl_private_key(), + callback.callback())); + + // The request completes. + ASSERT_THAT(rv, IsOk()); + EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code()); +} + } // namespace net
diff --git a/net/http/http_response_headers.cc b/net/http/http_response_headers.cc index 3910885..fe875ba 100644 --- a/net/http/http_response_headers.cc +++ b/net/http/http_response_headers.cc
@@ -194,7 +194,7 @@ } return base::MakeRefCounted<HttpResponseHeaders>( - HttpUtil::AssembleRawHeaders(headers.data(), headers.size())); + HttpUtil::AssembleRawHeaders(headers)); } void HttpResponseHeaders::Persist(base::Pickle* pickle,
diff --git a/net/http/http_util.cc b/net/http/http_util.cc index 4bc7de8..6c04368 100644 --- a/net/http/http_util.cc +++ b/net/http/http_util.cc
@@ -704,22 +704,22 @@ return end; // Not found. } -std::string HttpUtil::AssembleRawHeaders(const char* input_begin, - size_t input_len) { +std::string HttpUtil::AssembleRawHeaders(base::StringPiece input) { std::string raw_headers; - raw_headers.reserve(input_len); + raw_headers.reserve(input.size()); - const char* input_end = input_begin + input_len; + const char* input_end = input.data() + input.size(); // Skip any leading slop, since the consumers of this output // (HttpResponseHeaders) don't deal with it. - size_t status_begin_offset = LocateStartOfStatusLine(input_begin, input_len); + size_t status_begin_offset = + LocateStartOfStatusLine(input.data(), input.size()); if (status_begin_offset != std::string::npos) - input_begin += status_begin_offset; + input.remove_prefix(status_begin_offset); // Copy the status line. - const char* status_line_end = FindStatusLineEnd(input_begin, input_end); - raw_headers.append(input_begin, status_line_end); + const char* status_line_end = FindStatusLineEnd(input.data(), input_end); + raw_headers.append(input.data(), status_line_end); // After the status line, every subsequent line is a header line segment. // Should a segment start with LWS, it is a continuation of the previous
diff --git a/net/http/http_util.h b/net/http/http_util.h index c45b41a..1880257 100644 --- a/net/http/http_util.h +++ b/net/http/http_util.h
@@ -171,15 +171,14 @@ // Assemble "raw headers" in the format required by HttpResponseHeaders. // This involves normalizing line terminators, converting [CR]LF to \0 and // handling HTTP line continuations (i.e., lines starting with LWS are - // continuations of the previous line). |buf_len| indicates the position of - // the end-of-headers marker as defined by LocateEndOfHeaders. - // If a \0 appears within the headers themselves, it will be stripped. This - // is a workaround to avoid later code from incorrectly interpreting it as - // a line terminator. + // continuations of the previous line). |buf| should end at the + // end-of-headers marker as defined by LocateEndOfHeaders. If a \0 appears + // within the headers themselves, it will be stripped. This is a workaround to + // avoid later code from incorrectly interpreting it as a line terminator. // // TODO(crbug.com/671799): Should remove or internalize this to // HttpResponseHeaders. - static std::string AssembleRawHeaders(const char* buf, size_t buf_len); + static std::string AssembleRawHeaders(base::StringPiece buf); // Converts assembled "raw headers" back to the HTTP response format. That is // convert each \0 occurence to CRLF. This is used by DevTools.
diff --git a/net/http/http_util_unittest.cc b/net/http/http_util_unittest.cc index 0ddf34d..55672d5 100644 --- a/net/http/http_util_unittest.cc +++ b/net/http/http_util_unittest.cc
@@ -691,7 +691,7 @@ for (size_t i = 0; i < base::size(tests); ++i) { std::string input = tests[i].input; std::replace(input.begin(), input.end(), '|', '\0'); - std::string raw = HttpUtil::AssembleRawHeaders(input.data(), input.size()); + std::string raw = HttpUtil::AssembleRawHeaders(input); std::replace(raw.begin(), raw.end(), '\0', '|'); EXPECT_EQ(tests[i].expected_result, raw); }
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index 92197d7c..1290c5b 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc
@@ -1048,7 +1048,8 @@ bool headers_include_h2_stream_dependency, const quic::QuicTagVector& connection_options, const quic::QuicTagVector& client_connection_options, - bool enable_socket_recv_optimization) + bool enable_socket_recv_optimization, + int initial_rtt_for_handshake_milliseconds) : require_confirmation_(true), net_log_(net_log), host_resolver_(host_resolver), @@ -1118,6 +1119,8 @@ task_runner_(nullptr), ssl_config_service_(ssl_config_service), enable_socket_recv_optimization_(enable_socket_recv_optimization), + initial_rtt_for_handshake_milliseconds_( + initial_rtt_for_handshake_milliseconds), weak_factory_(this) { DCHECK(transport_security_state_); DCHECK(http_server_properties_); @@ -1924,6 +1927,13 @@ return; } + if (initial_rtt_for_handshake_milliseconds_ > 0) { + SetInitialRttEstimate(base::TimeDelta::FromMilliseconds( + initial_rtt_for_handshake_milliseconds_), + INITIAL_RTT_DEFAULT, config); + return; + } + SetInitialRttEstimate(base::TimeDelta(), INITIAL_RTT_DEFAULT, config); }
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h index aa59738..b7a988f6 100644 --- a/net/quic/quic_stream_factory.h +++ b/net/quic/quic_stream_factory.h
@@ -275,7 +275,8 @@ bool headers_include_h2_stream_dependency, const quic::QuicTagVector& connection_options, const quic::QuicTagVector& client_connection_options, - bool enable_socket_recv_optimization); + bool enable_socket_recv_optimization, + int initial_rtt_for_handshake_milliseconds); ~QuicStreamFactory() override; // Returns true if there is an existing session for |session_key| or if the @@ -628,6 +629,9 @@ // experimental optimization enabled for receiving data. bool enable_socket_recv_optimization_; + // The initial rtt for handshake. + const int initial_rtt_for_handshake_milliseconds_; + base::WeakPtrFactory<QuicStreamFactory> weak_factory_; DISALLOW_COPY_AND_ASSIGN(QuicStreamFactory);
diff --git a/net/quic/quic_stream_factory_fuzzer.cc b/net/quic/quic_stream_factory_fuzzer.cc index f9f7039..b200e1a5 100644 --- a/net/quic/quic_stream_factory_fuzzer.cc +++ b/net/quic/quic_stream_factory_fuzzer.cc
@@ -12,8 +12,7 @@ #include "net/cert/do_nothing_ct_verifier.h" #include "net/cert/mock_cert_verifier.h" #include "net/cert/x509_certificate.h" -#include "net/dns/context_host_resolver.h" -#include "net/dns/fuzzed_host_resolver_util.h" +#include "net/dns/fuzzed_context_host_resolver.h" #include "net/http/http_server_properties_impl.h" #include "net/http/transport_security_state.h" #include "net/quic/mock_crypto_client_stream_factory.h" @@ -84,10 +83,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { base::FuzzedDataProvider data_provider(data, size); - std::unique_ptr<ContextHostResolver> host_resolver = - CreateFuzzedContextHostResolver(HostResolver::ManagerOptions(), nullptr, - &data_provider, - true /* enable_caching */); + FuzzedContextHostResolver host_resolver(HostResolver::ManagerOptions(), + nullptr, &data_provider, + true /* enable_caching */); FuzzedSocketFactory socket_factory(&data_provider); // Initialize this on each loop since some options mutate this. @@ -130,9 +128,8 @@ std::unique_ptr<QuicStreamFactory> factory = std::make_unique<QuicStreamFactory>( - env->net_log.net_log(), host_resolver.get(), - env->ssl_config_service.get(), &socket_factory, - &http_server_properties, env->cert_verifier.get(), + env->net_log.net_log(), &host_resolver, env->ssl_config_service.get(), + &socket_factory, &http_server_properties, env->cert_verifier.get(), &env->ct_policy_enforcer, &env->transport_security_state, env->cert_transparency_verifier.get(), nullptr, &env->crypto_client_stream_factory, &env->random_generator, @@ -154,7 +151,7 @@ go_away_on_path_degrading, race_cert_verification, estimate_initial_rtt, headers_include_h2_stream_dependency, env->connection_options, env->client_connection_options, - enable_socket_recv_optimization); + enable_socket_recv_optimization, 0); QuicStreamRequest request(factory.get()); TestCompletionCallback callback;
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index b402896..52f94f4 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc
@@ -31,6 +31,7 @@ #include "net/quic/mock_crypto_client_stream_factory.h" #include "net/quic/mock_quic_data.h" #include "net/quic/properties_based_quic_server_info.h" +#include "net/quic/quic_chromium_alarm_factory.h" #include "net/quic/quic_http_stream.h" #include "net/quic/quic_http_utils.h" #include "net/quic/quic_server_info.h" @@ -296,7 +297,8 @@ test_params_.quic_headers_include_h2_stream_dependency, test_params_.quic_connection_options, test_params_.quic_client_connection_options, - test_params_.quic_enable_socket_recv_optimization)); + test_params_.quic_enable_socket_recv_optimization, + test_params_.quic_initial_rtt_for_handshake_milliseconds)); } void InitializeConnectionMigrationV2Test( @@ -10193,6 +10195,69 @@ EXPECT_TRUE(quic_data.AllWriteDataConsumed()); } +TEST_P(QuicStreamFactoryTest, ConfigInitialRttForHandshake) { + int kInitialRtt = 400; + test_params_.quic_initial_rtt_for_handshake_milliseconds = kInitialRtt; + crypto_client_stream_factory_.set_handshake_mode( + MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); + Initialize(); + factory_->set_require_confirmation(true); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + // Using a testing task runner so that we can control time. + auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); + + QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); + QuicStreamFactoryPeer::SetAlarmFactory( + factory_.get(), + std::make_unique<QuicChromiumAlarmFactory>(task_runner.get(), &clock_)); + + MockQuicData socket_data; + socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); + socket_data.AddWrite(ASYNC, client_maker_.MakeDummyCHLOPacket(1)); + socket_data.AddWrite(ASYNC, client_maker_.MakeDummyCHLOPacket(2)); + client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); + socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket(3, 0)); + socket_data.AddSocketDataToFactory(socket_factory_.get()); + + QuicStreamRequest request(factory_.get()); + EXPECT_EQ(ERR_IO_PENDING, + request.Request( + host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, + SocketTag(), + /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, + failed_on_default_network_callback_, callback_.callback())); + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(HasActiveSession(host_port_pair_)); + EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); + + // The pending task is scheduled for handshake timeout retransmission, + // which is 2 * 400ms for v99 and 1.5 * 400ms for others. + int handshake_timeout = + version_ == quic::QUIC_VERSION_99 ? 2 * kInitialRtt : 1.5 * kInitialRtt; + EXPECT_EQ(base::TimeDelta::FromMilliseconds(handshake_timeout), + task_runner->NextPendingTaskDelay()); + + // The alarm factory dependes on |clock_|, so clock is advanced to trigger + // retransmission alarm. + clock_.AdvanceTime( + quic::QuicTime::Delta::FromMilliseconds(handshake_timeout)); + task_runner->FastForwardBy( + base::TimeDelta::FromMilliseconds(handshake_timeout)); + + crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( + quic::QuicSession::HANDSHAKE_CONFIRMED); + + EXPECT_THAT(callback_.WaitForResult(), IsOk()); + + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); + EXPECT_EQ(400000u, session->config()->GetInitialRoundTripTimeUsToSend()); + EXPECT_TRUE(socket_data.AllReadDataConsumed()); + EXPECT_TRUE(socket_data.AllWriteDataConsumed()); +} + // Test that QuicStreamRequests with similar and different tags results in // reused and unique QUIC streams using appropriately tagged sockets. TEST_P(QuicStreamFactoryTest, Tag) {
diff --git a/net/server/http_server_unittest.cc b/net/server/http_server_unittest.cc index cc7d954c..ce54cb54 100644 --- a/net/server/http_server_unittest.cc +++ b/net/server/http_server_unittest.cc
@@ -157,8 +157,9 @@ // Return true if response has data equal to or more than content length. int64_t body_size = static_cast<int64_t>(response.size()) - end_of_headers; DCHECK_LE(0, body_size); - scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders( - HttpUtil::AssembleRawHeaders(response.data(), end_of_headers))); + auto headers = + base::MakeRefCounted<HttpResponseHeaders>(HttpUtil::AssembleRawHeaders( + base::StringPiece(response.data(), end_of_headers))); return body_size >= headers->GetContentLength(); }
diff --git a/net/socket/client_socket_handle.cc b/net/socket/client_socket_handle.cc index ca509f3..2e52f8c 100644 --- a/net/socket/client_socket_handle.cc +++ b/net/socket/client_socket_handle.cc
@@ -86,48 +86,6 @@ ResetErrorState(); } -void ClientSocketHandle::ResetInternal(bool cancel, bool cancel_connect_job) { - DCHECK(cancel || !cancel_connect_job); - - // Was Init called? - if (!group_id_.destination().IsEmpty()) { - // If so, we must have a pool. - CHECK(pool_); - if (is_initialized()) { - if (socket_) { - socket_->NetLog().EndEvent(NetLogEventType::SOCKET_IN_USE); - // Release the socket back to the ClientSocketPool so it can be - // deleted or reused. - pool_->ReleaseSocket(group_id_, std::move(socket_), group_generation_); - } else { - // If the handle has been initialized, we should still have a - // socket. - NOTREACHED(); - } - } else if (cancel) { - // If we did not get initialized yet and we have a socket - // request pending, cancel it. - pool_->CancelRequest(group_id_, this, cancel_connect_job); - } - } - is_initialized_ = false; - socket_.reset(); - group_id_ = ClientSocketPool::GroupId(); - reuse_type_ = ClientSocketHandle::UNUSED; - callback_.Reset(); - if (higher_pool_) - RemoveHigherLayeredPool(higher_pool_); - pool_ = nullptr; - idle_time_ = base::TimeDelta(); - connect_timing_ = LoadTimingInfo::ConnectTiming(); - group_generation_ = -1; -} - -void ClientSocketHandle::ResetErrorState() { - is_ssl_error_ = false; - ssl_cert_request_info_ = nullptr; -} - LoadState ClientSocketHandle::GetLoadState() const { CHECK(!is_initialized()); CHECK(!group_id_.destination().IsEmpty()); @@ -209,6 +167,10 @@ ssl_cert_request_info_ = connect_job->GetCertRequestInfo(); } +std::unique_ptr<StreamSocket> ClientSocketHandle::PassSocket() { + return std::move(socket_); +} + void ClientSocketHandle::OnIOComplete(int result) { TRACE_EVENT0(NetTracingCategory(), "ClientSocketHandle::OnIOComplete"); CompletionOnceCallback callback = std::move(callback_); @@ -217,10 +179,6 @@ std::move(callback).Run(result); } -std::unique_ptr<StreamSocket> ClientSocketHandle::PassSocket() { - return std::move(socket_); -} - void ClientSocketHandle::HandleInitCompletion(int result) { CHECK_NE(ERR_IO_PENDING, result); if (result != OK) { @@ -245,4 +203,46 @@ requesting_source_.ToEventParametersCallback()); } +void ClientSocketHandle::ResetInternal(bool cancel, bool cancel_connect_job) { + DCHECK(cancel || !cancel_connect_job); + + // Was Init called? + if (!group_id_.destination().IsEmpty()) { + // If so, we must have a pool. + CHECK(pool_); + if (is_initialized()) { + if (socket_) { + socket_->NetLog().EndEvent(NetLogEventType::SOCKET_IN_USE); + // Release the socket back to the ClientSocketPool so it can be + // deleted or reused. + pool_->ReleaseSocket(group_id_, std::move(socket_), group_generation_); + } else { + // If the handle has been initialized, we should still have a + // socket. + NOTREACHED(); + } + } else if (cancel) { + // If we did not get initialized yet and we have a socket + // request pending, cancel it. + pool_->CancelRequest(group_id_, this, cancel_connect_job); + } + } + is_initialized_ = false; + socket_.reset(); + group_id_ = ClientSocketPool::GroupId(); + reuse_type_ = ClientSocketHandle::UNUSED; + callback_.Reset(); + if (higher_pool_) + RemoveHigherLayeredPool(higher_pool_); + pool_ = nullptr; + idle_time_ = base::TimeDelta(); + connect_timing_ = LoadTimingInfo::ConnectTiming(); + group_generation_ = -1; +} + +void ClientSocketHandle::ResetErrorState() { + is_ssl_error_ = false; + ssl_cert_request_info_ = nullptr; +} + } // namespace net
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc index 3dcf31f2..007d237 100644 --- a/net/socket/socket_test_util.cc +++ b/net/socket/socket_test_util.cc
@@ -800,6 +800,18 @@ } EXPECT_EQ(next_ssl_data->expected_ssl_version_min, ssl_config.version_min); EXPECT_EQ(next_ssl_data->expected_ssl_version_max, ssl_config.version_max); + if (next_ssl_data->expected_send_client_cert) { + EXPECT_EQ(*next_ssl_data->expected_send_client_cert, + ssl_config.send_client_cert); + DCHECK_EQ(*next_ssl_data->expected_send_client_cert, + next_ssl_data->expected_client_cert != nullptr); + if (next_ssl_data->expected_client_cert) { + EXPECT_TRUE(next_ssl_data->expected_client_cert->EqualsIncludingChain( + ssl_config.client_cert.get())); + } else { + EXPECT_FALSE(ssl_config.client_cert); + } + } return std::unique_ptr<SSLClientSocket>(new MockSSLClientSocket( std::move(stream_socket), host_and_port, ssl_config, next_ssl_data)); }
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h index c96f2f94..f0b305a 100644 --- a/net/socket/socket_test_util.h +++ b/net/socket/socket_test_util.h
@@ -56,6 +56,7 @@ struct CommonConnectJobParams; class NetLog; struct NetworkTrafficAnnotationTag; +class X509Certificate; const NetworkChangeNotifier::NetworkHandle kDefaultNetworkForTests = 1; const NetworkChangeNotifier::NetworkHandle kNewNetworkForTests = 2; @@ -479,6 +480,8 @@ uint16_t expected_ssl_version_min; uint16_t expected_ssl_version_max; + base::Optional<bool> expected_send_client_cert; + scoped_refptr<X509Certificate> expected_client_cert; bool is_connect_data_consumed = false; bool is_confirm_data_consumed = false;
diff --git a/net/socket/transport_client_socket_pool.cc b/net/socket/transport_client_socket_pool.cc index 3665058..95b9427 100644 --- a/net/socket/transport_client_socket_pool.cc +++ b/net/socket/transport_client_socket_pool.cc
@@ -69,7 +69,7 @@ ~ConnectJobFactoryImpl() override = default; - // ClientSocketPoolBase::ConnectJobFactory methods. + // TransportClientSocketPool::ConnectJobFactory methods. std::unique_ptr<ConnectJob> NewConnectJob( ClientSocketPool::GroupId group_id, scoped_refptr<ClientSocketPool::SocketParams> socket_params, @@ -1217,38 +1217,39 @@ // // TODO(mmenke) this logic resembles the case where the job is assigned to a // request below. Look into merging the logic. - int64_t generation; - int pending_result; - std::unique_ptr<Request> request = - group->FindAndRemoveBoundRequestForConnectJob(job, &generation, - &pending_result); - if (request) { + base::Optional<Group::BoundRequest> bound_request = + group->FindAndRemoveBoundRequestForConnectJob(job); + if (bound_request) { --connecting_socket_count_; // If the ConnectJob is from a previous generation, and the socket pools // weren't flushed with an error, add the request back to the group, and // kick off another request. - if (generation != group->generation() && pending_result == OK) { - group->InsertUnboundRequest(std::move(request)); + if (bound_request->generation != group->generation() && + bound_request->pending_error == OK) { + group->InsertUnboundRequest(std::move(bound_request->request)); OnAvailableSocketSlot(group->group_id(), group); CheckForStalledSocketGroups(); return; } bool handed_out_socket = false; - if (pending_result != OK) { - result = pending_result; + if (bound_request->pending_error != OK) { + result = bound_request->pending_error; } else { + bound_request->request->handle()->SetAdditionalErrorState(job); if (socket) { handed_out_socket = true; HandOutSocket(std::move(socket), ClientSocketHandle::UNUSED, - connect_timing, request->handle(), base::TimeDelta(), - group, request->net_log()); + connect_timing, bound_request->request->handle(), + base::TimeDelta(), group, + bound_request->request->net_log()); } } - request->net_log().EndEventWithNetErrorCode(NetLogEventType::SOCKET_POOL, - result); - InvokeUserCallbackLater(request->handle(), request->release_callback(), - result, request->socket_tag()); + bound_request->request->net_log().EndEventWithNetErrorCode( + NetLogEventType::SOCKET_POOL, result); + InvokeUserCallbackLater(bound_request->request->handle(), + bound_request->request->release_callback(), result, + bound_request->request->socket_tag()); if (!handed_out_socket) { OnAvailableSocketSlot(group->group_id(), group); CheckForStalledSocketGroups(); @@ -1261,7 +1262,7 @@ if (result == OK) { DCHECK(socket.get()); - request = group->PopNextUnboundRequest(); + std::unique_ptr<Request> request = group->PopNextUnboundRequest(); RemoveConnectJob(job, group); if (request) { LogBoundConnectJobToRequest(job_log.source(), *request); @@ -1393,9 +1394,9 @@ TransportClientSocketPool::Group::Group( const GroupId& group_id, - TransportClientSocketPool* client_socket_pool_base_helper) + TransportClientSocketPool* client_socket_pool) : group_id_(group_id), - client_socket_pool_base_helper_(client_socket_pool_base_helper), + client_socket_pool_(client_socket_pool), never_assigned_job_count_(0), unbound_requests_(NUM_PRIORITIES), active_socket_count_(0), @@ -1412,7 +1413,7 @@ void TransportClientSocketPool::Group::OnConnectJobComplete(int result, ConnectJob* job) { DCHECK_NE(ERR_IO_PENDING, result); - client_socket_pool_base_helper_->OnConnectJobComplete(this, result, job); + client_socket_pool_->OnConnectJobComplete(this, result, job); } void TransportClientSocketPool::Group::OnNeedsProxyAuth( @@ -1420,9 +1421,9 @@ HttpAuthController* auth_controller, base::OnceClosure restart_with_auth_callback, ConnectJob* job) { - client_socket_pool_base_helper_->OnNeedsProxyAuth( - this, response, auth_controller, std::move(restart_with_auth_callback), - job); + client_socket_pool_->OnNeedsProxyAuth(this, response, auth_controller, + std::move(restart_with_auth_callback), + job); } void TransportClientSocketPool::Group::StartBackupJobTimer( @@ -1433,10 +1434,10 @@ // Unretained here is okay because |backup_job_timer_| is // automatically cancelled when it's destroyed. - backup_job_timer_.Start( - FROM_HERE, client_socket_pool_base_helper_->ConnectRetryInterval(), - base::BindOnce(&Group::OnBackupJobTimerFired, base::Unretained(this), - group_id)); + backup_job_timer_.Start(FROM_HERE, + client_socket_pool_->ConnectRetryInterval(), + base::BindOnce(&Group::OnBackupJobTimerFired, + base::Unretained(this), group_id)); } bool TransportClientSocketPool::Group::BackupJobTimerIsRunning() const { @@ -1532,9 +1533,8 @@ // If our old job is waiting on DNS, or if we can't create any sockets // right now due to limits, just reset the timer. - if (client_socket_pool_base_helper_->ReachedMaxSocketsLimit() || - !HasAvailableSocketSlot( - client_socket_pool_base_helper_->max_sockets_per_group_) || + if (client_socket_pool_->ReachedMaxSocketsLimit() || + !HasAvailableSocketSlot(client_socket_pool_->max_sockets_per_group_) || (*jobs_.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) { StartBackupJobTimer(group_id); return; @@ -1545,7 +1545,7 @@ Request* request = unbound_requests_.FirstMax().value().get(); std::unique_ptr<ConnectJob> owned_backup_job = - client_socket_pool_base_helper_->connect_job_factory_->NewConnectJob( + client_socket_pool_->connect_job_factory_->NewConnectJob( group_id, request->socket_params(), request->proxy_annotation_tag(), request->priority(), request->socket_tag(), this); owned_backup_job->net_log().AddEvent( @@ -1554,10 +1554,10 @@ true /* backup_job */, &group_id_)); ConnectJob* backup_job = owned_backup_job.get(); AddJob(std::move(owned_backup_job), false); - client_socket_pool_base_helper_->connecting_socket_count_++; + client_socket_pool_->connecting_socket_count_++; int rv = backup_job->Connect(); if (rv != ERR_IO_PENDING) { - client_socket_pool_base_helper_->OnConnectJobComplete(this, rv, backup_job); + client_socket_pool_->OnConnectJobComplete(this, rv, backup_job); } } @@ -1766,22 +1766,18 @@ return request; } -std::unique_ptr<TransportClientSocketPool::Request> +base::Optional<TransportClientSocketPool::Group::BoundRequest> TransportClientSocketPool::Group::FindAndRemoveBoundRequestForConnectJob( - ConnectJob* connect_job, - int64_t* generation, - int* pending_error) { + ConnectJob* connect_job) { for (auto bound_pair = bound_requests_.begin(); bound_pair != bound_requests_.end(); ++bound_pair) { if (bound_pair->connect_job.get() != connect_job) continue; - std::unique_ptr<Request> request = std::move(bound_pair->request); - *generation = bound_pair->generation; - *pending_error = bound_pair->pending_error; + BoundRequest ret = std::move(*bound_pair); bound_requests_.erase(bound_pair); - return request; + return std::move(ret); } - return nullptr; + return base::nullopt; } std::unique_ptr<TransportClientSocketPool::Request>
diff --git a/net/socket/transport_client_socket_pool.h b/net/socket/transport_client_socket_pool.h index 600cfa4..52eb2a9 100644 --- a/net/socket/transport_client_socket_pool.h +++ b/net/socket/transport_client_socket_pool.h
@@ -98,7 +98,7 @@ const base::Optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag, const NetLogWithSource& net_log); - virtual ~Request(); + ~Request(); ClientSocketHandle* handle() const { return handle_; } CompletionOnceCallback release_callback() { return std::move(callback_); } @@ -333,8 +333,33 @@ public: using JobList = std::list<std::unique_ptr<ConnectJob>>; + struct BoundRequest { + BoundRequest(); + BoundRequest(std::unique_ptr<ConnectJob> connect_job, + std::unique_ptr<Request> request, + int64_t generation); + BoundRequest(BoundRequest&& other); + BoundRequest& operator=(BoundRequest&& other); + ~BoundRequest(); + + std::unique_ptr<ConnectJob> connect_job; + std::unique_ptr<Request> request; + + // Generation of |connect_job|. If it doesn't match the current + // generation, ConnectJob will be destroyed, and a new one created on + // completion. + int64_t generation; + + // It's not safe to fail a request in a |CancelAllRequestsWithError| call + // while it's waiting on user input, as the request may have raw pointers + // to objects owned by |connect_job| that it could racily write to after + // |connect_job| is destroyed. Instead, just track an error in that case, + // and fail the request once the ConnectJob completes. + int pending_error; + }; + Group(const GroupId& group_id, - TransportClientSocketPool* client_socket_pool_base_helper); + TransportClientSocketPool* client_socket_pool); ~Group() override; // ConnectJob::Delegate methods: @@ -434,15 +459,10 @@ // callback, returns nullptr. const Request* BindRequestToConnectJob(ConnectJob* connect_job); - // Finds the request, if any, bound to |connect_job|, and returns it. - // Destroys the ConnectJob bound to the request, if there was one. - // |generation| is set to the group generation that ConnectJob belongs to. - // The pending error is written to |pending_error|, if - // SetPendingErrorForAllBoundRequests() was called, or OK, otherwise. - std::unique_ptr<Request> FindAndRemoveBoundRequestForConnectJob( - ConnectJob* connect_job, - int64_t* generation, - int* pending_error); + // Finds the request, if any, bound to |connect_job|, and returns the + // BoundRequest or base::nullopt if there was none. + base::Optional<BoundRequest> FindAndRemoveBoundRequestForConnectJob( + ConnectJob* connect_job); // Finds the bound request, if any, corresponding to |client_socket_handle| // and returns it. Destroys the ConnectJob bound to the request, if there @@ -476,31 +496,6 @@ int64_t generation() const { return generation_; } private: - struct BoundRequest { - BoundRequest(); - BoundRequest(std::unique_ptr<ConnectJob> connect_job, - std::unique_ptr<Request> request, - int64_t generation); - BoundRequest(BoundRequest&& other); - BoundRequest& operator=(BoundRequest&& other); - ~BoundRequest(); - - std::unique_ptr<ConnectJob> connect_job; - std::unique_ptr<Request> request; - - // Generation of |connect_job|. If it doesn't match the current - // generation, ConnectJob will be destroyed, and a new one created on - // completion. - int64_t generation; - - // It's not safe to fail a request in a |CancelAllRequestsWithError| call - // while it's waiting on user input, as the request may have raw pointers - // to objects owned by |connect_job| that it could racily write to after - // |connect_job| is destroyed. Instead, just track an error in that case, - // and fail the request once the ConnectJob completes. - int pending_error; - }; - // Returns the iterator's unbound request after removing it from // the queue. Expects the Group to pass SanityCheck() when called. std::unique_ptr<Request> RemoveUnboundRequest( @@ -561,7 +556,7 @@ void SanityCheck() const; const GroupId group_id_; - TransportClientSocketPool* const client_socket_pool_base_helper_; + TransportClientSocketPool* const client_socket_pool_; // Total number of ConnectJobs that have never been assigned to a Request. // Since jobs use late binding to requests, which ConnectJobs have or have
diff --git a/net/test/url_request/url_request_hanging_read_job.cc b/net/test/url_request/url_request_hanging_read_job.cc index 6790f6c..2cae64e 100644 --- a/net/test/url_request/url_request_hanging_read_job.cc +++ b/net/test/url_request/url_request_hanging_read_job.cc
@@ -81,8 +81,8 @@ "Content-type: text/plain\n"); raw_headers.append( base::StringPrintf("Content-Length: %1d\n", content_length_)); - info->headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( - raw_headers.c_str(), static_cast<int>(raw_headers.length()))); + info->headers = base::MakeRefCounted<HttpResponseHeaders>( + HttpUtil::AssembleRawHeaders(raw_headers)); } void URLRequestHangingReadJob::StartAsync() {
diff --git a/net/test/url_request/url_request_mock_data_job.cc b/net/test/url_request/url_request_mock_data_job.cc index b6d5471..b1d17fd 100644 --- a/net/test/url_request/url_request_mock_data_job.cc +++ b/net/test/url_request/url_request_mock_data_job.cc
@@ -158,8 +158,8 @@ raw_headers.append(base::StringPrintf("Content-Length: %1d\n", static_cast<int>(data_.length()))); } - info->headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( - raw_headers.c_str(), static_cast<int>(raw_headers.length()))); + info->headers = base::MakeRefCounted<HttpResponseHeaders>( + HttpUtil::AssembleRawHeaders(raw_headers)); } void URLRequestMockDataJob::StartAsync() {
diff --git a/net/url_request/http_with_dns_over_https_unittest.cc b/net/url_request/http_with_dns_over_https_unittest.cc index 3afa2951..71edf18 100644 --- a/net/url_request/http_with_dns_over_https_unittest.cc +++ b/net/url_request/http_with_dns_over_https_unittest.cc
@@ -74,8 +74,7 @@ resolver_->SetRequestContext(&request_context_); resolver_->SetProcParamsForTesting( ProcTaskParams(new TestHostResolverProc(), 1)); - resolver_->GetManagerForTesting()->SetDnsClientForTesting( - std::move(dns_client)); + resolver_->SetDnsClientForTesting(std::move(dns_client)); request_context_.set_host_resolver(resolver_.get()); request_context_.Init(); }
diff --git a/net/url_request/redirect_info_unittest.cc b/net/url_request/redirect_info_unittest.cc index 30b33d6..2a4876d 100644 --- a/net/url_request/redirect_info_unittest.cc +++ b/net/url_request/redirect_info_unittest.cc
@@ -446,9 +446,8 @@ std::string response_header_text = "HTTP/1.1 302 Redirect\n" + std::string(test.response_headers); - std::string raw_headers = HttpUtil::AssembleRawHeaders( - response_header_text.c_str(), - static_cast<int>(response_header_text.length())); + std::string raw_headers = + HttpUtil::AssembleRawHeaders(response_header_text); auto response_headers = base::MakeRefCounted<HttpResponseHeaders>(raw_headers); EXPECT_EQ(302, response_headers->response_code());
diff --git a/net/url_request/url_request_ftp_fuzzer.cc b/net/url_request/url_request_ftp_fuzzer.cc index 699e060..923b8b0 100644 --- a/net/url_request/url_request_ftp_fuzzer.cc +++ b/net/url_request/url_request_ftp_fuzzer.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "net/url_request/url_request.h" + #include <stddef.h> #include <stdint.h> @@ -9,8 +11,7 @@ #include "base/run_loop.h" #include "base/test/fuzzed_data_provider.h" #include "net/base/request_priority.h" -#include "net/dns/context_host_resolver.h" -#include "net/dns/fuzzed_host_resolver_util.h" +#include "net/dns/fuzzed_context_host_resolver.h" #include "net/ftp/ftp_network_transaction.h" #include "net/ftp/ftp_transaction_factory.h" #include "net/socket/client_socket_factory.h" @@ -59,17 +60,16 @@ url_request_context.set_client_socket_factory(&fuzzed_socket_factory); // Need to fuzz the HostResolver to select between IPv4 and IPv6. - std::unique_ptr<net::ContextHostResolver> host_resolver = - net::CreateFuzzedContextHostResolver(net::HostResolver::ManagerOptions(), - nullptr, &data_provider, - true /* enable_caching */); - url_request_context.set_host_resolver(host_resolver.get()); + net::FuzzedContextHostResolver host_resolver( + net::HostResolver::ManagerOptions(), nullptr, &data_provider, + true /* enable_caching */); + url_request_context.set_host_resolver(&host_resolver); net::URLRequestJobFactoryImpl job_factory; job_factory.SetProtocolHandler( "ftp", net::FtpProtocolHandler::CreateForTesting( std::make_unique<FuzzedFtpTransactionFactory>( - host_resolver.get(), &fuzzed_socket_factory))); + &host_resolver, &fuzzed_socket_factory))); url_request_context.set_job_factory(&job_factory); url_request_context.Init();
diff --git a/net/url_request/url_request_redirect_job.cc b/net/url_request/url_request_redirect_job.cc index e53413a..028d0b6 100644 --- a/net/url_request/url_request_redirect_job.cc +++ b/net/url_request/url_request_redirect_job.cc
@@ -111,9 +111,8 @@ http_origin.c_str()); } - fake_headers_ = new HttpResponseHeaders( - HttpUtil::AssembleRawHeaders(header_string.c_str(), - header_string.length())); + fake_headers_ = base::MakeRefCounted<HttpResponseHeaders>( + HttpUtil::AssembleRawHeaders(header_string)); DCHECK(fake_headers_->IsRedirect(nullptr)); request()->net_log().AddEvent(
diff --git a/net/url_request/url_request_test_job.cc b/net/url_request/url_request_test_job.cc index e0eacca..da2b8d61 100644 --- a/net/url_request/url_request_test_job.cc +++ b/net/url_request/url_request_test_job.cc
@@ -173,9 +173,8 @@ offset_(0), async_buf_(nullptr), async_buf_size_(0), - response_headers_(new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(response_headers.c_str(), - response_headers.size()))), + response_headers_(base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(response_headers))), response_headers_length_(response_headers.size()), async_reads_(false), weak_factory_(this) {} @@ -244,8 +243,8 @@ void URLRequestTestJob::SetResponseHeaders( const std::string& response_headers) { - response_headers_ = new HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - response_headers.c_str(), response_headers.size())); + response_headers_ = base::MakeRefCounted<HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(response_headers)); response_headers_length_ = response_headers.size(); }
diff --git a/remoting/client/jni/jni_client.cc b/remoting/client/jni/jni_client.cc index 987281e..dbf3ec2 100644 --- a/remoting/client/jni/jni_client.cc +++ b/remoting/client/jni/jni_client.cc
@@ -19,6 +19,7 @@ using base::android::ConvertJavaStringToUTF8; using base::android::ConvertUTF8ToJavaString; +using base::android::JavaObjectArrayReader; using base::android::JavaParamRef; using base::android::ScopedJavaLocalRef; @@ -245,14 +246,10 @@ // Iterate over the elements in the object array and transfer the data from // the java object to a native event object. - jsize length = env->GetArrayLength(touchEventObjectArray); - DCHECK_GE(length, 0); - for (jsize i = 0; i < length; ++i) { + JavaObjectArrayReader<jobject> java_touch_events(touchEventObjectArray); + DCHECK_GE(java_touch_events.size(), 0); + for (auto java_touch_event : java_touch_events) { protocol::TouchEventPoint* touch_point = touch_event.add_touch_points(); - - ScopedJavaLocalRef<jobject> java_touch_event( - env, env->GetObjectArrayElement(touchEventObjectArray, i)); - JniTouchEventData::CopyTouchPointData(env, java_touch_event, touch_point); }
diff --git a/services/device/device_service.cc b/services/device/device_service.cc index 2745f12..934dbbc4 100644 --- a/services/device/device_service.cc +++ b/services/device/device_service.cc
@@ -50,6 +50,7 @@ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + network::NetworkConnectionTracker* network_connection_tracker, const std::string& geolocation_api_key, bool use_gms_core_location_provider, const WakeLockContextCallback& wake_lock_context_callback, @@ -61,14 +62,16 @@ custom_location_provider_callback, use_gms_core_location_provider); return std::make_unique<DeviceService>( std::move(file_task_runner), std::move(io_task_runner), - std::move(url_loader_factory), geolocation_api_key, - wake_lock_context_callback, java_nfc_delegate, std::move(request)); + std::move(url_loader_factory), network_connection_tracker, + geolocation_api_key, wake_lock_context_callback, java_nfc_delegate, + std::move(request)); } #else std::unique_ptr<DeviceService> CreateDeviceService( scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + network::NetworkConnectionTracker* network_connection_tracker, const std::string& geolocation_api_key, const CustomLocationProviderCallback& custom_location_provider_callback, service_manager::mojom::ServiceRequest request) { @@ -77,7 +80,8 @@ custom_location_provider_callback); return std::make_unique<DeviceService>( std::move(file_task_runner), std::move(io_task_runner), - std::move(url_loader_factory), geolocation_api_key, std::move(request)); + std::move(url_loader_factory), network_connection_tracker, + geolocation_api_key, std::move(request)); } #endif @@ -86,6 +90,7 @@ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + network::NetworkConnectionTracker* network_connection_tracker, const std::string& geolocation_api_key, const WakeLockContextCallback& wake_lock_context_callback, const base::android::JavaRef<jobject>& java_nfc_delegate, @@ -94,6 +99,7 @@ file_task_runner_(std::move(file_task_runner)), io_task_runner_(std::move(io_task_runner)), url_loader_factory_(std::move(url_loader_factory)), + network_connection_tracker_(network_connection_tracker), geolocation_api_key_(geolocation_api_key), wake_lock_context_callback_(wake_lock_context_callback), wake_lock_provider_(file_task_runner_, wake_lock_context_callback_), @@ -105,12 +111,14 @@ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + network::NetworkConnectionTracker* network_connection_tracker, const std::string& geolocation_api_key, service_manager::mojom::ServiceRequest request) : service_binding_(this, std::move(request)), file_task_runner_(std::move(file_task_runner)), io_task_runner_(std::move(io_task_runner)), url_loader_factory_(std::move(url_loader_factory)), + network_connection_tracker_(network_connection_tracker), geolocation_api_key_(geolocation_api_key), wake_lock_provider_(file_task_runner_, wake_lock_context_callback_) {} #endif @@ -287,7 +295,8 @@ if (!public_ip_address_geolocation_provider_) { public_ip_address_geolocation_provider_ = std::make_unique<PublicIpAddressGeolocationProvider>( - url_loader_factory_, geolocation_api_key_); + url_loader_factory_, network_connection_tracker_, + geolocation_api_key_); } public_ip_address_geolocation_provider_->Bind(std::move(request)); }
diff --git a/services/device/device_service.h b/services/device/device_service.h index 87264e70..35e7535 100644 --- a/services/device/device_service.h +++ b/services/device/device_service.h
@@ -60,6 +60,7 @@ } namespace network { +class NetworkConnectionTracker; class SharedURLLoaderFactory; } // namespace network @@ -83,6 +84,7 @@ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + network::NetworkConnectionTracker* network_connection_tracker, const std::string& geolocation_api_key, bool use_gms_core_location_provider, const WakeLockContextCallback& wake_lock_context_callback, @@ -94,6 +96,7 @@ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + network::NetworkConnectionTracker* network_connection_tracker, const std::string& geolocation_api_key, const CustomLocationProviderCallback& custom_location_provider_callback, service_manager::mojom::ServiceRequest request); @@ -106,6 +109,7 @@ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + network::NetworkConnectionTracker* network_connection_tracker, const std::string& geolocation_api_key, const WakeLockContextCallback& wake_lock_context_callback, const base::android::JavaRef<jobject>& java_nfc_delegate, @@ -115,6 +119,7 @@ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + network::NetworkConnectionTracker* network_connection_tracker, const std::string& geolocation_api_key, service_manager::mojom::ServiceRequest request); #endif @@ -179,6 +184,7 @@ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; + network::NetworkConnectionTracker* network_connection_tracker_; const std::string geolocation_api_key_; WakeLockContextCallback wake_lock_context_callback_;
diff --git a/services/device/device_service_test_base.cc b/services/device/device_service_test_base.cc index 2bc3152c..70f751b 100644 --- a/services/device/device_service_test_base.cc +++ b/services/device/device_service_test_base.cc
@@ -17,6 +17,7 @@ #include "services/device/public/cpp/geolocation/location_provider.h" #include "services/device/public/mojom/constants.mojom.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_network_connection_tracker.h" #include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/mojom/service_factory.mojom.h" @@ -37,12 +38,14 @@ #if defined(OS_ANDROID) return CreateDeviceService( file_task_runner, io_task_runner, url_loader_factory, + network::TestNetworkConnectionTracker::GetInstance(), kTestGeolocationApiKey, false, WakeLockContextCallback(), base::BindRepeating(&GetCustomLocationProviderForTest), nullptr, std::move(request)); #else return CreateDeviceService( file_task_runner, io_task_runner, url_loader_factory, + network::TestNetworkConnectionTracker::GetInstance(), kTestGeolocationApiKey, base::BindRepeating(&GetCustomLocationProviderForTest), std::move(request)); @@ -56,6 +59,8 @@ {base::MayBlock(), base::TaskPriority::BEST_EFFORT})), io_task_runner_(base::CreateSingleThreadTaskRunnerWithTraits( {base::TaskPriority::USER_VISIBLE})), + network_connection_tracker_( + network::TestNetworkConnectionTracker::CreateInstance()), connector_(test_connector_factory_.CreateConnector()) {} DeviceServiceTestBase::~DeviceServiceTestBase() = default;
diff --git a/services/device/device_service_test_base.h b/services/device/device_service_test_base.h index 9585d3d..e43b9a4 100644 --- a/services/device/device_service_test_base.h +++ b/services/device/device_service_test_base.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "base/test/scoped_task_environment.h" +#include "services/network/test/test_network_connection_tracker.h" #include "services/network/test/test_url_loader_factory.h" #include "services/service_manager/public/cpp/test/test_connector_factory.h" #include "testing/gtest/include/gtest/gtest.h" @@ -42,6 +43,8 @@ private: service_manager::TestConnectorFactory test_connector_factory_; + std::unique_ptr<network::TestNetworkConnectionTracker> + network_connection_tracker_; std::unique_ptr<service_manager::Connector> connector_; std::unique_ptr<DeviceService> service_;
diff --git a/services/device/geolocation/public_ip_address_geolocation_provider.cc b/services/device/geolocation/public_ip_address_geolocation_provider.cc index f111ac8..44fc46c3 100644 --- a/services/device/geolocation/public_ip_address_geolocation_provider.cc +++ b/services/device/geolocation/public_ip_address_geolocation_provider.cc
@@ -12,13 +12,14 @@ PublicIpAddressGeolocationProvider::PublicIpAddressGeolocationProvider( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + network::NetworkConnectionTracker* network_connection_tracker, const std::string& api_key) { // Bind sequence_checker_ to the initialization sequence. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); public_ip_address_location_notifier_ = std::make_unique<PublicIpAddressLocationNotifier>( - std::move(url_loader_factory), api_key); + std::move(url_loader_factory), network_connection_tracker, api_key); } PublicIpAddressGeolocationProvider::~PublicIpAddressGeolocationProvider() {}
diff --git a/services/device/geolocation/public_ip_address_geolocation_provider.h b/services/device/geolocation/public_ip_address_geolocation_provider.h index 06dd4fa6..687824d32 100644 --- a/services/device/geolocation/public_ip_address_geolocation_provider.h +++ b/services/device/geolocation/public_ip_address_geolocation_provider.h
@@ -16,6 +16,10 @@ #include "services/device/public/mojom/geolocation.mojom.h" #include "services/device/public/mojom/public_ip_address_geolocation_provider.mojom.h" +namespace network { +class NetworkConnectionTracker; +} + namespace device { // Implementation of PublicIpAddressGeolocationProvider Mojo interface that will @@ -32,6 +36,7 @@ // |api_key| and |url_loader_factory| for network location requests. PublicIpAddressGeolocationProvider( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + network::NetworkConnectionTracker* network_connection_tracker, const std::string& api_key); ~PublicIpAddressGeolocationProvider() override;
diff --git a/services/device/geolocation/public_ip_address_geolocator_unittest.cc b/services/device/geolocation/public_ip_address_geolocator_unittest.cc index 6f61074..0fb69356 100644 --- a/services/device/geolocation/public_ip_address_geolocator_unittest.cc +++ b/services/device/geolocation/public_ip_address_geolocator_unittest.cc
@@ -12,6 +12,7 @@ #include "mojo/public/cpp/bindings/strong_binding_set.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_network_connection_tracker.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -25,10 +26,13 @@ public: PublicIpAddressGeolocatorTest() : scoped_task_environment_( - base::test::ScopedTaskEnvironment::MainThreadType::IO) { + base::test::ScopedTaskEnvironment::MainThreadType::IO), + network_connection_tracker_( + network::TestNetworkConnectionTracker::CreateInstance()) { notifier_.reset(new PublicIpAddressLocationNotifier( base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( &test_url_loader_factory_), + network::TestNetworkConnectionTracker::GetInstance(), kTestGeolocationApiKey)); } @@ -93,6 +97,10 @@ // List of any Mojo bad-message errors raised. std::vector<std::string> bad_messages_; + // Test NetworkConnectionTracker for PublicIpAddressLocationNotifier. + std::unique_ptr<network::TestNetworkConnectionTracker> + network_connection_tracker_; + // PublicIpAddressGeolocator requires a notifier. std::unique_ptr<PublicIpAddressLocationNotifier> notifier_;
diff --git a/services/device/geolocation/public_ip_address_location_notifier.cc b/services/device/geolocation/public_ip_address_location_notifier.cc index 2e9a9d2..52701dde 100644 --- a/services/device/geolocation/public_ip_address_location_notifier.cc +++ b/services/device/geolocation/public_ip_address_location_notifier.cc
@@ -20,19 +20,21 @@ PublicIpAddressLocationNotifier::PublicIpAddressLocationNotifier( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + network::NetworkConnectionTracker* network_connection_tracker, const std::string& api_key) : network_changed_since_last_request_(true), api_key_(api_key), url_loader_factory_(url_loader_factory), + network_connection_tracker_(network_connection_tracker), network_traffic_annotation_tag_(nullptr), weak_ptr_factory_(this) { // Subscribe to notifications of changes in network configuration. - net::NetworkChangeNotifier::AddNetworkChangeObserver(this); + network_connection_tracker_->AddNetworkConnectionObserver(this); } PublicIpAddressLocationNotifier::~PublicIpAddressLocationNotifier() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); + network_connection_tracker_->RemoveNetworkConnectionObserver(this); } void PublicIpAddressLocationNotifier::QueryNextPosition( @@ -69,8 +71,8 @@ callbacks_.push_back(std::move(callback)); } -void PublicIpAddressLocationNotifier::OnNetworkChanged( - net::NetworkChangeNotifier::ConnectionType type) { +void PublicIpAddressLocationNotifier::OnConnectionChanged( + network::mojom::ConnectionType type) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Post a cancelable task to react to this network change after a reasonable
diff --git a/services/device/geolocation/public_ip_address_location_notifier.h b/services/device/geolocation/public_ip_address_location_notifier.h index c304a61..74ad605 100644 --- a/services/device/geolocation/public_ip_address_location_notifier.h +++ b/services/device/geolocation/public_ip_address_location_notifier.h
@@ -13,11 +13,11 @@ #include "base/macros.h" #include "base/optional.h" #include "base/time/time.h" -#include "net/base/network_change_notifier.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/device/geolocation/geolocation_provider.h" #include "services/device/geolocation/network_location_request.h" #include "services/device/public/mojom/geoposition.mojom.h" +#include "services/network/public/cpp/network_connection_tracker.h" namespace device { @@ -29,12 +29,13 @@ // Sequencing: // * Must be created, used, and destroyed on the same sequence. class PublicIpAddressLocationNotifier - : public net::NetworkChangeNotifier::NetworkChangeObserver { + : public network::NetworkConnectionTracker::NetworkConnectionObserver { public: // Creates a notifier that uses the specified Google |api_key| and // |url_loader_factory| for network location requests. PublicIpAddressLocationNotifier( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + network::NetworkConnectionTracker* network_connection_tracker, const std::string& api_key); ~PublicIpAddressLocationNotifier() override; @@ -58,11 +59,10 @@ // Sequence checker for all methods. SEQUENCE_CHECKER(sequence_checker_); - // NetworkChangeNotifier::NetworkChangeObserver: + // NetworkConnectionTracker::NetworkConnectionObserver: // Network change notifications tend to come in a cluster in a short time, so // this just sets a task to run ReactToNetworkChange after a short time. - void OnNetworkChanged( - net::NetworkChangeNotifier::ConnectionType type) override; + void OnConnectionChanged(network::mojom::ConnectionType type) override; // Actually react to a network change, starting a network geolocation request // if any clients are waiting. @@ -94,6 +94,10 @@ // SharedURLLoaderFactory for network geolocation requests. const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; + // Used to listen to network connection changes. + // Must outlive this object. + network::NetworkConnectionTracker* network_connection_tracker_; + // Used to make calls to the Maps geolocate API. // Empty unless a call is currently in progress. std::unique_ptr<NetworkLocationRequest> network_location_request_;
diff --git a/services/device/geolocation/public_ip_address_location_notifier_unittest.cc b/services/device/geolocation/public_ip_address_location_notifier_unittest.cc index 97297322..daa152e 100644 --- a/services/device/geolocation/public_ip_address_location_notifier_unittest.cc +++ b/services/device/geolocation/public_ip_address_location_notifier_unittest.cc
@@ -13,6 +13,7 @@ #include "services/device/public/cpp/geolocation/geoposition.h" #include "services/device/public/mojom/geoposition.mojom.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_network_connection_tracker.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -49,10 +50,12 @@ }; PublicIpAddressLocationNotifierTest() - : network_change_notifier_(net::NetworkChangeNotifier::CreateMock()), + : network_connection_tracker_( + network::TestNetworkConnectionTracker::CreateInstance()), notifier_( base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( &test_url_loader_factory_), + network::TestNetworkConnectionTracker::GetInstance(), kTestGeolocationApiKey) {} ~PublicIpAddressLocationNotifierTest() override {} @@ -122,8 +125,9 @@ base::test::ScopedTaskEnvironment scoped_task_environment_{ base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME}; - // notifier_ requires a NetworkChangeNotifier to exist. - std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_; + // Test NetworkConnectionTracker instance. + std::unique_ptr<network::TestNetworkConnectionTracker> + network_connection_tracker_; // Test URLLoaderFactory for handling requests to the geolocation API. network::TestURLLoaderFactory test_url_loader_factory_; @@ -191,8 +195,8 @@ EXPECT_FALSE(query_2.position().has_value()); // Fake a network change notification. - net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( - net::NetworkChangeNotifier::CONNECTION_UNKNOWN); + network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( + network::mojom::ConnectionType::CONNECTION_UNKNOWN); // Wait for the notifier to complete its delayed reaction. scoped_task_environment_.FastForwardUntilNoTasksRemain(); @@ -224,8 +228,8 @@ // Fake several consecutive network changes notification. for (int i = 0; i < 10; ++i) { - net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( - net::NetworkChangeNotifier::CONNECTION_UNKNOWN); + network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( + network::mojom::ConnectionType::CONNECTION_UNKNOWN); scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(5)); } // Expect still no network request or callback. @@ -266,8 +270,8 @@ EXPECT_FALSE(query_3.position().has_value()); // Fake a network change notification. - net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( - net::NetworkChangeNotifier::CONNECTION_UNKNOWN); + network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( + network::mojom::ConnectionType::CONNECTION_UNKNOWN); // Wait for the notifier to complete its delayed reaction. scoped_task_environment_.FastForwardUntilNoTasksRemain();
diff --git a/services/network/cookie_manager_unittest.cc b/services/network/cookie_manager_unittest.cc index 35e20c8..a2711a46 100644 --- a/services/network/cookie_manager_unittest.cc +++ b/services/network/cookie_manager_unittest.cc
@@ -294,6 +294,16 @@ void InitializeCookieService( scoped_refptr<net::CookieMonster::PersistentCookieStore> store, scoped_refptr<SessionCleanupCookieStore> cleanup_store) { + if (cookie_service_) { + // Make sure that data from any previous store is fully saved. + // |cookie_service_| destroyed first since it may issue some writes to the + // |cookie_monster_|. + cookie_service_ = nullptr; + net::NoResultCookieCallback callback; + cookie_monster_->FlushStore(callback.MakeCallback()); + callback.WaitUntilDone(); + } + connection_error_seen_ = false; cookie_monster_ = std::make_unique<net::CookieMonster>( std::move(store), nullptr /* netlog */);
diff --git a/services/network/cross_origin_resource_policy_unittest.cc b/services/network/cross_origin_resource_policy_unittest.cc index 844cfea5..a19f3f4 100644 --- a/services/network/cross_origin_resource_policy_unittest.cc +++ b/services/network/cross_origin_resource_policy_unittest.cc
@@ -16,8 +16,7 @@ const std::string& test_headers) { std::string all_headers = "HTTP/1.1 200 OK\n" + test_headers + "\n"; auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(all_headers.c_str(), - all_headers.size())); + net::HttpUtil::AssembleRawHeaders(all_headers)); return CrossOriginResourcePolicy::ParseHeaderForTesting(headers.get()); }
diff --git a/services/network/host_resolver_unittest.cc b/services/network/host_resolver_unittest.cc index e585338..4743d5b8 100644 --- a/services/network/host_resolver_unittest.cc +++ b/services/network/host_resolver_unittest.cc
@@ -24,7 +24,6 @@ #include "net/dns/dns_config.h" #include "net/dns/dns_test_util.h" #include "net/dns/host_resolver.h" -#include "net/dns/host_resolver_manager.h" #include "net/dns/mock_host_resolver.h" #include "net/dns/public/dns_protocol.h" #include "net/log/net_log.h" @@ -1148,8 +1147,7 @@ net::NetLog net_log; std::unique_ptr<net::ContextHostResolver> inner_resolver = net::HostResolver::CreateStandaloneContextResolver(&net_log); - inner_resolver->GetManagerForTesting()->SetDnsClientForTesting( - std::move(dns_client)); + inner_resolver->SetDnsClientForTesting(std::move(dns_client)); inner_resolver->SetBaseDnsConfigForTesting(CreateValidDnsConfig()); HostResolver resolver(inner_resolver.get(), &net_log); @@ -1187,8 +1185,7 @@ net::NetLog net_log; std::unique_ptr<net::ContextHostResolver> inner_resolver = net::HostResolver::CreateStandaloneContextResolver(&net_log); - inner_resolver->GetManagerForTesting()->SetDnsClientForTesting( - std::move(dns_client)); + inner_resolver->SetDnsClientForTesting(std::move(dns_client)); inner_resolver->SetBaseDnsConfigForTesting(CreateValidDnsConfig()); HostResolver resolver(inner_resolver.get(), &net_log);
diff --git a/services/network/network_context.cc b/services/network/network_context.cc index 72ad228..ba7bc6c7 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc
@@ -1311,15 +1311,16 @@ // same net::HostResolver with the same scheduler and cache can be used with // different overrides. But since this is only used for special cases for // now, much easier to create entirely separate net::HostResolver instances. - net::HostResolver::ManagerOptions options; - options.dns_client_enabled = true; - options.dns_config_overrides = config_overrides.value(); private_internal_resolver = network_service_->host_resolver_factory()->CreateStandaloneResolver( - url_request_context_->net_log(), std::move(options), - "" /* host_mapping_rules */, false /* enable_caching */); + url_request_context_->net_log(), + net::HostResolver::ManagerOptions(), "" /* host_mapping_rules */, + false /* enable_caching */); private_internal_resolver->SetRequestContext(url_request_context_); internal_resolver = private_internal_resolver.get(); + + internal_resolver->SetDnsClientEnabled(true); + internal_resolver->SetDnsConfigOverrides(config_overrides.value()); } host_resolvers_.emplace(
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc index d4345da..0691bc5 100644 --- a/services/network/network_context_unittest.cc +++ b/services/network/network_context_unittest.cc
@@ -3187,8 +3187,7 @@ auto mock_dns_client = std::make_unique<net::MockDnsClient>(net::DnsConfig(), std::move(rules)); auto* mock_dns_client_ptr = mock_dns_client.get(); - internal_resolver->GetManagerForTesting()->SetDnsClientForTesting( - std::move(mock_dns_client)); + internal_resolver->SetDnsClientForTesting(std::move(mock_dns_client)); // Force the base configuration to ensure consistent overriding. net::DnsConfig base_configuration;
diff --git a/services/network/public/cpp/server/http_server_unittest.cc b/services/network/public/cpp/server/http_server_unittest.cc index 6ad13dac..6351ab5 100644 --- a/services/network/public/cpp/server/http_server_unittest.cc +++ b/services/network/public/cpp/server/http_server_unittest.cc
@@ -138,9 +138,9 @@ // Return true if response has data equal to or more than content length. int64_t body_size = static_cast<int64_t>(response.size()) - end_of_headers; DCHECK_LE(0, body_size); - scoped_refptr<net::HttpResponseHeaders> headers( - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - response.data(), end_of_headers))); + auto headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders( + base::StringPiece(response.data(), end_of_headers))); return body_size >= headers->GetContentLength(); }
diff --git a/services/network/public/cpp/simple_url_loader_unittest.cc b/services/network/public/cpp/simple_url_loader_unittest.cc index 4165904e..eab77316 100644 --- a/services/network/public/cpp/simple_url_loader_unittest.cc +++ b/services/network/public/cpp/simple_url_loader_unittest.cc
@@ -1797,8 +1797,8 @@ "HTTP/1.0 301 The Response Has Moved to Another Server\n" "Location: bar://foo/"); response_info.headers = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - headers.c_str(), headers.size())); + base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); client_->OnReceiveRedirect(redirect_info, response_info); break; } @@ -1806,8 +1806,8 @@ network::ResourceResponseHead response_info; std::string headers("HTTP/1.0 200 OK"); response_info.headers = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - headers.c_str(), headers.size())); + base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); client_->OnReceiveResponse(response_info); break; } @@ -1815,8 +1815,8 @@ network::ResourceResponseHead response_info; std::string headers("HTTP/1.0 401 Client Borkage"); response_info.headers = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - headers.c_str(), headers.size())); + base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); client_->OnReceiveResponse(response_info); break; } @@ -1824,8 +1824,8 @@ network::ResourceResponseHead response_info; std::string headers("HTTP/1.0 501 Server Borkage"); response_info.headers = - new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( - headers.c_str(), headers.size())); + base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); client_->OnReceiveResponse(response_info); break; }
diff --git a/services/network/test/test_utils.cc b/services/network/test/test_utils.cc index 8f59c20b8..671e13c 100644 --- a/services/network/test/test_utils.cc +++ b/services/network/test/test_utils.cc
@@ -29,8 +29,8 @@ base::StringPrintf("HTTP/1.1 %d %s", static_cast<int>(http_status), net::GetHttpReasonPhrase(http_status))); std::string headers = status_line + "\nContent-type: text/html\n\n"; - head.headers = new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); + head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); if (report_raw_headers) { head.raw_request_response_info = base::MakeRefCounted<HttpRawRequestResponseInfo>();
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index 343a801..41889aba 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -153,6 +153,12 @@ #define SK_SUPPORT_LEGACY_DRAWLOOPER #endif +// For now, Chrome should only attempt to reduce opList splitting when recording +// DDLs +#ifndef SK_DISABLE_REDUCE_OPLIST_SPLITTING +#define SK_DISABLE_REDUCE_OPLIST_SPLITTING +#endif + #ifndef SK_IGNORE_LINEONLY_AA_CONVEX_PATH_OPTS #define SK_IGNORE_LINEONLY_AA_CONVEX_PATH_OPTS #endif
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json index 53bb516..4c005ce 100644 --- a/testing/buildbot/chromium.perf.fyi.json +++ b/testing/buildbot/chromium.perf.fyi.json
@@ -52,10 +52,8 @@ { "args": [ "-v", - "--browser=exact", + "--browser=android-chrome", "--upload-results", - "--browser-executable=../../out/Release/bin/monochrome_64_32_bundle", - "--device=android", "--run-ref-build", "--test-shard-map-filename=android-pixel2-perf_map.json" ],
diff --git a/testing/buildbot/filters/fuchsia.content_unittests.filter b/testing/buildbot/filters/fuchsia.content_unittests.filter index d67a923..d64c8f38 100644 --- a/testing/buildbot/filters/fuchsia.content_unittests.filter +++ b/testing/buildbot/filters/fuchsia.content_unittests.filter
@@ -60,3 +60,7 @@ # Flaky, https://crbug.com/884250. -ReferrerSanitizerTest.SanitizesPolicyForNonEmptyReferrers + +# This test requires OSExchangeDataProviderFactory::CreateProvider to +# be implemented: https://crbug.com/750934. +-WebContentsViewAuraTest.DragDropFiles
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 9718179d..c5ac335 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -606,6 +606,26 @@ ] } ], + "AutofillDoNotUploadSaveUnsupportedCards": [ + { + "platforms": [ + "android", + "chromeos", + "ios", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "AutofillDoNotUploadSaveUnsupportedCards" + ] + } + ] + } + ], "AutofillDropdownLayout": [ { "platforms": [ @@ -777,6 +797,27 @@ ] } ], + "AutofillNoLocalSaveOnUnmaskOrUploadSuccess": [ + { + "platforms": [ + "android", + "chromeos", + "ios", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "AutofillNoLocalSaveOnUnmaskSuccess", + "AutofillNoLocalSaveOnUploadSuccess" + ] + } + ] + } + ], "AutofillOffNoServerData": [ { "platforms": [
diff --git a/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h b/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h index 50860f0..6c8e39e9 100644 --- a/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h +++ b/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h
@@ -35,7 +35,9 @@ // We need to track them too. kServiceWorkerControlledPage = 16, - kMaxValue = kServiceWorkerControlledPage + kOutstandingIndexedDBTransaction = 17, + + kMaxValue = kOutstandingIndexedDBTransaction }; } // namespace scheduler
diff --git a/third_party/blink/public/platform/web_gesture_event.h b/third_party/blink/public/platform/web_gesture_event.h index e705bb7..615e6487 100644 --- a/third_party/blink/public/platform/web_gesture_event.h +++ b/third_party/blink/public/platform/web_gesture_event.h
@@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_GESTURE_EVENT_H_ #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_GESTURE_EVENT_H_ +#include "cc/trees/element_id.h" #include "third_party/blink/public/platform/web_float_size.h" #include "third_party/blink/public/platform/web_gesture_device.h" #include "third_party/blink/public/platform/web_input_event.h" @@ -102,9 +103,14 @@ // True if this event is generated from a wheel event with synthetic // phase. bool synthetic; - // number of pointers down. int pointer_count; + // If set, used to target a scrollable area directly instead of performing + // a hit-test. Should be used for gestures queued up internally within + // the renderer process. This is an ElementIdType instead of ElementId + // due to the fact that ElementId has a non-trivial constructor that + // can't easily participate in this union of structs. + cc::ElementIdType scrollable_area_element_id; } scroll_begin; struct {
diff --git a/third_party/blink/public/web/web_settings.h b/third_party/blink/public/web/web_settings.h index 37733ade..6076ae1d 100644 --- a/third_party/blink/public/web/web_settings.h +++ b/third_party/blink/public/web/web_settings.h
@@ -168,7 +168,6 @@ virtual void SetFullscreenSupported(bool) = 0; virtual void SetHideDownloadUI(bool) = 0; virtual void SetHighlightAds(bool) = 0; - virtual void SetHistoryEntryRequiresUserGesture(bool) = 0; virtual void SetHyperlinkAuditingEnabled(bool) = 0; virtual void SetIgnoreMainFrameOverflowHiddenQuirk(bool) = 0; virtual void SetImageAnimationPolicy(ImageAnimationPolicy) = 0;
diff --git a/third_party/blink/renderer/core/accessibility/apply_dark_mode.cc b/third_party/blink/renderer/core/accessibility/apply_dark_mode.cc index 1be8571..8166679d 100644 --- a/third_party/blink/renderer/core/accessibility/apply_dark_mode.cc +++ b/third_party/blink/renderer/core/accessibility/apply_dark_mode.cc
@@ -53,7 +53,6 @@ dark_mode_settings.grayscale = frame_settings.GetDarkModeGrayscale(); dark_mode_settings.contrast = frame_settings.GetDarkModeContrast(); dark_mode_settings.image_policy = frame_settings.GetDarkModeImagePolicy(); - dark_mode_settings.image_style = frame_settings.GetDarkModeImageStyle(); return dark_mode_settings; }
diff --git a/third_party/blink/renderer/core/css/style_sheet_candidate.cc b/third_party/blink/renderer/core/css/style_sheet_candidate.cc index d558990..9db69be 100644 --- a/third_party/blink/renderer/core/css/style_sheet_candidate.cc +++ b/third_party/blink/renderer/core/css/style_sheet_candidate.cc
@@ -46,7 +46,7 @@ bool StyleSheetCandidate::IsXSL() const { return !GetNode().GetDocument().IsHTMLDocument() && type_ == kPi && - ToProcessingInstruction(GetNode()).IsXSL(); + To<ProcessingInstruction>(GetNode()).IsXSL(); } bool StyleSheetCandidate::IsImport() const { @@ -110,7 +110,7 @@ case kSVGStyle: return ToSVGStyleElement(GetNode()).sheet(); case kPi: - return ToProcessingInstruction(GetNode()).sheet(); + return To<ProcessingInstruction>(GetNode()).sheet(); default: NOTREACHED(); return nullptr;
diff --git a/third_party/blink/renderer/core/dom/character_data.cc b/third_party/blink/renderer/core/dom/character_data.cc index b8bdd0a..146bd34 100644 --- a/third_party/blink/renderer/core/dom/character_data.cc +++ b/third_party/blink/renderer/core/dom/character_data.cc
@@ -213,8 +213,9 @@ text_node->UpdateTextLayoutObject(offset_of_replaced_data, old_length); if (source != kUpdateFromParser) { - if (getNodeType() == kProcessingInstructionNode) - ToProcessingInstruction(this)->DidAttributeChanged(); + if (auto* processing_instruction_node = + DynamicTo<ProcessingInstruction>(this)) + processing_instruction_node->DidAttributeChanged(); GetDocument().NotifyUpdateCharacterData(this, offset_of_replaced_data, old_length, new_length);
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 47840fe..627300f 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -383,10 +383,6 @@ // adequate, but a little high for dual G5s. :) static const int kCLayoutScheduleThreshold = 250; -// After a document has been committed for this time, it can create a history -// entry even if the user hasn't interacted with the document. -static const int kElapsedTimeForHistoryEntryWithoutUserGestureMS = 5000; - // DOM Level 2 says (letters added): // // a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl. @@ -3758,24 +3754,6 @@ return static_cast<int>((CurrentTime() - start_time_) * 1000); } -bool Document::CanCreateHistoryEntry() const { - if (!frame_ || frame_->HasBeenActivated()) - return true; - if (ElapsedTime() >= kElapsedTimeForHistoryEntryWithoutUserGestureMS) - return true; - UseCounter::Count(*this, WebFeature::kSuppressHistoryEntryWithoutUserGesture); - // TODO(japhet): This flag controls an intervention to require a user gesture - // or a long time on page in order for a content-initiated navigation to add - // an entry to the back/forward list. Removing the flag and making this the - // default will require updating a couple hundred tests that currently depend - // on creating history entries without user gestures. I'm waiting to update - // the tests until the feature is proven to minimize churn. - // https://bugs.chromium.org/p/chromium/issues/detail?id=638198 - if (!GetSettings() || !GetSettings()->GetHistoryEntryRequiresUserGesture()) - return true; - return false; -} - void Document::write(const String& text, Document* entered_document, ExceptionState& exception_state) {
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index baf8bc57..849d5864 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h
@@ -757,8 +757,6 @@ bool ShouldScheduleLayout() const; int ElapsedTime() const; - bool CanCreateHistoryEntry() const; - TextLinkColors& GetTextLinkColors() { return text_link_colors_; } const TextLinkColors& GetTextLinkColors() const { return text_link_colors_; } VisitedLinkState& GetVisitedLinkState() const { return *visited_link_state_; } @@ -1528,6 +1526,15 @@ void RemoveLockedDisplayLock(); int LockedDisplayLockCount() const; + // Deferred compositor commits are disallowed by default, and are only allowed + // for same-origin navigations to an html document fetched with http. + bool DeferredCompositorCommitIsAllowed() { + return deferred_compositor_commit_is_allowed_; + } + void SetDeferredCompositorCommitIsAllowed(bool new_value) { + deferred_compositor_commit_is_allowed_ = new_value; + } + // Returns whether the document is inside the scope specified in the Web App // Manifest. If the document doesn't run in a context of a Web App or has no // associated Web App Manifest, it will return false. @@ -1956,11 +1963,11 @@ std::unique_ptr<DocumentOutliveTimeReporter> document_outlive_time_reporter_; - // |mojo_ukm_recorder_| and |source_id_| will allow objects that are part of - // the |ukm_recorder_| and |source_id_| will allow objects that are part of + // |ukm_recorder_| and |source_id_| will allow objects that are part of // the document to recorde UKM. std::unique_ptr<ukm::UkmRecorder> ukm_recorder_; int64_t ukm_source_id_; + bool needs_to_record_ukm_outlive_time_; #if DCHECK_IS_ON() unsigned slot_assignment_recalc_forbidden_recursion_depth_ = 0; @@ -1968,8 +1975,6 @@ unsigned slot_assignment_recalc_depth_ = 0; unsigned flat_tree_traversal_forbidden_recursion_depth_ = 0; - bool needs_to_record_ukm_outlive_time_; - Member<DOMFeaturePolicy> policy_; Member<SlotAssignmentEngine> slot_assignment_engine_; @@ -1988,6 +1993,8 @@ // Number of locked display locks in the document. int locked_display_lock_count_ = 0; + bool deferred_compositor_commit_is_allowed_ = false; + // A list of all the navigation_initiator bindings owned by this document. // Used to report CSP violations that result from CSP blocking // navigation requests that were initiated by this document.
diff --git a/third_party/blink/renderer/core/dom/document_type.h b/third_party/blink/renderer/core/dom/document_type.h index fa4bf12..8874150 100644 --- a/third_party/blink/renderer/core/dom/document_type.h +++ b/third_party/blink/renderer/core/dom/document_type.h
@@ -25,6 +25,7 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_DOCUMENT_TYPE_H_ #include "third_party/blink/renderer/core/dom/node.h" +#include "third_party/blink/renderer/platform/wtf/casting.h" namespace blink { @@ -63,7 +64,10 @@ String system_id_; }; -DEFINE_NODE_TYPE_CASTS(DocumentType, IsDocumentTypeNode()); +template <> +struct DowncastTraits<DocumentType> { + static bool AllowFrom(const Node& node) { return node.IsDocumentTypeNode(); } +}; } // namespace blink
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc index 5436447..b6e2081d 100644 --- a/third_party/blink/renderer/core/dom/node.cc +++ b/third_party/blink/renderer/core/dom/node.cc
@@ -1658,9 +1658,8 @@ if (other_child) return false; - if (IsDocumentTypeNode()) { - const DocumentType* document_type_this = ToDocumentType(this); - const DocumentType* document_type_other = ToDocumentType(other); + if (const auto* document_type_this = DynamicTo<DocumentType>(this)) { + const auto* document_type_other = To<DocumentType>(other); if (document_type_this->publicId() != document_type_other->publicId()) return false;
diff --git a/third_party/blink/renderer/core/dom/processing_instruction.h b/third_party/blink/renderer/core/dom/processing_instruction.h index 8975bc5a..93c9a12 100644 --- a/third_party/blink/renderer/core/dom/processing_instruction.h +++ b/third_party/blink/renderer/core/dom/processing_instruction.h
@@ -26,6 +26,7 @@ #include "third_party/blink/renderer/core/dom/character_data.h" #include "third_party/blink/renderer/core/loader/resource/text_resource.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_client.h" +#include "third_party/blink/renderer/platform/wtf/casting.h" namespace blink { @@ -109,12 +110,16 @@ Member<DetachableEventListener> listener_for_xslt_; }; -DEFINE_NODE_TYPE_CASTS(ProcessingInstruction, - getNodeType() == Node::kProcessingInstructionNode); +template <> +struct DowncastTraits<ProcessingInstruction> { + static bool AllowFrom(const Node& node) { + return node.getNodeType() == Node::kProcessingInstructionNode; + } +}; inline bool IsXSLStyleSheet(const Node& node) { return node.getNodeType() == Node::kProcessingInstructionNode && - ToProcessingInstruction(node).IsXSL(); + To<ProcessingInstruction>(node).IsXSL(); } } // namespace blink
diff --git a/third_party/blink/renderer/core/dom/range.cc b/third_party/blink/renderer/core/dom/range.cc index 0b12bdff..52c5fee7 100644 --- a/third_party/blink/renderer/core/dom/range.cc +++ b/third_party/blink/renderer/core/dom/range.cc
@@ -1064,12 +1064,12 @@ } return nullptr; case Node::kProcessingInstructionNode: - if (offset > ToProcessingInstruction(n)->data().length()) { + if (offset > To<ProcessingInstruction>(n)->data().length()) { exception_state.ThrowDOMException( DOMExceptionCode::kIndexSizeError, "The offset " + String::Number(offset) + " is larger than the node's length (" + - String::Number(ToProcessingInstruction(n)->data().length()) + + String::Number(To<ProcessingInstruction>(n)->data().length()) + ")."); } else if (offset > static_cast<unsigned>(std::numeric_limits<int>::max())) {
diff --git a/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc b/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc index 1db69e4..5837555 100644 --- a/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc +++ b/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc
@@ -166,12 +166,12 @@ case Node::kDocumentFragmentNode: break; case Node::kDocumentTypeNode: - AppendDocumentType(result, ToDocumentType(node)); + AppendDocumentType(result, To<DocumentType>(node)); break; case Node::kProcessingInstructionNode: AppendProcessingInstruction(result, - ToProcessingInstruction(node).target(), - ToProcessingInstruction(node).data()); + To<ProcessingInstruction>(node).target(), + To<ProcessingInstruction>(node).data()); break; case Node::kElementNode: NOTREACHED();
diff --git a/third_party/blink/renderer/core/editing/testing/selection_sample.cc b/third_party/blink/renderer/core/editing/testing/selection_sample.cc index 1c25120..349c344 100644 --- a/third_party/blink/renderer/core/editing/testing/selection_sample.cc +++ b/third_party/blink/renderer/core/editing/testing/selection_sample.cc
@@ -296,9 +296,10 @@ builder_.Append("-->"); return; } - if (node.getNodeType() == Node::kProcessingInstructionNode) { + if (auto* processing_instruction_node = + DynamicTo<ProcessingInstruction>(node)) { builder_.Append("<?"); - builder_.Append(ToProcessingInstruction(node).target()); + builder_.Append(processing_instruction_node->target()); builder_.Append(' '); HandleCharacterData(To<CharacterData>(node)); builder_.Append("?>");
diff --git a/third_party/blink/renderer/core/execution_context/security_context.cc b/third_party/blink/renderer/core/execution_context/security_context.cc index a3dc639..f1bf023a 100644 --- a/third_party/blink/renderer/core/execution_context/security_context.cc +++ b/third_party/blink/renderer/core/execution_context/security_context.cc
@@ -26,6 +26,7 @@ #include "third_party/blink/renderer/core/execution_context/security_context.h" +#include "base/metrics/histogram_macros.h" #include "third_party/blink/public/common/feature_policy/feature_policy.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h" @@ -34,6 +35,36 @@ namespace blink { +namespace { + +// Bucketize image compression into percentage in the following fashion: +// if an image's compression ratio is 0.1, it will be represented as 1 percent +// if an image's compression ratio is 5, it will be represented as 50 percents. +int BucketizeCompressionRatio(double compression_ratio) { + int compression_ratio_percent = 10 * compression_ratio; + if (compression_ratio_percent < 0) + return 0; + return compression_ratio_percent > 100 ? 100 : compression_ratio_percent; +} + +inline const char* GetImagePolicyHistogramName( + mojom::FeaturePolicyFeature feature) { + switch (feature) { + case mojom::FeaturePolicyFeature::kUnoptimizedLossyImages: + return "Blink.UseCounter.FeaturePolicy.LossyImageCompression"; + case mojom::FeaturePolicyFeature::kUnoptimizedLosslessImages: + return "Blink.UseCounter.FeaturePolicy.LosslessImageCompression"; + case mojom::FeaturePolicyFeature::kUnoptimizedLosslessImagesStrict: + return "Blink.UseCounter.FeaturePolicy.StrictLosslessImageCompression"; + default: + NOTREACHED(); + break; + } + return ""; +} + +} // namespace + // static std::vector<unsigned> SecurityContext::SerializeInsecureNavigationSet( const InsecureNavigationsSet& set) { @@ -255,6 +286,29 @@ // properly inherit the parent policy. DCHECK(feature_policy_); + // Log metrics for unoptimized-*-images policies. + if (feature == mojom::FeaturePolicyFeature::kUnoptimizedLossyImages || + feature == mojom::FeaturePolicyFeature::kUnoptimizedLosslessImages || + feature == + mojom::FeaturePolicyFeature::kUnoptimizedLosslessImagesStrict) { + // Only log metrics if an image policy is specified. + // If an image policy is specified, the policy value would be less than the + // max value, otherwise by default the policy value is set to be the max + // value. + const auto max_value = + PolicyValue::CreateMaxPolicyValue(mojom::PolicyValueType::kDecDouble); + if (!feature_policy_->IsFeatureEnabled(feature, max_value) && + threshold_value < max_value) { + STATIC_HISTOGRAM_POINTER_GROUP( + GetImagePolicyHistogramName(feature), static_cast<int>(feature), + static_cast<int>( + mojom::FeaturePolicyFeature::kUnoptimizedLosslessImagesStrict) + + 1, + Add(BucketizeCompressionRatio(threshold_value.DoubleValue())), + base::LinearHistogram::FactoryGet( + GetImagePolicyHistogramName(feature), 0, 100, 101, 0x1)); + } + } if (feature_policy_->IsFeatureEnabled(feature, threshold_value)) { if (report_only_feature_policy_ && !report_only_feature_policy_->IsFeatureEnabled(feature,
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.cc b/third_party/blink/renderer/core/exported/web_settings_impl.cc index f24c69b..818f377 100644 --- a/third_party/blink/renderer/core/exported/web_settings_impl.cc +++ b/third_party/blink/renderer/core/exported/web_settings_impl.cc
@@ -503,10 +503,6 @@ settings_->SetHighlightAds(enabled); } -void WebSettingsImpl::SetHistoryEntryRequiresUserGesture(bool enabled) { - settings_->SetHistoryEntryRequiresUserGesture(enabled); -} - void WebSettingsImpl::SetHyperlinkAuditingEnabled(bool enabled) { settings_->SetHyperlinkAuditingEnabled(enabled); }
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.h b/third_party/blink/renderer/core/exported/web_settings_impl.h index 238ce3c..f2f38f1f 100644 --- a/third_party/blink/renderer/core/exported/web_settings_impl.h +++ b/third_party/blink/renderer/core/exported/web_settings_impl.h
@@ -97,7 +97,6 @@ void SetHideDownloadUI(bool) override; void SetPresentationReceiver(bool) override; void SetHighlightAds(bool) override; - void SetHistoryEntryRequiresUserGesture(bool) override; void SetHyperlinkAuditingEnabled(bool) override; void SetIgnoreMainFrameOverflowHiddenQuirk(bool) override; void SetImageAnimationPolicy(ImageAnimationPolicy) override;
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc index 87db295..30ac731 100644 --- a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc +++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
@@ -68,9 +68,13 @@ scoped_refptr<base::SingleThreadTaskRunner> task_runner) : read_type_(read_type), client_(client), - handle_watcher_(FROM_HERE, - mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC, - task_runner), + // TODO(https://crbug.com/957651): task_runner should never be null, but + // if it is make sure SimpleWatcher doesn't crash and just use a default + // task runner instead for now. + handle_watcher_( + FROM_HERE, + mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC, + task_runner ? task_runner : base::SequencedTaskRunnerHandle::Get()), binding_(this), task_runner_(std::move(task_runner)), weak_factory_(this) {}
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index a64a3d880..1afc957 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -4171,10 +4171,9 @@ // This is enabled only if kAvoidFlashBetweenNavigation is enabled, and // the document loading is a regular HTML served over HTTP/HTTPs. Document* document = GetFrame().GetDocument(); - if (base::FeatureList::IsEnabled( - blink::features::kAvoidFlashBetweenNavigation) && - document && document->Url().ProtocolIsInHTTPFamily() && - document->IsHTMLDocument()) { + if (document && document->DeferredCompositorCommitIsAllowed() && + base::FeatureList::IsEnabled( + blink::features::kAvoidFlashBetweenNavigation)) { GetFrame().GetPage()->GetChromeClient().StartDeferringCommits( GetCommitDelayForAvoidFlashBetweenNavigation()); }
diff --git a/third_party/blink/renderer/core/frame/settings.json5 b/third_party/blink/renderer/core/frame/settings.json5 index 005d659..2247bd690 100644 --- a/third_party/blink/renderer/core/frame/settings.json5 +++ b/third_party/blink/renderer/core/frame/settings.json5
@@ -780,11 +780,6 @@ type: "double", }, - { - name: "historyEntryRequiresUserGesture", - initial: false, - }, - // Do we want to try to save screen real estate in the media player by hiding // the volume slider / mute button? { @@ -918,12 +913,6 @@ invalidate: "Paint", }, { - name: "darkModeImageStyle", - initial: "DarkModeImageStyle::kDefault", - type: "DarkModeImageStyle", - invalidate: "Paint", - }, - { name: "navigatorPlatformOverride", type: "String", },
diff --git a/third_party/blink/renderer/core/input/event_handler_test.cc b/third_party/blink/renderer/core/input/event_handler_test.cc index ce46db7..2cc5a61 100644 --- a/third_party/blink/renderer/core/input/event_handler_test.cc +++ b/third_party/blink/renderer/core/input/event_handler_test.cc
@@ -20,9 +20,12 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/settings.h" +#include "third_party/blink/renderer/core/frame/visual_viewport.h" #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" #include "third_party/blink/renderer/core/html/forms/html_input_element.h" #include "third_party/blink/renderer/core/html/html_iframe_element.h" +#include "third_party/blink/renderer/core/layout/layout_box.h" +#include "third_party/blink/renderer/core/layout/layout_embedded_content.h" #include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/layout_view.h" #include "third_party/blink/renderer/core/loader/empty_clients.h" @@ -1769,4 +1772,203 @@ EXPECT_EQ(0, GetDocument().getElementById("outer")->scrollLeft()); } +TEST_F(EventHandlerSimTest, ElementTargetedGestureScroll) { + WebView().MainFrameWidget()->Resize(WebSize(800, 600)); + SimRequest request("https://example.com/test.html", "text/html"); + LoadURL("https://example.com/test.html"); + request.Complete(R"HTML( + <!DOCTYPE html> + <style> + #scroller { + overflow-y:scroll; + height:200px; + } + #talldiv { + height:1000px; + } + </style> + <div id="talldiv">Tall text to create viewport scrollbar</div> + <div id="scroller"> + <div style="height:2000px">To create subscroller scrollbar</div> + </div> + )HTML"); + Compositor().BeginFrame(); + + Element* const scroller = GetDocument().getElementById("scroller"); + constexpr float delta_y = 100; + // Send GSB/GSU at 0,0 to target the viewport first, then verify that + // the viewport scrolled accordingly. + WebGestureEvent gesture_scroll_begin{ + WebInputEvent::kGestureScrollBegin, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()}; + gesture_scroll_begin.SetFrameScale(1); + gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0; + gesture_scroll_begin.data.scroll_begin.delta_y_hint = -delta_y; + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_begin); + + WebGestureEvent gesture_scroll_update{ + WebInputEvent::kGestureScrollUpdate, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()}; + gesture_scroll_update.SetFrameScale(1); + gesture_scroll_update.data.scroll_update.delta_x = 0; + gesture_scroll_update.data.scroll_update.delta_y = -delta_y; + + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_update); + + WebGestureEvent gesture_scroll_end{ + WebInputEvent::kGestureScrollEnd, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()}; + gesture_scroll_end.SetFrameScale(1); + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_end); + + LocalFrameView* frame_view = GetDocument().View(); + ASSERT_EQ(frame_view->LayoutViewport()->GetScrollOffset().Height(), delta_y); + + // Switch to the element_id-based targeting for GSB, then resend GSU + // and validate that the subscroller scrolled (and that the viewport + // did not). + ScrollableArea* scrollable_area = + scroller->GetLayoutBox()->GetScrollableArea(); + gesture_scroll_begin.data.scroll_begin.scrollable_area_element_id = + scrollable_area->GetCompositorElementId().GetInternalValue(); + + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_begin); + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_update); + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_end); + + ASSERT_EQ(scrollable_area->ScrollOffsetInt().Height(), delta_y); + ASSERT_EQ(frame_view->LayoutViewport()->GetScrollOffset().Height(), delta_y); + + // Remove the scroller, update layout, and ensure the same gestures + // don't crash or scroll the layout viewport. + scroller->remove(); + GetDocument().UpdateStyleAndLayout(); + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_begin); + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_update); + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_end); + + ASSERT_EQ(frame_view->LayoutViewport()->GetScrollOffset().Height(), delta_y); +} + +TEST_F(EventHandlerSimTest, ElementTargetedGestureScrollIFrame) { + WebView().MainFrameWidget()->Resize(WebSize(800, 600)); + SimRequest request_outer("https://example.com/test-outer.html", "text/html"); + SimRequest request_inner("https://example.com/test-inner.html", "text/html"); + LoadURL("https://example.com/test-outer.html"); + request_outer.Complete(R"HTML( + <!DOCTYPE html> + <iframe id="iframe" src="test-inner.html"></iframe> + <div style="height:1000px"></div> + )HTML"); + + request_inner.Complete(R"HTML( + <!DOCTYPE html> + <div style="height:1000px"></div> + )HTML"); + Compositor().BeginFrame(); + + HTMLFrameElementBase* const iframe = + ToHTMLFrameElementBase(GetDocument().getElementById("iframe")); + FrameView* child_frame_view = + iframe->GetLayoutEmbeddedContent()->ChildFrameView(); + auto* local_child_frame_view = DynamicTo<LocalFrameView>(child_frame_view); + ScrollableArea* scrollable_area = local_child_frame_view->GetScrollableArea(); + + // Target the iframe scrollable area and make sure it scrolls when targeted + // with gestures. + constexpr float delta_y = 100; + WebGestureEvent gesture_scroll_begin{ + WebInputEvent::kGestureScrollBegin, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()}; + gesture_scroll_begin.SetFrameScale(1); + gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0; + gesture_scroll_begin.data.scroll_begin.delta_y_hint = -delta_y; + gesture_scroll_begin.data.scroll_begin.scrollable_area_element_id = + scrollable_area->GetCompositorElementId().GetInternalValue(); + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_begin); + + WebGestureEvent gesture_scroll_update{ + WebInputEvent::kGestureScrollUpdate, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()}; + gesture_scroll_update.SetFrameScale(1); + gesture_scroll_update.data.scroll_update.delta_x = 0; + gesture_scroll_update.data.scroll_update.delta_y = -delta_y; + + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_update); + + WebGestureEvent gesture_scroll_end{ + WebInputEvent::kGestureScrollEnd, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()}; + gesture_scroll_end.SetFrameScale(1); + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_end); + + LocalFrameView* frame_view = GetDocument().View(); + ASSERT_EQ(frame_view->LayoutViewport()->GetScrollOffset().Height(), 0); + ASSERT_EQ(scrollable_area->ScrollOffsetInt().Height(), delta_y); +} + +TEST_F(EventHandlerSimTest, ElementTargetedGestureScrollViewport) { + WebView().MainFrameWidget()->Resize(WebSize(800, 600)); + // Set a page scale factor so that the VisualViewport will also scroll. + SimRequest request("https://example.com/test.html", "text/html"); + LoadURL("https://example.com/test.html"); + request.Complete(R"HTML( + <!DOCTYPE html> + <div style="height:1000px">Tall text to create viewport scrollbar</div> + )HTML"); + WebView().SetPageScaleFactor(2); + Compositor().BeginFrame(); + + // Target the visual viewport (which is a ScrollableArea), and validate + // that the layout viewport scrolled. + constexpr float delta_y = 700; + const VisualViewport& visual_viewport = + GetDocument().GetPage()->GetVisualViewport(); + + WebGestureEvent gesture_scroll_begin{ + WebInputEvent::kGestureScrollBegin, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()}; + gesture_scroll_begin.SetFrameScale(1); + gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0; + gesture_scroll_begin.data.scroll_begin.delta_y_hint = -delta_y; + gesture_scroll_begin.data.scroll_begin.scrollable_area_element_id = + visual_viewport.GetCompositorElementId().GetInternalValue(); + + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_begin); + + WebGestureEvent gesture_scroll_update{ + WebInputEvent::kGestureScrollUpdate, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()}; + gesture_scroll_update.SetFrameScale(1); + gesture_scroll_update.data.scroll_update.delta_x = 0; + gesture_scroll_update.data.scroll_update.delta_y = -delta_y; + + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_update); + + WebGestureEvent gesture_scroll_end{ + WebInputEvent::kGestureScrollEnd, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()}; + gesture_scroll_end.SetFrameScale(1); + GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent( + gesture_scroll_end); + + LocalFrameView* frame_view = GetDocument().View(); + ASSERT_EQ(frame_view->LayoutViewport()->GetScrollOffset().Height(), 400); + ASSERT_EQ(visual_viewport.GetScrollOffset().Height(), 300); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/input/scroll_manager.cc b/third_party/blink/renderer/core/input/scroll_manager.cc index f1d6d5b..a3c597b 100644 --- a/third_party/blink/renderer/core/input/scroll_manager.cc +++ b/third_party/blink/renderer/core/input/scroll_manager.cc
@@ -14,6 +14,7 @@ #include "third_party/blink/renderer/core/frame/browser_controls.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" +#include "third_party/blink/renderer/core/frame/visual_viewport.h" #include "third_party/blink/renderer/core/html/html_frame_owner_element.h" #include "third_party/blink/renderer/core/input/event_handler.h" #include "third_party/blink/renderer/core/input/event_handling_util.h" @@ -27,6 +28,7 @@ #include "third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h" #include "third_party/blink/renderer/core/page/scrolling/root_scroller_util.h" #include "third_party/blink/renderer/core/page/scrolling/scroll_state.h" +#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h" #include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" @@ -79,7 +81,6 @@ } void ScrollManager::Clear() { - last_gesture_scroll_over_embedded_content_view_ = false; scrollbar_handling_scroll_gesture_ = nullptr; resize_scrollable_area_ = nullptr; offset_from_resize_corner_ = LayoutSize(); @@ -95,6 +96,7 @@ } void ScrollManager::ClearGestureScrollState() { + last_gesture_scroll_over_embedded_content_view_ = false; scroll_gesture_handling_node_ = nullptr; previous_gesture_scrolled_node_ = nullptr; delta_consumed_for_scroll_sequence_ = false; @@ -814,6 +816,24 @@ if (gesture_event.GetType() != WebInputEvent::kGestureScrollBegin) { scrollbar = scrollbar_handling_scroll_gesture_.Get(); event_target = scroll_gesture_handling_node_.Get(); + } else if (gesture_event.GetType() == WebInputEvent::kGestureScrollBegin && + gesture_event.data.scroll_begin.scrollable_area_element_id) { + CompositorElementId element_id = CompositorElementId( + gesture_event.data.scroll_begin.scrollable_area_element_id); + event_target = NodeTargetForScrollableAreaElementId(element_id); + if (!event_target) { + // If we couldn't find a node associated with the targeted scrollable + // area, just drop the gesture. This may be due to the fact that the + // targeted has been removed from the tree between when the gesture + // was queued and when we handle it. + return WebInputEventResult::kNotHandled; + } + + ClearGestureScrollState(); + scroll_gesture_handling_node_ = event_target; + if (event_target->GetLayoutObject()->IsLayoutEmbeddedContent()) { + last_gesture_scroll_over_embedded_content_view_ = true; + } } if (!event_target) { @@ -836,6 +856,7 @@ last_gesture_scroll_over_embedded_content_view_ = result.IsOverEmbeddedContentView(); + scroll_gesture_handling_node_ = event_target; previous_gesture_scrolled_node_ = nullptr; delta_consumed_for_scroll_sequence_ = false; @@ -898,6 +919,58 @@ } } +Node* ScrollManager::NodeTargetForScrollableAreaElementId( + CompositorElementId element_id) const { + Page* page = frame_->GetPage(); + DCHECK(page); + ScrollableArea* scrollable_area = nullptr; + if (page->GetVisualViewport().GetCompositorElementId() == element_id) { + // If the element_id is the visual viewport, redirect to the + // root LocalFrameView's scrollable area (i.e. the RootFrameViewport). + scrollable_area = frame_->LocalFrameRoot().View()->GetScrollableArea(); + } else { + ScrollingCoordinator* scrolling_coordinator = + page->GetScrollingCoordinator(); + scrollable_area = + scrolling_coordinator->ScrollableAreaWithElementIdInAllLocalFrames( + element_id); + } + + // It is possible for an unrelated task to run between the time that + // the gesture targeting element_id is queued and when we're processing + // the gesture here, so we must validate the scrollable_area still + // exists along with it's layout information. If not, just drop this + // gesture since there is no relevant data on where to target the gesture. + LayoutBox* layout_box = + scrollable_area ? scrollable_area->GetLayoutBox() : nullptr; + if (!layout_box) { + return nullptr; + } + + Node* event_target = nullptr; + if (layout_box->GetDocument().GetFrame() == frame_) { + event_target = scrollable_area->GetLayoutBox()->GetNode(); + } else { + // The targeted ScrollableArea may not belong to this frame. If that + // is the case, target its ancestor HTMLFrameOwnerElement that exists + // in this view, so that the gesture handling can be passed down to + // the appropriate event handler. + LocalFrame* current_frame = layout_box->GetDocument().GetFrame(); + while (current_frame) { + HTMLFrameOwnerElement* owner = current_frame->GetDocument()->LocalOwner(); + LocalFrame* owner_frame = + owner ? owner->GetDocument().GetFrame() : nullptr; + if (owner_frame == frame_) { + event_target = owner; + break; + } + current_frame = owner_frame; + } + } + + return event_target; +} + bool ScrollManager::IsScrollbarHandlingGestures() const { return scrollbar_handling_scroll_gesture_.Get(); } @@ -998,6 +1071,7 @@ update_event.data.scroll_update.delta_y; scroll_begin.data.scroll_begin.delta_hint_units = update_event.data.scroll_update.delta_units; + scroll_begin.data.scroll_begin.scrollable_area_element_id = 0; return scroll_begin; }
diff --git a/third_party/blink/renderer/core/input/scroll_manager.h b/third_party/blink/renderer/core/input/scroll_manager.h index ac9cd83..8c83aeb 100644 --- a/third_party/blink/renderer/core/input/scroll_manager.h +++ b/third_party/blink/renderer/core/input/scroll_manager.h
@@ -16,6 +16,7 @@ #include "third_party/blink/renderer/core/page/event_with_hit_test_results.h" #include "third_party/blink/renderer/core/scroll/scroll_types.h" #include "third_party/blink/renderer/platform/geometry/layout_size.h" +#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/visitor.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" @@ -106,6 +107,8 @@ void AnimateSnapFling(base::TimeTicks monotonic_time); private: + Node* NodeTargetForScrollableAreaElementId( + CompositorElementId scrollable_area_element_id) const; WebInputEventResult HandleGestureScrollUpdate(const WebGestureEvent&); WebInputEventResult HandleGestureScrollBegin(const WebGestureEvent&);
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc index daf887e0..5ff810d 100644 --- a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
@@ -1536,8 +1536,7 @@ value->setDocumentURL(DocumentURLString(document)); value->setBaseURL(DocumentBaseURLString(document)); value->setXmlVersion(document->xmlVersion()); - } else if (node->IsDocumentTypeNode()) { - DocumentType* doc_type = ToDocumentType(node); + } else if (auto* doc_type = DynamicTo<DocumentType>(node)) { value->setPublicId(doc_type->publicId()); value->setSystemId(doc_type->systemId()); } else if (node->IsAttributeNode()) {
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc b/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc index bb9a94d..eebeb9a1 100644 --- a/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc
@@ -463,8 +463,7 @@ value->setScrollOffsetX(offset.Width()); value->setScrollOffsetY(offset.Height()); } - } else if (node->IsDocumentTypeNode()) { - DocumentType* doc_type = ToDocumentType(node); + } else if (auto* doc_type = DynamicTo<DocumentType>(node)) { value->setPublicId(doc_type->publicId()); value->setSystemId(doc_type->systemId()); }
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index 56dce472..5246db39 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -5665,9 +5665,7 @@ } LayoutBox::PaginationBreakability LayoutBox::GetPaginationBreakability() const { - // TODO(mstensho): It is wrong to check isAtomicInlineLevel() as we - // actually look for replaced elements. - if (IsAtomicInlineLevel() || HasUnsplittableScrollingOverflow() || + if (ShouldBeConsideredAsReplaced() || HasUnsplittableScrollingOverflow() || (Parent() && IsWritingModeRoot()) || (IsOutOfFlowPositioned() && StyleRef().GetPosition() == EPosition::kFixed) ||
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc index 0a312155..a4c6f822 100644 --- a/third_party/blink/renderer/core/loader/document_loader.cc +++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -444,11 +444,6 @@ // Update the data source's request with the new URL to fake the URL change frame_->GetDocument()->SetURL(new_url); - if (type == WebFrameLoadType::kStandard && initiating_document && - !initiating_document->CanCreateHistoryEntry()) { - type = WebFrameLoadType::kReplaceCurrentItem; - } - KURL old_url = url_; original_url_ = new_url; url_ = new_url; @@ -1708,6 +1703,20 @@ document->ApplyReportOnlyFeaturePolicyFromHeader(report_only_feature_policy); GetFrameLoader().DispatchDidClearDocumentOfWindowObject(); + + // Determine if the load is from a document from the same origin to enable + // deferred commits to avoid white flash on load. We only want to delay + // commits on same origin loads to avoid confusing users. We also require + // that this be an html document served via http. + if (initiator_origin) { + const scoped_refptr<const SecurityOrigin> url_origin = + SecurityOrigin::Create(Url()); + document->SetDeferredCompositorCommitIsAllowed( + initiator_origin->IsSameSchemeHostPort(url_origin.get()) && + Url().ProtocolIsInHTTPFamily() && document->IsHTMLDocument()); + } else { + document->SetDeferredCompositorCommitIsAllowed(false); + } } const AtomicString& DocumentLoader::MimeType() const {
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc index 10f24d6..2fa808a 100644 --- a/third_party/blink/renderer/core/loader/frame_loader.cc +++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -590,9 +590,6 @@ return WebFrameLoadType::kReplaceCurrentItem; } - if (origin_document && !origin_document->CanCreateHistoryEntry()) - return WebFrameLoadType::kReplaceCurrentItem; - return WebFrameLoadType::kStandard; }
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.cc b/third_party/blink/renderer/core/page/spatial_navigation.cc index 71593f89..3781848 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation.cc +++ b/third_party/blink/renderer/core/page/spatial_navigation.cc
@@ -66,7 +66,7 @@ return; visible_node = node; - rect_in_root_frame = NodeRectInRootFrame(node); + rect_in_root_frame = NodeRectInRootFrame(node, true /* ignore border */); } focusable_node = node; @@ -377,28 +377,13 @@ } } -LayoutRect NodeRectInRootFrame(const Node* node) { +LayoutRect NodeRectInRootFrame(const Node* node, bool ignore_border) { DCHECK(node); DCHECK(node->GetLayoutObject()); DCHECK(!node->GetDocument().View()->NeedsLayout()); - LayoutObject* object = node->GetLayoutObject(); - - LayoutRect rect = LayoutRect(object->LocalBoundingBoxRectForAccessibility()); - - // Inset the bounding box by the border. - // TODO(bokan): As far as I can tell, this is to work around empty iframes - // that have a border. It's unclear if that's still useful. - rect.Move(node->GetLayoutObject()->Style()->BorderLeftWidth(), - node->GetLayoutObject()->Style()->BorderTopWidth()); - rect.SetWidth(LayoutUnit( - rect.Width() - node->GetLayoutObject()->Style()->BorderLeftWidth() - - node->GetLayoutObject()->Style()->BorderRightWidth())); - rect.SetHeight(LayoutUnit( - rect.Height() - node->GetLayoutObject()->Style()->BorderTopWidth() - - node->GetLayoutObject()->Style()->BorderBottomWidth())); - - object->MapToVisualRectInAncestorSpace(/*ancestor=*/nullptr, rect); + LayoutRect rect = node->GetDocument().GetFrame()->View()->ConvertToRootFrame( + node->BoundingBox()); // Ensure the rect isn't empty. This can happen in some cases as the bounding // box is made up of the corners of multiple child elements. If the first @@ -406,6 +391,19 @@ // be empty. Ensure its not empty so intersections with the root frame don't // lie about being off-screen. rect.UniteEvenIfEmpty(LayoutRect(rect.Location(), LayoutSize(1, 1))); + + // For authors that use border instead of outline in their CSS, we compensate + // by ignoring the border when calculating the rect of the focused element. + if (ignore_border) { + rect.Move(node->GetLayoutObject()->Style()->BorderLeftWidth(), + node->GetLayoutObject()->Style()->BorderTopWidth()); + rect.SetWidth(LayoutUnit( + rect.Width() - node->GetLayoutObject()->Style()->BorderLeftWidth() - + node->GetLayoutObject()->Style()->BorderRightWidth())); + rect.SetHeight(LayoutUnit( + rect.Height() - node->GetLayoutObject()->Style()->BorderTopWidth() - + node->GetLayoutObject()->Style()->BorderBottomWidth())); + } return rect; } @@ -676,7 +674,7 @@ if (area_element) return StartEdgeForAreaElement(*area_element, direction); - LayoutRect box_in_root_frame = NodeRectInRootFrame(focus_node); + LayoutRect box_in_root_frame = NodeRectInRootFrame(focus_node, true); return Intersection(box_in_root_frame, viewport_rect_of_root_frame); } @@ -684,7 +682,7 @@ while (container) { if (!IsOffscreen(container)) { // The first scroller that encloses focus and is [partially] visible. - LayoutRect box_in_root_frame = NodeRectInRootFrame(container); + LayoutRect box_in_root_frame = NodeRectInRootFrame(container, true); return OppositeEdge(direction, Intersection(box_in_root_frame, viewport_rect_of_root_frame)); }
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.h b/third_party/blink/renderer/core/page/spatial_navigation.h index 5a6e272..ca7e4c8 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation.h +++ b/third_party/blink/renderer/core/page/spatial_navigation.h
@@ -85,7 +85,8 @@ double ComputeDistanceDataForNode(SpatialNavigationDirection, const FocusCandidate& current_interest, const FocusCandidate& candidate); -CORE_EXPORT LayoutRect NodeRectInRootFrame(const Node*); +CORE_EXPORT LayoutRect NodeRectInRootFrame(const Node*, + bool ignore_border = false); CORE_EXPORT LayoutRect OppositeEdge(SpatialNavigationDirection side, const LayoutRect& box, LayoutUnit thickness = LayoutUnit());
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc index 53ae3fd1..e912dd0 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc +++ b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
@@ -82,8 +82,8 @@ candidate.rect_in_root_frame.IsEmpty())) return; - // Ignore off-screen focusables, if there's nothing in the direction we'll - // scroll until they come on-screen. + // Ignore off-screen focusables that are not exposed after one "scroll step" + // in the direction. if (candidate.is_offscreen) return;
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_test.cc b/third_party/blink/renderer/core/page/spatial_navigation_test.cc index e0716b1..e5b817b1 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation_test.cc +++ b/third_party/blink/renderer/core/page/spatial_navigation_test.cc
@@ -198,7 +198,7 @@ EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, SpatialNavigationDirection::kDown), - NodeRectInRootFrame(b)); + NodeRectInRootFrame(b, true)); } TEST_F(SpatialNavigationTest, StartAtVisibleFocusedScroller) { @@ -220,7 +220,7 @@ Element* scroller = GetDocument().getElementById("scroller"); EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), scroller, SpatialNavigationDirection::kDown), - NodeRectInRootFrame(scroller)); + NodeRectInRootFrame(scroller, true)); } TEST_F(SpatialNavigationTest, StartAtVisibleFocusedIframe) { @@ -241,7 +241,7 @@ Element* iframe = GetDocument().getElementById("iframe"); EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), iframe, SpatialNavigationDirection::kDown), - NodeRectInRootFrame(iframe)); + NodeRectInRootFrame(iframe, true)); } TEST_F(SpatialNavigationTest, StartAtTopWhenGoingDownwardsWithoutFocus) { @@ -317,7 +317,7 @@ Element* b = GetDocument().getElementById("b"); const Element* container = GetDocument().getElementById("container"); - const LayoutRect container_box = NodeRectInRootFrame(container); + const LayoutRect container_box = NodeRectInRootFrame(container, true); // TODO(crbug.com/889840): // VisibleBoundsInVisualViewport does not (yet) take div-clipping into @@ -433,7 +433,7 @@ EXPECT_FALSE(IsOffscreen(b)); // <button> is not completely offscreen. - LayoutRect button_in_root_frame = NodeRectInRootFrame(b); + LayoutRect button_in_root_frame = NodeRectInRootFrame(b, true); EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, SpatialNavigationDirection::kUp), @@ -442,7 +442,7 @@ // Do some scrolling. ScrollableArea* root_scroller = GetDocument().View()->GetScrollableArea(); root_scroller->SetScrollOffset(ScrollOffset(0, 600), kProgrammaticScroll); - LayoutRect button_after_scroll = NodeRectInRootFrame(b); + LayoutRect button_after_scroll = NodeRectInRootFrame(b, true); ASSERT_NE(button_in_root_frame, button_after_scroll); // As we scrolled, the // <button>'s position in @@ -559,7 +559,7 @@ EXPECT_TRUE(IsOffscreen(child_element)); // Completely offscreen. EXPECT_FALSE(IsOffscreen(enclosing_container)); // Partially visible. - LayoutRect iframe = NodeRectInRootFrame(enclosing_container); + LayoutRect iframe = NodeRectInRootFrame(enclosing_container, true); // When searching downwards we start at activeElement's // container's (here: the iframe's) topmost visible edge.
diff --git a/third_party/blink/renderer/core/testing/core_unit_test_helper.cc b/third_party/blink/renderer/core/testing/core_unit_test_helper.cc index a2e8030a..65f22f7c 100644 --- a/third_party/blink/renderer/core/testing/core_unit_test_helper.cc +++ b/third_party/blink/renderer/core/testing/core_unit_test_helper.cc
@@ -100,7 +100,7 @@ auto* state_machine = ChildDocument().GetFrame()->Loader().StateMachine(); if (state_machine->IsDisplayingInitialEmptyDocument()) state_machine->AdvanceTo(FrameLoaderStateMachine::kCommittedFirstRealLoad); - // And let the frame view exit the initial throttled state. + // And let the frame view exit the initial throttled state. ChildDocument().View()->BeginLifecycleUpdates(); }
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc index e79cafc3..8c25fad 100644 --- a/third_party/blink/renderer/core/timing/performance.cc +++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -724,6 +724,12 @@ NotifyObserversOfEntry(*entry); } +UserTiming& Performance::GetUserTiming() { + if (!user_timing_) + user_timing_ = MakeGarbageCollected<UserTiming>(*this); + return *user_timing_; +} + PerformanceMark* Performance::mark(ScriptState* script_state, const AtomicString& mark_name, ExceptionState& exception_state) { @@ -734,21 +740,19 @@ const AtomicString& mark_name, PerformanceMarkOptions* mark_options, ExceptionState& exception_state) { - if (!user_timing_) - user_timing_ = MakeGarbageCollected<UserTiming>(*this); - PerformanceMark* performance_mark = user_timing_->Mark( + PerformanceMark* performance_mark = GetUserTiming().CreatePerformanceMark( script_state, mark_name, mark_options, exception_state); - if (performance_mark) + if (performance_mark) { + GetUserTiming().AddMarkToPerformanceTimeline(*performance_mark); NotifyObserversOfEntry(*performance_mark); + } if (RuntimeEnabledFeatures::CustomUserTimingEnabled()) return performance_mark; return nullptr; } void Performance::clearMarks(const AtomicString& mark_name) { - if (!user_timing_) - user_timing_ = MakeGarbageCollected<UserTiming>(*this); - user_timing_->ClearMarks(mark_name); + GetUserTiming().ClearMarks(mark_name); } PerformanceMeasure* Performance::measure(ScriptState* script_state, @@ -875,20 +879,16 @@ StringOrDouble original_start = start; StringOrDouble original_end = end; - if (!user_timing_) - user_timing_ = MakeGarbageCollected<UserTiming>(*this); PerformanceMeasure* performance_measure = - user_timing_->Measure(script_state, measure_name, original_start, - original_end, detail, exception_state); + GetUserTiming().Measure(script_state, measure_name, original_start, + original_end, detail, exception_state); if (performance_measure) NotifyObserversOfEntry(*performance_measure); return performance_measure; } void Performance::clearMeasures(const AtomicString& measure_name) { - if (!user_timing_) - user_timing_ = MakeGarbageCollected<UserTiming>(*this); - user_timing_->ClearMeasures(measure_name); + GetUserTiming().ClearMeasures(measure_name); } void Performance::RegisterPerformanceObserver(PerformanceObserver& observer) {
diff --git a/third_party/blink/renderer/core/timing/performance.h b/third_party/blink/renderer/core/timing/performance.h index a543900f..82575a6 100644 --- a/third_party/blink/renderer/core/timing/performance.h +++ b/third_party/blink/renderer/core/timing/performance.h
@@ -230,6 +230,7 @@ kMaxValue = kDomLoading }; + UserTiming& GetUserTiming(); PerformanceMeasure* measure(ScriptState*, const AtomicString& measure_name, ExceptionState&);
diff --git a/third_party/blink/renderer/core/timing/performance_mark.cc b/third_party/blink/renderer/core/timing/performance_mark.cc index c757a78..be3675a9 100644 --- a/third_party/blink/renderer/core/timing/performance_mark.cc +++ b/third_party/blink/renderer/core/timing/performance_mark.cc
@@ -6,7 +6,12 @@ #include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h" #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value_factory.h" +#include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/performance_entry_names.h" +#include "third_party/blink/renderer/core/timing/dom_window_performance.h" +#include "third_party/blink/renderer/core/timing/performance.h" +#include "third_party/blink/renderer/core/timing/performance_mark_options.h" +#include "third_party/blink/renderer/core/timing/performance_user_timing.h" namespace blink { @@ -22,6 +27,29 @@ detail_.Set(detail.GetIsolate(), detail.V8Value()); } +// static +PerformanceMark* PerformanceMark::Create(ScriptState* script_state, + const AtomicString& mark_name, + ExceptionState& exception_state) { + return Create(script_state, mark_name, nullptr, exception_state); +} + +// static +PerformanceMark* PerformanceMark::Create(ScriptState* script_state, + const AtomicString& mark_name, + PerformanceMarkOptions* mark_options, + ExceptionState& exception_state) { + LocalDOMWindow* window = LocalDOMWindow::From(script_state); + if (!window) + return nullptr; + Performance* performance = DOMWindowPerformance::performance(*window); + if (!performance) + return nullptr; + + return performance->GetUserTiming().CreatePerformanceMark( + script_state, mark_name, mark_options, exception_state); +} + AtomicString PerformanceMark::entryType() const { return performance_entry_names::kMark; }
diff --git a/third_party/blink/renderer/core/timing/performance_mark.h b/third_party/blink/renderer/core/timing/performance_mark.h index a472017..f4512df 100644 --- a/third_party/blink/renderer/core/timing/performance_mark.h +++ b/third_party/blink/renderer/core/timing/performance_mark.h
@@ -33,6 +33,9 @@ namespace blink { +class ExceptionState; +class PerformanceMarkOptions; + class CORE_EXPORT PerformanceMark final : public PerformanceEntry { DEFINE_WRAPPERTYPEINFO(); @@ -45,6 +48,17 @@ detail); } + // This method is required by the constructor defined in performance_mark.idl. + static PerformanceMark* Create(ScriptState*, + const AtomicString& mark_name, + ExceptionState&); + + // This method is required by the constructor defined in performance_mark.idl. + static PerformanceMark* Create(ScriptState*, + const AtomicString& mark_name, + PerformanceMarkOptions*, + ExceptionState&); + PerformanceMark(ScriptState*, const AtomicString& name, double start_time,
diff --git a/third_party/blink/renderer/core/timing/performance_mark.idl b/third_party/blink/renderer/core/timing/performance_mark.idl index 2dd8d60f..b5cd0ae3 100644 --- a/third_party/blink/renderer/core/timing/performance_mark.idl +++ b/third_party/blink/renderer/core/timing/performance_mark.idl
@@ -25,7 +25,10 @@ // https://w3c.github.io/user-timing/#performancemark -[Exposed=(Window,Worker)] +[Exposed=(Window,Worker), + Constructor(DOMString markName, optional PerformanceMarkOptions markOptions), + ConstructorCallWith=ScriptState, + RaisesException=Constructor] interface PerformanceMark : PerformanceEntry { [CallWith=ScriptState, RuntimeEnabled=CustomUserTiming] readonly attribute any detail; };
diff --git a/third_party/blink/renderer/core/timing/performance_user_timing.cc b/third_party/blink/renderer/core/timing/performance_user_timing.cc index d16f9a9..dcd06c85 100644 --- a/third_party/blink/renderer/core/timing/performance_user_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_user_timing.cc
@@ -26,6 +26,8 @@ #include "third_party/blink/renderer/core/timing/performance_user_timing.h" #include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/renderer/core/frame/local_dom_window.h" +#include "third_party/blink/renderer/core/timing/dom_window_performance.h" #include "third_party/blink/renderer/core/timing/performance.h" #include "third_party/blink/renderer/core/timing/performance_mark.h" #include "third_party/blink/renderer/core/timing/performance_mark_options.h" @@ -100,13 +102,11 @@ performance_entry_map.erase(name); } -PerformanceMark* UserTiming::Mark(ScriptState* script_state, - const AtomicString& mark_name, - PerformanceMarkOptions* mark_options, - ExceptionState& exception_state) { - if (!RuntimeEnabledFeatures::CustomUserTimingEnabled()) - DCHECK(!mark_options); - +PerformanceMark* UserTiming::CreatePerformanceMark( + ScriptState* script_state, + const AtomicString& mark_name, + PerformanceMarkOptions* mark_options, + ExceptionState& exception_state) { DOMHighResTimeStamp start = 0.0; if (mark_options && mark_options->hasStartTime()) { start = mark_options->startTime(); @@ -114,20 +114,10 @@ start = performance_->now(); } - // Pass in a null ScriptValue if the mark's detail doesn't exist. ScriptValue detail = ScriptValue::CreateNull(script_state); - if (mark_options) + if (RuntimeEnabledFeatures::CustomUserTimingEnabled() && mark_options) detail = mark_options->detail(); - return MarkInternal(script_state, mark_name, start, detail, exception_state); -} - -PerformanceMark* UserTiming::MarkInternal(ScriptState* script_state, - const AtomicString& mark_name, - const DOMHighResTimeStamp& start_time, - const ScriptValue& detail, - ExceptionState& exception_state) { - DCHECK(performance_); bool is_worker_global_scope = performance_->GetExecutionContext() && performance_->GetExecutionContext()->IsWorkerGlobalScope(); @@ -140,20 +130,22 @@ return nullptr; } + return PerformanceMark::Create(script_state, mark_name, start, detail); +} + +void UserTiming::AddMarkToPerformanceTimeline(PerformanceMark& mark) { if (performance_->timing()) { - TRACE_EVENT_COPY_MARK1("blink.user_timing", mark_name.Utf8().data(), "data", + TRACE_EVENT_COPY_MARK1("blink.user_timing", mark.name().Utf8().data(), + "data", performance_->timing()->GetNavigationTracingData()); } else { - TRACE_EVENT_COPY_MARK("blink.user_timing", mark_name.Utf8().data()); + TRACE_EVENT_COPY_MARK("blink.user_timing", mark.name().Utf8().data()); } - PerformanceMark* mark = - PerformanceMark::Create(script_state, mark_name, start_time, detail); - InsertPerformanceEntry(marks_map_, *mark); + InsertPerformanceEntry(marks_map_, mark); DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, user_timing_mark_histogram, ("PLT.UserTiming_Mark", 0, 600000, 100)); - user_timing_mark_histogram.Count(static_cast<int>(start_time)); - return mark; + user_timing_mark_histogram.Count(static_cast<int>(mark.startTime())); } void UserTiming::ClearMarks(const AtomicString& mark_name) {
diff --git a/third_party/blink/renderer/core/timing/performance_user_timing.h b/third_party/blink/renderer/core/timing/performance_user_timing.h index d70dd47..ffb07ce 100644 --- a/third_party/blink/renderer/core/timing/performance_user_timing.h +++ b/third_party/blink/renderer/core/timing/performance_user_timing.h
@@ -44,10 +44,10 @@ public: explicit UserTiming(Performance&); - PerformanceMark* Mark(ScriptState* script_state, - const AtomicString& mark_name, - PerformanceMarkOptions* mark_options, - ExceptionState& exception_state); + PerformanceMark* CreatePerformanceMark(ScriptState*, + const AtomicString& mark_name, + PerformanceMarkOptions*, + ExceptionState&); void ClearMarks(const AtomicString& mark_name); @@ -61,6 +61,7 @@ PerformanceEntryVector GetMarks() const; PerformanceEntryVector GetMeasures() const; + void AddMarkToPerformanceTimeline(PerformanceMark&); PerformanceEntryVector GetMarks(const AtomicString& name) const; PerformanceEntryVector GetMeasures(const AtomicString& name) const; @@ -68,11 +69,6 @@ void Trace(blink::Visitor*); private: - PerformanceMark* MarkInternal(ScriptState*, - const AtomicString& mark_name, - const DOMHighResTimeStamp& start_time, - const ScriptValue& detail, - ExceptionState&); double FindExistingMarkStartTime(const AtomicString& mark_name, ExceptionState&); double GetTimeOrFindMarkTime(const StringOrDouble& mark_or_time,
diff --git a/third_party/blink/renderer/core/xml/document_xslt.cc b/third_party/blink/renderer/core/xml/document_xslt.cc index ab5aa46..19f8065 100644 --- a/third_party/blink/renderer/core/xml/document_xslt.cc +++ b/third_party/blink/renderer/core/xml/document_xslt.cc
@@ -95,11 +95,8 @@ ProcessingInstruction* DocumentXSLT::FindXSLStyleSheet(Document& document) { for (Node* node = document.firstChild(); node; node = node->nextSibling()) { - if (node->getNodeType() != Node::kProcessingInstructionNode) - continue; - - ProcessingInstruction* pi = ToProcessingInstruction(node); - if (pi->IsXSL()) + auto* pi = DynamicTo<ProcessingInstruction>(node); + if (pi && pi->IsXSL()) return pi; } return nullptr;
diff --git a/third_party/blink/renderer/core/xml/xpath_functions.cc b/third_party/blink/renderer/core/xml/xpath_functions.cc index f478651b..f34df6c 100644 --- a/third_party/blink/renderer/core/xml/xpath_functions.cc +++ b/third_party/blink/renderer/core/xml/xpath_functions.cc
@@ -386,7 +386,7 @@ case Node::kAttributeNode: return To<Attr>(node)->localName(); case Node::kProcessingInstructionNode: - return ToProcessingInstruction(node)->target(); + return To<ProcessingInstruction>(node)->target(); default: return String(); }
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc b/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc index a16a2be..7106e79 100644 --- a/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc +++ b/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
@@ -87,7 +87,13 @@ scope_(scope), event_queue_( MakeGarbageCollected<EventQueue>(ExecutionContext::From(script_state), - TaskType::kDatabaseAccess)) { + TaskType::kDatabaseAccess)), + feature_handle_for_scheduler_( + ExecutionContext::From(script_state) + ->GetScheduler() + ->RegisterFeature( + SchedulingPolicy::Feature::kOutstandingIndexedDBTransaction, + {SchedulingPolicy::RecordMetricsForBackForwardCache()})) { DCHECK(database_); DCHECK(!scope_.IsEmpty()) << "Non-versionchange transactions must operate " "on a well-defined set of stores"; @@ -640,6 +646,8 @@ deleted_indexes_.clear(); deleted_object_stores_.clear(); + + feature_handle_for_scheduler_.reset(); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_transaction.h b/third_party/blink/renderer/modules/indexeddb/idb_transaction.h index d5d81c0..913cb29 100644 --- a/third_party/blink/renderer/modules/indexeddb/idb_transaction.h +++ b/third_party/blink/renderer/modules/indexeddb/idb_transaction.h
@@ -42,6 +42,7 @@ #include "third_party/blink/renderer/modules/indexeddb/web_idb_transaction.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" #include "third_party/blink/renderer/platform/wtf/deque.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/vector.h" @@ -290,6 +291,9 @@ IDBDatabaseMetadata old_database_metadata_; Member<EventQueue> event_queue_; + + FrameScheduler::SchedulingAffectingFeatureHandle + feature_handle_for_scheduler_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc index 0d3796f2..c7e61d8 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc +++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -138,7 +138,6 @@ const char kScrubbingMessageCSSClass[] = "scrubbing-message"; const char kTestModeCSSClass[] = "test-mode"; const char kImmersiveModeCSSClass[] = "immersive-mode"; -const char kPipPresentedCSSClass[] = "pip-presented"; // The delay between two taps to be recognized as a double tap gesture. constexpr WTF::TimeDelta kDoubleTapDelay = TimeDelta::FromMilliseconds(300); @@ -1418,7 +1417,6 @@ MaybeRecordElementsDisplayed(); - UpdateOverflowAndTrackListCSSClassForPip(); UpdateOverflowMenuItemCSSClass(); } @@ -1449,21 +1447,6 @@ scrubbing_message_->SetDoesFit(size_.Width() >= kMinScrubbingMessageWidth); } -// We want to have wider menu when pip is enabled so that "Exit picture in -// picture" text won't be truncated. When pip is disable (e.g. on mobile -// device), we don't want to enlarged the menu because it would look empty -// when "picture in picture" text is not presented. -void MediaControlsImpl::UpdateOverflowAndTrackListCSSClassForPip() const { - if (picture_in_picture_button_.Get() && - picture_in_picture_button_.Get()->OverflowElementIsWanted()) { - overflow_list_->classList().Add(kPipPresentedCSSClass); - text_track_list_->classList().Add(kPipPresentedCSSClass); - } else { - overflow_list_->classList().Remove(kPipPresentedCSSClass); - text_track_list_->classList().Remove(kPipPresentedCSSClass); - } -} - void MediaControlsImpl::UpdateSizingCSSClass() { MediaControlsSizingClass sizing_class = MediaControls::GetSizingClass(size_.Width());
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.h b/third_party/blink/renderer/modules/media_controls/media_controls_impl.h index 36f8f881..abd4608 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.h +++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
@@ -292,7 +292,6 @@ void UpdateOverflowMenuWanted() const; void UpdateOverflowMenuItemCSSClass() const; void UpdateScrubbingMessageFits() const; - void UpdateOverflowAndTrackListCSSClassForPip() const; void UpdateSizingCSSClass(); void MaybeRecordElementsDisplayed() const;
diff --git a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css index a5197b65..a6eecff 100644 --- a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css +++ b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
@@ -836,13 +836,13 @@ video::-internal-media-controls-overflow-menu-list { position: fixed; z-index: 2; /* Keep the menus above the loading animation at z-index 1. */ - max-width: 50%; + max-width: 75%; max-height: 250px; - min-width: 180px; + width: 200px; overflow-x: hidden; overflow-y: auto; white-space: nowrap; - font-size: 14px; + font-size: 12px; background: #FFFFFF; box-shadow: 0 1px 9px 0 rgba(0,0,0,0.40); border-radius: 2px; @@ -872,7 +872,7 @@ justify-content: flex-start; font-family: Roboto-Regular, Roboto, sans-serif; - font-size: 14px; + font-size: 12px; color: rgba(0,0,0,0.87); letter-spacing: 0; @@ -891,12 +891,6 @@ transform: translateZ(0); } -video::-webkit-media-controls div[pseudo="-internal-media-controls-text-track-list" i].pip-presented, -video::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i].pip-presented { - max-width: 260px; - width: 100%; -} - video::-webkit-media-controls.sizing-small label[pseudo="-internal-media-controls-overflow-menu-list-item" i] input, video::-webkit-media-controls.sizing-medium label[pseudo="-internal-media-controls-overflow-menu-list-item" i] input { margin-left: 0;
diff --git a/third_party/blink/renderer/platform/exported/web_input_event.cc b/third_party/blink/renderer/platform/exported/web_input_event.cc index ede00b1..4852aad 100644 --- a/third_party/blink/renderer/platform/exported/web_input_event.cc +++ b/third_party/blink/renderer/platform/exported/web_input_event.cc
@@ -58,7 +58,7 @@ }; struct SameSizeAsWebGestureEvent : public SameSizeAsWebInputEvent { - int gesture_data[16]; + int gesture_data[18]; }; struct SameSizeAsWebTouchEvent : public SameSizeAsWebInputEvent {
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc index 5d0233c2..7229c9e 100644 --- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc +++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
@@ -1,32 +1,12 @@ #include "third_party/blink/renderer/platform/graphics/dark_mode_filter.h" -#include "base/optional.h" -#include "third_party/blink/renderer/platform/graphics/dark_mode_settings.h" #include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/effects/SkHighContrastFilter.h" #include "third_party/skia/include/effects/SkTableColorFilter.h" namespace blink { -namespace { - -bool ShouldApplyToImage(const DarkModeSettings& settings, - const FloatRect& src_rect, - Image* image) { - switch (settings.image_policy) { - case DarkModeImagePolicy::kFilterSmart: - return image->ShouldApplyDarkModeFilter(src_rect); - case DarkModeImagePolicy::kFilterAll: - return true; - default: - return false; - } -} - -} // namespace - -DarkModeFilter::DarkModeFilter() - : default_filter_(nullptr), image_filter_(nullptr) { +DarkModeFilter::DarkModeFilter() : default_filter_(nullptr) { settings_.mode = DarkMode::kOff; settings_.image_policy = DarkModeImagePolicy::kFilterNone; } @@ -38,7 +18,6 @@ switch (settings_.mode) { case DarkMode::kOff: default_filter_.reset(nullptr); - image_filter_.reset(nullptr); return; case DarkMode::kSimpleInvertForTesting: { uint8_t identity[256], invert[256]; @@ -48,7 +27,6 @@ } default_filter_ = SkTableColorFilter::MakeARGB(identity, invert, invert, invert); - image_filter_.reset(nullptr); return; } case DarkMode::kInvertBrightness: @@ -63,49 +41,32 @@ config.fGrayscale = settings_.grayscale; config.fContrast = settings_.contrast; default_filter_ = SkHighContrastFilter::Make(config); +} - if (settings_.image_style == DarkModeImageStyle::kGrayscale) { - config.fGrayscale = true; - image_filter_ = SkHighContrastFilter::Make(config); - } else { - image_filter_.reset(nullptr); +sk_sp<SkColorFilter> DarkModeFilter::GetColorFilter() { + return default_filter_; +} + +bool DarkModeFilter::ShouldApplyToImage(Image& image, + const FloatRect& src_rect) { + if (!GetColorFilter()) + return false; + + switch (settings_.image_policy) { + case DarkModeImagePolicy::kFilterSmart: + return image.ShouldApplyDarkModeFilter(src_rect); + case DarkModeImagePolicy::kFilterAll: + return true; + default: + return false; } } -Color DarkModeFilter::ApplyIfNeeded(const Color& color) { - if (!default_filter_) - return color; - return Color(default_filter_->filterColor(color.Rgb())); -} - -// TODO(gilmanmh): Investigate making |image| a const reference. This code -// relies on Image::ShouldApplyDarkModeFilter(), which is not const. If it could -// be made const, then |image| could also be const. -void DarkModeFilter::ApplyToImageFlagsIfNeeded(const FloatRect& src_rect, - Image* image, - cc::PaintFlags* flags) { - sk_sp<SkColorFilter> filter = image_filter_; +Color DarkModeFilter::Apply(const Color& color) { + sk_sp<SkColorFilter> filter = GetColorFilter(); if (!filter) - filter = default_filter_; - - if (!filter || !ShouldApplyToImage(settings(), src_rect, image)) - return; - flags->setColorFilter(std::move(filter)); -} - -base::Optional<cc::PaintFlags> DarkModeFilter::ApplyToFlagsIfNeeded( - const cc::PaintFlags& flags) { - if (!default_filter_) - return base::nullopt; - - cc::PaintFlags dark_mode_flags = flags; - if (flags.HasShader()) { - dark_mode_flags.setColorFilter(default_filter_); - } else { - dark_mode_flags.setColor(default_filter_->filterColor(flags.getColor())); - } - - return base::make_optional<cc::PaintFlags>(std::move(dark_mode_flags)); + return color; + return Color(filter->filterColor(color.Rgb())); } } // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.h b/third_party/blink/renderer/platform/graphics/dark_mode_filter.h index 3f8a1fae..6052af1 100644 --- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.h +++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.h
@@ -1,7 +1,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_DARK_MODE_FILTER_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_DARK_MODE_FILTER_H_ -#include "cc/paint/paint_flags.h" #include "third_party/blink/renderer/platform/geometry/float_rect.h" #include "third_party/blink/renderer/platform/graphics/color.h" #include "third_party/blink/renderer/platform/graphics/dark_mode_settings.h" @@ -19,22 +18,15 @@ const DarkModeSettings& settings() const { return settings_; } void UpdateSettings(const DarkModeSettings& new_settings); - Color ApplyIfNeeded(const Color& color); + sk_sp<SkColorFilter> GetColorFilter(); - // |image| and |flags| must not be null. - void ApplyToImageFlagsIfNeeded(const FloatRect& src_rect, - Image* image, - cc::PaintFlags* flags); + bool ShouldApplyToImage(Image& image, const FloatRect& src_rect); - // |flags| must not be null. - base::Optional<cc::PaintFlags> ApplyToFlagsIfNeeded( - const cc::PaintFlags& flags); + Color Apply(const Color& color); private: DarkModeSettings settings_; - sk_sp<SkColorFilter> default_filter_; - sk_sp<SkColorFilter> image_filter_; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_settings.h b/third_party/blink/renderer/platform/graphics/dark_mode_settings.h index 21d1d9e2..42f67d8 100644 --- a/third_party/blink/renderer/platform/graphics/dark_mode_settings.h +++ b/third_party/blink/renderer/platform/graphics/dark_mode_settings.h
@@ -25,14 +25,6 @@ kFilterSmart, }; -// For images that should have a filter applied, which filter should be used? -enum class DarkModeImageStyle { - // Invert images the same way as other elements - kDefault, - // Apply grayscale to images as well as inverting them - kGrayscale -}; - enum class DarkModePagePolicy { // Apply dark-mode filter to all frames, regardless of content. kFilterAll, @@ -45,7 +37,6 @@ bool grayscale = false; float contrast = 0.0; // Valid range from -1.0 to 1.0 DarkModeImagePolicy image_policy = DarkModeImagePolicy::kFilterAll; - DarkModeImageStyle image_style = DarkModeImageStyle::kDefault; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc index efe0bd83..340fbf38 100644 --- a/third_party/blink/renderer/platform/graphics/graphics_context.cc +++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -59,23 +59,25 @@ namespace blink { -// Effectively allows modifying the provided |flags| without technically -// violating its constness. -// -// TODO(gilmanmh): Investigate removing const from |flags| in the calling -// methods so that this isn't necessary. class GraphicsContext::DarkModeFlags final { STACK_ALLOCATED(); public: // This helper's lifetime should never exceed |flags|'. DarkModeFlags(GraphicsContext* gc, const PaintFlags& flags) { - dark_mode_flags_ = gc->dark_mode_filter_.ApplyToFlagsIfNeeded(flags); - if (dark_mode_flags_) { + sk_sp<SkColorFilter> filter = gc->dark_mode_filter_.GetColorFilter(); + if (!filter) { + flags_ = &flags; + } else { + dark_mode_flags_ = flags; + if (flags.HasShader()) { + dark_mode_flags_->setColorFilter(filter); + } else { + dark_mode_flags_->setColor(filter->filterColor(flags.getColor())); + } + flags_ = &dark_mode_flags_.value(); - return; } - flags_ = &flags; } operator const PaintFlags&() const { return *flags_; } @@ -385,15 +387,15 @@ void GraphicsContext::DrawFocusRingPath(const SkPath& path, const Color& color, float width) { - DrawPlatformFocusRing(path, canvas_, - dark_mode_filter_.ApplyIfNeeded(color).Rgb(), width); + DrawPlatformFocusRing(path, canvas_, dark_mode_filter_.Apply(color).Rgb(), + width); } void GraphicsContext::DrawFocusRingRect(const SkRect& rect, const Color& color, float width) { - DrawPlatformFocusRing(rect, canvas_, - dark_mode_filter_.ApplyIfNeeded(color).Rgb(), width); + DrawPlatformFocusRing(rect, canvas_, dark_mode_filter_.Apply(color).Rgb(), + width); } void GraphicsContext::DrawFocusRing(const Path& focus_ring_path, @@ -468,7 +470,7 @@ if (ContextDisabled()) return; - Color shadow_color = dark_mode_filter_.ApplyIfNeeded(orig_shadow_color); + Color shadow_color = dark_mode_filter_.Apply(orig_shadow_color); FloatRect hole_rect(rect.Rect()); hole_rect.Inflate(-shadow_spread); @@ -871,8 +873,9 @@ image_flags.setBlendMode(op); image_flags.setColor(SK_ColorBLACK); image_flags.setFilterQuality(ComputeFilterQuality(image, dest, src)); - - dark_mode_filter_.ApplyToImageFlagsIfNeeded(src, image, &image_flags); + if (dark_mode_filter_.ShouldApplyToImage(*image, src)) { + image_flags.setColorFilter(dark_mode_filter_.GetColorFilter()); + } image->Draw(canvas_, image_flags, dest, src, should_respect_image_orientation, Image::kClampImageToSourceRect, decode_mode); @@ -907,8 +910,9 @@ image_flags.setColor(SK_ColorBLACK); image_flags.setFilterQuality( ComputeFilterQuality(image, dest.Rect(), src_rect)); - - dark_mode_filter_.ApplyToImageFlagsIfNeeded(src_rect, image, &image_flags); + if (dark_mode_filter_.ShouldApplyToImage(*image, src_rect)) { + image_flags.setColorFilter(dark_mode_filter_.GetColorFilter()); + } bool use_shader = (visible_src == src_rect) && (respect_orientation == kDoNotRespectImageOrientation); @@ -1118,7 +1122,7 @@ canvas_->drawDRRect(outer, inner, ImmutableState()->FillFlags()); } else { PaintFlags flags(ImmutableState()->FillFlags()); - flags.setColor(dark_mode_filter_.ApplyIfNeeded(color).Rgb()); + flags.setColor(dark_mode_filter_.Apply(color).Rgb()); canvas_->drawDRRect(outer, inner, flags); } @@ -1131,7 +1135,7 @@ stroke_r_rect.inset(stroke_width / 2, stroke_width / 2); PaintFlags stroke_flags(ImmutableState()->FillFlags()); - stroke_flags.setColor(dark_mode_filter_.ApplyIfNeeded(color).Rgb()); + stroke_flags.setColor(dark_mode_filter_.Apply(color).Rgb()); stroke_flags.setStyle(PaintFlags::kStroke_Style); stroke_flags.setStrokeWidth(stroke_width); @@ -1326,7 +1330,7 @@ return; PaintFlags flags(ImmutableState()->FillFlags()); - flags.setColor(dark_mode_filter_.ApplyIfNeeded(color).Rgb()); + flags.setColor(dark_mode_filter_.Apply(color).Rgb()); canvas_->drawDRRect(SkRRect::MakeRect(rect), rounded_hole_rect, flags); }
diff --git a/third_party/blink/renderer/platform/network/http_parsers.cc b/third_party/blink/renderer/platform/network/http_parsers.cc index 4a1b211..cfeefad 100644 --- a/third_party/blink/renderer/platform/network/http_parsers.cc +++ b/third_party/blink/renderer/platform/network/http_parsers.cc
@@ -596,9 +596,8 @@ std::string headers("HTTP/1.1 200 OK\r\n"); headers.append(bytes, headers_end_pos); - scoped_refptr<net::HttpResponseHeaders> response_headers = - new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.data(), headers.length())); + auto response_headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); std::string mime_type, charset; response_headers->GetMimeTypeAndCharset(&mime_type, &charset); @@ -640,9 +639,8 @@ std::string headers("HTTP/1.1 200 OK\r\n"); headers.append(bytes, headers_end_pos); - scoped_refptr<net::HttpResponseHeaders> responseHeaders = - new net::HttpResponseHeaders( - net::HttpUtil::AssembleRawHeaders(headers.data(), headers.length())); + auto responseHeaders = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(headers)); // Copy selected header fields. const AtomicString* const headerNamePointers[] = {
diff --git a/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc b/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc index 99e5bc5..636ee59 100644 --- a/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc +++ b/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc
@@ -14,6 +14,7 @@ case Feature::kWebRTC: case Feature::kDedicatedWorkerOrWorklet: case Feature::kOutstandingNetworkRequest: + case Feature::kOutstandingIndexedDBTransaction: return false; case Feature::kMainResourceHasCacheControlNoStore: case Feature::kMainResourceHasCacheControlNoCache:
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index eef918d..088113f 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -107,6 +107,9 @@ # //base/metrics/histogram_functions.h 'base::UmaHistogram.+', + # //base/metrics/histogram.h + 'base::LinearHistogram', + # //base/metrics/field_trial_params.h. 'base::GetFieldTrialParamValueByFeature', 'base::GetFieldTrialParamByFeatureAsBool',
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index c067c30..dc13f4c 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -449,11 +449,6 @@ }, { "prefix": "dark-mode", - "base": "paint/dark-mode/grayscale-images", - "args": ["--blink-settings=darkMode=3,darkModeImagePolicy=0,darkModeImageStyle=1"] - }, - { - "prefix": "dark-mode", "base": "paint/dark-mode/image-filter-all", "args": ["--blink-settings=darkMode=3,darkModeImagePolicy=0"] }, @@ -1074,6 +1069,11 @@ "args": ["--enable-features=NativeFileSystemAPI"] }, { + "prefix": "controls-refresh", + "base": "fast/forms/controls-new-ui", + "args": ["--enable-features=FormControlsRefresh"] + }, + { "prefix": "user-timing-l2", "base": "external/wpt/user-timing", "args": ["--disable-blink-features=CustomUserTiming"]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/form-control.html b/third_party/blink/web_tests/external/wpt/css/css-break/form-control.html new file mode 100644 index 0000000..8ef6eed --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-break/form-control.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://www.w3.org/TR/css-break-3/#possible-breaks"> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht"> +<meta name="assert" content="Replaced content should be considered to be monolithic"> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div style="width:100px; height:100px; background:red;"> + <div style="columns:3; column-gap:0;"> + <input style="display:block; margin:0; border:none; padding:0; width:100px; height:100px; background:green;"> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/fixed-z-index-blend-ref.html b/third_party/blink/web_tests/external/wpt/css/css-position/fixed-z-index-blend-ref.html new file mode 100644 index 0000000..2675401 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-position/fixed-z-index-blend-ref.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<title>fixed position, z-index, and mix-blend-mode</title> +<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org"> + +<div style="width: 100px; height:4000px;"></div> +<div style="background: green; width: 100px; height:100px;"></div> + +<script> +requestAnimationFrame(()=>{ + requestAnimationFrame(()=>{ + window.scrollBy(0, 3000); + }); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/fixed-z-index-blend.html b/third_party/blink/web_tests/external/wpt/css/css-position/fixed-z-index-blend.html new file mode 100644 index 0000000..55582286 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-position/fixed-z-index-blend.html
@@ -0,0 +1,62 @@ +<!DOCTYPE html> +<html class="reftest-wait" style="overflow-x:hidden;"> +<title>fixed position, z-index, and mix-blend-mode</title> +<link rel="help" href="https://www.w3.org/TR/CSS2/visuren.html#fixed-positioning"> +<link rel="help" href="https://www.w3.org/TR/CSS2/visuren.html#propdef-z-index"> +<link rel="help" href="https://www.w3.org/TR/compositing-1/#mix-blend-mode"> +<meta name="assert" content="Tests fixed, z-index, and mix-blend-mode. +Passes if there is a green box when the page is scrolled to the bottom."> +<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org"> +<link rel="match" href="fixed-z-index-blend-ref.html"> + +<div class="blend"></div> +<div class="background"></div> +<div class="text"> + <div style="width: 100px; height:4000px;"></div> + <div style="background: green; width: 100px; height:100px;"></div> +</div> + +<style> +.blend { + display: block; + position: fixed; + z-index: 2; + top: 0; + left: 0; + bottom: 0; + right: 0; + mix-blend-mode: overlay; +} + +.background { + pointer-events: none; + position: fixed; + z-index: 1; + top: 0; + left: 0; + bottom: 0; + right: 0; + opacity: 1; +} + +.text { + position: relative; + z-index: 3; + overflow: hidden; + width: 100vw; + min-height: 100vh; + font-size: 50px; + line-height: 2; +} +</style> + +<script src="/common/reftest-wait.js"></script> +<script> +requestAnimationFrame(()=>{ + requestAnimationFrame(()=>{ + window.scrollBy(0, 3000); + takeScreenshot(); + }); +}); +</script> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/element-timing/image-not-added.html b/third_party/blink/web_tests/external/wpt/element-timing/image-not-added.html new file mode 100644 index 0000000..59a254e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/element-timing/image-not-added.html
@@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>Element Timing: do not observe a disconnected image</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + async_test(function (t) { + const observer = new PerformanceObserver( + t.step_func_done(() => { + // The image should not have caused an entry, so fail test. + assert_unreached('Should not have received an entry!'); + }) + ); + observer.observe({entryTypes: ['element']}); + // We add the image during onload to be sure that the observer is registered + // in time for it to observe the element timing. + window.onload = () => { + // Add image of width equal to 100 and height equal to 100. + const img = document.createElement('img'); + img.src = 'resources/square100.png'; + img.setAttribute('elementtiming', 'my_image'); + img.setAttribute('id', 'my_id'); + // Image has been created but not added. + // Wait for 500ms and end test, ensuring no entry was created. + t.step_timeout(() => { + t.done(); + }, 500); + }; + }, 'Image which is not added to DOM tree is not observable.'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any-expected.txt b/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any-expected.txt deleted file mode 100644 index 13e883b..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any-expected.txt +++ /dev/null
@@ -1,75 +0,0 @@ -This is a testharness.js-based test. -Found 71 tests; 70 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS idlharness -PASS idl_test setup -PASS Partial interface Performance: original interface defined -PASS PerformanceEntry interface: existence and properties of interface object -PASS PerformanceEntry interface object length -PASS PerformanceEntry interface object name -PASS PerformanceEntry interface: existence and properties of interface prototype object -PASS PerformanceEntry interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceEntry interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceEntry interface: attribute name -PASS PerformanceEntry interface: attribute entryType -PASS PerformanceEntry interface: attribute startTime -PASS PerformanceEntry interface: attribute duration -PASS PerformanceEntry interface: operation toJSON() -PASS PerformanceObserver interface: existence and properties of interface object -PASS PerformanceObserver interface object length -PASS PerformanceObserver interface object name -PASS PerformanceObserver interface: existence and properties of interface prototype object -PASS PerformanceObserver interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceObserver interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceObserver interface: operation observe(PerformanceObserverInit) -PASS PerformanceObserver interface: operation disconnect() -PASS PerformanceObserver interface: operation takeRecords() -PASS PerformanceObserver interface: attribute supportedEntryTypes -PASS PerformanceObserver must be primary interface of observer -PASS Stringification of observer -PASS PerformanceObserver interface: observer must inherit property "observe(PerformanceObserverInit)" with the proper type -PASS PerformanceObserver interface: calling observe(PerformanceObserverInit) on observer with too few arguments must throw TypeError -PASS PerformanceObserver interface: observer must inherit property "disconnect()" with the proper type -PASS PerformanceObserver interface: observer must inherit property "takeRecords()" with the proper type -PASS PerformanceObserver interface: observer must inherit property "supportedEntryTypes" with the proper type -PASS PerformanceObserverEntryList interface: existence and properties of interface object -PASS PerformanceObserverEntryList interface object length -PASS PerformanceObserverEntryList interface object name -PASS PerformanceObserverEntryList interface: existence and properties of interface prototype object -PASS PerformanceObserverEntryList interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceObserverEntryList interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceObserverEntryList interface: operation getEntries() -PASS PerformanceObserverEntryList interface: operation getEntriesByType(DOMString) -PASS PerformanceObserverEntryList interface: operation getEntriesByName(DOMString, DOMString) -PASS PerformanceObserverEntryList must be primary interface of entryList -PASS Stringification of entryList -PASS PerformanceObserverEntryList interface: entryList must inherit property "getEntries()" with the proper type -PASS PerformanceObserverEntryList interface: entryList must inherit property "getEntriesByType(DOMString)" with the proper type -PASS PerformanceObserverEntryList interface: calling getEntriesByType(DOMString) on entryList with too few arguments must throw TypeError -PASS PerformanceObserverEntryList interface: entryList must inherit property "getEntriesByName(DOMString, DOMString)" with the proper type -PASS PerformanceObserverEntryList interface: calling getEntriesByName(DOMString, DOMString) on entryList with too few arguments must throw TypeError -PASS Performance interface: operation getEntries() -PASS Performance interface: operation getEntriesByType(DOMString) -PASS Performance interface: operation getEntriesByName(DOMString, DOMString) -PASS Performance interface: performance must inherit property "getEntries()" with the proper type -PASS Performance interface: performance must inherit property "getEntriesByType(DOMString)" with the proper type -PASS Performance interface: calling getEntriesByType(DOMString) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "getEntriesByName(DOMString, DOMString)" with the proper type -PASS Performance interface: calling getEntriesByName(DOMString, DOMString) on performance with too few arguments must throw TypeError -PASS PerformanceMark interface: existence and properties of interface object -FAIL PerformanceMark interface object length assert_equals: wrong value for PerformanceMark.length expected 1 but got 0 -PASS PerformanceMark interface object name -PASS PerformanceMark interface: existence and properties of interface prototype object -PASS PerformanceMark interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceMark interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceMark interface: attribute detail -PASS PerformanceMark must be primary interface of mark -PASS Stringification of mark -PASS PerformanceMark interface: mark must inherit property "detail" with the proper type -PASS PerformanceEntry interface: mark must inherit property "name" with the proper type -PASS PerformanceEntry interface: mark must inherit property "entryType" with the proper type -PASS PerformanceEntry interface: mark must inherit property "startTime" with the proper type -PASS PerformanceEntry interface: mark must inherit property "duration" with the proper type -PASS PerformanceEntry interface: mark must inherit property "toJSON()" with the proper type -PASS PerformanceEntry interface: default toJSON operation on mark -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.serviceworker-expected.txt deleted file mode 100644 index 13e883b..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.serviceworker-expected.txt +++ /dev/null
@@ -1,75 +0,0 @@ -This is a testharness.js-based test. -Found 71 tests; 70 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS idlharness -PASS idl_test setup -PASS Partial interface Performance: original interface defined -PASS PerformanceEntry interface: existence and properties of interface object -PASS PerformanceEntry interface object length -PASS PerformanceEntry interface object name -PASS PerformanceEntry interface: existence and properties of interface prototype object -PASS PerformanceEntry interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceEntry interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceEntry interface: attribute name -PASS PerformanceEntry interface: attribute entryType -PASS PerformanceEntry interface: attribute startTime -PASS PerformanceEntry interface: attribute duration -PASS PerformanceEntry interface: operation toJSON() -PASS PerformanceObserver interface: existence and properties of interface object -PASS PerformanceObserver interface object length -PASS PerformanceObserver interface object name -PASS PerformanceObserver interface: existence and properties of interface prototype object -PASS PerformanceObserver interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceObserver interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceObserver interface: operation observe(PerformanceObserverInit) -PASS PerformanceObserver interface: operation disconnect() -PASS PerformanceObserver interface: operation takeRecords() -PASS PerformanceObserver interface: attribute supportedEntryTypes -PASS PerformanceObserver must be primary interface of observer -PASS Stringification of observer -PASS PerformanceObserver interface: observer must inherit property "observe(PerformanceObserverInit)" with the proper type -PASS PerformanceObserver interface: calling observe(PerformanceObserverInit) on observer with too few arguments must throw TypeError -PASS PerformanceObserver interface: observer must inherit property "disconnect()" with the proper type -PASS PerformanceObserver interface: observer must inherit property "takeRecords()" with the proper type -PASS PerformanceObserver interface: observer must inherit property "supportedEntryTypes" with the proper type -PASS PerformanceObserverEntryList interface: existence and properties of interface object -PASS PerformanceObserverEntryList interface object length -PASS PerformanceObserverEntryList interface object name -PASS PerformanceObserverEntryList interface: existence and properties of interface prototype object -PASS PerformanceObserverEntryList interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceObserverEntryList interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceObserverEntryList interface: operation getEntries() -PASS PerformanceObserverEntryList interface: operation getEntriesByType(DOMString) -PASS PerformanceObserverEntryList interface: operation getEntriesByName(DOMString, DOMString) -PASS PerformanceObserverEntryList must be primary interface of entryList -PASS Stringification of entryList -PASS PerformanceObserverEntryList interface: entryList must inherit property "getEntries()" with the proper type -PASS PerformanceObserverEntryList interface: entryList must inherit property "getEntriesByType(DOMString)" with the proper type -PASS PerformanceObserverEntryList interface: calling getEntriesByType(DOMString) on entryList with too few arguments must throw TypeError -PASS PerformanceObserverEntryList interface: entryList must inherit property "getEntriesByName(DOMString, DOMString)" with the proper type -PASS PerformanceObserverEntryList interface: calling getEntriesByName(DOMString, DOMString) on entryList with too few arguments must throw TypeError -PASS Performance interface: operation getEntries() -PASS Performance interface: operation getEntriesByType(DOMString) -PASS Performance interface: operation getEntriesByName(DOMString, DOMString) -PASS Performance interface: performance must inherit property "getEntries()" with the proper type -PASS Performance interface: performance must inherit property "getEntriesByType(DOMString)" with the proper type -PASS Performance interface: calling getEntriesByType(DOMString) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "getEntriesByName(DOMString, DOMString)" with the proper type -PASS Performance interface: calling getEntriesByName(DOMString, DOMString) on performance with too few arguments must throw TypeError -PASS PerformanceMark interface: existence and properties of interface object -FAIL PerformanceMark interface object length assert_equals: wrong value for PerformanceMark.length expected 1 but got 0 -PASS PerformanceMark interface object name -PASS PerformanceMark interface: existence and properties of interface prototype object -PASS PerformanceMark interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceMark interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceMark interface: attribute detail -PASS PerformanceMark must be primary interface of mark -PASS Stringification of mark -PASS PerformanceMark interface: mark must inherit property "detail" with the proper type -PASS PerformanceEntry interface: mark must inherit property "name" with the proper type -PASS PerformanceEntry interface: mark must inherit property "entryType" with the proper type -PASS PerformanceEntry interface: mark must inherit property "startTime" with the proper type -PASS PerformanceEntry interface: mark must inherit property "duration" with the proper type -PASS PerformanceEntry interface: mark must inherit property "toJSON()" with the proper type -PASS PerformanceEntry interface: default toJSON operation on mark -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.sharedworker-expected.txt deleted file mode 100644 index 13e883b..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.sharedworker-expected.txt +++ /dev/null
@@ -1,75 +0,0 @@ -This is a testharness.js-based test. -Found 71 tests; 70 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS idlharness -PASS idl_test setup -PASS Partial interface Performance: original interface defined -PASS PerformanceEntry interface: existence and properties of interface object -PASS PerformanceEntry interface object length -PASS PerformanceEntry interface object name -PASS PerformanceEntry interface: existence and properties of interface prototype object -PASS PerformanceEntry interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceEntry interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceEntry interface: attribute name -PASS PerformanceEntry interface: attribute entryType -PASS PerformanceEntry interface: attribute startTime -PASS PerformanceEntry interface: attribute duration -PASS PerformanceEntry interface: operation toJSON() -PASS PerformanceObserver interface: existence and properties of interface object -PASS PerformanceObserver interface object length -PASS PerformanceObserver interface object name -PASS PerformanceObserver interface: existence and properties of interface prototype object -PASS PerformanceObserver interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceObserver interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceObserver interface: operation observe(PerformanceObserverInit) -PASS PerformanceObserver interface: operation disconnect() -PASS PerformanceObserver interface: operation takeRecords() -PASS PerformanceObserver interface: attribute supportedEntryTypes -PASS PerformanceObserver must be primary interface of observer -PASS Stringification of observer -PASS PerformanceObserver interface: observer must inherit property "observe(PerformanceObserverInit)" with the proper type -PASS PerformanceObserver interface: calling observe(PerformanceObserverInit) on observer with too few arguments must throw TypeError -PASS PerformanceObserver interface: observer must inherit property "disconnect()" with the proper type -PASS PerformanceObserver interface: observer must inherit property "takeRecords()" with the proper type -PASS PerformanceObserver interface: observer must inherit property "supportedEntryTypes" with the proper type -PASS PerformanceObserverEntryList interface: existence and properties of interface object -PASS PerformanceObserverEntryList interface object length -PASS PerformanceObserverEntryList interface object name -PASS PerformanceObserverEntryList interface: existence and properties of interface prototype object -PASS PerformanceObserverEntryList interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceObserverEntryList interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceObserverEntryList interface: operation getEntries() -PASS PerformanceObserverEntryList interface: operation getEntriesByType(DOMString) -PASS PerformanceObserverEntryList interface: operation getEntriesByName(DOMString, DOMString) -PASS PerformanceObserverEntryList must be primary interface of entryList -PASS Stringification of entryList -PASS PerformanceObserverEntryList interface: entryList must inherit property "getEntries()" with the proper type -PASS PerformanceObserverEntryList interface: entryList must inherit property "getEntriesByType(DOMString)" with the proper type -PASS PerformanceObserverEntryList interface: calling getEntriesByType(DOMString) on entryList with too few arguments must throw TypeError -PASS PerformanceObserverEntryList interface: entryList must inherit property "getEntriesByName(DOMString, DOMString)" with the proper type -PASS PerformanceObserverEntryList interface: calling getEntriesByName(DOMString, DOMString) on entryList with too few arguments must throw TypeError -PASS Performance interface: operation getEntries() -PASS Performance interface: operation getEntriesByType(DOMString) -PASS Performance interface: operation getEntriesByName(DOMString, DOMString) -PASS Performance interface: performance must inherit property "getEntries()" with the proper type -PASS Performance interface: performance must inherit property "getEntriesByType(DOMString)" with the proper type -PASS Performance interface: calling getEntriesByType(DOMString) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "getEntriesByName(DOMString, DOMString)" with the proper type -PASS Performance interface: calling getEntriesByName(DOMString, DOMString) on performance with too few arguments must throw TypeError -PASS PerformanceMark interface: existence and properties of interface object -FAIL PerformanceMark interface object length assert_equals: wrong value for PerformanceMark.length expected 1 but got 0 -PASS PerformanceMark interface object name -PASS PerformanceMark interface: existence and properties of interface prototype object -PASS PerformanceMark interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceMark interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceMark interface: attribute detail -PASS PerformanceMark must be primary interface of mark -PASS Stringification of mark -PASS PerformanceMark interface: mark must inherit property "detail" with the proper type -PASS PerformanceEntry interface: mark must inherit property "name" with the proper type -PASS PerformanceEntry interface: mark must inherit property "entryType" with the proper type -PASS PerformanceEntry interface: mark must inherit property "startTime" with the proper type -PASS PerformanceEntry interface: mark must inherit property "duration" with the proper type -PASS PerformanceEntry interface: mark must inherit property "toJSON()" with the proper type -PASS PerformanceEntry interface: default toJSON operation on mark -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.worker-expected.txt deleted file mode 100644 index 13e883b..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/idlharness.any.worker-expected.txt +++ /dev/null
@@ -1,75 +0,0 @@ -This is a testharness.js-based test. -Found 71 tests; 70 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS idlharness -PASS idl_test setup -PASS Partial interface Performance: original interface defined -PASS PerformanceEntry interface: existence and properties of interface object -PASS PerformanceEntry interface object length -PASS PerformanceEntry interface object name -PASS PerformanceEntry interface: existence and properties of interface prototype object -PASS PerformanceEntry interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceEntry interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceEntry interface: attribute name -PASS PerformanceEntry interface: attribute entryType -PASS PerformanceEntry interface: attribute startTime -PASS PerformanceEntry interface: attribute duration -PASS PerformanceEntry interface: operation toJSON() -PASS PerformanceObserver interface: existence and properties of interface object -PASS PerformanceObserver interface object length -PASS PerformanceObserver interface object name -PASS PerformanceObserver interface: existence and properties of interface prototype object -PASS PerformanceObserver interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceObserver interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceObserver interface: operation observe(PerformanceObserverInit) -PASS PerformanceObserver interface: operation disconnect() -PASS PerformanceObserver interface: operation takeRecords() -PASS PerformanceObserver interface: attribute supportedEntryTypes -PASS PerformanceObserver must be primary interface of observer -PASS Stringification of observer -PASS PerformanceObserver interface: observer must inherit property "observe(PerformanceObserverInit)" with the proper type -PASS PerformanceObserver interface: calling observe(PerformanceObserverInit) on observer with too few arguments must throw TypeError -PASS PerformanceObserver interface: observer must inherit property "disconnect()" with the proper type -PASS PerformanceObserver interface: observer must inherit property "takeRecords()" with the proper type -PASS PerformanceObserver interface: observer must inherit property "supportedEntryTypes" with the proper type -PASS PerformanceObserverEntryList interface: existence and properties of interface object -PASS PerformanceObserverEntryList interface object length -PASS PerformanceObserverEntryList interface object name -PASS PerformanceObserverEntryList interface: existence and properties of interface prototype object -PASS PerformanceObserverEntryList interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceObserverEntryList interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceObserverEntryList interface: operation getEntries() -PASS PerformanceObserverEntryList interface: operation getEntriesByType(DOMString) -PASS PerformanceObserverEntryList interface: operation getEntriesByName(DOMString, DOMString) -PASS PerformanceObserverEntryList must be primary interface of entryList -PASS Stringification of entryList -PASS PerformanceObserverEntryList interface: entryList must inherit property "getEntries()" with the proper type -PASS PerformanceObserverEntryList interface: entryList must inherit property "getEntriesByType(DOMString)" with the proper type -PASS PerformanceObserverEntryList interface: calling getEntriesByType(DOMString) on entryList with too few arguments must throw TypeError -PASS PerformanceObserverEntryList interface: entryList must inherit property "getEntriesByName(DOMString, DOMString)" with the proper type -PASS PerformanceObserverEntryList interface: calling getEntriesByName(DOMString, DOMString) on entryList with too few arguments must throw TypeError -PASS Performance interface: operation getEntries() -PASS Performance interface: operation getEntriesByType(DOMString) -PASS Performance interface: operation getEntriesByName(DOMString, DOMString) -PASS Performance interface: performance must inherit property "getEntries()" with the proper type -PASS Performance interface: performance must inherit property "getEntriesByType(DOMString)" with the proper type -PASS Performance interface: calling getEntriesByType(DOMString) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "getEntriesByName(DOMString, DOMString)" with the proper type -PASS Performance interface: calling getEntriesByName(DOMString, DOMString) on performance with too few arguments must throw TypeError -PASS PerformanceMark interface: existence and properties of interface object -FAIL PerformanceMark interface object length assert_equals: wrong value for PerformanceMark.length expected 1 but got 0 -PASS PerformanceMark interface object name -PASS PerformanceMark interface: existence and properties of interface prototype object -PASS PerformanceMark interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceMark interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceMark interface: attribute detail -PASS PerformanceMark must be primary interface of mark -PASS Stringification of mark -PASS PerformanceMark interface: mark must inherit property "detail" with the proper type -PASS PerformanceEntry interface: mark must inherit property "name" with the proper type -PASS PerformanceEntry interface: mark must inherit property "entryType" with the proper type -PASS PerformanceEntry interface: mark must inherit property "startTime" with the proper type -PASS PerformanceEntry interface: mark must inherit property "duration" with the proper type -PASS PerformanceEntry interface: mark must inherit property "toJSON()" with the proper type -PASS PerformanceEntry interface: default toJSON operation on mark -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/idlharness.any-expected.txt b/third_party/blink/web_tests/external/wpt/user-timing/idlharness.any-expected.txt deleted file mode 100644 index e4665ff..0000000 --- a/third_party/blink/web_tests/external/wpt/user-timing/idlharness.any-expected.txt +++ /dev/null
@@ -1,37 +0,0 @@ -This is a testharness.js-based test. -PASS idl_test setup -PASS Partial interface Performance: original interface defined -PASS PerformanceMark interface: existence and properties of interface object -FAIL PerformanceMark interface object length assert_equals: wrong value for PerformanceMark.length expected 1 but got 0 -PASS PerformanceMark interface object name -PASS PerformanceMark interface: existence and properties of interface prototype object -PASS PerformanceMark interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceMark interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceMark interface: attribute detail -PASS PerformanceMark must be primary interface of mark -PASS Stringification of mark -PASS PerformanceMark interface: mark must inherit property "detail" with the proper type -PASS PerformanceMeasure interface: existence and properties of interface object -PASS PerformanceMeasure interface object length -PASS PerformanceMeasure interface object name -PASS PerformanceMeasure interface: existence and properties of interface prototype object -PASS PerformanceMeasure interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceMeasure interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceMeasure interface: attribute detail -PASS PerformanceMeasure must be primary interface of measure -PASS Stringification of measure -PASS PerformanceMeasure interface: measure must inherit property "detail" with the proper type -PASS Performance interface: operation mark(DOMString, PerformanceMarkOptions) -PASS Performance interface: operation clearMarks(DOMString) -PASS Performance interface: operation measure(DOMString, [object Object],[object Object], DOMString) -PASS Performance interface: operation clearMeasures(DOMString) -PASS Performance interface: performance must inherit property "mark(DOMString, PerformanceMarkOptions)" with the proper type -PASS Performance interface: calling mark(DOMString, PerformanceMarkOptions) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "clearMarks(DOMString)" with the proper type -PASS Performance interface: calling clearMarks(DOMString) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "measure(DOMString, [object Object],[object Object], DOMString)" with the proper type -PASS Performance interface: calling measure(DOMString, [object Object],[object Object], DOMString) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "clearMeasures(DOMString)" with the proper type -PASS Performance interface: calling clearMeasures(DOMString) on performance with too few arguments must throw TypeError -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/idlharness.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/user-timing/idlharness.any.serviceworker-expected.txt deleted file mode 100644 index e4665ff..0000000 --- a/third_party/blink/web_tests/external/wpt/user-timing/idlharness.any.serviceworker-expected.txt +++ /dev/null
@@ -1,37 +0,0 @@ -This is a testharness.js-based test. -PASS idl_test setup -PASS Partial interface Performance: original interface defined -PASS PerformanceMark interface: existence and properties of interface object -FAIL PerformanceMark interface object length assert_equals: wrong value for PerformanceMark.length expected 1 but got 0 -PASS PerformanceMark interface object name -PASS PerformanceMark interface: existence and properties of interface prototype object -PASS PerformanceMark interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceMark interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceMark interface: attribute detail -PASS PerformanceMark must be primary interface of mark -PASS Stringification of mark -PASS PerformanceMark interface: mark must inherit property "detail" with the proper type -PASS PerformanceMeasure interface: existence and properties of interface object -PASS PerformanceMeasure interface object length -PASS PerformanceMeasure interface object name -PASS PerformanceMeasure interface: existence and properties of interface prototype object -PASS PerformanceMeasure interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceMeasure interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceMeasure interface: attribute detail -PASS PerformanceMeasure must be primary interface of measure -PASS Stringification of measure -PASS PerformanceMeasure interface: measure must inherit property "detail" with the proper type -PASS Performance interface: operation mark(DOMString, PerformanceMarkOptions) -PASS Performance interface: operation clearMarks(DOMString) -PASS Performance interface: operation measure(DOMString, [object Object],[object Object], DOMString) -PASS Performance interface: operation clearMeasures(DOMString) -PASS Performance interface: performance must inherit property "mark(DOMString, PerformanceMarkOptions)" with the proper type -PASS Performance interface: calling mark(DOMString, PerformanceMarkOptions) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "clearMarks(DOMString)" with the proper type -PASS Performance interface: calling clearMarks(DOMString) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "measure(DOMString, [object Object],[object Object], DOMString)" with the proper type -PASS Performance interface: calling measure(DOMString, [object Object],[object Object], DOMString) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "clearMeasures(DOMString)" with the proper type -PASS Performance interface: calling clearMeasures(DOMString) on performance with too few arguments must throw TypeError -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/idlharness.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/user-timing/idlharness.any.sharedworker-expected.txt deleted file mode 100644 index e4665ff..0000000 --- a/third_party/blink/web_tests/external/wpt/user-timing/idlharness.any.sharedworker-expected.txt +++ /dev/null
@@ -1,37 +0,0 @@ -This is a testharness.js-based test. -PASS idl_test setup -PASS Partial interface Performance: original interface defined -PASS PerformanceMark interface: existence and properties of interface object -FAIL PerformanceMark interface object length assert_equals: wrong value for PerformanceMark.length expected 1 but got 0 -PASS PerformanceMark interface object name -PASS PerformanceMark interface: existence and properties of interface prototype object -PASS PerformanceMark interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceMark interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceMark interface: attribute detail -PASS PerformanceMark must be primary interface of mark -PASS Stringification of mark -PASS PerformanceMark interface: mark must inherit property "detail" with the proper type -PASS PerformanceMeasure interface: existence and properties of interface object -PASS PerformanceMeasure interface object length -PASS PerformanceMeasure interface object name -PASS PerformanceMeasure interface: existence and properties of interface prototype object -PASS PerformanceMeasure interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceMeasure interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceMeasure interface: attribute detail -PASS PerformanceMeasure must be primary interface of measure -PASS Stringification of measure -PASS PerformanceMeasure interface: measure must inherit property "detail" with the proper type -PASS Performance interface: operation mark(DOMString, PerformanceMarkOptions) -PASS Performance interface: operation clearMarks(DOMString) -PASS Performance interface: operation measure(DOMString, [object Object],[object Object], DOMString) -PASS Performance interface: operation clearMeasures(DOMString) -PASS Performance interface: performance must inherit property "mark(DOMString, PerformanceMarkOptions)" with the proper type -PASS Performance interface: calling mark(DOMString, PerformanceMarkOptions) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "clearMarks(DOMString)" with the proper type -PASS Performance interface: calling clearMarks(DOMString) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "measure(DOMString, [object Object],[object Object], DOMString)" with the proper type -PASS Performance interface: calling measure(DOMString, [object Object],[object Object], DOMString) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "clearMeasures(DOMString)" with the proper type -PASS Performance interface: calling clearMeasures(DOMString) on performance with too few arguments must throw TypeError -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/idlharness.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/user-timing/idlharness.any.worker-expected.txt deleted file mode 100644 index e4665ff..0000000 --- a/third_party/blink/web_tests/external/wpt/user-timing/idlharness.any.worker-expected.txt +++ /dev/null
@@ -1,37 +0,0 @@ -This is a testharness.js-based test. -PASS idl_test setup -PASS Partial interface Performance: original interface defined -PASS PerformanceMark interface: existence and properties of interface object -FAIL PerformanceMark interface object length assert_equals: wrong value for PerformanceMark.length expected 1 but got 0 -PASS PerformanceMark interface object name -PASS PerformanceMark interface: existence and properties of interface prototype object -PASS PerformanceMark interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceMark interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceMark interface: attribute detail -PASS PerformanceMark must be primary interface of mark -PASS Stringification of mark -PASS PerformanceMark interface: mark must inherit property "detail" with the proper type -PASS PerformanceMeasure interface: existence and properties of interface object -PASS PerformanceMeasure interface object length -PASS PerformanceMeasure interface object name -PASS PerformanceMeasure interface: existence and properties of interface prototype object -PASS PerformanceMeasure interface: existence and properties of interface prototype object's "constructor" property -PASS PerformanceMeasure interface: existence and properties of interface prototype object's @@unscopables property -PASS PerformanceMeasure interface: attribute detail -PASS PerformanceMeasure must be primary interface of measure -PASS Stringification of measure -PASS PerformanceMeasure interface: measure must inherit property "detail" with the proper type -PASS Performance interface: operation mark(DOMString, PerformanceMarkOptions) -PASS Performance interface: operation clearMarks(DOMString) -PASS Performance interface: operation measure(DOMString, [object Object],[object Object], DOMString) -PASS Performance interface: operation clearMeasures(DOMString) -PASS Performance interface: performance must inherit property "mark(DOMString, PerformanceMarkOptions)" with the proper type -PASS Performance interface: calling mark(DOMString, PerformanceMarkOptions) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "clearMarks(DOMString)" with the proper type -PASS Performance interface: calling clearMarks(DOMString) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "measure(DOMString, [object Object],[object Object], DOMString)" with the proper type -PASS Performance interface: calling measure(DOMString, [object Object],[object Object], DOMString) on performance with too few arguments must throw TypeError -PASS Performance interface: performance must inherit property "clearMeasures(DOMString)" with the proper type -PASS Performance interface: calling clearMeasures(DOMString) on performance with too few arguments must throw TypeError -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/mark-entry-constructor.html b/third_party/blink/web_tests/external/wpt/user-timing/mark-entry-constructor.html new file mode 100644 index 0000000..47c9a64 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/user-timing/mark-entry-constructor.html
@@ -0,0 +1,50 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/user-timing-helper.js"></script> +<title>User Timing L3: create mark entry by constructor</title> +<h1>User Timing L3: create mark entry by constructor</h1> +<p> +User Timing L3: Mark entry can be created by using constructor." +</p> +<script> + test(()=>{ + const entry = new PerformanceMark("name"); + assert_true(entry instanceof PerformanceMark); + checkEntry(entry, {name: "name", entryType: "mark"}); + }, "Mark entry can be created by 'new PerformanceMark(string)'."); + + test(()=>{ + const entry = new PerformanceMark("name", {}); + assert_true(entry instanceof PerformanceMark); + checkEntry(entry, {name: "name", entryType: "mark"}); + }, "Mark entry can be created by 'new PerformanceMark(string, {})'."); + + test(()=>{ + const entry = new PerformanceMark("name", {startTime: 1}); + assert_true(entry instanceof PerformanceMark); + checkEntry(entry, {name: "name", entryType: "mark", startTime: 1}); + }, "Mark entry can be created by 'new PerformanceMark(string, {startTime})'."); + + test(()=>{ + const entry = new PerformanceMark("name", {detail: {info: "abc"}}); + assert_true(entry instanceof PerformanceMark); + checkEntry(entry, {name: "name", entryType: "mark", detail: {info: "abc"}}); + }, "Mark entry can be created by 'new PerformanceMark(string, {detail})'."); + + test(()=>{ + const entry = + new PerformanceMark("name", {startTime: 1, detail: {info: "abc"}}); + assert_true(entry instanceof PerformanceMark); + checkEntry(entry, {name: "name", entryType: "mark", startTime: 1, detail: {info: "abc"}}); + }, "Mark entry can be created by " + + "'new PerformanceMark(string, {startTime, detail})'."); + + test(()=>{ + const entry = new PerformanceMark("name"); + assert_true(entry instanceof PerformanceMark); + checkEntry(entry, {name: "name", entryType: "mark"}); + assert_equals(performance.getEntriesByName("name").length, 0); + }, "Using new PerformanceMark() shouldn't add the entry to performance timeline."); +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png new file mode 100644 index 0000000..cbf0d672a --- /dev/null +++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic.html new file mode 100644 index 0000000..de005b2 --- /dev/null +++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic.html
@@ -0,0 +1,61 @@ +<!DOCTYPE html> +<script src="../../../../resources/run-after-layout-and-paint.js"></script> +<script src="../../resources/common.js"></script> +<body style="background-color: blue"> + +<!-- no style for reference --> +<input type="checkbox"> +<input type="checkbox" checked> +<br> + +<!-- border --> +<input type="checkbox" style="border: 3px solid lime;"> +<input type="checkbox" style="border-radius: 6px;"> <br> + +<!-- background --> +<input type="checkbox" style="background: linear-gradient(to bottom, #dea 0%,#9c7 44%,#494 100%);"> <br> + +<!-- shadow --> +<input type="checkbox" style="box-shadow: 4px 4px 10px rgba(255,0,0,0.5), inset 4px 4px 4px rgba(0,255,0,0.5);"> <br> + +<!-- size --> +<input type="checkbox" style="width: 8px; height; 8px;"> +<input type="checkbox" style="width: 16px; height; 16px;"> +<input type="checkbox" style="width: 24px; height; 24px;"> +<input type="checkbox" style="width: 26px; height: 20px;"> +<input type="checkbox" style="width: 1px; height: 1px;"> <br> + +<!-- disabled --> +<input type="checkbox" disabled> +<input type="checkbox" disabled checked> <br> + +<!-- indeterminate --> +<input type="checkbox" id="indeterminateCheckbox"> +<input type="checkbox" id="indeterminateDisabledCheckbox" disabled> <br> + +<!-- zoom --> +<input type="checkbox" style="zoom: 1.5;"> +<input type="checkbox" style="zoom: 2;"> +<input type="checkbox" style="zoom: 4;"> <br> + +<div style="background-color: white"> + <input type="checkbox" disabled> + <input type="checkbox" disabled checked> <br> + <input type="checkbox" checked> <br> + <input type="checkbox" id="hoverTarget"/> +</div> + +<script> + +if (window.testRunner) + testRunner.setUseMockTheme(false); + +runAfterLayoutAndPaint(function() { + indeterminateCheckbox.indeterminate = true; + indeterminateDisabledCheckbox.indeterminate = true; + + var target = document.getElementById('hoverTarget'); + hoverOverElement(target); +}, true); +</script> +</body>
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png new file mode 100644 index 0000000..5ccf12fc --- /dev/null +++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/radio/radio-appearance-basic.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/radio/radio-appearance-basic.html new file mode 100644 index 0000000..13b2a38 --- /dev/null +++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/radio/radio-appearance-basic.html
@@ -0,0 +1,55 @@ +<!DOCTYPE html> +<script src="../../../../resources/run-after-layout-and-paint.js"></script> +<script src="../../resources/common.js"></script> +<body style="background-color: blue"> + +<!-- no style for reference --> +<input type="radio"> +<input type="radio" name="group"> +<input type="radio" name="group" checked> <br> + +<!-- border --> +<input type="radio" style="border: 3px solid lime;"> +<input type="radio" style="border-radius: 6px;"> <br> + +<!-- background --> +<input type="radio" style="background: linear-gradient(to bottom, #dea 0%,#9c7 44%,#494 100%);"> <br> + +<!-- shadow --> +<input type="radio" style="box-shadow: 4px 4px 10px rgba(255,0,0,0.5), inset 4px 4px 4px rgba(0,255,0,0.5);"> <br> + +<!-- size --> +<input type="radio" style="width: 8px; height; 8px;"> +<input type="radio" style="width: 16px; height; 16px;"> +<input type="radio" style="width: 24px; height; 24px;"> +<input type="radio" style="width: 26px; height: 20px;"> +<input type="radio" style="width: 1px; height: 1px;"> <br> + +<!-- disabled --> +<input type="radio" disabled> +<input type="radio" disabled checked> <br> + +<!-- zoom --> +<input type="radio" style="zoom: 1.5;"> +<input type="radio" style="zoom: 2;"> +<input type="radio" style="zoom: 4;"> <br> + +<div style="background-color: white"> + <input type="radio" disabled> + <input type="radio" disabled checked> <br> + <input type="radio" checked> <br> + <input type="radio" id="hoverTarget"/> +</div> + +<script> + +if (window.testRunner) + testRunner.setUseMockTheme(false); + +runAfterLayoutAndPaint(function() { + var target = document.getElementById('hoverTarget'); + hoverOverElement(target); +}, true); + +</script> +</body> \ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/history/history-entry-requires-user-gesture-expected.txt b/third_party/blink/web_tests/http/tests/history/history-entry-requires-user-gesture-expected.txt deleted file mode 100644 index 14d3485..0000000 --- a/third_party/blink/web_tests/http/tests/history/history-entry-requires-user-gesture-expected.txt +++ /dev/null
@@ -1,6 +0,0 @@ - - -============== Back Forward List ============== - http://127.0.0.1:8000/history/resources/navigation-with-user-gesture.html -curr-> http://127.0.0.1:8000/resources/notify-done.html -===============================================
diff --git a/third_party/blink/web_tests/http/tests/history/history-entry-requires-user-gesture-push-state-expected.txt b/third_party/blink/web_tests/http/tests/history/history-entry-requires-user-gesture-push-state-expected.txt deleted file mode 100644 index ebea9be..0000000 --- a/third_party/blink/web_tests/http/tests/history/history-entry-requires-user-gesture-push-state-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ - - -============== Back Forward List ============== -curr-> http://127.0.0.1:8000/resources/dummy.html -===============================================
diff --git a/third_party/blink/web_tests/http/tests/history/history-entry-requires-user-gesture-push-state.html b/third_party/blink/web_tests/http/tests/history/history-entry-requires-user-gesture-push-state.html deleted file mode 100644 index d5013606..0000000 --- a/third_party/blink/web_tests/http/tests/history/history-entry-requires-user-gesture-push-state.html +++ /dev/null
@@ -1,17 +0,0 @@ -<body onload="loaded();"> -<script> -if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.dumpBackForwardList(); - internals.settings.setHistoryEntryRequiresUserGesture(true); -} - -/* Because user gesture required flag is enabled this html file will not be part - * of history - */ -function loaded() { - history.pushState(null, "", "../resources/dummy.html"); -} - -</script> -</body>
diff --git a/third_party/blink/web_tests/http/tests/history/history-entry-requires-user-gesture.html b/third_party/blink/web_tests/http/tests/history/history-entry-requires-user-gesture.html deleted file mode 100644 index 3424aba..0000000 --- a/third_party/blink/web_tests/http/tests/history/history-entry-requires-user-gesture.html +++ /dev/null
@@ -1,14 +0,0 @@ -<body onload="loaded();"> -<script> -if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.dumpBackForwardList(); - testRunner.waitUntilDone(); - internals.settings.setHistoryEntryRequiresUserGesture(true); -} - -function loaded() { - setTimeout("location = 'resources/navigation-with-user-gesture.html'", 0); -} -</script> -</body>
diff --git a/third_party/blink/web_tests/media/controls/large-overflow-menu-when-pip-enabled.html b/third_party/blink/web_tests/media/controls/large-overflow-menu-when-pip-enabled.html deleted file mode 100644 index c272e2a..0000000 --- a/third_party/blink/web_tests/media/controls/large-overflow-menu-when-pip-enabled.html +++ /dev/null
@@ -1,45 +0,0 @@ -<!DOCTYPE html> -<title>Large overflow menu when pip enabled</title> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<script src="../../resources/run-after-layout-and-paint.js"></script> -<script src="../media-controls.js"></script> -<body> -<video controls></video> -<script> -async_test(t => { - let video = document.querySelector("video"); - video.src = "../content/test.ogv"; - enableTestMode(video); - - const overflowMenuList = overflowMenu(video); - const textTrackList = textTrackMenu(video); - - assert_true(document.pictureInPictureEnabled, 'pip should be enabled'); - - video.onloadedmetadata = t.step_func(() => { - expectOverflowMenuAndTrackListContainsPip(); - - video.setAttribute('disablepictureinpicture', ''); - runAfterLayoutAndPaint(t.step_func(() => { - expectOverflowMenuAndTrackListNotContainsPip(); - - video.removeAttribute('disablepictureinpicture'); - runAfterLayoutAndPaint(t.step_func_done(() => { - expectOverflowMenuAndTrackListContainsPip(); - })); - })); - }); - - function expectOverflowMenuAndTrackListContainsPip() { - assert_true(overflowMenuList.classList.contains('pip-presented'), 'overflow menu should have pip-presented'); - assert_true(textTrackList.classList.contains('pip-presented'), 'track list should have pip-presented'); - } - - function expectOverflowMenuAndTrackListNotContainsPip() { - assert_false(overflowMenuList.classList.contains('pip-presented'), 'overflow menu should not have pip-presented'); - assert_false(textTrackList.classList.contains('pip-presented'), 'track list should not have pip-presented'); - } -}); -</script> -</body>
diff --git a/third_party/blink/web_tests/paint/dark-mode/grayscale-images/desaturate-before-inversion-expected.png b/third_party/blink/web_tests/paint/dark-mode/grayscale-images/desaturate-before-inversion-expected.png deleted file mode 100644 index 87a54af4..0000000 --- a/third_party/blink/web_tests/paint/dark-mode/grayscale-images/desaturate-before-inversion-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/paint/dark-mode/grayscale-images/desaturate-before-inversion.html b/third_party/blink/web_tests/paint/dark-mode/grayscale-images/desaturate-before-inversion.html deleted file mode 100644 index 09ebc168..0000000 --- a/third_party/blink/web_tests/paint/dark-mode/grayscale-images/desaturate-before-inversion.html +++ /dev/null
@@ -1,4 +0,0 @@ -<!DOCTYPE html> -<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100"> - <circle cx="50" cy="50" r="40" stroke="black" stroke-width="2" fill="navy" /> -</svg>
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png new file mode 100644 index 0000000..bad8ab5 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png new file mode 100644 index 0000000..5475c6c --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png new file mode 100644 index 0000000..bad8ab5 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png new file mode 100644 index 0000000..5475c6c --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png new file mode 100644 index 0000000..bad8ab5 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png new file mode 100644 index 0000000..5475c6c --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png new file mode 100644 index 0000000..46fcd38 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png new file mode 100644 index 0000000..b15ed7f5 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png new file mode 100644 index 0000000..46fcd38 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png new file mode 100644 index 0000000..b15ed7f5 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png new file mode 100644 index 0000000..eccccb65 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png new file mode 100644 index 0000000..f9a174cc --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png new file mode 100644 index 0000000..eccccb65 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png new file mode 100644 index 0000000..f9a174cc --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png new file mode 100644 index 0000000..eccccb65 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png new file mode 100644 index 0000000..f9a174cc --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-mode/paint/dark-mode/grayscale-images/desaturate-before-inversion-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-mode/paint/dark-mode/grayscale-images/desaturate-before-inversion-expected.png deleted file mode 100644 index 9b9bd4a6..0000000 --- a/third_party/blink/web_tests/platform/mac/virtual/dark-mode/paint/dark-mode/grayscale-images/desaturate-before-inversion-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/README.txt b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/README.txt new file mode 100644 index 0000000..7c6aa706 --- /dev/null +++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/README.txt
@@ -0,0 +1 @@ +# This suite runs tests with --enable-features=FormControlsRefresh
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png new file mode 100644 index 0000000..d5acb531 --- /dev/null +++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/checkbox/checkbox-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png new file mode 100644 index 0000000..1b1cb502 --- /dev/null +++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/radio/radio-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/dark-mode/paint/dark-mode/grayscale-images/README.txt b/third_party/blink/web_tests/virtual/dark-mode/paint/dark-mode/grayscale-images/README.txt deleted file mode 100644 index 895eda8..0000000 --- a/third_party/blink/web_tests/virtual/dark-mode/paint/dark-mode/grayscale-images/README.txt +++ /dev/null
@@ -1,3 +0,0 @@ -# This suite runs the tests in LayoutTests/paint/dark-mode -# with --blink-settings="darkMode=3,darkModeImagePolicy=0,darkModeImageStyle=1" -# See the virtual_test_suites() method in tools/blinkpy/web_tests/port/base.py.
diff --git a/third_party/blink/web_tests/virtual/dark-mode/paint/dark-mode/grayscale-images/desaturate-before-inversion-expected.png b/third_party/blink/web_tests/virtual/dark-mode/paint/dark-mode/grayscale-images/desaturate-before-inversion-expected.png deleted file mode 100644 index cc7960a..0000000 --- a/third_party/blink/web_tests/virtual/dark-mode/paint/dark-mode/grayscale-images/desaturate-before-inversion-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-account-for-clip.html b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-account-for-clip.html deleted file mode 100644 index 2364b16..0000000 --- a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-account-for-clip.html +++ /dev/null
@@ -1,59 +0,0 @@ -<!DOCTYPE html> -<script src="../../../../../resources/testharness.js"></script> -<script src="../../../../../resources/testharnessreport.js"></script> -<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/third_party/blink/public/mojom/page/spatial_navigation.mojom.js"></script> -<script src="../../../../../fast/spatial-navigation/resources/mock-snav-service.js"></script> -<script src="../../../../../fast/spatial-navigation/resources/snav-testharness.js"></script> - -<style> - div { - width: 130px; - height: 130px; - border: 1px solid black; - } - - #clip { - margin: 5px; - width: 100px; - height: 100px; - overflow: hidden; - background-color: lightgrey; - } - - #target { - margin: 20px; - height: 50px; - } - - pre { - position: absolute; - top: 400px; - } - -</style> -<div tabindex="0"> - Outer Target - <div id="clip" tabindex="0"> - Clip - <div id="target" tabindex="0">Inner Target</div> - </div> -</div> - -<script> - const target = document.getElementById("target"); - - // This test checks that the spatial navigation overlap testing works - // correctly in the presence of clipping. The spatial navigation algorithm - // attempts to prioritize the inner element when one valid target is fully - // contained by another valid target. This test ensures the inner is - // considered fully contained even if it has clipped overflow that would - // spill outside the outer target. - test(() => { - assert_true(!!window.internals); - snav.triggerMove('Down'); - assert_equals(window.internals.interestedElement, - target, - "Expected interest to move to |target| element."); - }, "Navigation to fully contained but clipped element."); -</script>
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any-expected.txt index 0990fcc..4fc30f1 100644 --- a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any-expected.txt +++ b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any-expected.txt
@@ -2,7 +2,7 @@ PASS idl_test setup PASS Partial interface Performance: original interface defined PASS PerformanceMark interface: existence and properties of interface object -FAIL PerformanceMark interface object length assert_equals: wrong value for PerformanceMark.length expected 1 but got 0 +PASS PerformanceMark interface object length PASS PerformanceMark interface object name PASS PerformanceMark interface: existence and properties of interface prototype object PASS PerformanceMark interface: existence and properties of interface prototype object's "constructor" property
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any.serviceworker-expected.txt index 0990fcc..4fc30f1 100644 --- a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any.serviceworker-expected.txt +++ b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any.serviceworker-expected.txt
@@ -2,7 +2,7 @@ PASS idl_test setup PASS Partial interface Performance: original interface defined PASS PerformanceMark interface: existence and properties of interface object -FAIL PerformanceMark interface object length assert_equals: wrong value for PerformanceMark.length expected 1 but got 0 +PASS PerformanceMark interface object length PASS PerformanceMark interface object name PASS PerformanceMark interface: existence and properties of interface prototype object PASS PerformanceMark interface: existence and properties of interface prototype object's "constructor" property
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any.sharedworker-expected.txt index 0990fcc..4fc30f1 100644 --- a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any.sharedworker-expected.txt +++ b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any.sharedworker-expected.txt
@@ -2,7 +2,7 @@ PASS idl_test setup PASS Partial interface Performance: original interface defined PASS PerformanceMark interface: existence and properties of interface object -FAIL PerformanceMark interface object length assert_equals: wrong value for PerformanceMark.length expected 1 but got 0 +PASS PerformanceMark interface object length PASS PerformanceMark interface object name PASS PerformanceMark interface: existence and properties of interface prototype object PASS PerformanceMark interface: existence and properties of interface prototype object's "constructor" property
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any.worker-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any.worker-expected.txt index 0990fcc..4fc30f1 100644 --- a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any.worker-expected.txt +++ b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/idlharness.any.worker-expected.txt
@@ -2,7 +2,7 @@ PASS idl_test setup PASS Partial interface Performance: original interface defined PASS PerformanceMark interface: existence and properties of interface object -FAIL PerformanceMark interface object length assert_equals: wrong value for PerformanceMark.length expected 1 but got 0 +PASS PerformanceMark interface object length PASS PerformanceMark interface object name PASS PerformanceMark interface: existence and properties of interface prototype object PASS PerformanceMark interface: existence and properties of interface prototype object's "constructor" property
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-entry-constructor-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-entry-constructor-expected.txt new file mode 100644 index 0000000..fe290ee --- /dev/null +++ b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-entry-constructor-expected.txt
@@ -0,0 +1,9 @@ +This is a testharness.js-based test. +PASS Mark entry can be created by 'new PerformanceMark(string)'. +PASS Mark entry can be created by 'new PerformanceMark(string, {})'. +PASS Mark entry can be created by 'new PerformanceMark(string, {startTime})'. +FAIL Mark entry can be created by 'new PerformanceMark(string, {detail})'. assert_equals: expected (string) "{\"info\":\"abc\"}" but got (undefined) undefined +FAIL Mark entry can be created by 'new PerformanceMark(string, {startTime, detail})'. assert_equals: expected (string) "{\"info\":\"abc\"}" but got (undefined) undefined +PASS Using new PerformanceMark() shouldn't add the entry to performance timeline. +Harness: the test ran to completion. +
diff --git a/tools/grit/grit/extern/FP.py b/tools/grit/grit/extern/FP.py index 69892ca..0932f75 100644 --- a/tools/grit/grit/extern/FP.py +++ b/tools/grit/grit/extern/FP.py
@@ -22,8 +22,8 @@ """Generate a 64-bit fingerprint by taking the first half of the md5 of the string. """ - hex128 = _new_md5(str).hexdigest() - int64 = long(hex128[:16], 16) + hex128 = _new_md5(str.encode(encoding)).hexdigest() + int64 = int(hex128[:16], 16) return int64 @@ -40,8 +40,8 @@ def FingerPrint(str, encoding='utf-8'): fp = UnsignedFingerPrint(str, encoding=encoding) # interpret fingerprint as signed longs - if fp & 0x8000000000000000L: - fp = - ((~fp & 0xFFFFFFFFFFFFFFFFL) + 1) + if fp & 0x8000000000000000: + fp = -((~fp & 0xFFFFFFFFFFFFFFFF) + 1) return fp
diff --git a/tools/grit/grit/extern/tclib.py b/tools/grit/grit/extern/tclib.py index d7294731..bbefd7f 100644 --- a/tools/grit/grit/extern/tclib.py +++ b/tools/grit/grit/extern/tclib.py
@@ -10,8 +10,6 @@ # for creating Windows .rc and .h files. These are the only parts needed by # the Chrome build process. -import exceptions - from grit.extern import FP # This module assumes that within a bundle no two messages can have the @@ -41,12 +39,14 @@ else: fp = fp2 + (fp << 1) # To avoid negative ids we strip the high-order bit - return str(fp & 0x7fffffffffffffffL) + return str(fp & 0x7fffffffffffffff) # ------------------------------------------------------------------------- # The MessageTranslationError class is used to signal tclib-specific errors. -class MessageTranslationError(exceptions.Exception): + +class MessageTranslationError(Exception): + def __init__(self, args = ''): self.args = args @@ -122,16 +122,16 @@ # Append a placeholder to the message def AppendPlaceholder(self, placeholder): if not isinstance(placeholder, Placeholder): - raise MessageTranslationError, ("Invalid message placeholder %s in " - "message %s" % (placeholder, self.GetId())) + raise MessageTranslationError("Invalid message placeholder %s in " + "message %s" % (placeholder, self.GetId())) # Are there other placeholders with the same presentation? # If so, they need to be the same. for other in self.GetPlaceholders(): if placeholder.GetPresentation() == other.GetPresentation(): if not placeholder.EqualTo(other): - raise MessageTranslationError, \ - "Conflicting declarations of %s within message" % \ - placeholder.GetPresentation() + raise MessageTranslationError( + "Conflicting declarations of %s within message" % + placeholder.GetPresentation()) # update placeholder list dup = 0 for item in self.__content: @@ -204,9 +204,9 @@ if source_msg: ph = source_msg.GetPlaceholder(item.GetPresentation()) if not ph: - raise MessageTranslationError, \ - "Placeholder %s doesn't exist in message: %s" % \ - (item.GetPresentation(), source_msg); + raise MessageTranslationError( + "Placeholder %s doesn't exist in message: %s" % + (item.GetPresentation(), source_msg)) original_content += ph.GetOriginal() else: original_content += item.GetOriginal() @@ -442,7 +442,7 @@ is_hidden : 0 or 1 - if the message should be hidden, 0 otherwise """ if is_hidden not in [0, 1]: - raise MessageTranslationError, "is_hidden must be 0 or 1, got %s" + raise MessageTranslationError("is_hidden must be 0 or 1, got %s") self.__is_hidden = is_hidden def IsHidden(self):
diff --git a/tools/grit/grit/tclib.py b/tools/grit/grit/tclib.py index 4101824..da8ad32 100644 --- a/tools/grit/grit/tclib.py +++ b/tools/grit/grit/tclib.py
@@ -141,10 +141,8 @@ return self.id def GenerateId(self): - # Must use a UTF-8 encoded version of the presentable content, along with - # the meaning attribute, to match the TC. - return grit.extern.tclib.GenerateMessageId( - self.GetPresentableContent().encode('utf-8'), self.meaning) + return grit.extern.tclib.GenerateMessageId(self.GetPresentableContent(), + self.meaning) def GetPlaceholders(self): return self.placeholders
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index c4d3f59e..6a827b9 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -27740,6 +27740,24 @@ <int value="2" label="Dismissed"/> </enum> +<enum name="HeapProfilingMode"> + <int value="0" label="None"/> + <int value="1" label="Minimal"/> + <int value="2" label="All"/> + <int value="3" label="Browser"/> + <int value="4" label="Gpu"/> + <int value="5" label="Renderer Sampling"/> + <int value="6" label="All renderers"/> + <int value="7" label="Manual"/> +</enum> + +<enum name="HeapProfilingProcessType"> + <int value="0" label="Other"/> + <int value="1" label="Browser"/> + <int value="2" label="Renderer"/> + <int value="3" label="GPU"/> +</enum> + <enum name="HeavyPageCappingInfoBarInteraction"> <int value="0" label="InfoBar shown"> The user was shown the capping heavy pages InfoBar. @@ -42572,24 +42590,6 @@ <int value="10" label="Hide for now"/> </enum> -<enum name="OutOfProcessHeapProfilingMode"> - <int value="0" label="None"/> - <int value="1" label="Minimal"/> - <int value="2" label="All"/> - <int value="3" label="Browser"/> - <int value="4" label="Gpu"/> - <int value="5" label="Renderer Sampling"/> - <int value="6" label="All renderers"/> - <int value="7" label="Manual"/> -</enum> - -<enum name="OutOfProcessHeapProfilingProcessType"> - <int value="0" label="Other"/> - <int value="1" label="Browser"/> - <int value="2" label="Renderer"/> - <int value="3" label="GPU"/> -</enum> - <enum name="OutputDeviceStatus"> <int value="0" label="Ok"/> <int value="1" label="Not found"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 7f4f2ea..f1d9cb07 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -13033,6 +13033,34 @@ </summary> </histogram> +<histogram name="Blink.UseCounter.FeaturePolicy.LosslessImageCompression" + units="%" expires_after="M77"> + <owner>loonybear@chromium.org</owner> + <owner>iclelland@chromium.org</owner> + <summary> + Logs compression ratio in percentage with 1KB overhead for lossless type + images enforced by feature policy unoptimized-lossless-images policy going + into origin trials in M75. If an image's compression ratio is 0.1, it will + be represented as 1 percent, if an image's compression ratio is 5, it will + be represented as 50 percents. Recorded when unoptimized-lossless-images + policy is enforced and the image finishes decoding its mime type. + </summary> +</histogram> + +<histogram name="Blink.UseCounter.FeaturePolicy.LossyImageCompression" + units="%" expires_after="M77"> + <owner>loonybear@chromium.org</owner> + <owner>iclelland@chromium.org</owner> + <summary> + Logs compression ratio with 1KB overhead for lossy type images enforced by + feature policy unoptimized-lossy-images policy going into origin trials in + M75. If an image's compression ratio is 0.1, it will be represented as 1 + percent, if an image's compression ratio is 5, it will be represented as 50 + percents. Recorded when unoptimized-lossy-images policy is enforced and the + image finishes decoding its mime type. + </summary> +</histogram> + <histogram name="Blink.UseCounter.FeaturePolicy.PotentialViolation" enum="FeaturePolicyFeature" expires_after="2019-12-15"> <owner>ekaramad@chromium.org</owner> @@ -13046,6 +13074,20 @@ </summary> </histogram> +<histogram name="Blink.UseCounter.FeaturePolicy.StrictLosslessImageCompression" + units="%" expires_after="M77"> + <owner>loonybear@chromium.org</owner> + <owner>iclelland@chromium.org</owner> + <summary> + Logs compression ratio with 10KB overhead for lossless type images enforced + by feature policy unoptimized-lossless-images-strict policy going into + origin trials in M75. If an image's compression ratio is 0.1, it will be + represented as 1 percent, if an image's compression ratio is 5, it will be + represented as 50 percents. Recorded when unoptimized-lossless-images-strict + policy is enforced and the image finishes decoding its mime type. + </summary> +</histogram> + <histogram name="Blink.UseCounter.Features" enum="FeatureObserver" expires_after="never"> <!-- expires-never: used by Chrome Platform Status dashboard --> @@ -43733,6 +43775,52 @@ </summary> </histogram> +<histogram name="HeapProfiling.ProfiledProcess.Type" + enum="HeapProfilingProcessType" expires_after="M77"> + <owner>erikchen@chromium.org</owner> + <summary> + One metric is emitted every 24-hours after Chrome is launched for every + process that is being profiled. The timer is reset if Chrome exits. + </summary> +</histogram> + +<histogram name="HeapProfiling.ProfilingMode" enum="HeapProfilingMode" + expires_after="M77"> + <owner>erikchen@chromium.org</owner> + <summary> + One metric is emitted every 24-hours after Chrome is launched for every + Chrome instance that is using out of process heap profiling. The timer is + reset if Chrome exits. + </summary> +</histogram> + +<histogram name="HeapProfiling.RecordTrace.Success" enum="BooleanSuccess" + expires_after="M77"> + <owner>erikchen@chromium.org</owner> + <summary> + The metric is emitted each time Chrome attempts to record a memory-infra + trace to upload an out-of-process heap-profiling memory dump. + </summary> +</histogram> + +<histogram name="HeapProfiling.UploadTrace.Size" units="bytes" + expires_after="M77"> + <owner>erikchen@chromium.org</owner> + <summary> + The metric is emitted each time Chrome uploads a trace. It reflects the + uncompressed size of the trace. + </summary> +</histogram> + +<histogram name="HeapProfiling.UploadTrace.Success" enum="BooleanSuccess" + expires_after="M77"> + <owner>erikchen@chromium.org</owner> + <summary> + The metric is emitted each time Chrome uploads a trace. It reflects whether + the upload was successful. + </summary> +</histogram> + <histogram name="HeavyPageCapping.BlacklistReason" enum="OptOutBlacklistReason" expires_after="M75"> <obsolete> @@ -82907,7 +82995,10 @@ </histogram> <histogram name="OutOfProcessHeapProfiling.ProfiledProcess.Type" - enum="OutOfProcessHeapProfilingProcessType" expires_after="M77"> + enum="HeapProfilingProcessType" expires_after="M77"> + <obsolete> + Replaced with HeapProfiling.ProfiledProcess.Type. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> One metric is emitted every 24-hours after Chrome is launched for every @@ -82916,7 +83007,10 @@ </histogram> <histogram name="OutOfProcessHeapProfiling.ProfilingMode" - enum="OutOfProcessHeapProfilingMode" expires_after="M77"> + enum="HeapProfilingMode" expires_after="M77"> + <obsolete> + Replaced with HeapProfiling.ProfilingMode. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> One metric is emitted every 24-hours after Chrome is launched for every @@ -82927,6 +83021,9 @@ <histogram name="OutOfProcessHeapProfiling.RecordTrace.Success" enum="BooleanSuccess" expires_after="M77"> + <obsolete> + Replaced with HeapProfiling.RecordTrace.Success. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> The metric is emitted each time Chrome attempts to record a memory-infra @@ -82936,6 +83033,9 @@ <histogram name="OutOfProcessHeapProfiling.UploadTrace.Size" units="bytes" expires_after="M77"> + <obsolete> + Replaced with HeapProfiling.UploadTrace.Size. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> The metric is emitted each time Chrome uploads a trace. It reflects the @@ -82945,6 +83045,9 @@ <histogram name="OutOfProcessHeapProfiling.UploadTrace.Success" enum="BooleanSuccess" expires_after="M77"> + <obsolete> + Replaced with HeapProfiling.UploadTrace.Success. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> The metric is emitted each time Chrome uploads a trace. It reflects whether @@ -143295,6 +143398,24 @@ <affected-histogram name="Media.AudioService.SystemInfoClient"/> </histogram_suffixes> +<histogram_suffixes name="AutofillAddressFormType" separator="."> + <suffix name="AddressOnly" label="Form has name and address fields"/> + <suffix name="AddressPlusContact" + label="Encompasses AddressPlusEmail, AddressPlusPhone, and + AddressPlusEmailPlusPhone"/> + <suffix name="AddressPlusEmail" + label="Form has name, address, and email fields"/> + <suffix name="AddressPlusEmailPlusPhone" + label="Form has name, address, email, and phone fields"/> + <suffix name="AddressPlusPhone" + label="Form has name, address, and phone fields"/> + <suffix name="ContactOnly" label="Form has name and phone or email fields"/> + <suffix name="Other" + label="Another form type was encountered, such as a form with all + unknown fields"/> + <affected-histogram name="Autofill.FormEvents.Address"/> +</histogram_suffixes> + <histogram_suffixes name="AutofillCreditCardInfoBarSaveType" separator="."> <suffix name="Local" label="Local credit card save"/> <suffix name="Server" label="Server/upload credit card save"/>
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py index 74b7406..4cab5a4 100755 --- a/tools/perf/core/perf_data_generator.py +++ b/tools/perf/core/perf_data_generator.py
@@ -130,7 +130,6 @@ } ], 'platform': 'android-chrome', - 'browser': 'bin/monochrome_64_32_bundle', 'dimension': { 'pool': 'chrome.tests.perf-fyi', 'os': 'Android', @@ -969,8 +968,6 @@ # For trybot testing we always use the reference build if tester_config.get('testing', False): browser_name = 'reference' - elif 'browser' in tester_config: - browser_name = 'exact' elif tester_config['platform'] == 'android': browser_name = 'android-chromium' elif tester_config['platform'].startswith('android-'): @@ -987,13 +984,7 @@ '--upload-results' ] - if 'browser' in tester_config: - test_args.append('--browser-executable=../../out/Release/%s' % - tester_config['browser']) - if tester_config['platform'].startswith('android'): - test_args.append('--device=android') - - if tester_config['platform'].startswith('android-webview'): + if browser_name.startswith('android-webview'): test_args.append( '--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk')
diff --git a/tools/perf/core/perf_data_generator_unittest.py b/tools/perf/core/perf_data_generator_unittest.py index 7697b49..3f326e7 100644 --- a/tools/perf/core/perf_data_generator_unittest.py +++ b/tools/perf/core/perf_data_generator_unittest.py
@@ -97,61 +97,6 @@ } self.assertEquals(returned_test, expected_generated_test) - def testGeneratePerformanceTestSuiteExact(self): - swarming_dimensions = [ - {'os': 'SkyNet', 'pool': 'T-RIP'} - ] - test_config = { - 'platform': 'android-webview', - 'browser': 'bin/monochrome_64_32_bundle', - 'dimension': swarming_dimensions, - } - test = { - 'isolate': 'performance_test_suite', - 'extra_args': [ - '--run-ref-build', - '--test-shard-map-filename=shard_map.json', - ], - 'num_shards': 26 - } - returned_test = perf_data_generator.generate_performance_test( - test_config, test) - - expected_generated_test = { - 'override_compile_targets': ['performance_test_suite'], - 'isolate_name': 'performance_test_suite', - 'args': ['-v', '--browser=exact', '--upload-results', - '--browser-executable=../../out/Release' - '/bin/monochrome_64_32_bundle', - '--device=android', - '--webview-embedder-apk=../../out/Release' - '/apks/SystemWebViewShell.apk', - '--run-ref-build', - '--test-shard-map-filename=shard_map.json'], - 'trigger_script': { - 'args': [ - '--multiple-dimension-script-verbose', - 'True' - ], - 'requires_simultaneous_shard_dispatch': True, - 'script': '//testing/trigger_scripts/perf_device_trigger.py' - }, - 'merge': { - 'script': '//tools/perf/process_perf_results.py' - }, - 'swarming': { - 'ignore_task_failure': False, - 'can_use_on_swarming_builders': True, - 'expiration': 7200, - 'io_timeout': 1800, - 'hard_timeout': 36000, - 'dimension_sets': [[{'os': 'SkyNet', 'pool': 'T-RIP'}]], - 'shards': 26 - }, - 'name': 'performance_test_suite' - } - self.assertEquals(returned_test, expected_generated_test) - def testGeneratePerformanceTestSuiteWebview(self): swarming_dimensions = [ {'os': 'SkyNet', 'pool': 'T-RIP'}
diff --git a/tools/perf/core/perf_json_config_validator.py b/tools/perf/core/perf_json_config_validator.py index 7ace5f3..df7cd111 100644 --- a/tools/perf/core/perf_json_config_validator.py +++ b/tools/perf/core/perf_json_config_validator.py
@@ -81,18 +81,17 @@ browser_options = _ParseBrowserFlags(test_config['args']) if 'WebView' in builder_name or 'webview' in builder_name: if browser_options.browser not in ( - 'android-webview', 'android-webview-google', 'exact'): + 'android-webview', 'android-webview-google'): raise ValueError( - "%s must use 'android-webview', 'android-webview-google' or 'exact' " - "browser" % builder_name) + "%s must use 'android-webview' or 'android-webview-google' browser" % + builder_name) if not browser_options.webview_embedder_apk: raise ValueError('%s must set --webview-embedder-apk flag' % builder_name) elif 'Android' in builder_name or 'android' in builder_name: - if browser_options.browser not in ( - 'android-chromium', 'android-chrome', 'exact'): + if browser_options.browser not in ('android-chromium', 'android-chrome'): raise ValueError( - "%s must use 'android-chromium', 'android-chrome' or 'exact' " - "browser" % builder_name) + "%s must use 'android-chromium' or 'android-chrome' browser" % + builder_name) elif builder_name in ('win-10-perf', 'Win 7 Nvidia GPU Perf'): if browser_options.browser != 'release_x64': raise ValueError("%s must use 'release_x64' browser type" %
diff --git a/tools/translation/upload_screenshots.py b/tools/translation/upload_screenshots.py index 03a38054..a22825f4 100755 --- a/tools/translation/upload_screenshots.py +++ b/tools/translation/upload_screenshots.py
@@ -50,7 +50,7 @@ GIT = 'git' -def query_yes_no(question, default='yes'): +def query_yes_no(question, default='no'): """Ask a yes/no question via raw_input() and return their answer. "question" is a string that is presented to the user. @@ -201,7 +201,8 @@ # Always ask if the .sha1 files should be added to the CL, even if they are # already part of the CL. If the files are not modified, adding again is a # no-op. - if not query_yes_no('Do you want to add these files to your CL?'): + if not query_yes_no('Do you want to add these files to your CL?', + default='yes'): exit(0) if not args.dry_run:
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc index 1b7b8abb..581179c0 100644 --- a/ui/accessibility/platform/ax_platform_node_base.cc +++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -1609,4 +1609,32 @@ boundary, offset, direction, affinity)); } +int AXPlatformNodeBase::NearestTextIndexToPoint(gfx::Point point) { + // For text objects, find the text position nearest to the point.The nearest + // index of a non-text object is implicitly 0. Text fields such as textarea + // have an embedded div inside them that holds all the text, + // GetRangeBoundsRect will correctly handle these nodes + int nearest_index = 0; + const AXCoordinateSystem coordinate_system = AXCoordinateSystem::kScreen; + const AXClippingBehavior clipping_behavior = AXClippingBehavior::kUnclipped; + + // Manhattan Distance is used to provide faster distance estimates. + // get the distance from the point to the bounds of each character. + float shortest_distance = GetDelegate() + ->GetInnerTextRangeBoundsRect( + 0, 1, coordinate_system, clipping_behavior) + .ManhattanDistanceToPoint(point); + for (int i = 1, text_length = GetInnerText().length(); i < text_length; ++i) { + float current_distance = + GetDelegate() + ->GetInnerTextRangeBoundsRect(i, i + 1, coordinate_system, + clipping_behavior) + .ManhattanDistanceToPoint(point); + if (current_distance < shortest_distance) { + shortest_distance = current_distance; + nearest_index = i; + } + } + return nearest_index; +} } // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h index aa6721e1..f56e782 100644 --- a/ui/accessibility/platform/ax_platform_node_base.h +++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -207,6 +207,13 @@ // Returns true if this node can be scrolled in the vertical direction. bool IsVerticallyScrollable() const; + // Returns true if this node has role of StaticText, LineBreak, or + // InlineTextBox + bool IsTextOnlyObject() const; + + // Returns true if the node is an editable text field. + bool IsPlainTextField() const; + bool HasFocus(); // Returns the text of this node and represent the text of descendant nodes @@ -252,6 +259,12 @@ }; bool ScrollToNode(ScrollType scroll_type); + // Return the nearest text index to a point in screen coordinates for an + // accessibility node. If the node is not a text only node, the implicit + // nearest index is zero. Note this will only find the index of text on the + // input node. The node's subtree will not be searched. + int NearestTextIndexToPoint(gfx::Point point); + // // Delegate. This is a weak reference which owns |this|. // @@ -259,8 +272,6 @@ protected: bool IsDocument() const; - bool IsTextOnlyObject() const; - bool IsPlainTextField() const; // Is in a focused textfield with a related suggestion popup available, // such as for the Autofill feature. The suggestion popup can be either hidden // and available or already visible. This indicates next down arrow key will
diff --git a/ui/accessibility/platform/ax_platform_node_textprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textprovider_win.cc index 6b54b21..436bc18 100644 --- a/ui/accessibility/platform/ax_platform_node_textprovider_win.cc +++ b/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
@@ -133,7 +133,71 @@ STDMETHODIMP AXPlatformNodeTextProviderWin::GetVisibleRanges( SAFEARRAY** visible_ranges) { WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_TEXT_GETVISIBLERANGES); - return E_NOTIMPL; + UIA_VALIDATE_TEXTPROVIDER_CALL(); + + const AXPlatformNodeDelegate* delegate = owner()->GetDelegate(); + + // Get the Clipped Frame Bounds of the current node, not from the root, + // so if this node is wrapped with overflow styles it will have the + // correct bounds + const gfx::Rect frame_rect = delegate->GetBoundsRect( + AXCoordinateSystem::kFrame, AXClippingBehavior::kClipped); + + const auto start = delegate->CreateTextPositionAt(0); + const auto end = start->CreatePositionAtEndOfAnchor(); + DCHECK(start->GetAnchor() == end->GetAnchor()); + + // SAFEARRAYs are not dynamic, so fill the visible ranges in a vector + // and then transfer to an appropriately-sized SAFEARRAY + std::vector<CComPtr<ITextRangeProvider>> ranges; + + auto current_line_start = start->Clone(); + while (!current_line_start->IsNullPosition() && *current_line_start < *end) { + auto current_line_end = current_line_start->CreateNextLineEndPosition( + AXBoundaryBehavior::CrossBoundary); + if (current_line_end->IsNullPosition() || *current_line_end > *end) + current_line_end = end->Clone(); + + gfx::Rect current_rect = delegate->GetInnerTextRangeBoundsRect( + current_line_start->text_offset(), current_line_end->text_offset(), + AXCoordinateSystem::kFrame, AXClippingBehavior::kUnclipped); + + if (frame_rect.Contains(current_rect)) { + CComPtr<ITextRangeProvider> text_range_provider = + AXPlatformNodeTextRangeProviderWin::CreateTextRangeProvider( + owner_, current_line_start->Clone(), current_line_end->Clone()); + + ranges.emplace_back(text_range_provider); + } + + current_line_start = current_line_start->CreateNextLineStartPosition( + AXBoundaryBehavior::CrossBoundary); + } + + base::win::ScopedSafearray scoped_visible_ranges( + SafeArrayCreateVector(VT_UNKNOWN /* element type */, 0 /* lower bound */, + ranges.size() /* number of elements */)); + + if (!scoped_visible_ranges.Get()) + return E_OUTOFMEMORY; + + LONG index = 0; + for (CComPtr<ITextRangeProvider>& current_provider : ranges) { + HRESULT hr = SafeArrayPutElement(scoped_visible_ranges.Get(), &index, + current_provider); + DCHECK(SUCCEEDED(hr)); + + // Since DCHECK only happens in debug builds, return immediately to ensure + // that we're not leaking the SAFEARRAY on release builds + if (FAILED(hr)) + return E_FAIL; + + ++index; + } + + *visible_ranges = scoped_visible_ranges.Release(); + + return S_OK; } STDMETHODIMP AXPlatformNodeTextProviderWin::RangeFromChild( @@ -160,7 +224,30 @@ UiaPoint uia_point, ITextRangeProvider** range) { WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_TEXT_RANGEFROMPOINT); - return E_NOTIMPL; + UIA_VALIDATE_TEXTPROVIDER_CALL(); + *range = nullptr; + + // Retrieve the closest accessibility node via hit testing the point. No + // coordinate unit conversion is needed, hit testing input is also in screen + // coordinates. + gfx::NativeViewAccessible nearest_native_view_accessible = + owner()->GetDelegate()->HitTestSync(uia_point.x, uia_point.y); + DCHECK(nearest_native_view_accessible); + + AXPlatformNodeWin* nearest_node = static_cast<AXPlatformNodeWin*>( + AXPlatformNode::FromNativeViewAccessible(nearest_native_view_accessible)); + DCHECK(nearest_node); + + AXNodePosition::AXPositionInstance start, end; + start = nearest_node->GetDelegate()->CreateTextPositionAt( + nearest_node->NearestTextIndexToPoint( + gfx::Point(uia_point.x, uia_point.y))); + DCHECK(!start->IsNullPosition()); + end = start->Clone(); + + *range = AXPlatformNodeTextRangeProviderWin::CreateTextRangeProvider( + nearest_node, std::move(start), std::move(end)); + return S_OK; } STDMETHODIMP AXPlatformNodeTextProviderWin::get_DocumentRange(
diff --git a/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc index f4627d1..b59ea570 100644 --- a/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc
@@ -13,6 +13,7 @@ #include "ui/accessibility/platform/ax_fragment_root_win.h" #include "ui/accessibility/platform/ax_platform_node_textprovider_win.h" #include "ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h" +#include "ui/accessibility/platform/test_ax_node_wrapper.h" #include "ui/base/win/accessibility_misc_utils.h" using Microsoft::WRL::ComPtr; @@ -175,6 +176,62 @@ other_root_node_raw.Get(), &text_range_provider)); } +TEST_F(AXPlatformNodeTextProviderTest, TestNearestTextIndexToPoint) { + ui::AXNodeData text_data; + text_data.id = 2; + text_data.role = ax::mojom::Role::kInlineTextBox; + text_data.SetName("text"); + // spacing: "t-e-x---t--" + text_data.AddIntListAttribute(ax::mojom::IntListAttribute::kCharacterOffsets, + {2, 2, 4, 2}); + + ui::AXNodeData root_data; + root_data.id = 1; + root_data.role = ax::mojom::Role::kStaticText; + root_data.relative_bounds.bounds = gfx::RectF(1, 1, 2, 2); + root_data.child_ids.push_back(2); + + Init(root_data, text_data); + + AXNode* root_node = GetRootNode(); + AXNodePosition::SetTreeForTesting(tree_.get()); + AXNode* text_node = root_node->children()[0]; + + struct NearestTextIndexTestData { + AXNode* node; + struct point_offset_expected_index_pair { + int point_offset_x; + int expected_index; + }; + std::vector<point_offset_expected_index_pair> test_data; + }; + NearestTextIndexTestData nodes[] = { + {text_node, + {{0, 0}, {2, 0}, {3, 1}, {4, 1}, {5, 2}, {8, 2}, {9, 3}, {10, 3}}}, + {root_node, + {{0, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {8, 0}, {9, 0}, {10, 0}}}}; + for (auto data : nodes) { + ComPtr<IRawElementProviderSimple> element_provider = + QueryInterfaceFromNode<IRawElementProviderSimple>(data.node); + ComPtr<ITextProvider> text_provider; + EXPECT_HRESULT_SUCCEEDED(element_provider->GetPatternProvider( + UIA_TextPatternId, &text_provider)); + // get internal implementation to access helper for testing + ComPtr<AXPlatformNodeTextProviderWin> platform_text_provider; + EXPECT_HRESULT_SUCCEEDED( + text_provider->QueryInterface(IID_PPV_ARGS(&platform_text_provider))); + + ComPtr<AXPlatformNodeWin> platform_node; + EXPECT_HRESULT_SUCCEEDED( + element_provider->QueryInterface(IID_PPV_ARGS(&platform_node))); + + for (auto pair : data.test_data) { + EXPECT_EQ(pair.expected_index, platform_node->NearestTextIndexToPoint( + gfx::Point(pair.point_offset_x, 0))); + } + } +} + TEST_F(AXPlatformNodeTextProviderTest, TestITextProviderDocumentRange) { ui::AXNodeData text_data; text_data.id = 2;
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc index bbaf15b..8b422d5 100644 --- a/ui/accessibility/platform/test_ax_node_wrapper.cc +++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -145,6 +145,41 @@ } } +gfx::Rect TestAXNodeWrapper::GetInnerTextRangeBoundsRect( + const int start_offset, + const int end_offset, + const AXCoordinateSystem coordinate_system, + const AXClippingBehavior clipping_behavior, + AXOffscreenResult* offscreen_result) const { + switch (coordinate_system) { + case AXCoordinateSystem::kScreen: { + gfx::RectF bounds = GetData().relative_bounds.bounds; + bounds.Offset(g_offset); + if (GetData().HasIntListAttribute( + ax::mojom::IntListAttribute::kCharacterOffsets)) { + const std::vector<int32_t>& offsets = GetData().GetIntListAttribute( + ax::mojom::IntListAttribute::kCharacterOffsets); + int32_t x = bounds.x(); + int32_t width = 0; + for (int i = 0; i < static_cast<int>(offsets.size()); i++) { + if (i < start_offset) + x += offsets[i]; + else if (i < end_offset) + width += offsets[i]; + else + break; + } + bounds = gfx::RectF(x, bounds.y(), width, bounds.height()); + } + return gfx::ToEnclosingRect(bounds); + } + case AXCoordinateSystem::kRootFrame: + case AXCoordinateSystem::kFrame: + NOTIMPLEMENTED(); + return gfx::Rect(); + } +} + gfx::Rect TestAXNodeWrapper::GetHypertextRangeBoundsRect( const int start_offset, const int end_offset,
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.h b/ui/accessibility/platform/test_ax_node_wrapper.h index 89ee6c7..638b797 100644 --- a/ui/accessibility/platform/test_ax_node_wrapper.h +++ b/ui/accessibility/platform/test_ax_node_wrapper.h
@@ -59,6 +59,12 @@ gfx::Rect GetBoundsRect(const AXCoordinateSystem coordinate_system, const AXClippingBehavior clipping_behavior, AXOffscreenResult* offscreen_result) const override; + gfx::Rect GetInnerTextRangeBoundsRect( + const int start_offset, + const int end_offset, + const AXCoordinateSystem coordinate_system, + const AXClippingBehavior clipping_behavior, + AXOffscreenResult* offscreen_result) const override; gfx::Rect GetHypertextRangeBoundsRect( const int start_offset, const int end_offset,
diff --git a/ui/aura/mus/os_exchange_data_provider_mus.cc b/ui/aura/mus/os_exchange_data_provider_mus.cc index 587516a..0c3ca11c 100644 --- a/ui/aura/mus/os_exchange_data_provider_mus.cc +++ b/ui/aura/mus/os_exchange_data_provider_mus.cc
@@ -252,6 +252,8 @@ // These methods were added in an ad-hoc way to different operating // systems. We need to support them until they get cleaned up. +// TODO(https://crbug.com/951547): Clean up OSExchangeDataProviderMus methods +// that were added in an ad-hoc way #if defined(USE_X11) || defined(OS_WIN) void OSExchangeDataProviderMus::SetFileContents( const base::FilePath& filename, @@ -269,6 +271,27 @@ return false; } +void OSExchangeDataProviderMus::SetVirtualFileContentsForTesting( + const std::vector<std::pair<base::FilePath, std::string>>& + filenames_and_contents, + DWORD tymed) {} + +bool OSExchangeDataProviderMus::HasVirtualFilenames() const { + return false; +} + +bool OSExchangeDataProviderMus::GetVirtualFilenames( + std::vector<ui::FileInfo>* filenames) const { + return false; +} + +bool OSExchangeDataProviderMus::GetVirtualFilesAsTempFiles( + base::OnceCallback< + void(const std::vector<std::pair<base::FilePath, base::FilePath>>&)> + callback) const { + return false; +} + void OSExchangeDataProviderMus::SetDownloadFileInfo( const ui::OSExchangeData::DownloadFileInfo& download) {} #endif
diff --git a/ui/aura/mus/os_exchange_data_provider_mus.h b/ui/aura/mus/os_exchange_data_provider_mus.h index ce1b44a0..2915f32c 100644 --- a/ui/aura/mus/os_exchange_data_provider_mus.h +++ b/ui/aura/mus/os_exchange_data_provider_mus.h
@@ -76,6 +76,16 @@ bool GetFileContents(base::FilePath* filename, std::string* file_contents) const override; bool HasFileContents() const override; + void SetVirtualFileContentsForTesting( + const std::vector<std::pair<base::FilePath, std::string>>& + filenames_and_contents, + DWORD tymed) override; + bool HasVirtualFilenames() const override; + bool GetVirtualFilenames(std::vector<ui::FileInfo>* filenames) const override; + bool GetVirtualFilesAsTempFiles( + base::OnceCallback< + void(const std::vector<std::pair<base::FilePath, base::FilePath>>&)> + callback) const override; void SetDownloadFileInfo( const ui::OSExchangeData::DownloadFileInfo& download) override; #endif
diff --git a/ui/base/clipboard/clipboard_format_type.h b/ui/base/clipboard/clipboard_format_type.h index eb5b91ff..089a45c 100644 --- a/ui/base/clipboard/clipboard_format_type.h +++ b/ui/base/clipboard/clipboard_format_type.h
@@ -5,6 +5,8 @@ #ifndef UI_BASE_CLIPBOARD_CLIPBOARD_FORMAT_TYPE_H_ #define UI_BASE_CLIPBOARD_CLIPBOARD_FORMAT_TYPE_H_ +#include <map> +#include <memory> #include <string> #include "base/component_export.h" @@ -60,7 +62,9 @@ static const ClipboardFormatType& GetTextHtmlType(); static const ClipboardFormatType& GetCFHDropType(); static const ClipboardFormatType& GetFileDescriptorType(); + static const ClipboardFormatType& GetFileDescriptorWType(); static const ClipboardFormatType& GetFileContentZeroType(); + static const ClipboardFormatType& GetFileContentAtIndexType(LONG index); static const ClipboardFormatType& GetIDListType(); #endif @@ -99,7 +103,17 @@ #if defined(OS_WIN) explicit ClipboardFormatType(UINT native_format); ClipboardFormatType(UINT native_format, LONG index); - FORMATETC data_; + ClipboardFormatType(UINT native_format, LONG index, DWORD tymed); + + // When there are multiple files in the data store and they are described + // using a file group descriptor, the file contents are retrieved by + // requesting the CFSTR_FILECONTENTS clipboard format type and also providing + // an index into the data (the first file corresponds to index 0). This + // function returns a map of index to CFSTR_FILECONTENTS clipboard format + // type. + static std::map<LONG, ClipboardFormatType>& GetFileContentTypeMap(); + + FORMATETC data_{}; #elif defined(USE_AURA) || defined(OS_ANDROID) || defined(OS_FUCHSIA) explicit ClipboardFormatType(const std::string& native_format); std::string data_;
diff --git a/ui/base/clipboard/clipboard_format_type_win.cc b/ui/base/clipboard/clipboard_format_type_win.cc index 86e7d916..a3bd4d1 100644 --- a/ui/base/clipboard/clipboard_format_type_win.cc +++ b/ui/base/clipboard/clipboard_format_type_win.cc
@@ -8,15 +8,16 @@ #include "base/lazy_instance.h" #include "base/logging.h" +#include "base/memory/ptr_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" namespace ui { // ClipboardFormatType implementation. -ClipboardFormatType::ClipboardFormatType() : data_() {} +ClipboardFormatType::ClipboardFormatType() {} -ClipboardFormatType::ClipboardFormatType(UINT native_format) : data_() { +ClipboardFormatType::ClipboardFormatType(UINT native_format) { // There's no good way to actually initialize this in the constructor in // C++03. data_.cfFormat = static_cast<CLIPFORMAT>(native_format); @@ -25,8 +26,7 @@ data_.tymed = TYMED_HGLOBAL; } -ClipboardFormatType::ClipboardFormatType(UINT native_format, LONG index) - : data_() { +ClipboardFormatType::ClipboardFormatType(UINT native_format, LONG index) { // There's no good way to actually initialize this in the constructor in // C++03. data_.cfFormat = static_cast<CLIPFORMAT>(native_format); @@ -35,6 +35,18 @@ data_.tymed = TYMED_HGLOBAL; } +// TODO(https://crbug.com/949411): Use delegating constructors. +ClipboardFormatType::ClipboardFormatType(UINT native_format, + LONG index, + DWORD tymed) { + // There's no good way to actually initialize this in the constructor in + // C++03. + data_.cfFormat = static_cast<CLIPFORMAT>(native_format); + data_.dwAspect = DVASPECT_CONTENT; + data_.lindex = index; + data_.tymed = tymed; +} + ClipboardFormatType::~ClipboardFormatType() {} std::string ClipboardFormatType::Serialize() const { @@ -167,21 +179,61 @@ return type.Get(); } +// Nothing prevents the drag source app from using the CFSTR_FILEDESCRIPTORA +// ANSI format (e.g., it could be that it doesn't support UNICODE). So need to +// register both the ANSI and UNICODE file group descriptors. // static const ClipboardFormatType& ClipboardFormatType::GetFileDescriptorType() { CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE( - type, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR)); + type, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA)); + return type.Get(); +} + +// static +const ClipboardFormatType& ClipboardFormatType::GetFileDescriptorWType() { + CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE( + type, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW)); return type.Get(); } // static const ClipboardFormatType& ClipboardFormatType::GetFileContentZeroType() { + // Note this uses a storage media type of TYMED_HGLOBAL, which is not commonly + // used with CFSTR_FILECONTENTS (but used in Chromium--see + // OSExchangeDataProviderWin::SetFileContents). Use GetFileContentAtIndexType + // if TYMED_ISTREAM and TYMED_ISTORAGE are needed. + // TODO(https://crbug.com/950756): Should TYMED_ISTREAM / TYMED_ISTORAGE be + // used instead of TYMED_HGLOBAL in + // OSExchangeDataProviderWin::SetFileContents. CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE( type, ::RegisterClipboardFormat(CFSTR_FILECONTENTS), 0); return type.Get(); } // static +std::map<LONG, ClipboardFormatType>& +ClipboardFormatType::GetFileContentTypeMap() { + static base::NoDestructor<std::map<LONG, ClipboardFormatType>> + index_to_type_map; + return *index_to_type_map; +} + +// static +const ClipboardFormatType& ClipboardFormatType::GetFileContentAtIndexType( + LONG index) { + auto& index_to_type_map = GetFileContentTypeMap(); + + // Use base::WrapUnique instead of std::make_unique here since + // ClipboardFormatType constructor is private. See + // https://chromium.googlesource.com/chromium/src/+/HEAD/styleguide/c++/c++-dos-and-donts.md. + auto insert_or_assign_result = index_to_type_map.insert( + {index, + ClipboardFormatType(::RegisterClipboardFormat(CFSTR_FILECONTENTS), index, + TYMED_HGLOBAL | TYMED_ISTREAM | TYMED_ISTORAGE)}); + return insert_or_assign_result.first->second; +} + +// static const ClipboardFormatType& ClipboardFormatType::GetIDListType() { CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE( type, ::RegisterClipboardFormat(CFSTR_SHELLIDLIST));
diff --git a/ui/base/clipboard/clipboard_util_win.cc b/ui/base/clipboard/clipboard_util_win.cc index 077df5a6..a460c37 100644 --- a/ui/base/clipboard/clipboard_util_win.cc +++ b/ui/base/clipboard/clipboard_util_win.cc
@@ -6,14 +6,21 @@ #include <shellapi.h> #include <wininet.h> // For INTERNET_MAX_URL_LENGTH. +#include <wrl/client.h> +#include <algorithm> +#include <limits> +#include <utility> -#include "base/files/file_path.h" +#include "base/files/file_util.h" #include "base/logging.h" #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/task/post_task.h" +#include "base/task/task_traits.h" +#include "base/threading/scoped_blocking_call.h" #include "base/win/scoped_hglobal.h" #include "base/win/shlwapi.h" #include "net/base/filename_util.h" @@ -85,6 +92,354 @@ } } +// Performs a case-insensitive search for a file path in a vector of existing +// filepaths. Case-insensivity is needed for file systems such as Windows where +// A.txt and a.txt are considered the same file name. +bool ContainsFilePathCaseInsensitive( + const std::vector<base::FilePath>& existing_filenames, + const base::FilePath& candidate_path) { + return std::find_if(std::begin(existing_filenames), + std::end(existing_filenames), + [&candidate_path](const base::FilePath& elem) { + return base::FilePath::CompareEqualIgnoreCase( + elem.value(), candidate_path.value()); + }) != std::end(existing_filenames); +} + +// Returns a unique display name for a virtual file, as it is possible that the +// filenames found in the file group descriptor are not unique (e.g. multiple +// emails with the same subject line are dragged out of Outlook.exe). +// |uniquifier| is incremented on encountering a non-unique file name. +base::FilePath GetUniqueVirtualFilename( + const base::string16& candidate_name, + const std::vector<base::FilePath>& existing_filenames, + unsigned int* uniquifier) { + // Remove any possible filepath components/separators that drag source may + // have included in virtual file name. + base::FilePath unique_name = base::FilePath(candidate_name).BaseName(); + + // To mitigate against running up against MAX_PATH limitations (temp files + // failing to be created), truncate the display name. + const size_t kTruncatedDisplayNameLength = 128; + const base::string16 extension = unique_name.Extension(); + unique_name = unique_name.RemoveExtension(); + base::string16 truncated = unique_name.value(); + if (truncated.length() > kTruncatedDisplayNameLength) { + truncated.erase(kTruncatedDisplayNameLength); + unique_name = base::FilePath(truncated); + } + unique_name = unique_name.AddExtension(extension); + + // Replace any file name illegal characters. + unique_name = net::GenerateFileName(GURL(), std::string(), std::string(), + base::UTF16ToUTF8(unique_name.value()), + std::string(), std::string()); + + // Make the file name unique. This is more involved than just marching through + // |existing_filenames|, finding the first match, uniquifying, then breaking + // out of the loop. For example, consider an array of candidate display names + // {"A (1) (2)", "A", "A (1) ", "A"}. In the first three iterations of the + // outer loop in GetVirtualFilenames, the candidate names are already unique + // and so simply pushed to the vector of |filenames|. On the fourth iteration + // of the outer loop and second iteration of the inner loop (that in + // GetUniqueVirtualFilename), the duplicate name is encountered and the fourth + // item is tentatively uniquified to "A (1)". If this inner loop were exited + // now, the final |filenames| would be {"A (1) (2)", "A", "A (1) ", "A (1)"} + // and would contain duplicate entries. So try not breaking out of the + // inner loop. In that case on the third iteration of the inner loop, the + // tentative unique name encounters another duplicate, so now gets uniquefied + // to "A (1) (2)" and if we then don't restart the loop, we would end up with + // the final |filenames| being {"A (1) (2)", "A", "A (1) ", "A (1) (2)"} and + // we still have duplicate entries. Instead we need to test against the + // entire collection of existing names on each uniquification attempt. + + // Same value used in base::GetUniquePathNumber. + static const int kMaxUniqueFiles = 100; + int count = 1; + for (; count <= kMaxUniqueFiles; ++count) { + if (!ContainsFilePathCaseInsensitive(existing_filenames, unique_name)) + break; + + unique_name = unique_name.InsertBeforeExtensionASCII( + base::StringPrintf(" (%d)", (*uniquifier)++)); + } + if (count > kMaxUniqueFiles) + unique_name = base::FilePath(); + + return unique_name; +} + +// Creates a uniquely-named temporary file based on the suggested filename, or +// an empty path on error. The file will be empty and all handles closed after +// this function returns. +base::FilePath CreateTemporaryFileWithSuggestedName( + const base::FilePath& suggested_name) { + base::FilePath temp_path1; + if (!base::CreateTemporaryFile(&temp_path1)) + return base::FilePath(); + + base::FilePath temp_path2 = temp_path1.DirName().Append(suggested_name); + + // Make filename unique. + temp_path2 = base::GetUniquePath(temp_path2); + + base::File::Error replace_file_error = base::File::FILE_OK; + if (!ReplaceFile(temp_path1, temp_path2, &replace_file_error)) + return base::FilePath(); + + return temp_path2; +} + +// This method performs file I/O and thus is executed on a worker thread. An +// empty FilePath for the temp file is returned on failure. +base::FilePath WriteFileContentsToTempFile(const base::FilePath& suggested_name, + HGLOBAL hdata) { + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, + base::BlockingType::MAY_BLOCK); + + base::FilePath temp_path = base::FilePath(); + + if (!hdata) + return temp_path; + + temp_path = CreateTemporaryFileWithSuggestedName(suggested_name); + + if (!temp_path.empty()) { + base::win::ScopedHGlobal<char*> data(hdata); + // Don't write to the temp file for empty content--leave it at 0-bytes. + if (!(data.Size() == 1 && data.get()[0] == '\0')) { + if (base::WriteFile(temp_path, data.get(), data.Size()) < 0) { + base::DeleteFile(temp_path, false); + return base::FilePath(); + } + } + } + + ::GlobalFree(hdata); + + return temp_path; +} + +std::vector< + std::pair</*temp path*/ base::FilePath, /*display name*/ base::FilePath>> +WriteAllFileContentsToTempFiles( + const std::vector<base::FilePath>& display_names, + const std::vector<HGLOBAL>& memory_backed_contents) { + DCHECK_EQ(display_names.size(), memory_backed_contents.size()); + + std::vector<std::pair<base::FilePath, base::FilePath>> filepaths_and_names; + for (size_t i = 0; i < display_names.size(); i++) { + base::FilePath temp_path = WriteFileContentsToTempFile( + display_names[i], memory_backed_contents[i]); + + filepaths_and_names.push_back({temp_path, display_names[i]}); + } + + return filepaths_and_names; +} + +// Caller's responsibility to call GlobalFree on returned HGLOBAL when done with +// the data. This method must be performed on main thread as it is using the +// IDataObject marshalled there. +HGLOBAL CopyFileContentsToHGlobal(IDataObject* data_object, LONG index) { + DCHECK(data_object); + HGLOBAL hdata = nullptr; + + if (!HasData(data_object, + ClipboardFormatType::GetFileContentAtIndexType(index))) + return hdata; + + STGMEDIUM content; + if (!GetData(data_object, + ClipboardFormatType::GetFileContentAtIndexType(index), &content)) + return hdata; + + HRESULT hr = S_OK; + + if (content.tymed == TYMED_ISTORAGE) { + // For example, messages dragged out of Outlook.exe. + + Microsoft::WRL::ComPtr<ILockBytes> lock_bytes; + hr = ::CreateILockBytesOnHGlobal(nullptr, /* fDeleteOnRelease*/ FALSE, + &lock_bytes); + + Microsoft::WRL::ComPtr<IStorage> storage; + if (SUCCEEDED(hr)) { + hr = ::StgCreateDocfileOnILockBytes( + lock_bytes.Get(), STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, + 0, &storage); + } + + if (SUCCEEDED(hr)) + hr = content.pstg->CopyTo(0, nullptr, nullptr, storage.Get()); + + if (SUCCEEDED(hr)) + hr = storage->Commit(STGC_OVERWRITE); + + if (SUCCEEDED(hr)) + hr = ::GetHGlobalFromILockBytes(lock_bytes.Get(), &hdata); + + if (FAILED(hr)) + hdata = nullptr; + } else if (content.tymed == TYMED_ISTREAM) { + // For example, attachments dragged out of messages in Outlook.exe. + + Microsoft::WRL::ComPtr<IStream> stream; + hr = + ::CreateStreamOnHGlobal(nullptr, /* fDeleteOnRelease */ FALSE, &stream); + if (SUCCEEDED(hr)) { + // A properly implemented IDataObject::GetData moves the stream pointer to + // the end. Need to seek to the beginning before copying the data then + // seek back to the original position. + const LARGE_INTEGER zero_displacement = {}; + ULARGE_INTEGER original_position = {}; + // Obtain the original stream pointer position. If the stream doesn't + // support seek, will still attempt to copy the data unless the failure is + // due to access being denied (enterprise protected data e.g.). + HRESULT hr_seek = content.pstm->Seek(zero_displacement, STREAM_SEEK_CUR, + &original_position); + if (hr_seek != E_ACCESSDENIED) { + if (SUCCEEDED(hr_seek)) { + // Seek to the beginning. + hr_seek = + content.pstm->Seek(zero_displacement, STREAM_SEEK_SET, nullptr); + } + + // Copy all data to the file stream. + ULARGE_INTEGER max_bytes; + max_bytes.QuadPart = std::numeric_limits<uint64_t>::max(); + hr = content.pstm->CopyTo(stream.Get(), max_bytes, nullptr, nullptr); + + if (SUCCEEDED(hr_seek)) { + // Restore the stream pointer to its original position. + LARGE_INTEGER original_offset; + original_offset.QuadPart = original_position.QuadPart; + content.pstm->Seek(original_offset, STREAM_SEEK_SET, nullptr); + } + } else { + // Access was denied. + hr = hr_seek; + } + + if (SUCCEEDED(hr)) + hr = ::GetHGlobalFromStream(stream.Get(), &hdata); + + if (FAILED(hr)) + hdata = nullptr; + } + } else if (content.tymed == TYMED_HGLOBAL) { + // For example, anchor (internet shortcut) dragged out of Spartan Edge. + // Copy the data as it will be written to a file on a worker thread and we + // need to call ReleaseStgMedium to free the memory allocated by the drag + // source. + base::win::ScopedHGlobal<char*> data_source(content.hGlobal); + hdata = ::GlobalAlloc(GHND, data_source.Size()); + if (hdata) { + base::win::ScopedHGlobal<char*> data_destination(hdata); + memcpy(data_destination.get(), data_source.get(), data_source.Size()); + } + } + + // Safe to release the medium now since all the data has been copied. + ReleaseStgMedium(&content); + + return hdata; +} + +base::string16 ConvertString(const char* string) { + return base::UTF8ToWide(string); +} + +base::string16 ConvertString(const wchar_t* string) { + return string; +} + +template <typename FileGroupDescriptorType> +struct FileGroupDescriptorData; + +template <> +struct FileGroupDescriptorData<FILEGROUPDESCRIPTORW> { + static bool get(IDataObject* data_object, STGMEDIUM* medium) { + return GetData(data_object, ClipboardFormatType::GetFileDescriptorWType(), + medium); + } +}; + +template <> +struct FileGroupDescriptorData<FILEGROUPDESCRIPTORA> { + static bool get(IDataObject* data_object, STGMEDIUM* medium) { + return GetData(data_object, ClipboardFormatType::GetFileDescriptorType(), + medium); + } +}; + +// Retrieves display names of virtual files, making sure they are unique. +// Use template parameter of FILEGROUPDESCRIPTORW for retrieving unicode data +// and FILEGROUPDESCRIPTORA for ascii. +template <typename FileGroupDescriptorType> +bool GetVirtualFilenames(IDataObject* data_object, + std::vector<base::FilePath>* filenames) { + STGMEDIUM medium; + + if (!FileGroupDescriptorData<FileGroupDescriptorType>::get(data_object, + &medium)) + return false; + + { + base::win::ScopedHGlobal<FileGroupDescriptorType*> fgd(medium.hGlobal); + if (!fgd.get()) + return false; + + unsigned int num_files = fgd->cItems; + // We expect there to be at least one file in here. + DCHECK_GE(num_files, 1u); + + // Value to be incremented to ensure a unique display name, as it is + // possible that the filenames found in the file group descriptor are not + // unique (e.g. multiple emails with the same subject line are dragged out + // of Outlook.exe). + unsigned int uniquifier = 1; + + for (size_t i = 0; i < num_files; i++) { + base::FilePath display_name; + // Folder entries not currently supported--skip this item. + if ((fgd->fgd[i].dwFlags & FD_ATTRIBUTES) && + (fgd->fgd[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + DLOG(WARNING) << "GetVirtualFilenames: display name '" + << ConvertString(fgd->fgd[i].cFileName) + << "' refers to a directory (not supported)."; + continue; + } + display_name = GetUniqueVirtualFilename( + ConvertString(fgd->fgd[i].cFileName), *filenames, &uniquifier); + + filenames->push_back(display_name); + } + } + + ReleaseStgMedium(&medium); + return !filenames->empty(); +} + +template <typename FileGroupDescriptorType> +bool GetFileNameFromFirstDescriptor(IDataObject* data_object, + base::string16* filename) { + STGMEDIUM medium; + + if (!FileGroupDescriptorData<FileGroupDescriptorType>::get(data_object, + &medium)) + return false; + + { + base::win::ScopedHGlobal<FileGroupDescriptorType*> fgd(medium.hGlobal); + // We expect there to be at least one file in here. + DCHECK_GE(fgd->cItems, 1u); + filename->assign(ConvertString(fgd->fgd[0].cFileName)); + } + ReleaseStgMedium(&medium); + return true; +} + } // namespace bool ClipboardUtil::HasUrl(IDataObject* data_object, bool convert_filenames) { @@ -102,9 +457,21 @@ HasData(data_object, ClipboardFormatType::GetFilenameType()); } +bool ClipboardUtil::HasVirtualFilenames(IDataObject* data_object) { + DCHECK(data_object); + // Favor real files on the file system over virtual files. + return !HasFilenames(data_object) && + HasData(data_object, + ClipboardFormatType::GetFileContentAtIndexType(0)) && + (HasData(data_object, ClipboardFormatType::GetFileDescriptorWType()) || + HasData(data_object, ClipboardFormatType::GetFileDescriptorType())); +} + bool ClipboardUtil::HasFileContents(IDataObject* data_object) { DCHECK(data_object); - return HasData(data_object, ClipboardFormatType::GetFileContentZeroType()); + return HasData(data_object, ClipboardFormatType::GetFileContentZeroType()) && + (HasData(data_object, ClipboardFormatType::GetFileDescriptorWType()) || + HasData(data_object, ClipboardFormatType::GetFileDescriptorType())); } bool ClipboardUtil::HasHtml(IDataObject* data_object) { @@ -216,6 +583,57 @@ return false; } +bool ClipboardUtil::GetVirtualFilenames( + IDataObject* data_object, + std::vector<base::FilePath>* filenames) { + DCHECK(data_object && filenames); + if (!HasVirtualFilenames(data_object)) + return false; + + // Nothing prevents the drag source app from using the CFSTR_FILEDESCRIPTORA + // ANSI format (e.g., it could be that it doesn't support UNICODE). So need to + // check for both the ANSI and UNICODE file group descriptors. + if (ui::GetVirtualFilenames<FILEGROUPDESCRIPTORW>(data_object, filenames)) { + // file group descriptor using unicode. + return true; + } + + if (ui::GetVirtualFilenames<FILEGROUPDESCRIPTORA>(data_object, filenames)) { + // file group descriptor using ascii. + return true; + } + + return false; +} + +bool ClipboardUtil::GetVirtualFilesAsTempFiles( + IDataObject* data_object, + base::OnceCallback< + void(const std::vector<std::pair</*temp path*/ base::FilePath, + /*display name*/ base::FilePath>>&)> + callback) { + // Retrieve the display names of the virtual files. + std::vector<base::FilePath> display_names; + if (!GetVirtualFilenames(data_object, &display_names)) + return false; + + // Write the file contents to global memory. + std::vector<HGLOBAL> memory_backed_contents; + for (size_t i = 0; i < display_names.size(); i++) { + HGLOBAL hdata = CopyFileContentsToHGlobal(data_object, i); + memory_backed_contents.push_back(hdata); + } + + // Queue a task to actually write the temp files on a worker thread. + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, + base::BindOnce(&WriteAllFileContentsToTempFiles, display_names, + memory_backed_contents), + std::move(callback)); // callback on the UI thread + + return true; +} + bool ClipboardUtil::GetPlainText(IDataObject* data_object, base::string16* plain_text) { DCHECK(data_object && plain_text); @@ -289,10 +707,10 @@ } bool ClipboardUtil::GetFileContents(IDataObject* data_object, - base::string16* filename, std::string* file_contents) { + base::string16* filename, + std::string* file_contents) { DCHECK(data_object && filename && file_contents); - if (!HasData(data_object, ClipboardFormatType::GetFileContentZeroType()) && - !HasData(data_object, ClipboardFormatType::GetFileDescriptorType())) + if (!HasFileContents(data_object)) return false; STGMEDIUM content; @@ -307,18 +725,22 @@ ReleaseStgMedium(&content); } - STGMEDIUM description; - if (GetData(data_object, ClipboardFormatType::GetFileDescriptorType(), - &description)) { - { - base::win::ScopedHGlobal<FILEGROUPDESCRIPTOR*> fgd(description.hGlobal); - // We expect there to be at least one file in here. - DCHECK_GE(fgd->cItems, 1u); - filename->assign(fgd->fgd[0].cFileName); - } - ReleaseStgMedium(&description); + // Nothing prevents the drag source app from using the CFSTR_FILEDESCRIPTORA + // ANSI format (e.g., it could be that it doesn't support UNICODE). So need to + // check for both the ANSI and UNICODE file group descriptors. + if (GetFileNameFromFirstDescriptor<FILEGROUPDESCRIPTORW>(data_object, + filename)) { + // file group descriptor using unicode. + return true; } - return true; + + if (GetFileNameFromFirstDescriptor<FILEGROUPDESCRIPTORA>(data_object, + filename)) { + // file group descriptor using ASCII. + return true; + } + + return false; } bool ClipboardUtil::GetWebCustomData(
diff --git a/ui/base/clipboard/clipboard_util_win.h b/ui/base/clipboard/clipboard_util_win.h index b4d0ae9..bfcea85c 100644 --- a/ui/base/clipboard/clipboard_util_win.h +++ b/ui/base/clipboard/clipboard_util_win.h
@@ -11,9 +11,11 @@ #include <stddef.h> #include <string> #include <unordered_map> +#include <utility> #include <vector> #include "base/component_export.h" +#include "base/files/file_path.h" #include "base/strings/string16.h" class GURL; @@ -27,6 +29,7 @@ // Returns true if it does. static bool HasUrl(IDataObject* data_object, bool convert_filenames); static bool HasFilenames(IDataObject* data_object); + static bool HasVirtualFilenames(IDataObject* data_object); static bool HasPlainText(IDataObject* data_object); static bool HasFileContents(IDataObject* data_object); static bool HasHtml(IDataObject* data_object); @@ -43,6 +46,32 @@ // Only returns true if |*filenames| is not empty. static bool GetFilenames(IDataObject* data_object, std::vector<base::string16>* filenames); + + // Fills a vector of display names of "virtual files" in the data store, but + // does not actually retrieve the file contents. Display names are assured to + // be unique. Method is called on drag enter of the Chromium drop target, when + // only the display names are needed. Method only returns true if |filenames| + // is not empty. + static bool GetVirtualFilenames(IDataObject* data_object, + std::vector<base::FilePath>* filenames); + + // Retrieves "virtual file" contents via creation of intermediary temp files. + // Method is called on dropping on the Chromium drop target. Since creating + // the temp files involves file I/O, the method is asynchronous and the caller + // must provide a callback function that receives a vector of pairs of temp + // file paths and display names. Method immediately returns false if there are + // no virtual files in the data object, in which case the callback will never + // be invoked. + // TODO(https://crbug.com/951574): Implement virtual file extraction to + // dynamically stream data to the renderer when File's bytes are actually + // requested + static bool GetVirtualFilesAsTempFiles( + IDataObject* data_object, + base::OnceCallback< + void(const std::vector<std::pair</*temp path*/ base::FilePath, + /*display name*/ base::FilePath>>&)> + callback); + static bool GetPlainText(IDataObject* data_object, base::string16* plain_text); static bool GetHtml(IDataObject* data_object, @@ -72,6 +101,6 @@ size_t* fragment_start, size_t* fragment_end); }; -} +} // namespace ui #endif // UI_BASE_CLIPBOARD_CLIPBOARD_UTIL_WIN_H_
diff --git a/ui/base/dragdrop/os_exchange_data.cc b/ui/base/dragdrop/os_exchange_data.cc index 11cf7db..5afdbe8 100644 --- a/ui/base/dragdrop/os_exchange_data.cc +++ b/ui/base/dragdrop/os_exchange_data.cc
@@ -4,6 +4,10 @@ #include "ui/base/dragdrop/os_exchange_data.h" +#include <utility> +#include <vector> + +#include "base/callback.h" #include "base/pickle.h" #include "build/build_config.h" #include "ui/base/clipboard/clipboard_format_type.h" @@ -136,6 +140,22 @@ return provider_->GetFileContents(filename, file_contents); } +bool OSExchangeData::HasVirtualFilenames() const { + return provider_->HasVirtualFilenames(); +} + +bool OSExchangeData::GetVirtualFilenames( + std::vector<FileInfo>* filenames) const { + return provider_->GetVirtualFilenames(filenames); +} + +bool OSExchangeData::GetVirtualFilesAsTempFiles( + base::OnceCallback< + void(const std::vector<std::pair<base::FilePath, base::FilePath>>&)> + callback) const { + return provider_->GetVirtualFilesAsTempFiles(std::move(callback)); +} + void OSExchangeData::SetDownloadFileInfo(const DownloadFileInfo& download) { provider_->SetDownloadFileInfo(download); }
diff --git a/ui/base/dragdrop/os_exchange_data.h b/ui/base/dragdrop/os_exchange_data.h index cd91515..343689e 100644 --- a/ui/base/dragdrop/os_exchange_data.h +++ b/ui/base/dragdrop/os_exchange_data.h
@@ -8,6 +8,8 @@ #include <memory> #include <set> #include <string> +#include <utility> +#include <vector> #include "build/build_config.h" @@ -121,6 +123,18 @@ virtual bool GetFileContents(base::FilePath* filename, std::string* file_contents) const = 0; virtual bool HasFileContents() const = 0; + virtual bool HasVirtualFilenames() const = 0; + virtual bool GetVirtualFilenames( + std::vector<FileInfo>* file_names) const = 0; + virtual bool GetVirtualFilesAsTempFiles( + base::OnceCallback<void( + const std::vector<std::pair</*temp path*/ base::FilePath, + /*display name*/ base::FilePath>>&)> + callback) const = 0; + virtual void SetVirtualFileContentsForTesting( + const std::vector<std::pair<base::FilePath, std::string>>& + filenames_and_contents, + DWORD tymed) = 0; virtual void SetDownloadFileInfo(const DownloadFileInfo& download) = 0; #endif @@ -213,6 +227,44 @@ bool GetFileContents(base::FilePath* filename, std::string* file_contents) const; + // Methods used to query and retrieve file data from a drag source + // IDataObject implementation packaging the data with the + // CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS clipboard formats instead of the + // more common CF_HDROP. These formats are intended to represent "virtual + // files," not files that live on the platform file system. For a drop target + // to read the file contents, it must be streamed from the drag source + // application. + + // Method that returns true if there are virtual files packaged in the data + // store. + bool HasVirtualFilenames() const; + + // Retrieves names of any "virtual files" in the data store packaged using the + // CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS clipboard formats instead of the + // more common CF_HDROP used for "real files." Real files are preferred over + // virtual files here to avoid duplication, as the data store may package + // the same file lists using different formats. GetVirtualFilenames just + // retrieves the display names but not the temp file paths. The temp files + // are only created upon drop via a call to the async method + // GetVirtualFilesAsTempFiles. + bool GetVirtualFilenames(std::vector<FileInfo>* file_names) const; + + // Retrieves "virtual file" contents via creation of intermediary temp files. + // Method is called on dropping on the Chromium drop target. Since creating + // the temp files involves file I/O, the method is asynchronous and the caller + // must provide a callback function that receives a vector of pairs of temp + // file paths and display names. Method immediately returns false if there are + // no virtual files in the data object, in which case the callback will never + // be invoked. + // TODO(https://crbug.com/951574): Implement virtual file extraction to + // dynamically stream data to the renderer when File's bytes are actually + // requested + bool GetVirtualFilesAsTempFiles( + base::OnceCallback<void(const std::vector</*temp path*/ std::pair< + base::FilePath, + /*display name*/ base::FilePath>>&)> callback) + const; + // Adds a download file with full path (CF_HDROP). void SetDownloadFileInfo(const DownloadFileInfo& download); #endif
diff --git a/ui/base/dragdrop/os_exchange_data_provider_win.cc b/ui/base/dragdrop/os_exchange_data_provider_win.cc index a9bd4912f..291b9501 100644 --- a/ui/base/dragdrop/os_exchange_data_provider_win.cc +++ b/ui/base/dragdrop/os_exchange_data_provider_win.cc
@@ -4,6 +4,7 @@ #include "ui/base/dragdrop/os_exchange_data_provider_win.h" +#include <coml2api.h> #include <objbase.h> #include <objidl.h> #include <shlobj.h> @@ -14,6 +15,8 @@ #include <algorithm> #include <iterator> +#include "base/callback.h" +#include "base/containers/span.h" #include "base/files/file_path.h" #include "base/i18n/file_util_icu.h" #include "base/logging.h" @@ -23,6 +26,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/win/scoped_hdc.h" #include "base/win/scoped_hglobal.h" +#include "base/win/shlwapi.h" #include "net/base/filename_util.h" #include "skia/ext/skia_utils_win.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -372,6 +376,124 @@ ClipboardFormatType::GetCFHDropType().ToFormatEtc(), storage)); } +void OSExchangeDataProviderWin::SetVirtualFileContentsForTesting( + const std::vector<std::pair<base::FilePath, std::string>>& + filenames_and_contents, + DWORD tymed) { + size_t num_files = filenames_and_contents.size(); + if (!num_files) + return; + + // Allocate storage for the file group descriptor as CFSTR_FILEDESCRIPTORW. + // The fgd[] member of FILEGROUPDESCRIPTORW is of size one, thus sizeof + // (FILEDESCRIPTORW) is already the correct allocation size if there is only + // one item. Otherwise need to add room for each FILEDESCRIPTORW struct. + const size_t total_bytes_fgd = sizeof(FILEGROUPDESCRIPTORW) + + (sizeof(FILEDESCRIPTORW) * (num_files - 1)); + + HANDLE hdata = ::GlobalAlloc(GPTR, total_bytes_fgd); + if (!hdata) + return; + + base::win::ScopedHGlobal<FILEGROUPDESCRIPTORW*> locked_mem(hdata); + + FILEGROUPDESCRIPTORW* descriptor = locked_mem.get(); + descriptor->cItems = num_files; + + STGMEDIUM* storage = new STGMEDIUM; + storage->tymed = TYMED_HGLOBAL; + storage->hGlobal = hdata; + storage->pUnkForRelease = NULL; + + data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>( + ClipboardFormatType::GetFileDescriptorWType().ToFormatEtc(), storage)); + + for (size_t i = 0; i < num_files; i++) { + // Fill in each FILEDESCRIPTORW with file name. + descriptor->fgd[i].dwFlags |= FD_UNICODE; + base::string16 file_name = filenames_and_contents[i].first.value(); + wcsncpy_s(descriptor->fgd[i].cFileName, MAX_PATH, file_name.c_str(), + std::min(file_name.size(), static_cast<size_t>(MAX_PATH - 1u))); + + // Add the contents of each file as CFSTR_FILECONTENTS. + base::span<const uint8_t> data_buffer = + base::make_span(reinterpret_cast<const uint8_t*>( + filenames_and_contents[i].second.data()), + filenames_and_contents[i].second.length()); + SetVirtualFileContentAtIndexForTesting(data_buffer, tymed, i); + } +} + +void OSExchangeDataProviderWin::SetVirtualFileContentAtIndexForTesting( + base::span<const uint8_t> data_buffer, + DWORD tymed, + size_t index) { + std::unique_ptr<STGMEDIUM> storage_for_contents; + + if (tymed == TYMED_ISTORAGE) { + storage_for_contents = std::make_unique<STGMEDIUM>(); + storage_for_contents->pUnkForRelease = nullptr; + + Microsoft::WRL::ComPtr<ILockBytes> lock_bytes; + HRESULT hr = ::CreateILockBytesOnHGlobal( + nullptr, /* fDeleteOnRelease*/ TRUE, &lock_bytes); + + if (SUCCEEDED(hr)) { + hr = ::StgCreateDocfileOnILockBytes( + lock_bytes.Get(), STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, + 0, &storage_for_contents->pstg); + } + + Microsoft::WRL::ComPtr<IStream> destination_stream; + if (SUCCEEDED(hr)) { + hr = storage_for_contents->pstg->CreateStream( + L"Contents", STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0, + 0, &destination_stream); + } + + Microsoft::WRL::ComPtr<IStream> source_stream; + if (SUCCEEDED(hr)) { + source_stream = + ::SHCreateMemStream(data_buffer.data(), data_buffer.size_bytes()); + } + + if (source_stream) { + // Copy the data to the storage stream. + ULARGE_INTEGER bytes_to_copy; + bytes_to_copy.QuadPart = data_buffer.size_bytes(); + hr = source_stream->CopyTo(destination_stream.Get(), bytes_to_copy, + nullptr, nullptr); + } + if (SUCCEEDED(hr)) + hr = storage_for_contents->pstg->Commit(STGC_DEFAULT); + if (SUCCEEDED(hr)) + storage_for_contents->tymed = TYMED_ISTORAGE; + + } else if (tymed == TYMED_ISTREAM) { + storage_for_contents = std::make_unique<STGMEDIUM>(); + storage_for_contents->pUnkForRelease = nullptr; + storage_for_contents->pstm = + ::SHCreateMemStream(data_buffer.data(), data_buffer.size_bytes()); + if (storage_for_contents->pstm) { + // A properly implemented IDataObject::GetData moves the stream pointer + // to end. + const LARGE_INTEGER zero_displacement = {}; + HRESULT hr = storage_for_contents->pstm->Seek(zero_displacement, + STREAM_SEEK_END, nullptr); + if (SUCCEEDED(hr)) + storage_for_contents->tymed = TYMED_ISTREAM; + } + } else if (tymed == TYMED_HGLOBAL) { + storage_for_contents.reset( + GetStorageForBytes(data_buffer.data(), data_buffer.size_bytes())); + } + ClipboardFormatType type = + ClipboardFormatType::GetFileContentAtIndexType(index); + // Pass ownership of |storage_for_contents| here. + data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>( + type.ToFormatEtc(), storage_for_contents.release())); +} + void OSExchangeDataProviderWin::SetPickledData( const ClipboardFormatType& format, const base::Pickle& data) { @@ -383,12 +505,12 @@ void OSExchangeDataProviderWin::SetFileContents( const base::FilePath& filename, const std::string& file_contents) { - // Add CFSTR_FILEDESCRIPTOR + // Add CFSTR_FILEDESCRIPTORW. STGMEDIUM* storage = GetStorageForFileDescriptor(filename); data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>( - ClipboardFormatType::GetFileDescriptorType().ToFormatEtc(), storage)); + ClipboardFormatType::GetFileDescriptorWType().ToFormatEtc(), storage)); - // Add CFSTR_FILECONTENTS + // Add CFSTR_FILECONTENTS. storage = GetStorageForBytes(file_contents.data(), file_contents.length()); data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>( ClipboardFormatType::GetFileContentZeroType().ToFormatEtc(), storage)); @@ -457,6 +579,39 @@ return success; } +bool OSExchangeDataProviderWin::HasVirtualFilenames() const { + return ClipboardUtil::HasVirtualFilenames(source_object_.Get()); +} + +bool OSExchangeDataProviderWin::GetVirtualFilenames( + std::vector<FileInfo>* filenames) const { + // ui_base_clipboard can't use FileInfo struct which is part of ui_base, so + // use FilePath instead. + // TODO(https://crbug.com/950360): ui_base_clipboard can't use FileInfo struct + // which is part of ui_base (layering issue). + std::vector<base::FilePath> display_names; + bool success = + ClipboardUtil::GetVirtualFilenames(source_object_.Get(), &display_names); + + if (success) { + // On dragenter scenarios, need a placeholder file path for drag metadata + // checks without actually creating the temp file. + base::FilePath temp_path(FILE_PATH_LITERAL("temp.tmp")); + + for (const auto& display_name : display_names) + filenames->push_back(FileInfo(temp_path, display_name)); + } + return success; +} + +bool OSExchangeDataProviderWin::GetVirtualFilesAsTempFiles( + base::OnceCallback< + void(const std::vector<std::pair<base::FilePath, base::FilePath>>&)> + callback) const { + return ClipboardUtil::GetVirtualFilesAsTempFiles(source_object_.Get(), + std::move(callback)); +} + bool OSExchangeDataProviderWin::GetPickledData( const ClipboardFormatType& format, base::Pickle* data) const { @@ -1119,10 +1274,10 @@ const base::FilePath& path) { base::string16 file_name = path.value(); DCHECK(!file_name.empty()); - HANDLE hdata = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR)); - base::win::ScopedHGlobal<FILEGROUPDESCRIPTOR*> locked_mem(hdata); + HANDLE hdata = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTORW)); + base::win::ScopedHGlobal<FILEGROUPDESCRIPTORW*> locked_mem(hdata); - FILEGROUPDESCRIPTOR* descriptor = locked_mem.get(); + FILEGROUPDESCRIPTORW* descriptor = locked_mem.get(); descriptor->cItems = 1; descriptor->fgd[0].dwFlags = FD_LINKUI; wcsncpy_s(descriptor->fgd[0].cFileName, MAX_PATH, file_name.c_str(),
diff --git a/ui/base/dragdrop/os_exchange_data_provider_win.h b/ui/base/dragdrop/os_exchange_data_provider_win.h index 96fa77ec..a914f043 100644 --- a/ui/base/dragdrop/os_exchange_data_provider_win.h +++ b/ui/base/dragdrop/os_exchange_data_provider_win.h
@@ -9,6 +9,7 @@ #include <shlobj.h> #include <stddef.h> #include <wrl/client.h> +#include <utility> #include <memory> #include <string> @@ -154,6 +155,13 @@ void SetURL(const GURL& url, const base::string16& title) override; void SetFilename(const base::FilePath& path) override; void SetFilenames(const std::vector<FileInfo>& filenames) override; + // Test only method for adding virtual file content to the data store. The + // first value in the pair is the file display name, the second is a string + // providing the file content. + void SetVirtualFileContentsForTesting( + const std::vector<std::pair<base::FilePath, std::string>>& + filenames_and_contents, + DWORD tymed) override; void SetPickledData(const ClipboardFormatType& format, const base::Pickle& data) override; void SetFileContents(const base::FilePath& filename, @@ -166,6 +174,12 @@ base::string16* title) const override; bool GetFilename(base::FilePath* path) const override; bool GetFilenames(std::vector<FileInfo>* filenames) const override; + bool HasVirtualFilenames() const override; + bool GetVirtualFilenames(std::vector<FileInfo>* filenames) const override; + bool GetVirtualFilesAsTempFiles( + base::OnceCallback< + void(const std::vector<std::pair<base::FilePath, base::FilePath>>&)> + callback) const override; bool GetPickledData(const ClipboardFormatType& format, base::Pickle* data) const override; bool GetFileContents(base::FilePath* filename, @@ -185,6 +199,10 @@ gfx::Vector2d GetDragImageOffset() const override; private: + void SetVirtualFileContentAtIndexForTesting(base::span<const uint8_t> data, + DWORD tymed, + size_t index); + scoped_refptr<DataObjectImpl> data_; Microsoft::WRL::ComPtr<IDataObject> source_object_;
diff --git a/ui/base/dragdrop/os_exchange_data_win_unittest.cc b/ui/base/dragdrop/os_exchange_data_win_unittest.cc index 161c251..889c759 100644 --- a/ui/base/dragdrop/os_exchange_data_win_unittest.cc +++ b/ui/base/dragdrop/os_exchange_data_win_unittest.cc
@@ -6,10 +6,15 @@ #include <memory> +#include "base/bind.h" +#include "base/callback.h" +#include "base/files/file_util.h" #include "base/memory/ref_counted.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_task_environment.h" #include "base/win/scoped_hglobal.h" #include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" #include "ui/base/clipboard/clipboard_format_type.h" #include "ui/base/dragdrop/file_info.h" #include "ui/base/dragdrop/os_exchange_data_provider_win.h" @@ -17,8 +22,41 @@ namespace ui { +namespace { +const std::vector<DWORD> kStorageMediaTypesForVirtualFiles = { + TYMED_ISTORAGE, + TYMED_ISTREAM, + TYMED_HGLOBAL, +}; + +} // namespace + +class OSExchangeDataWinTest : public ::testing::Test { + public: + OSExchangeDataWinTest() + : scoped_task_environment_( + base::test::ScopedTaskEnvironment::MainThreadType::UI) {} + + void OnGotVirtualFilesAsTempFiles( + const std::vector<std::pair<base::FilePath, base::FilePath>>& + filepaths_and_names) { + // Clear any previous results and cache a vector of FileInfo objects for + // verification. + retrieved_virtual_files_.clear(); + + for (const auto& filepath_and_name : filepaths_and_names) { + retrieved_virtual_files_.push_back( + FileInfo(filepath_and_name.first, filepath_and_name.second)); + } + } + + protected: + std::vector<FileInfo> retrieved_virtual_files_; + base::test::ScopedTaskEnvironment scoped_task_environment_; +}; + // Test getting using the IDataObject COM API -TEST(OSExchangeDataWinTest, StringDataAccessViaCOM) { +TEST_F(OSExchangeDataWinTest, StringDataAccessViaCOM) { OSExchangeData data; std::wstring input = L"O hai googlz."; data.SetString(input); @@ -38,7 +76,7 @@ } // Test setting using the IDataObject COM API -TEST(OSExchangeDataWinTest, StringDataWritingViaCOM) { +TEST_F(OSExchangeDataWinTest, StringDataWritingViaCOM) { OSExchangeData data; std::wstring input = L"http://www.google.com/"; @@ -72,7 +110,7 @@ } // Verifies SetData invoked twice with the same data clobbers existing data. -TEST(OSExchangeDataWinTest, RemoveData) { +TEST_F(OSExchangeDataWinTest, RemoveData) { OSExchangeData data; std::wstring input = L"http://www.google.com/"; std::wstring input2 = L"http://www.google2.com/"; @@ -118,7 +156,7 @@ EXPECT_EQ(GURL(input2).spec(), url_from_data.spec()); } -TEST(OSExchangeDataWinTest, URLDataAccessViaCOM) { +TEST_F(OSExchangeDataWinTest, URLDataAccessViaCOM) { OSExchangeData data; GURL url("http://www.google.com/"); data.SetURL(url, L""); @@ -138,7 +176,7 @@ ReleaseStgMedium(&medium); } -TEST(OSExchangeDataWinTest, MultipleFormatsViaCOM) { +TEST_F(OSExchangeDataWinTest, MultipleFormatsViaCOM) { OSExchangeData data; std::string url_spec = "http://www.google.com/"; GURL url(url_spec); @@ -173,7 +211,7 @@ ReleaseStgMedium(&medium); } -TEST(OSExchangeDataWinTest, EnumerationViaCOM) { +TEST_F(OSExchangeDataWinTest, EnumerationViaCOM) { OSExchangeData data; data.SetURL(GURL("http://www.google.com/"), L""); data.SetString(L"O hai googlz."); @@ -262,7 +300,7 @@ } } -TEST(OSExchangeDataWinTest, TestURLExchangeFormatsViaCOM) { +TEST_F(OSExchangeDataWinTest, TestURLExchangeFormatsViaCOM) { OSExchangeData data; std::string url_spec = "http://www.google.com/"; GURL url(url_spec); @@ -291,7 +329,7 @@ } } -TEST(OSExchangeDataWinTest, FileContents) { +TEST_F(OSExchangeDataWinTest, FileContents) { OSExchangeData data; std::string file_contents("data\0with\0nulls", 15); data.SetFileContents(base::FilePath(L"filename.txt"), file_contents); @@ -304,7 +342,451 @@ EXPECT_EQ(file_contents, read_contents); } -TEST(OSExchangeDataWinTest, CFHtml) { +TEST_F(OSExchangeDataWinTest, VirtualFiles) { + const base::FilePath path_placeholder(FILE_PATH_LITERAL("temp.tmp")); + + const std::vector<std::pair<base::FilePath, std::string>> + kTestFilenames_and_Contents = { + {base::FilePath(FILE_PATH_LITERAL("filename.txt")), + std::string("just some data")}, + {base::FilePath(FILE_PATH_LITERAL("another filename.txt")), + std::string("just some data\0with\0nulls", 25)}, + {base::FilePath(FILE_PATH_LITERAL("and another filename.txt")), + std::string("just some more data")}, + }; + + for (const auto& tymed : kStorageMediaTypesForVirtualFiles) { + OSExchangeData data; + data.provider().SetVirtualFileContentsForTesting( + kTestFilenames_and_Contents, tymed); + + OSExchangeData copy(data.provider().Clone()); + std::vector<FileInfo> file_infos; + EXPECT_TRUE(copy.GetVirtualFilenames(&file_infos)); + EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size()); + for (size_t i = 0; i < file_infos.size(); i++) { + EXPECT_EQ(kTestFilenames_and_Contents[i].first, + file_infos[i].display_name); + EXPECT_EQ(path_placeholder, file_infos[i].path); + } + + std::string read_contents; + base::FilePath temp_dir; + EXPECT_TRUE(base::GetTempDir(&temp_dir)); + + // Callback for GetVirtualFilesAsTempFiles is executed when all virtual + // files are backed by temp files. + auto callback = + base::BindOnce(&OSExchangeDataWinTest::OnGotVirtualFilesAsTempFiles, + base::Unretained(this)); + + EXPECT_TRUE(copy.GetVirtualFilesAsTempFiles(std::move(callback))); + + // RunUntilIdle assures all async tasks are run. + scoped_task_environment_.RunUntilIdle(); + + EXPECT_EQ(kTestFilenames_and_Contents.size(), + retrieved_virtual_files_.size()); + for (size_t i = 0; i < retrieved_virtual_files_.size(); i++) { + EXPECT_EQ(kTestFilenames_and_Contents[i].first, + retrieved_virtual_files_[i].display_name); + EXPECT_EQ(temp_dir, retrieved_virtual_files_[i].path.DirName()); + EXPECT_EQ(kTestFilenames_and_Contents[i].first.Extension(), + retrieved_virtual_files_[i].path.Extension()); + EXPECT_TRUE(base::ReadFileToString(retrieved_virtual_files_[i].path, + &read_contents)); + if (tymed != TYMED_ISTORAGE) { + EXPECT_EQ(kTestFilenames_and_Contents[i].second, read_contents); + } else { + // IStorage uses compound files, so temp files won't be flat text files. + // Just make sure the original contents appears in the compound files. + EXPECT_TRUE(read_contents.find(kTestFilenames_and_Contents[i].second) != + std::string::npos); + } + } + } +} + +TEST_F(OSExchangeDataWinTest, VirtualFilesRealFilesPreferred) { + // Verify that no virtual files retrieved if there is real file data. + const std::vector<FileInfo> kTestFilenames = { + {base::FilePath(FILE_PATH_LITERAL("C:\\tmp\\test_file1")), + base::FilePath()}, + {base::FilePath(FILE_PATH_LITERAL("C:\\tmp\\test_file2")), + base::FilePath()}, + }; + + const std::vector<std::pair<base::FilePath, std::string>> + kTestFilenames_and_Contents = { + {base::FilePath(FILE_PATH_LITERAL("filename.txt")), + std::string("just some data")}, + {base::FilePath(FILE_PATH_LITERAL("another filename.txt")), + std::string("just some data\0with\0nulls", 25)}, + {base::FilePath(FILE_PATH_LITERAL("and another filename.txt")), + std::string("just some more data")}, + }; + + for (const auto& tymed : kStorageMediaTypesForVirtualFiles) { + OSExchangeData data; + data.SetFilenames(kTestFilenames); + data.provider().SetVirtualFileContentsForTesting( + kTestFilenames_and_Contents, tymed); + + OSExchangeData copy(data.provider().Clone()); + + std::vector<FileInfo> real_filenames; + EXPECT_TRUE(copy.GetFilenames(&real_filenames)); + EXPECT_EQ(kTestFilenames.size(), real_filenames.size()); + EXPECT_EQ(kTestFilenames, real_filenames); + + std::vector<FileInfo> file_infos; + EXPECT_FALSE(copy.GetVirtualFilenames(&file_infos)); + EXPECT_EQ(static_cast<size_t>(0), file_infos.size()); + + // Callback for GetVirtualFilesAsTempFiles is executed when all virtual + // files are backed by temp files. + auto callback = + base::BindOnce(&OSExchangeDataWinTest::OnGotVirtualFilesAsTempFiles, + base::Unretained(this)); + + EXPECT_FALSE(copy.GetVirtualFilesAsTempFiles(std::move(callback))); + + // RunUntilIdle assures all async tasks are run. + scoped_task_environment_.RunUntilIdle(); + + EXPECT_EQ(static_cast<size_t>(0), retrieved_virtual_files_.size()); + } +} + +TEST_F(OSExchangeDataWinTest, VirtualFilesDuplicateNames) { + const std::vector<std::pair<base::FilePath, std::string>> + kTestFilenames_and_Contents = { + {base::FilePath(FILE_PATH_LITERAL("A (1) (2).txt")), + std::string("just some data")}, + {base::FilePath(FILE_PATH_LITERAL("A.txt")), + std::string("just some more data")}, + {base::FilePath(FILE_PATH_LITERAL("A (1).txt")), + std::string("just some more more data")}, + {base::FilePath(FILE_PATH_LITERAL("A.txt")), + std::string("just some more more more data")}, + }; + + for (const auto& tymed : kStorageMediaTypesForVirtualFiles) { + OSExchangeData data; + data.provider().SetVirtualFileContentsForTesting( + kTestFilenames_and_Contents, tymed); + + OSExchangeData copy(data.provider().Clone()); + std::vector<FileInfo> file_infos; + EXPECT_TRUE(copy.GetVirtualFilenames(&file_infos)); + EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size()); + for (size_t i = 0; i < file_infos.size(); i++) { + // Check that display name is unique. + for (size_t j = 0; j < i; j++) { + EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase( + file_infos[j].display_name.value(), + file_infos[i].display_name.value())); + } + } + + std::string read_contents; + base::FilePath temp_dir; + EXPECT_TRUE(base::GetTempDir(&temp_dir)); + + // Callback for GetVirtualFilesAsTempFiles is executed when all virtual + // files are backed by temp files. + auto callback = + base::BindOnce(&OSExchangeDataWinTest::OnGotVirtualFilesAsTempFiles, + base::Unretained(this)); + + EXPECT_TRUE(copy.GetVirtualFilesAsTempFiles(std::move(callback))); + + // RunUntilIdle assures all async tasks are run. + scoped_task_environment_.RunUntilIdle(); + + EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size()); + for (size_t i = 0; i < retrieved_virtual_files_.size(); i++) { + // Check that display name is unique. + for (size_t j = 0; j < i; j++) { + EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase( + retrieved_virtual_files_[j].display_name.value(), + retrieved_virtual_files_[i].display_name.value())); + } + + // Check that temp file path is unique. + for (size_t j = 0; j < i; j++) { + EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase( + retrieved_virtual_files_[j].path.value(), + retrieved_virtual_files_[i].path.value())); + } + + EXPECT_EQ(temp_dir, retrieved_virtual_files_[i].path.DirName()); + EXPECT_EQ(kTestFilenames_and_Contents[i].first.Extension(), + retrieved_virtual_files_[i].path.Extension()); + EXPECT_TRUE(base::ReadFileToString(retrieved_virtual_files_[i].path, + &read_contents)); + if (tymed != TYMED_ISTORAGE) { + EXPECT_EQ(kTestFilenames_and_Contents[i].second, read_contents); + } else { + // IStorage uses compound files, so temp files won't be flat text files. + // Just make sure the original contents appears in the compound files. + EXPECT_TRUE(read_contents.find(kTestFilenames_and_Contents[i].second) != + std::string::npos); + } + } + } +} // namespace ui + +TEST_F(OSExchangeDataWinTest, VirtualFilesDuplicateNamesCaseInsensitivity) { + const std::vector<std::pair<base::FilePath, std::string>> + kTestFilenames_and_Contents = { + {base::FilePath(FILE_PATH_LITERAL("a.txt")), + std::string("just some data")}, + {base::FilePath(FILE_PATH_LITERAL("B.txt")), + std::string("just some more data")}, + {base::FilePath(FILE_PATH_LITERAL("A.txt")), + std::string("just some more more data")}, + }; + + for (const auto& tymed : kStorageMediaTypesForVirtualFiles) { + OSExchangeData data; + data.provider().SetVirtualFileContentsForTesting( + kTestFilenames_and_Contents, tymed); + + OSExchangeData copy(data.provider().Clone()); + std::vector<FileInfo> file_infos; + EXPECT_TRUE(copy.GetVirtualFilenames(&file_infos)); + EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size()); + for (size_t i = 0; i < file_infos.size(); i++) { + // Check that display name is unique. + for (size_t j = 0; j < i; j++) { + EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase( + file_infos[j].display_name.value(), + file_infos[i].display_name.value())); + } + } + + std::string read_contents; + base::FilePath temp_dir; + EXPECT_TRUE(base::GetTempDir(&temp_dir)); + + // Callback for GetVirtualFilesAsTempFiles is executed when all virtual + // files are backed by temp files. + auto callback = + base::BindOnce(&OSExchangeDataWinTest::OnGotVirtualFilesAsTempFiles, + base::Unretained(this)); + + EXPECT_TRUE(copy.GetVirtualFilesAsTempFiles(std::move(callback))); + + // RunUntilIdle assures all async tasks are run. + scoped_task_environment_.RunUntilIdle(); + + EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size()); + for (size_t i = 0; i < retrieved_virtual_files_.size(); i++) { + // Check that display name is unique. + for (size_t j = 0; j < i; j++) { + EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase( + retrieved_virtual_files_[j].display_name.value(), + retrieved_virtual_files_[i].display_name.value())); + } + + // Check that temp file path is unique. + for (size_t j = 0; j < i; j++) { + EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase( + retrieved_virtual_files_[j].path.value(), + retrieved_virtual_files_[i].path.value())); + } + + EXPECT_EQ(temp_dir, retrieved_virtual_files_[i].path.DirName()); + EXPECT_EQ(kTestFilenames_and_Contents[i].first.Extension(), + retrieved_virtual_files_[i].path.Extension()); + EXPECT_TRUE(base::ReadFileToString(retrieved_virtual_files_[i].path, + &read_contents)); + if (tymed != TYMED_ISTORAGE) { + EXPECT_EQ(kTestFilenames_and_Contents[i].second, read_contents); + } else { + // IStorage uses compound files, so temp files won't be flat text files. + // Just make sure the original contents appears in the compound files. + EXPECT_TRUE(read_contents.find(kTestFilenames_and_Contents[i].second) != + std::string::npos); + } + } + } +} + +TEST_F(OSExchangeDataWinTest, VirtualFilesInvalidAndDuplicateNames) { + const base::string16 kInvalidFileNameCharacters( + FILE_PATH_LITERAL("\\/:*?\"<>|")); + const base::string16 kInvalidFilePathCharacters( + FILE_PATH_LITERAL("/*?\"<>|")); + const base::FilePath pathWithInvalidFileNameCharacters = + base::FilePath(kInvalidFileNameCharacters) + .AddExtension(FILE_PATH_LITERAL("txt")); + const base::FilePath empty_display_name(FILE_PATH_LITERAL("")); + const base::FilePath maxpath_display_name = + base::FilePath(base::string16(MAX_PATH - 5, L'a')) + .AddExtension(FILE_PATH_LITERAL("txt")); + + const std::vector<std::pair<base::FilePath, std::string>> + kTestFilenames_and_Contents = { + {pathWithInvalidFileNameCharacters, std::string("just some data")}, + {pathWithInvalidFileNameCharacters, + std::string("just some data\0with\0nulls", 25)}, + {// Test that still get a unique name if a previous uniquified + // name is duplicate of this one. + pathWithInvalidFileNameCharacters.InsertBeforeExtension( + FILE_PATH_LITERAL(" (1)")), + std::string("just some more data")}, + // Expect a default display name to be generated ("download" if it + // matters). + {empty_display_name, std::string("data for an empty display name")}, + {empty_display_name, + std::string("data for another empty display name")}, + // Expect a good behavior if the display name length exceeds MAX_PATH. + {maxpath_display_name, + std::string("data for a >MAX_PATH display name")}, + {maxpath_display_name, + std::string("data for another >MAX_PATH display name")}, + }; + + for (const auto& tymed : kStorageMediaTypesForVirtualFiles) { + OSExchangeData data; + data.provider().SetVirtualFileContentsForTesting( + kTestFilenames_and_Contents, tymed); + + OSExchangeData copy(data.provider().Clone()); + std::vector<FileInfo> file_infos; + EXPECT_TRUE(copy.GetVirtualFilenames(&file_infos)); + EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size()); + for (size_t i = 0; i < file_infos.size(); i++) { + // Check that display name does not contain invalid characters. + EXPECT_EQ(std::string::npos, + file_infos[i].display_name.value().find_first_of( + kInvalidFileNameCharacters)); + // Check that display name is unique. + for (size_t j = 0; j < i; j++) { + EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase( + file_infos[j].display_name.value(), + file_infos[i].display_name.value())); + } + } + + std::string read_contents; + base::FilePath temp_dir; + EXPECT_TRUE(base::GetTempDir(&temp_dir)); + + // Callback for GetVirtualFilesAsTempFiles is executed when all virtual + // files are backed by temp files. + auto callback = + base::BindOnce(&OSExchangeDataWinTest::OnGotVirtualFilesAsTempFiles, + base::Unretained(this)); + + EXPECT_TRUE(copy.GetVirtualFilesAsTempFiles(std::move(callback))); + + // RunUntilIdle assures all async tasks are run. + scoped_task_environment_.RunUntilIdle(); + + EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size()); + for (size_t i = 0; i < retrieved_virtual_files_.size(); i++) { + // Check that display name does not contain invalid characters. + EXPECT_EQ(std::string::npos, + retrieved_virtual_files_[i].display_name.value().find_first_of( + kInvalidFileNameCharacters)); + // Check that display name is unique. + for (size_t j = 0; j < i; j++) { + EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase( + retrieved_virtual_files_[j].display_name.value(), + retrieved_virtual_files_[i].display_name.value())); + } + // Check that temp file path does not contain invalid characters (except + // for separator). + EXPECT_EQ(std::string::npos, + retrieved_virtual_files_[i].path.value().find_first_of( + kInvalidFilePathCharacters)); + // Check that temp file path is unique. + for (size_t j = 0; j < i; j++) { + EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase( + retrieved_virtual_files_[j].path.value(), + retrieved_virtual_files_[i].path.value())); + } + + EXPECT_EQ(temp_dir, retrieved_virtual_files_[i].path.DirName()); + EXPECT_EQ(kTestFilenames_and_Contents[i].first.Extension(), + retrieved_virtual_files_[i].path.Extension()); + // Ability to read the contents implies a temp file was successfully + // created on the file system even though the original suggested display + // name had invalid filename characters. + EXPECT_TRUE(base::ReadFileToString(retrieved_virtual_files_[i].path, + &read_contents)); + if (tymed != TYMED_ISTORAGE) { + EXPECT_EQ(kTestFilenames_and_Contents[i].second, read_contents); + } else { + // IStorage uses compound files, so temp files won't be flat text files. + // Just make sure the original contents appears in the compound files. + EXPECT_TRUE(read_contents.find(kTestFilenames_and_Contents[i].second) != + std::string::npos); + } + } + } +} + +TEST_F(OSExchangeDataWinTest, VirtualFilesEmptyContents) { + const std::vector<std::pair<base::FilePath, std::string>> + kTestFilenames_and_Contents = { + {base::FilePath(FILE_PATH_LITERAL("file_with_no_contents.txt")), + std::string()}, + }; + + for (const auto& tymed : kStorageMediaTypesForVirtualFiles) { + OSExchangeData data; + data.provider().SetVirtualFileContentsForTesting( + kTestFilenames_and_Contents, tymed); + + OSExchangeData copy(data.provider().Clone()); + std::vector<FileInfo> file_infos; + EXPECT_TRUE(copy.GetVirtualFilenames(&file_infos)); + EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size()); + for (size_t i = 0; i < file_infos.size(); i++) { + EXPECT_EQ(kTestFilenames_and_Contents[i].first, + file_infos[i].display_name); + } + + std::string read_contents; + base::FilePath temp_dir; + EXPECT_TRUE(base::GetTempDir(&temp_dir)); + + // Callback for GetVirtualFilesAsTempFiles is executed when all virtual + // files are backed by temp files. + auto callback = + base::BindOnce(&OSExchangeDataWinTest::OnGotVirtualFilesAsTempFiles, + base::Unretained(this)); + + EXPECT_TRUE(copy.GetVirtualFilesAsTempFiles(std::move(callback))); + + // RunUntilIdle assures all async tasks are run. + scoped_task_environment_.RunUntilIdle(); + + EXPECT_EQ(kTestFilenames_and_Contents.size(), + retrieved_virtual_files_.size()); + for (size_t i = 0; i < retrieved_virtual_files_.size(); i++) { + EXPECT_EQ(kTestFilenames_and_Contents[i].first, + retrieved_virtual_files_[i].display_name); + EXPECT_EQ(temp_dir, retrieved_virtual_files_[i].path.DirName()); + EXPECT_EQ(kTestFilenames_and_Contents[i].first.Extension(), + retrieved_virtual_files_[i].path.Extension()); + EXPECT_TRUE(base::ReadFileToString(retrieved_virtual_files_[i].path, + &read_contents)); + // IStorage uses compound files, so temp files won't be flat text files. + // Just make sure the original contents appear in the compound files. + if (tymed != TYMED_ISTORAGE) { + EXPECT_EQ(kTestFilenames_and_Contents[i].second, read_contents); + EXPECT_EQ(static_cast<size_t>(0), read_contents.length()); + } + } + } +} + +TEST_F(OSExchangeDataWinTest, CFHtml) { OSExchangeData data; GURL url("http://www.google.com/"); std::wstring html( @@ -332,13 +814,13 @@ ReleaseStgMedium(&medium); } -TEST(OSExchangeDataWinTest, SetURLWithMaxPath) { +TEST_F(OSExchangeDataWinTest, SetURLWithMaxPath) { OSExchangeData data; std::wstring long_title(L'a', MAX_PATH + 1); data.SetURL(GURL("http://google.com"), long_title); } -TEST(OSExchangeDataWinTest, ProvideURLForPlainTextURL) { +TEST_F(OSExchangeDataWinTest, ProvideURLForPlainTextURL) { OSExchangeData data; data.SetString(L"http://google.com");
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc index e9e01b0..b409030 100644 --- a/ui/base/ui_base_features.cc +++ b/ui/base/ui_base_features.cc
@@ -138,6 +138,13 @@ const base::Feature kMojoIMF = {"MojoIMF", base::FEATURE_DISABLED_BY_DEFAULT}; #endif +const base::Feature kFormControlsRefresh = {"FormControlsRefresh", + base::FEATURE_DISABLED_BY_DEFAULT}; + +bool IsFormControlsRefreshEnabled() { + return base::FeatureList::IsEnabled(features::kFormControlsRefresh); +} + bool IsUsingWindowService() { return IsSingleProcessMash() || IsMultiProcessMash(); }
diff --git a/ui/base/ui_base_features.h b/ui/base/ui_base_features.h index 462b7ab..918dcb5 100644 --- a/ui/base/ui_base_features.h +++ b/ui/base/ui_base_features.h
@@ -83,6 +83,11 @@ COMPONENT_EXPORT(UI_BASE_FEATURES) extern const base::Feature kMojoIMF; #endif +// Used to enable the new controls UI. +COMPONENT_EXPORT(UI_BASE_FEATURES) +extern const base::Feature kFormControlsRefresh; +COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsFormControlsRefreshEnabled(); + // Returns true if Chrome's aura usage is backed by the WindowService. COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsUsingWindowService();
diff --git a/ui/events/blink/blink_event_util.cc b/ui/events/blink/blink_event_util.cc index d29859e..f71c8e2 100644 --- a/ui/events/blink/blink_event_util.cc +++ b/ui/events/blink/blink_event_util.cc
@@ -1215,6 +1215,29 @@ return EventPointerType::POINTER_TYPE_UNKNOWN; } +blink::WebGestureEvent ScrollBeginFromScrollUpdate( + const blink::WebGestureEvent& gesture_update) { + DCHECK(gesture_update.GetType() == WebInputEvent::kGestureScrollUpdate); + + WebGestureEvent scroll_begin(gesture_update); + scroll_begin.SetType(WebInputEvent::kGestureScrollBegin); + + scroll_begin.data.scroll_begin.delta_x_hint = + gesture_update.data.scroll_update.delta_x; + scroll_begin.data.scroll_begin.delta_y_hint = + gesture_update.data.scroll_update.delta_y; + scroll_begin.data.scroll_begin.delta_hint_units = + gesture_update.data.scroll_update.delta_units; + scroll_begin.data.scroll_begin.target_viewport = false; + scroll_begin.data.scroll_begin.inertial_phase = + gesture_update.data.scroll_update.inertial_phase; + scroll_begin.data.scroll_begin.synthetic = false; + scroll_begin.data.scroll_begin.pointer_count = 0; + scroll_begin.data.scroll_begin.scrollable_area_element_id = 0; + + return scroll_begin; +} + #if defined(OS_ANDROID) std::unique_ptr<WebGestureEvent> CreateWebGestureEventFromGestureEventAndroid( const GestureEventAndroid& event) {
diff --git a/ui/events/blink/blink_event_util.h b/ui/events/blink/blink_event_util.h index d354ec32..9649fad 100644 --- a/ui/events/blink/blink_event_util.h +++ b/ui/events/blink/blink_event_util.h
@@ -110,6 +110,9 @@ return static_cast<const blink::WebGestureEvent&>(event); } +blink::WebGestureEvent ScrollBeginFromScrollUpdate( + const blink::WebGestureEvent& scroll_update); + #if defined(OS_ANDROID) // Convenience method that converts an instance to blink event. std::unique_ptr<blink::WebGestureEvent>
diff --git a/ui/events/ozone/evdev/event_device_info.cc b/ui/events/ozone/evdev/event_device_info.cc index fd279b18..8642f0f 100644 --- a/ui/events/ozone/evdev/event_device_info.cc +++ b/ui/events/ozone/evdev/event_device_info.cc
@@ -480,8 +480,9 @@ uint16_t vid; uint16_t pid; } kUSBInternalDevices[] = { - { 0x18d1, 0x5030 }, // Google, Hammer PID - { 0x1fd2, 0x8103 } // LG, Internal TouchScreen PID + {0x18d1, 0x5030}, // Google, Hammer PID (nocturne) + {0x18d1, 0x502b}, // Google, Hammer PID (soraka) + {0x1fd2, 0x8103}, // LG, Internal TouchScreen PID }; if (id.bustype == BUS_USB) {
diff --git a/ui/native_theme/native_theme_aura.cc b/ui/native_theme/native_theme_aura.cc index e30452b..0e50ee39 100644 --- a/ui/native_theme/native_theme_aura.cc +++ b/ui/native_theme/native_theme_aura.cc
@@ -14,6 +14,7 @@ #include "cc/paint/paint_flags.h" #include "third_party/skia/include/core/SkPath.h" #include "ui/base/layout.h" +#include "ui/base/ui_base_features.h" #include "ui/gfx/animation/tween.h" #include "ui/gfx/canvas.h" #include "ui/gfx/color_palette.h" @@ -42,6 +43,20 @@ const SkColor kTrackColor = SkColorSetRGB(0xF1, 0xF1, 0xF1); +const int kCheckboxBorderRadius = 2; +const int kCheckboxAndRadioBorderWidth = 1; +const SkColor kCheckboxAndRadioTinyColor = SK_ColorGRAY; +const SkColor kCkeckboxAndRadioBackgroundColor = + SkColorSetRGB(0xFF, 0xFF, 0xFF); +const SkColor kCheckboxAndRadioBorderColor = SkColorSetRGB(0xCE, 0xCE, 0xCE); +const SkColor kCheckboxAndRadioBorderHoveredColor = + SkColorSetRGB(0x9D, 0x9D, 0x9D); +const SkColor kCheckboxAndRadioBorderDisabledColor = + SkColorSetRGB(0xC5, 0xC5, 0xC5); +const SkColor kCheckboxAndRadioStrokeColor = SkColorSetRGB(0x73, 0x73, 0x73); +const SkColor kCheckboxAndRadioStrokeDisabledColor = + SkColorSetRGB(0xC5, 0xC5, 0xC5); + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -300,6 +315,135 @@ canvas->drawIRect(RectToSkIRect(rect), flags); } +void NativeThemeAura::PaintCheckbox(cc::PaintCanvas* canvas, + State state, + const gfx::Rect& rect, + const ButtonExtraParams& button) const { + if (!features::IsFormControlsRefreshEnabled()) { + return NativeThemeBase::PaintCheckbox(canvas, state, rect, button); + } + + SkRect skrect = PaintCheckboxRadioCommon( + canvas, state, rect, SkIntToScalar(kCheckboxBorderRadius)); + + if (!skrect.isEmpty()) { + // Draw the checkmark / dash. + cc::PaintFlags flags; + flags.setAntiAlias(true); + + if (state == kDisabled) { + flags.setColor(kCheckboxAndRadioStrokeDisabledColor); + } else { + flags.setColor(kCheckboxAndRadioStrokeColor); + } + + if (button.indeterminate) { + const auto indeterminate = + skrect.makeInset(skrect.width() * 0.2, skrect.height() * 0.2); + flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->drawRoundRect(indeterminate, SkIntToScalar(kCheckboxBorderRadius), + SkIntToScalar(kCheckboxBorderRadius), flags); + } else if (button.checked) { + SkPath check; + check.moveTo(skrect.x() + skrect.width() * 0.2, skrect.centerY()); + check.rLineTo(skrect.width() * 0.2, skrect.height() * 0.2); + check.lineTo(skrect.right() - skrect.width() * 0.2, + skrect.y() + skrect.height() * 0.2); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(SkFloatToScalar(skrect.height() * 0.16)); + canvas->drawPath(check, flags); + } + } +} + +void NativeThemeAura::PaintRadio(cc::PaintCanvas* canvas, + State state, + const gfx::Rect& rect, + const ButtonExtraParams& button) const { + if (!features::IsFormControlsRefreshEnabled()) { + return NativeThemeBase::PaintRadio(canvas, state, rect, button); + } + + // Most of a radio button is the same as a checkbox, except the the rounded + // square is a circle (i.e. border radius >= 100%). + const SkScalar radius = SkFloatToScalar( + static_cast<float>(std::max(rect.width(), rect.height())) * 0.5); + + SkRect skrect = PaintCheckboxRadioCommon(canvas, state, rect, radius); + if (!skrect.isEmpty() && button.checked) { + // Draw the dot. + cc::PaintFlags flags; + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kFill_Style); + if (state == kDisabled) { + flags.setColor(kCheckboxAndRadioStrokeDisabledColor); + } else { + flags.setColor(kCheckboxAndRadioStrokeColor); + } + skrect.inset(skrect.width() * 0.2, skrect.height() * 0.2); + // Use drawRoundedRect instead of drawOval to be completely consistent + // with the border in PaintCheckboxRadioNewCommon. + canvas->drawRoundRect(skrect, radius, radius, flags); + } +} + +// Draws the common elements of checkboxes and radio buttons. +// Returns the rectangle within which any additional decorations should be +// drawn, or empty if none. +SkRect NativeThemeAura::PaintCheckboxRadioCommon( + cc::PaintCanvas* canvas, + State state, + const gfx::Rect& rect, + const SkScalar borderRadius) const { + SkRect skrect = gfx::RectToSkRect(rect); + + // Use the largest square that fits inside the provided rectangle. + // No other browser seems to support non-square widget, so accidentally + // having non-square sizes is common (eg. amazon and webkit dev tools). + if (skrect.width() != skrect.height()) { + SkScalar size = SkMinScalar(skrect.width(), skrect.height()); + skrect.inset((skrect.width() - size) / 2, (skrect.height() - size) / 2); + } + + // If the rectangle is too small then paint only a rectangle. We don't want + // to have to worry about '- 1' and '+ 1' calculations below having overflow + // or underflow. + if (skrect.width() <= 2) { + cc::PaintFlags flags; + flags.setColor(kCheckboxAndRadioTinyColor); + flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->drawRect(skrect, flags); + // Too small to draw anything more. + return SkRect::MakeEmpty(); + } + + cc::PaintFlags flags; + flags.setAntiAlias(true); + + const SkScalar borderWidth = SkIntToScalar(kCheckboxAndRadioBorderWidth); + + // Paint the background (is not visible behind the rounded corners). + skrect.inset(borderWidth / 2, borderWidth / 2); + flags.setColor(kCkeckboxAndRadioBackgroundColor); + flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->drawRoundRect(skrect, borderRadius, borderRadius, flags); + + // Draw the border. + if (state == kHovered) { + flags.setColor(kCheckboxAndRadioBorderHoveredColor); + } else if (state == kDisabled) { + flags.setColor(kCheckboxAndRadioBorderDisabledColor); + } else { + flags.setColor(kCheckboxAndRadioBorderColor); + } + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(borderWidth); + canvas->drawRoundRect(skrect, borderRadius, borderRadius, flags); + + // Return the rectangle for drawing any additional decorations. + return skrect; +} + gfx::Size NativeThemeAura::GetPartSize(Part part, State state, const ExtraParams& extra) const {
diff --git a/ui/native_theme/native_theme_aura.h b/ui/native_theme/native_theme_aura.h index 8618514..6ce6a8a4 100644 --- a/ui/native_theme/native_theme_aura.h +++ b/ui/native_theme/native_theme_aura.h
@@ -52,6 +52,14 @@ void PaintScrollbarCorner(cc::PaintCanvas* canvas, State state, const gfx::Rect& rect) const override; + void PaintCheckbox(cc::PaintCanvas* canvas, + State state, + const gfx::Rect& rect, + const ButtonExtraParams& button) const override; + void PaintRadio(cc::PaintCanvas* canvas, + State state, + const gfx::Rect& rect, + const ButtonExtraParams& button) const override; gfx::Size GetPartSize(Part part, State state, const ExtraParams& extra) const override; @@ -60,6 +68,13 @@ gfx::Rect GetNinePatchAperture(Part part) const override; private: + // Paint the common parts of the checkboxes and radio buttons. + // borderRadius specifies how rounded the corners should be. + SkRect PaintCheckboxRadioCommon(cc::PaintCanvas* canvas, + State state, + const gfx::Rect& rect, + const SkScalar borderRadius) const; + bool use_overlay_scrollbars_; DISALLOW_COPY_AND_ASSIGN(NativeThemeAura);
diff --git a/ui/ozone/demo/vulkan_renderer.cc b/ui/ozone/demo/vulkan_renderer.cc index 106a88c..945937f 100644 --- a/ui/ozone/demo/vulkan_renderer.cc +++ b/ui/ozone/demo/vulkan_renderer.cc
@@ -16,6 +16,7 @@ #include "gpu/vulkan/vulkan_command_buffer.h" #include "gpu/vulkan/vulkan_command_pool.h" #include "gpu/vulkan/vulkan_device_queue.h" +#include "gpu/vulkan/vulkan_fence_helper.h" #include "gpu/vulkan/vulkan_function_pointers.h" #include "gpu/vulkan/vulkan_implementation.h" #include "gpu/vulkan/vulkan_surface.h" @@ -24,6 +25,64 @@ namespace ui { +namespace { +VkPipelineStageFlags GetPipelineStageFlags(const VkImageLayout layout) { + switch (layout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + case VK_IMAGE_LAYOUT_GENERAL: + return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + case VK_IMAGE_LAYOUT_PREINITIALIZED: + return VK_PIPELINE_STAGE_HOST_BIT; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + return VK_PIPELINE_STAGE_TRANSFER_BIT; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | + VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | + VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + default: + NOTREACHED() << "layout=" << layout; + } + return 0; +} + +VkAccessFlags GetAccessMask(const VkImageLayout layout) { + switch (layout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + return 0; + case VK_IMAGE_LAYOUT_GENERAL: + DLOG(WARNING) << "VK_IMAGE_LAYOUT_GENERAL is used."; + return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_HOST_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT; + case VK_IMAGE_LAYOUT_PREINITIALIZED: + return VK_ACCESS_HOST_WRITE_BIT; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + return VK_ACCESS_TRANSFER_READ_BIT; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + return VK_ACCESS_TRANSFER_WRITE_BIT; + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + return 0; + default: + NOTREACHED() << "layout=" << layout; + } + return 0; +} +} // namespace + VulkanRenderer::VulkanRenderer( std::unique_ptr<PlatformWindowSurface> window_surface, std::unique_ptr<gpu::VulkanSurface> vulkan_surface, @@ -155,13 +214,6 @@ gpu::VulkanSwapChain* vulkan_swap_chain = vulkan_surface_->GetSwapChain(); const uint32_t num_images = vulkan_swap_chain->num_images(); framebuffers_.resize(num_images); - - for (uint32_t image = 0; image < num_images; ++image) { - framebuffers_[image] = - Framebuffer::Create(device_queue_.get(), command_pool_.get(), - render_pass_, vulkan_surface_.get(), image); - CHECK(framebuffers_[image]); - } } void VulkanRenderer::RenderFrame() { @@ -172,42 +224,87 @@ gpu::VulkanSwapChain* vulkan_swap_chain = vulkan_surface_->GetSwapChain(); const uint32_t image = vulkan_swap_chain->current_image(); - const Framebuffer& framebuffer = *framebuffers_[image]; - - gpu::VulkanCommandBuffer& command_buffer = *framebuffer.command_buffer(); - + gpu::VulkanSwapChain::ScopedWrite scoped_write(vulkan_swap_chain); { - gpu::ScopedSingleUseCommandBufferRecorder recorder(command_buffer); + auto& framebuffer = framebuffers_[image]; + if (!framebuffer) { + framebuffer = Framebuffer::Create( + device_queue_.get(), command_pool_.get(), render_pass_, + vulkan_surface_.get(), scoped_write.image()); + CHECK(framebuffer); + } - VkRenderPassBeginInfo begin_info = { - /* .sType = */ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - /* .pNext = */ nullptr, - /* .renderPass = */ render_pass_, - /* .framebuffer = */ framebuffer.vk_framebuffer(), - /* .renderArea = */ - { - /* .offset = */ { - /* .x = */ 0, - /* .y = */ 0, - }, - /* .extent = */ - { - /* .width = */ vulkan_swap_chain->size().width(), - /* .height = */ vulkan_swap_chain->size().height(), - }, - }, - /* .clearValueCount = */ 1, - /* .pClearValues = */ &clear_value, - }; + gpu::VulkanCommandBuffer& command_buffer = *framebuffer->command_buffer(); - vkCmdBeginRenderPass(recorder.handle(), &begin_info, - VK_SUBPASS_CONTENTS_INLINE); + { + gpu::ScopedSingleUseCommandBufferRecorder recorder(command_buffer); + VkImageLayout old_layout = scoped_write.image_layout(); + VkImageLayout layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkImageMemoryBarrier image_memory_barrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = GetAccessMask(old_layout), + .dstAccessMask = GetAccessMask(layout), + .oldLayout = old_layout, + .newLayout = layout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = scoped_write.image(), + .subresourceRange = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + vkCmdPipelineBarrier( + recorder.handle(), GetPipelineStageFlags(old_layout), + GetPipelineStageFlags(layout), 0 /* dependencyFlags */, + 0 /* memoryBarrierCount */, nullptr /* pMemoryBarriers */, + 0 /* bufferMemoryBarrierCount */, nullptr /* pBufferMemoryBarriers */, + 1, &image_memory_barrier); + scoped_write.set_image_layout(layout); - vkCmdEndRenderPass(recorder.handle()); + VkRenderPassBeginInfo begin_info = { + /* .sType = */ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + /* .pNext = */ nullptr, + /* .renderPass = */ render_pass_, + /* .framebuffer = */ framebuffer->vk_framebuffer(), + /* .renderArea = */ + { + /* .offset = */ { + /* .x = */ 0, + /* .y = */ 0, + }, + /* .extent = */ + { + /* .width = */ vulkan_swap_chain->size().width(), + /* .height = */ vulkan_swap_chain->size().height(), + }, + }, + /* .clearValueCount = */ 1, + /* .pClearValues = */ &clear_value, + }; + + vkCmdBeginRenderPass(recorder.handle(), &begin_info, + VK_SUBPASS_CONTENTS_INLINE); + + vkCmdEndRenderPass(recorder.handle()); + } + VkSemaphore begin_semaphore = scoped_write.TakeBeginSemaphore(); + VkSemaphoreCreateInfo vk_semaphore_create_info = { + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; + VkSemaphore end_semaphore; + CHECK(vkCreateSemaphore(device_queue_->GetVulkanDevice(), + &vk_semaphore_create_info, nullptr /* pAllocator */, + &end_semaphore) == VK_SUCCESS); + CHECK(command_buffer.Submit(1, &begin_semaphore, 1, &end_semaphore)); + scoped_write.SetEndSemaphore(end_semaphore); + device_queue_->GetFenceHelper()->EnqueueSemaphoreCleanupForSubmittedWork( + begin_semaphore); } - - CHECK(command_buffer.Submit(0, nullptr, 0, nullptr)); - vulkan_swap_chain->SwapBuffers(); PostRenderFrameTask(); @@ -234,14 +331,14 @@ gpu::VulkanCommandPool* vulkan_command_pool, VkRenderPass vk_render_pass, gpu::VulkanSurface* vulkan_surface, - uint32_t vulkan_swap_chain_image_index) { + VkImage image) { gpu::VulkanSwapChain* vulkan_swap_chain = vulkan_surface->GetSwapChain(); const VkDevice vk_device = vulkan_device_queue->GetVulkanDevice(); VkImageViewCreateInfo vk_image_view_create_info = { /* .sType = */ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, /* .pNext = */ nullptr, /* .flags = */ 0, - /* .image = */ vulkan_swap_chain->GetImage(vulkan_swap_chain_image_index), + /* .image = */ image, /* .viewType = */ VK_IMAGE_VIEW_TYPE_2D, /* .format = */ vulkan_surface->surface_format().format, /* .components = */
diff --git a/ui/ozone/demo/vulkan_renderer.h b/ui/ozone/demo/vulkan_renderer.h index b340f14b..0542a94 100644 --- a/ui/ozone/demo/vulkan_renderer.h +++ b/ui/ozone/demo/vulkan_renderer.h
@@ -52,7 +52,7 @@ gpu::VulkanCommandPool* vulkan_command_pool, VkRenderPass vk_render_pass, gpu::VulkanSurface* vulkan_surface, - uint32_t vulkan_swap_chain_image_index); + VkImage image); VkImageView vk_image_view() const { return vk_image_view_; } VkFramebuffer vk_framebuffer() const { return vk_framebuffer_; }
diff --git a/ui/views/controls/native/native_view_host.cc b/ui/views/controls/native/native_view_host.cc index f8e2082d..c53aaa7 100644 --- a/ui/views/controls/native/native_view_host.cc +++ b/ui/views/controls/native/native_view_host.cc
@@ -33,13 +33,13 @@ DCHECK(!native_view_); native_view_ = native_view; native_wrapper_->AttachNativeView(); - // This does not use InvalidateLayout() to ensure the visibility state of - // the NativeView is correctly set (if this View isn't visible, Layout() - // won't, be called, resulting in the NativeView potentially having the wrong - // visibility state). - // TODO(https://crbug.com/947051): inestigate removing updating visibility - // immediately and calling InvalidateLayout() to update bounds. - Layout(); + InvalidateLayout(); + // The call to InvalidateLayout() triggers an async call to Layout(), which + // updates the visibility of the NativeView. The call to Layout() only happens + // if |this| is drawn. Call hide if not drawn as otherwise the NativeView + // could be visible when |this| is not. + if (!IsDrawn()) + native_wrapper_->HideWidget(); Widget* widget = Widget::GetWidgetForNativeView(native_view); if (widget) @@ -221,7 +221,8 @@ } void NativeViewHost::SetVisible(bool visible) { - native_wrapper_->SetVisible(visible); + if (native_view_) + native_wrapper_->SetVisible(visible); View::SetVisible(visible); }
diff --git a/ui/views/controls/native/native_view_host_aura_unittest.cc b/ui/views/controls/native/native_view_host_aura_unittest.cc index 2587ff5..11da73e 100644 --- a/ui/views/controls/native/native_view_host_aura_unittest.cc +++ b/ui/views/controls/native/native_view_host_aura_unittest.cc
@@ -324,6 +324,10 @@ // a regression test for http://crbug.com/389261. TEST_F(NativeViewHostAuraTest, ParentAfterDetach) { CreateHost(); + // Force a Layout() now so that the visibility is set to false (because the + // bounds is empty). + host()->Layout(); + aura::Window* child_win = child()->GetNativeView(); aura::Window* root_window = child_win->GetRootWindow(); aura::WindowTreeHost* child_win_tree_host = child_win->GetHost(); @@ -397,6 +401,10 @@ host()->Attach(child()->GetNativeView()); + // Visibiliity is not updated until Layout() happens. This is normally async, + // but force a Layout() so this code doesn't have to wait. + host()->Layout(); + ASSERT_EQ(3u, test_observer.events().size()); EXPECT_EQ(NativeViewHostWindowObserver::EVENT_BOUNDS_CHANGED, test_observer.events()[0].type); @@ -550,4 +558,20 @@ DestroyTopLevel(); } +TEST_F(NativeViewHostAuraTest, WindowHiddenWhenAttached) { + std::unique_ptr<aura::Window> window = + std::make_unique<aura::Window>(nullptr); + window->Init(ui::LAYER_NOT_DRAWN); + window->set_owned_by_parent(false); + window->Show(); + EXPECT_TRUE(window->TargetVisibility()); + CreateTopLevel(); + NativeViewHost* host = toplevel()->GetRootView()->AddChildView( + std::make_unique<NativeViewHost>()); + host->SetVisible(false); + host->Attach(window.get()); + // Is |host| is not visible, |window| should immediately be hidden. + EXPECT_FALSE(window->TargetVisibility()); +} + } // namespace views
diff --git a/ui/views/controls/native/native_view_host_mac_unittest.mm b/ui/views/controls/native/native_view_host_mac_unittest.mm index 2e9881b9..56d26ce2 100644 --- a/ui/views/controls/native/native_view_host_mac_unittest.mm +++ b/ui/views/controls/native/native_view_host_mac_unittest.mm
@@ -126,6 +126,8 @@ EXPECT_TRUE([native_view_ superview]); EXPECT_TRUE([native_view_ window]); + // Layout() is normally async, call it now to ensure bounds have been applied. + host()->Layout(); // Expect the top-left to be 10 pixels below the titlebar. int bottom = toplevel()->GetClientAreaBoundsInScreen().height() - 10 - 60; EXPECT_NSEQ(NSMakeRect(10, bottom, 80, 60), [native_view_ frame]); @@ -198,6 +200,9 @@ host()->SetVisible(true); EXPECT_TRUE([native_view_ isHidden]); // Stays hidden. host()->Attach(native_view_.get()); + // Layout() updates visibility, and is normally async, call it now to ensure + // visibility updated. + host()->Layout(); EXPECT_FALSE([native_view_ isHidden]); // Made visible when attached. EXPECT_TRUE([native_view_ superview]);
diff --git a/ui/views/controls/webview/webview_unittest.cc b/ui/views/controls/webview/webview_unittest.cc index 3431a5d..8950e86 100644 --- a/ui/views/controls/webview/webview_unittest.cc +++ b/ui/views/controls/webview/webview_unittest.cc
@@ -214,6 +214,8 @@ EXPECT_FALSE(observer1.was_shown()); web_view()->SetWebContents(web_contents1.get()); + // Layout() is normally async, call it now to ensure visibility is updated. + web_view()->Layout(); EXPECT_TRUE(observer1.was_shown()); #if defined(USE_AURA) EXPECT_TRUE(web_contents1->GetNativeView()->IsVisible()); @@ -232,6 +234,8 @@ // Setting the new WebContents should hide the existing one. web_view()->SetWebContents(web_contents2.get()); + // Layout() is normally async, call it now to ensure visibility is updated. + web_view()->Layout(); EXPECT_FALSE(observer1.was_shown()); EXPECT_TRUE(observer2.was_shown()); EXPECT_TRUE(observer2.valid_root_while_shown()); @@ -249,6 +253,8 @@ EXPECT_EQ(1, observer1.shown_count()); web_view()->SetWebContents(web_contents1.get()); + // Layout() is normally async, call it now to ensure visibility is updated. + web_view()->Layout(); EXPECT_EQ(1, observer1.shown_count()); // Nothing else should change.