diff --git a/DEPS b/DEPS index 2f4d620..790cec54 100644 --- a/DEPS +++ b/DEPS
@@ -162,11 +162,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': '8050d94ae227c9d5427b130d8a3d3671d2e0c87d', + 'skia_revision': 'a3d88db57fc52dc42455179ee29aa15ad34cc1e3', # 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': 'b2ea4d05947ae3eaa20c1fa9c53f8565cbc1d3b9', + 'v8_revision': '23c7a63ca141f53efe4d2982fb9abf767837a7c3', # 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. @@ -174,11 +174,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'c26869d540f3a01ab720401f69f7979b743612af', + 'angle_revision': '4376600310936a326d7fbefea686e92c39d6994b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '920100cd4246da21d35f49cbd21bea97616bb1c2', + 'swiftshader_revision': '92577e5ada3774834fbf8c117394de832cb24cab', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -301,7 +301,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'quiche_revision': '45f8f861073d321294d735c077b67fddb5ba2cee', + 'quiche_revision': 'a702be24f14465228289a929ad33f4216afdea99', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ios_webkit # and whatever else without interference from each other. @@ -1246,7 +1246,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '0241d109250612661024b3918cdaccc81f9512ef', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '9082eee1ee320369975a3572a53a8d05fe51d8d0', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1414,7 +1414,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'abaae129d9a0c6e1e092067e0b105475df43352e', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'ce202a0f987c51f70a3643a2d9dd05b7abfb01ba', + Var('webrtc_git') + '/src.git' + '@' + '1aa7e2fa2d6de586253d93575b2d3b6ae70cb056', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1455,7 +1455,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d597c831131ea4aeb6c72eec1773f0332dbb9d1f', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d084daf67ccab650341df35248d924fbfe5b1664', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn index e7df6730..aec353a 100644 --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn
@@ -883,6 +883,7 @@ ":strings_grd", ":system_webview_manifest", "//base:base_java", + "//base:jni_java", "//components/autofill/android:autofill_java", "//components/autofill/android:provider_java", "//components/background_task_scheduler:background_task_scheduler_task_ids_java", @@ -907,6 +908,7 @@ "//third_party/blink/public:blink_headers_java", "//ui/android:ui_java", ] + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] if (enable_spellcheck) { deps += [ "//components/spellcheck/browser/android:java" ]
diff --git a/android_webview/apk/BUILD.gn b/android_webview/apk/BUILD.gn index 2daa630..bc42c2b 100644 --- a/android_webview/apk/BUILD.gn +++ b/android_webview/apk/BUILD.gn
@@ -34,7 +34,9 @@ "//android_webview:android_webview_locale_config_java", "//android_webview:common_commandline_java", "//base:base_java", + "//base:jni_java", "//components/embedder_support/android:application_java", "//ui/android:ui_java", ] + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] }
diff --git a/android_webview/apk/java/src/com/android/webview/chromium/WebViewApkApplication.java b/android_webview/apk/java/src/com/android/webview/chromium/WebViewApkApplication.java index da9af528..07be7667 100644 --- a/android_webview/apk/java/src/com/android/webview/chromium/WebViewApkApplication.java +++ b/android_webview/apk/java/src/com/android/webview/chromium/WebViewApkApplication.java
@@ -12,6 +12,7 @@ import org.chromium.base.ContextUtils; import org.chromium.base.PathUtils; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.components.embedder_support.application.FontPreloadingWorkaround; import org.chromium.ui.base.ResourceBundle; @@ -78,9 +79,12 @@ return false; } LibraryLoader.getInstance().switchCommandLineForWebView(); - nativeInitializePakResources(); + WebViewApkApplicationJni.get().initializePakResources(); return true; } - private static native void nativeInitializePakResources(); + @NativeMethods + interface Natives { + void initializePakResources(); + } }
diff --git a/android_webview/glue/BUILD.gn b/android_webview/glue/BUILD.gn index 5906de6..dde944083 100644 --- a/android_webview/glue/BUILD.gn +++ b/android_webview/glue/BUILD.gn
@@ -17,12 +17,14 @@ "//android_webview/support_library/boundary_interfaces:boundary_interface_java", "//android_webview/support_library/callback:callback_java", "//base:base_java", + "//base:jni_java", "//components/autofill/android:autofill_java", "//components/autofill/android:provider_java", "//content/public/android:content_java", "//net/android:net_java", "//ui/android:ui_java", ] + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] alternative_android_sdk_dep = "//third_party/android_sdk:public_framework_system_java"
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/DrawFunctor.java b/android_webview/glue/java/src/com/android/webview/chromium/DrawFunctor.java index 6ebd1cb2..2763aae 100644 --- a/android_webview/glue/java/src/com/android/webview/chromium/DrawFunctor.java +++ b/android_webview/glue/java/src/com/android/webview/chromium/DrawFunctor.java
@@ -3,10 +3,15 @@ // found in the LICENSE file. package com.android.webview.chromium; +import org.chromium.base.annotations.NativeMethods; class DrawFunctor { public static long getDrawFnFunctionTable() { - return nativeGetFunctionTable(); + return DrawFunctorJni.get().getFunctionTable(); } - private static native long nativeGetFunctionTable(); + + @NativeMethods + interface Natives { + long getFunctionTable(); + } }
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/DrawGLFunctor.java b/android_webview/glue/java/src/com/android/webview/chromium/DrawGLFunctor.java index 5fbf7e57..d3f86bef 100644 --- a/android_webview/glue/java/src/com/android/webview/chromium/DrawGLFunctor.java +++ b/android_webview/glue/java/src/com/android/webview/chromium/DrawGLFunctor.java
@@ -11,6 +11,7 @@ import com.android.webview.chromium.WebViewDelegateFactory.WebViewDelegate; import org.chromium.android_webview.AwContents; +import org.chromium.base.annotations.NativeMethods; /** * Simple Java abstraction and wrapper for the native DrawGLFunctor flow. @@ -26,7 +27,7 @@ private long mNativeDrawGLFunctor; public DrawGLFunctor(long viewContext, WebViewDelegate webViewDelegate) { - mNativeDrawGLFunctor = nativeCreateGLFunctor(viewContext); + mNativeDrawGLFunctor = DrawGLFunctorJni.get().createGLFunctor(viewContext); mWebViewDelegate = webViewDelegate; } @@ -80,15 +81,18 @@ @Override public void destroy() { assert mNativeDrawGLFunctor != 0; - nativeDestroyGLFunctor(mNativeDrawGLFunctor); + DrawGLFunctorJni.get().destroyGLFunctor(mNativeDrawGLFunctor); mNativeDrawGLFunctor = 0; } public static void setChromiumAwDrawGLFunction(long functionPointer) { - nativeSetChromiumAwDrawGLFunction(functionPointer); + DrawGLFunctorJni.get().setChromiumAwDrawGLFunction(functionPointer); } - private static native long nativeCreateGLFunctor(long viewContext); - private static native void nativeDestroyGLFunctor(long functor); - private static native void nativeSetChromiumAwDrawGLFunction(long functionPointer); + @NativeMethods + interface Natives { + long createGLFunctor(long viewContext); + void destroyGLFunctor(long functor); + void setChromiumAwDrawGLFunction(long functionPointer); + } }
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/GraphicsUtils.java b/android_webview/glue/java/src/com/android/webview/chromium/GraphicsUtils.java index 64ff225..ab4b627 100644 --- a/android_webview/glue/java/src/com/android/webview/chromium/GraphicsUtils.java +++ b/android_webview/glue/java/src/com/android/webview/chromium/GraphicsUtils.java
@@ -3,16 +3,20 @@ // found in the LICENSE file. package com.android.webview.chromium; +import org.chromium.base.annotations.NativeMethods; abstract class GraphicsUtils { public static long getDrawSWFunctionTable() { - return nativeGetDrawSWFunctionTable(); + return GraphicsUtilsJni.get().getDrawSWFunctionTable(); } public static long getDrawGLFunctionTable() { - return nativeGetDrawGLFunctionTable(); + return GraphicsUtilsJni.get().getDrawGLFunctionTable(); } - private static native long nativeGetDrawSWFunctionTable(); - private static native long nativeGetDrawGLFunctionTable(); + @NativeMethods + interface Natives { + long getDrawSWFunctionTable(); + long getDrawGLFunctionTable(); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AndroidProtocolHandler.java b/android_webview/java/src/org/chromium/android_webview/AndroidProtocolHandler.java index 10a0090..75154513 100644 --- a/android_webview/java/src/org/chromium/android_webview/AndroidProtocolHandler.java +++ b/android_webview/java/src/org/chromium/android_webview/AndroidProtocolHandler.java
@@ -12,6 +12,7 @@ import org.chromium.base.ContextUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import java.io.IOException; import java.io.InputStream; @@ -60,9 +61,10 @@ try { if (uri.getScheme().equals(FILE_SCHEME)) { String path = uri.getPath(); - if (path.startsWith(nativeGetAndroidAssetPath())) { + if (path.startsWith(AndroidProtocolHandlerJni.get().getAndroidAssetPath())) { return openAsset(uri); - } else if (path.startsWith(nativeGetAndroidResourcePath())) { + } else if (path.startsWith( + AndroidProtocolHandlerJni.get().getAndroidResourcePath())) { return openResource(uri); } } else if (uri.getScheme().equals(CONTENT_SCHEME)) { @@ -124,7 +126,7 @@ private static InputStream openResource(Uri uri) { assert uri.getScheme().equals(FILE_SCHEME); assert uri.getPath() != null; - assert uri.getPath().startsWith(nativeGetAndroidResourcePath()); + assert uri.getPath().startsWith(AndroidProtocolHandlerJni.get().getAndroidResourcePath()); // The path must be of the form "/android_res/asset_type/asset_name.ext". List<String> pathSegments = uri.getPathSegments(); if (pathSegments.size() != 3) { @@ -134,9 +136,12 @@ String assetPath = pathSegments.get(0); String assetType = pathSegments.get(1); String assetName = pathSegments.get(2); - if (!("/" + assetPath + "/").equals(nativeGetAndroidResourcePath())) { - Log.e(TAG, "Resource path does not start with " + nativeGetAndroidResourcePath() - + ": " + uri); + if (!("/" + assetPath + "/") + .equals(AndroidProtocolHandlerJni.get().getAndroidResourcePath())) { + Log.e(TAG, + "Resource path does not start with " + + AndroidProtocolHandlerJni.get().getAndroidResourcePath() + ": " + + uri); return null; } // Drop the file extension. @@ -165,8 +170,9 @@ private static InputStream openAsset(Uri uri) { assert uri.getScheme().equals(FILE_SCHEME); assert uri.getPath() != null; - assert uri.getPath().startsWith(nativeGetAndroidAssetPath()); - String path = uri.getPath().replaceFirst(nativeGetAndroidAssetPath(), ""); + assert uri.getPath().startsWith(AndroidProtocolHandlerJni.get().getAndroidAssetPath()); + String path = uri.getPath().replaceFirst( + AndroidProtocolHandlerJni.get().getAndroidAssetPath(), ""); try { AssetManager assets = ContextUtils.getApplicationContext().getAssets(); return assets.open(path, AssetManager.ACCESS_STREAMING); @@ -215,7 +221,7 @@ return mimeType; // Asset files may have a known extension. } else if (uri.getScheme().equals(FILE_SCHEME) - && path.startsWith(nativeGetAndroidAssetPath())) { + && path.startsWith(AndroidProtocolHandlerJni.get().getAndroidAssetPath())) { String mimeType = URLConnection.guessContentTypeFromName(path); if (mimeType == null) { AwHistogramRecorder.recordMimeType( @@ -268,7 +274,9 @@ return uri; } - private static native String nativeGetAndroidAssetPath(); - - private static native String nativeGetAndroidResourcePath(); + @NativeMethods + interface Natives { + String getAndroidAssetPath(); + String getAndroidResourcePath(); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwAutofillClient.java b/android_webview/java/src/org/chromium/android_webview/AwAutofillClient.java index 4012849a..52771aa 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwAutofillClient.java +++ b/android_webview/java/src/org/chromium/android_webview/AwAutofillClient.java
@@ -9,6 +9,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import org.chromium.components.autofill.AutofillDelegate; import org.chromium.components.autofill.AutofillPopup; import org.chromium.components.autofill.AutofillSuggestion; @@ -45,18 +46,20 @@ if (mAutofillPopup == null) { if (WindowAndroid.activityFromContext(mContext) == null) { - nativeDismissed(mNativeAwAutofillClient); + AwAutofillClientJni.get().dismissed(mNativeAwAutofillClient, AwAutofillClient.this); return; } try { mAutofillPopup = new AutofillPopup(mContext, anchorView, new AutofillDelegate() { @Override public void dismissed() { - nativeDismissed(mNativeAwAutofillClient); + AwAutofillClientJni.get().dismissed( + mNativeAwAutofillClient, AwAutofillClient.this); } @Override public void suggestionSelected(int listIndex) { - nativeSuggestionSelected(mNativeAwAutofillClient, listIndex); + AwAutofillClientJni.get().suggestionSelected( + mNativeAwAutofillClient, AwAutofillClient.this, listIndex); } @Override public void deleteSuggestion(int listIndex) {} @@ -67,7 +70,7 @@ } catch (RuntimeException e) { // Deliberately swallowing exception because bad fraemwork implementation can // throw exceptions in ListPopupWindow constructor. - nativeDismissed(mNativeAwAutofillClient); + AwAutofillClientJni.get().dismissed(mNativeAwAutofillClient, AwAutofillClient.this); return; } } @@ -101,7 +104,9 @@ false /* isMultilineLabel */, false /* isBoldLabel */); } - private native void nativeDismissed(long nativeAwAutofillClient); - private native void nativeSuggestionSelected(long nativeAwAutofillClient, - int position); + @NativeMethods + interface Natives { + void dismissed(long nativeAwAutofillClient, AwAutofillClient caller); + void suggestionSelected(long nativeAwAutofillClient, AwAutofillClient caller, int position); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java b/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java index cf9191d..77a8afd 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java +++ b/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java
@@ -13,6 +13,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import org.chromium.base.memory.MemoryPressureMonitor; import org.chromium.content_public.browser.ContentViewStatics; @@ -96,8 +97,8 @@ public AwQuotaManagerBridge getQuotaManagerBridge() { if (mQuotaManagerBridge == null) { - mQuotaManagerBridge = - new AwQuotaManagerBridge(nativeGetQuotaManagerBridge(mNativeAwBrowserContext)); + mQuotaManagerBridge = new AwQuotaManagerBridge( + AwBrowserContextJni.get().getQuotaManagerBridge(mNativeAwBrowserContext)); } return mQuotaManagerBridge; } @@ -141,7 +142,7 @@ private static AwBrowserContext sInstance; public static AwBrowserContext getDefault() { if (sInstance == null) { - sInstance = nativeGetDefaultJava(); + sInstance = AwBrowserContextJni.get().getDefaultJava(); } return sInstance; } @@ -158,6 +159,9 @@ return new AwBrowserContext(sharedPreferences, nativeAwBrowserContext, isDefault); } - private static native AwBrowserContext nativeGetDefaultJava(); - private static native long nativeGetQuotaManagerBridge(long nativeAwBrowserContext); + @NativeMethods + interface Natives { + AwBrowserContext getDefaultJava(); + long getQuotaManagerBridge(long nativeAwBrowserContext); + } }
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 c89c838..8aeaac3c 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -64,6 +64,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.CalledByNativeUnchecked; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.ScopedSysTraceEvent; import org.chromium.base.task.AsyncTask; @@ -175,7 +176,7 @@ private static class ForceAuxiliaryBitmapRendering { private static final boolean sResult = lazyCheck(); private static boolean lazyCheck() { - return !nativeHasRequiredHardwareExtensions(); + return !AwContentsJni.get().hasRequiredHardwareExtensions(); } } @@ -422,7 +423,7 @@ // The base background color, i.e. not accounting for any CSS body from the current page. private int mBaseBackgroundColor = Color.WHITE; - // Must call nativeUpdateLastHitTestData first to update this before use. + // Must call AwContentsJni.get().updateLastHitTestData first to update this before use. private final HitTestData mPossiblyStaleHitTestData = new HitTestData(); private final DefaultVideoPosterRequestHandler mDefaultVideoPosterRequestHandler; @@ -526,7 +527,7 @@ @Override public void run() { - nativeDestroy(mNativeAwContents); + AwContentsJni.get().destroy(mNativeAwContents); } } @@ -744,13 +745,16 @@ @Override public void scrollNativeTo(int x, int y) { - if (!isDestroyed(NO_WARN)) nativeScrollTo(mNativeAwContents, x, y); + if (!isDestroyed(NO_WARN)) { + AwContentsJni.get().scrollTo(mNativeAwContents, AwContents.this, x, y); + } } @Override public void smoothScroll(int targetX, int targetY, long durationMs) { if (!isDestroyed(NO_WARN)) { - nativeSmoothScroll(mNativeAwContents, targetX, targetY, durationMs); + AwContentsJni.get().smoothScroll( + mNativeAwContents, AwContents.this, targetX, targetY, durationMs); } } @@ -828,7 +832,7 @@ mDrawFunctor.trimMemory(); } } - nativeTrimMemory(mNativeAwContents, level, visible); + AwContentsJni.get().trimMemory(mNativeAwContents, AwContents.this, level, visible); }); } @@ -850,7 +854,7 @@ public void onDIPScaleChanged(float dipScale) { if (TRACE) Log.i(TAG, "%s onDIPScaleChanged dipScale=%f", this, dipScale); - nativeSetDipScale(mNativeAwContents, dipScale); + AwContentsJni.get().setDipScale(mNativeAwContents, AwContents.this, dipScale); mLayoutSizer.setDIPScale(dipScale); mSettings.setDIPScale(dipScale); } @@ -945,7 +949,7 @@ setOverScrollMode(mContainerView.getOverScrollMode()); setScrollBarStyle(mInternalAccessAdapter.super_getScrollBarStyle()); - setNewAwContents(nativeInit(mBrowserContext.getNativePointer())); + setNewAwContents(AwContentsJni.get().init(mBrowserContext.getNativePointer())); onContainerViewChanged(); } @@ -1069,7 +1073,7 @@ } if (!isDestroyed(NO_WARN)) { - nativeRestoreScrollAfterTransition(mNativeAwContents, + AwContentsJni.get().restoreScrollAfterTransition(mNativeAwContents, AwContents.this, mFullScreenTransitionsState.getScrollX(), mFullScreenTransitionsState.getScrollY()); } @@ -1199,7 +1203,8 @@ // Android N. LocaleUtils.getDefaultLocaleString() is capable for UI language but // it is not guaranteed to be listed at the first of sCurrentLocales. Therefore, // both values are passed to native. - nativeUpdateDefaultLocale(LocaleUtils.getDefaultLocaleString(), sCurrentLocales); + AwContentsJni.get().updateDefaultLocale( + LocaleUtils.getDefaultLocaleString(), sCurrentLocales); mSettings.updateAcceptLanguages(); } } @@ -1214,7 +1219,7 @@ } private void updateNativeAwGLFunctor() { - nativeSetCompositorFrameConsumer(mNativeAwContents, + AwContentsJni.get().setCompositorFrameConsumer(mNativeAwContents, AwContents.this, mDrawFunctor != null ? mDrawFunctor.getNativeCompositorFrameConsumer() : 0); } @@ -1254,8 +1259,8 @@ mNativeAwContents = newAwContentsPtr; updateNativeAwGLFunctor(); - mWebContents = nativeGetWebContents(mNativeAwContents); - mBrowserContext = nativeGetBrowserContext(mNativeAwContents); + mWebContents = AwContentsJni.get().getWebContents(mNativeAwContents, AwContents.this); + mBrowserContext = AwContentsJni.get().getBrowserContext(mNativeAwContents, AwContents.this); mWindowAndroid = getWindowAndroid(mContext); mViewAndroidDelegate = @@ -1263,8 +1268,9 @@ mWebContentsInternalsHolder = new WebContentsInternalsHolder(this); initWebContents(mViewAndroidDelegate, mInternalAccessAdapter, mWebContents, mWindowAndroid.getWindowAndroid(), mWebContentsInternalsHolder); - nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge, - mNetworkClient, mInterceptNavigationDelegate, mAutofillProvider); + AwContentsJni.get().setJavaPeers(mNativeAwContents, AwContents.this, this, + mWebContentsDelegate, mContentsClientBridge, mNetworkClient, + mInterceptNavigationDelegate, mAutofillProvider); GestureListenerManager.fromWebContents(mWebContents) .addListener(new AwGestureStateListener()); @@ -1296,14 +1302,15 @@ */ public void supplyContentsForPopup(AwContents newContents) { if (isDestroyed(WARN)) return; - long popupNativeAwContents = nativeReleasePopupAwContents(mNativeAwContents); + long popupNativeAwContents = + AwContentsJni.get().releasePopupAwContents(mNativeAwContents, AwContents.this); if (popupNativeAwContents == 0) { Log.w(TAG, "Popup WebView bind failed: no pending content."); if (newContents != null) newContents.destroy(); return; } if (newContents == null) { - nativeDestroy(popupNativeAwContents); + AwContentsJni.get().destroy(popupNativeAwContents); return; } @@ -1341,7 +1348,8 @@ setNewAwContents(popupNativeAwContents); // We defer loading any URL on the popup until it has been properly intialized (through // setNewAwContents). We resume the load here. - nativeResumeLoadingCreatedPopupWebContents(mNativeAwContents); + AwContentsJni.get().resumeLoadingCreatedPopupWebContents( + mNativeAwContents, AwContents.this); // Finally refresh all view state for mNativeAwContents. if (!wasPaused) onResume(); @@ -1389,14 +1397,14 @@ @CalledByNativeUnchecked protected boolean onRenderProcessGone(int childProcessID, boolean crashed) { if (isDestroyed(NO_WARN)) return true; - return mContentsClient.onRenderProcessGone(new AwRenderProcessGoneDetail( - crashed, nativeGetEffectivePriority(mNativeAwContents))); + return mContentsClient.onRenderProcessGone(new AwRenderProcessGoneDetail(crashed, + AwContentsJni.get().getEffectivePriority(mNativeAwContents, AwContents.this))); } @VisibleForTesting public @RendererPriority int getEffectivePriorityForTesting() { assert !isDestroyed(NO_WARN); - return nativeGetEffectivePriority(mNativeAwContents); + return AwContentsJni.get().getEffectivePriority(mNativeAwContents, AwContents.this); } /** @@ -1499,17 +1507,18 @@ if (isDestroyed(WARN)) return null; if (mAwPdfExporter == null) { mAwPdfExporter = new AwPdfExporter(mContainerView); - nativeCreatePdfExporter(mNativeAwContents, mAwPdfExporter); + AwContentsJni.get().createPdfExporter( + mNativeAwContents, AwContents.this, mAwPdfExporter); } return mAwPdfExporter; } public static void setAwDrawSWFunctionTable(long functionTablePointer) { - nativeSetAwDrawSWFunctionTable(functionTablePointer); + AwContentsJni.get().setAwDrawSWFunctionTable(functionTablePointer); } public static void setAwDrawGLFunctionTable(long functionTablePointer) { - nativeSetAwDrawGLFunctionTable(functionTablePointer); + AwContentsJni.get().setAwDrawGLFunctionTable(functionTablePointer); } public static long getAwDrawGLFunction() { @@ -1517,7 +1526,7 @@ } public static void setShouldDownloadFavicons() { - nativeSetShouldDownloadFavicons(); + AwContentsJni.get().setShouldDownloadFavicons(); } public static Activity activityFromContext(Context context) { @@ -1543,7 +1552,7 @@ */ @VisibleForTesting public static int getNativeInstanceCount() { - return nativeGetNativeInstanceCount(); + return AwContentsJni.get().getNativeInstanceCount(); } // This is only to avoid heap allocations inside getGlobalVisibleRect. It should treated @@ -1595,14 +1604,14 @@ public Picture capturePicture() { if (TRACE) Log.i(TAG, "%s capturePicture", this); if (isDestroyed(WARN)) return null; - return new AwPicture(nativeCapturePicture(mNativeAwContents, + return new AwPicture(AwContentsJni.get().capturePicture(mNativeAwContents, AwContents.this, mScrollOffsetManager.computeHorizontalScrollRange(), mScrollOffsetManager.computeVerticalScrollRange())); } public void clearView() { if (TRACE) Log.i(TAG, "%s clearView", this); - if (!isDestroyed(WARN)) nativeClearView(mNativeAwContents); + if (!isDestroyed(WARN)) AwContentsJni.get().clearView(mNativeAwContents, AwContents.this); } /** @@ -1618,22 +1627,28 @@ } else if (enabled && mPictureListenerContentProvider == null) { mPictureListenerContentProvider = () -> capturePicture(); } - nativeEnableOnNewPicture(mNativeAwContents, enabled); + AwContentsJni.get().enableOnNewPicture(mNativeAwContents, AwContents.this, enabled); } public void findAllAsync(String searchString) { if (TRACE) Log.i(TAG, "%s findAllAsync", this); - if (!isDestroyed(WARN)) nativeFindAllAsync(mNativeAwContents, searchString); + if (!isDestroyed(WARN)) { + AwContentsJni.get().findAllAsync(mNativeAwContents, AwContents.this, searchString); + } } public void findNext(boolean forward) { if (TRACE) Log.i(TAG, "%s findNext", this); - if (!isDestroyed(WARN)) nativeFindNext(mNativeAwContents, forward); + if (!isDestroyed(WARN)) { + AwContentsJni.get().findNext(mNativeAwContents, AwContents.this, forward); + } } public void clearMatches() { if (TRACE) Log.i(TAG, "%s clearMatches", this); - if (!isDestroyed(WARN)) nativeClearMatches(mNativeAwContents); + if (!isDestroyed(WARN)) { + AwContentsJni.get().clearMatches(mNativeAwContents, AwContents.this); + } } /** @@ -1662,7 +1677,7 @@ PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> { if (!isDestroyed(NO_WARN)) { - nativeAddVisitedLinks(mNativeAwContents, value); + AwContentsJni.get().addVisitedLinks(mNativeAwContents, AwContents.this, value); } }); }; @@ -1918,7 +1933,8 @@ // file:///android_res/ URLs. If AwSettings.getAllowFileAccess permits, it will also // allow access to file:// URLs (subject to OS level permission checks). params.setCanLoadLocalResources(true); - nativeGrantFileSchemeAccesstoChildProcess(mNativeAwContents); + AwContentsJni.get().grantFileSchemeAccesstoChildProcess( + mNativeAwContents, AwContents.this); } // If we are reloading the same url, then set transition type as reload. @@ -1951,8 +1967,8 @@ } } - nativeSetExtraHeadersForUrl( - mNativeAwContents, params.getUrl(), params.getExtraHttpRequestHeadersString()); + AwContentsJni.get().setExtraHeadersForUrl(mNativeAwContents, AwContents.this, + params.getUrl(), params.getExtraHttpRequestHeadersString()); params.setExtraHeaders(new HashMap<String, String>()); mNavigationController.loadUrl(params); @@ -1999,7 +2015,9 @@ public void setBackgroundColor(int color) { mBaseBackgroundColor = color; - if (!isDestroyed(WARN)) nativeSetBackgroundColor(mNativeAwContents, color); + if (!isDestroyed(WARN)) { + AwContentsJni.get().setBackgroundColor(mNativeAwContents, AwContents.this, color); + } } /** @@ -2252,7 +2270,7 @@ if (TRACE) Log.i(TAG, "%s onPause", this); if (mIsPaused || isDestroyed(NO_WARN)) return; mIsPaused = true; - nativeSetIsPaused(mNativeAwContents, mIsPaused); + AwContentsJni.get().setIsPaused(mNativeAwContents, AwContents.this, mIsPaused); // Geolocation is paused/resumed via the page visibility mechanism. updateWebContentsVisibility(); @@ -2265,7 +2283,7 @@ if (TRACE) Log.i(TAG, "%s onResume", this); if (!mIsPaused || isDestroyed(NO_WARN)) return; mIsPaused = false; - nativeSetIsPaused(mNativeAwContents, mIsPaused); + AwContentsJni.get().setIsPaused(mNativeAwContents, AwContents.this, mIsPaused); updateWebContentsVisibility(); } @@ -2312,7 +2330,9 @@ */ public void clearCache(boolean includeDiskFiles) { if (TRACE) Log.i(TAG, "%s clearCache", this); - if (!isDestroyed(WARN)) nativeClearCache(mNativeAwContents, includeDiskFiles); + if (!isDestroyed(WARN)) { + AwContentsJni.get().clearCache(mNativeAwContents, AwContents.this, includeDiskFiles); + } } @VisibleForTesting @@ -2322,11 +2342,13 @@ throw new IllegalStateException("killRenderProcess() shouldn't be invoked after render" + " process is gone or webview is destroyed"); } - nativeKillRenderProcess(mNativeAwContents); + AwContentsJni.get().killRenderProcess(mNativeAwContents, AwContents.this); } public void documentHasImages(Message message) { - if (!isDestroyed(WARN)) nativeDocumentHasImages(mNativeAwContents, message); + if (!isDestroyed(WARN)) { + AwContentsJni.get().documentHasImages(mNativeAwContents, AwContents.this, message); + } } public void saveWebArchive( @@ -2390,7 +2412,8 @@ public SslCertificate getCertificate() { return isDestroyed(WARN) ? null - : SslUtil.getCertificateFromDerBytes(nativeGetCertificate(mNativeAwContents)); + : SslUtil.getCertificateFromDerBytes( + AwContentsJni.get().getCertificate(mNativeAwContents, AwContents.this)); } /** @@ -2410,7 +2433,7 @@ public HitTestData getLastHitTestResult() { if (TRACE) Log.i(TAG, "%s getLastHitTestResult", this); if (isDestroyed(WARN)) return null; - nativeUpdateLastHitTestData(mNativeAwContents); + AwContentsJni.get().updateLastHitTestData(mNativeAwContents, AwContents.this); return mPossiblyStaleHitTestData; } @@ -2421,7 +2444,7 @@ if (TRACE) Log.i(TAG, "%s requestFocusNodeHref", this); if (msg == null || isDestroyed(WARN)) return; - nativeUpdateLastHitTestData(mNativeAwContents); + AwContentsJni.get().updateLastHitTestData(mNativeAwContents, AwContents.this); Bundle data = msg.getData(); // In order to maintain compatibility with the old WebView's implementation, @@ -2440,7 +2463,7 @@ if (TRACE) Log.i(TAG, "%s requestImageRef", this); if (msg == null || isDestroyed(WARN)) return; - nativeUpdateLastHitTestData(mNativeAwContents); + AwContentsJni.get().updateLastHitTestData(mNativeAwContents, AwContents.this); Bundle data = msg.getData(); data.putString("url", mPossiblyStaleHitTestData.imgSrc); msg.setData(data); @@ -2495,8 +2518,9 @@ } mWebMessageListener = listener; - final String exceptionMessage = nativeSetJsApiService(mNativeAwContents, - /* needToInjectJsObject*/ true, jsObjectName, allowedOriginRules); + final String exceptionMessage = + AwContentsJni.get().setJsApiService(mNativeAwContents, AwContents.this, + /* needToInjectJsObject*/ true, jsObjectName, allowedOriginRules); if (!TextUtils.isEmpty(exceptionMessage)) { mWebMessageListener = null; @@ -2510,8 +2534,8 @@ */ public void unsetWebMessageListener() { mWebMessageListener = null; - nativeSetJsApiService( - mNativeAwContents, /* needToInjectJsObject */ false, "", new String[0]); + AwContentsJni.get().setJsApiService(mNativeAwContents, AwContents.this, + /* needToInjectJsObject */ false, "", new String[0]); } /** @@ -2633,7 +2657,7 @@ if (delta < 0.01f || delta > 100.0f) { throw new IllegalStateException("zoom delta value outside [0.01, 100] range."); } - nativeZoomBy(mNativeAwContents, delta); + AwContentsJni.get().zoomBy(mNativeAwContents, AwContents.this, delta); } /** @@ -2649,7 +2673,8 @@ */ public void preauthorizePermission(Uri origin, long resources) { if (isDestroyed(NO_WARN)) return; - nativePreauthorizePermission(mNativeAwContents, origin.toString(), resources); + AwContentsJni.get().preauthorizePermission( + mNativeAwContents, AwContents.this, origin.toString(), resources); } /** @@ -2891,7 +2916,8 @@ private void setViewVisibilityInternal(boolean visible) { mIsViewVisible = visible; if (!isDestroyed(NO_WARN)) { - nativeSetViewVisibility(mNativeAwContents, mIsViewVisible); + AwContentsJni.get().setViewVisibility( + mNativeAwContents, AwContents.this, mIsViewVisible); } postUpdateWebContentsVisibility(); } @@ -2901,7 +2927,8 @@ && visible && !mIsWindowVisible; mIsWindowVisible = visible; if (!isDestroyed(NO_WARN)) { - nativeSetWindowVisibility(mNativeAwContents, mIsWindowVisible); + AwContentsJni.get().setWindowVisibility( + mNativeAwContents, AwContents.this, mIsWindowVisible); } postUpdateWebContentsVisibility(); } @@ -2925,7 +2952,7 @@ private void updateWebContentsVisibility() { mIsUpdateVisibilityTaskPending = false; if (isDestroyed(NO_WARN)) return; - boolean contentVisible = nativeIsVisible(mNativeAwContents); + boolean contentVisible = AwContentsJni.get().isVisible(mNativeAwContents, AwContents.this); if (contentVisible && !mIsContentVisible) { mWebContents.onShow(); @@ -2945,7 +2972,7 @@ @VisibleForTesting public boolean isPageVisible() { if (isDestroyed(NO_WARN)) return mIsContentVisible; - return nativeIsVisible(mNativeAwContents); + return AwContentsJni.get().isVisible(mNativeAwContents, AwContents.this); } /** @@ -2961,7 +2988,7 @@ if (TRACE) Log.i(TAG, "%s saveState", this); if (isDestroyed(WARN) || outState == null) return false; - byte[] state = nativeGetOpaqueState(mNativeAwContents); + byte[] state = AwContentsJni.get().getOpaqueState(mNativeAwContents, AwContents.this); if (state == null) return false; outState.putByteArray(SAVE_RESTORE_STATE_KEY, state); @@ -2980,7 +3007,8 @@ byte[] state = inState.getByteArray(SAVE_RESTORE_STATE_KEY); if (state == null) return false; - boolean result = nativeRestoreFromOpaqueState(mNativeAwContents, state); + boolean result = AwContentsJni.get().restoreFromOpaqueState( + mNativeAwContents, AwContents.this, state); // The onUpdateTitle callback normally happens when a page is loaded, // but is optimized out in the restoreState case because the title is @@ -3054,7 +3082,7 @@ // Network Information API to prevent inconsistencies, // see crbug.com/520088. NetworkChangeNotifier.setAutoDetectConnectivityState(false); - nativeSetJsOnlineProperty(mNativeAwContents, networkUp); + AwContentsJni.get().setJsOnlineProperty(mNativeAwContents, AwContents.this, networkUp); } } @@ -3079,7 +3107,8 @@ if (TRACE) Log.i(TAG, "%s insertVisualStateCallback", this); if (isDestroyed(NO_WARN)) throw new IllegalStateException( "insertVisualStateCallback cannot be called after the WebView has been destroyed"); - nativeInsertVisualStateCallback(mNativeAwContents, requestId, callback); + AwContentsJni.get().insertVisualStateCallback( + mNativeAwContents, AwContents.this, requestId, callback); } public boolean isPopupWindow() { @@ -3140,7 +3169,7 @@ if (isDestroyed(WARN)) { return null; } - return nativeGetRenderProcess(mNativeAwContents); + return AwContentsJni.get().getRenderProcess(mNativeAwContents, AwContents.this); } //-------------------------------------------------------------------------------------------- @@ -3192,7 +3221,8 @@ public void invokeGeolocationCallback(boolean value, String requestingFrame) { if (isDestroyed(NO_WARN)) return; - nativeInvokeGeolocationCallback(mNativeAwContents, value, requestingFrame); + AwContentsJni.get().invokeGeolocationCallback( + mNativeAwContents, AwContents.this, value, requestingFrame); } @CalledByNative @@ -3201,13 +3231,14 @@ AwGeolocationPermissions permissions = mBrowserContext.getGeolocationPermissions(); // Reject if geoloaction is disabled, or the origin has a retained deny if (!mSettings.getGeolocationEnabled()) { - nativeInvokeGeolocationCallback(mNativeAwContents, false, origin); + AwContentsJni.get().invokeGeolocationCallback( + mNativeAwContents, AwContents.this, false, origin); return; } // Allow if the origin has a retained allow if (permissions.hasOrigin(origin)) { - nativeInvokeGeolocationCallback(mNativeAwContents, permissions.isOriginAllowed(origin), - origin); + AwContentsJni.get().invokeGeolocationCallback(mNativeAwContents, AwContents.this, + permissions.isOriginAllowed(origin), origin); return; } mContentsClient.onGeolocationPermissionsShowPrompt( @@ -3259,7 +3290,7 @@ PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> callback.onComplete(requestId)); } - // Called as a result of nativeUpdateLastHitTestData. + // Called as a result of AwContentsJni.get().updateLastHitTestData. @CalledByNative private void updateHitTestData( int type, String extra, String href, String anchorText, String imgSrc) { @@ -3417,7 +3448,8 @@ jsCallback = jsonResult -> callback.onResult(jsonResult); } - nativeEvaluateJavaScriptOnInterstitialForTesting(mNativeAwContents, script, jsCallback); + AwContentsJni.get().evaluateJavaScriptOnInterstitialForTesting( + mNativeAwContents, AwContents.this, script, jsCallback); } @CalledByNative @@ -3432,7 +3464,7 @@ */ @VisibleForTesting public static String getSafeBrowsingLocaleForTesting() { - return nativeGetSafeBrowsingLocaleForTesting(); + return AwContentsJni.get().getSafeBrowsingLocaleForTesting(); } // ------------------------------------------------------------------------------------------- @@ -3463,7 +3495,7 @@ PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> callback.onResult(null)); } else { - nativeGenerateMHTML(mNativeAwContents, path, callback); + AwContentsJni.get().generateMHTML(mNativeAwContents, AwContents.this, path, callback); } } @@ -3519,7 +3551,8 @@ long requestId, VisualStateCallback callback) { if (TRACE) Log.i(TAG, "%s insertVisualStateCallbackIfNotDestroyed", this); if (isDestroyed(NO_WARN)) return; - nativeInsertVisualStateCallback(mNativeAwContents, requestId, callback); + AwContentsJni.get().insertVisualStateCallback( + mNativeAwContents, AwContents.this, requestId, callback); } public static boolean isDpadEvent(KeyEvent event) { @@ -3594,12 +3627,13 @@ } canvas.drawRect(0, 0, 1, 1, mPaintForNWorkaround); } - boolean did_draw = nativeOnDraw(mNativeAwContents, canvas, - canvas.isHardwareAccelerated(), scrollX, scrollY, globalVisibleRect.left, - globalVisibleRect.top, globalVisibleRect.right, globalVisibleRect.bottom, - ForceAuxiliaryBitmapRendering.sResult); + boolean did_draw = AwContentsJni.get().onDraw(mNativeAwContents, AwContents.this, + canvas, canvas.isHardwareAccelerated(), scrollX, scrollY, + globalVisibleRect.left, globalVisibleRect.top, globalVisibleRect.right, + globalVisibleRect.bottom, ForceAuxiliaryBitmapRendering.sResult); if (canvas.isHardwareAccelerated() - && nativeNeedToDrawBackgroundColor(mNativeAwContents)) { + && AwContentsJni.get().needToDrawBackgroundColor( + mNativeAwContents, AwContents.this)) { TraceEvent.instant("DrawBackgroundColor"); canvas.drawColor(getEffectiveBackgroundColor()); } @@ -3637,7 +3671,7 @@ public void requestFocus() { if (isDestroyed(NO_WARN)) return; if (!mContainerView.isInTouchMode() && mSettings.shouldFocusFirstNode()) { - nativeFocusFirstNode(mNativeAwContents); + AwContentsJni.get().focusFirstNode(mNativeAwContents, AwContents.this); } } @@ -3716,7 +3750,8 @@ eventY /= dipScale; touchMajor /= dipScale; } - nativeRequestNewHitTestDataAt(mNativeAwContents, eventX, eventY, touchMajor); + AwContentsJni.get().requestNewHitTestDataAt( + mNativeAwContents, AwContents.this, eventX, eventY, touchMajor); } if (mOverScrollGlow != null) { @@ -3763,8 +3798,8 @@ mIsAttachedToWindow = true; mViewEventSink.onAttachedToWindow(); - nativeOnAttachedToWindow(mNativeAwContents, mContainerView.getWidth(), - mContainerView.getHeight()); + AwContentsJni.get().onAttachedToWindow(mNativeAwContents, AwContents.this, + mContainerView.getWidth(), mContainerView.getHeight()); updateHardwareAcceleratedFeaturesToggle(); postUpdateWebContentsVisibility(); @@ -3784,7 +3819,7 @@ } mIsAttachedToWindow = false; hideAutofillPopup(); - nativeOnDetachedFromWindow(mNativeAwContents); + AwContentsJni.get().onDetachedFromWindow(mNativeAwContents, AwContents.this); mViewEventSink.onDetachedFromWindow(); updateHardwareAcceleratedFeaturesToggle(); @@ -3824,7 +3859,7 @@ // to enter fixedLayoutSize mode is sent before the first resize // update. mLayoutSizer.onSizeChanged(w, h, ow, oh); - nativeOnSizeChanged(mNativeAwContents, w, h, ow, oh); + AwContentsJni.get().onSizeChanged(mNativeAwContents, AwContents.this, w, h, ow, oh); } @Override @@ -3894,7 +3929,8 @@ @Override public void computeScroll() { if (isDestroyed(NO_WARN)) return; - nativeOnComputeScroll(mNativeAwContents, AnimationUtils.currentAnimationTimeMillis()); + AwContentsJni.get().onComputeScroll(mNativeAwContents, AwContents.this, + AnimationUtils.currentAnimationTimeMillis()); } @Override @@ -3928,106 +3964,94 @@ return true; } - //-------------------------------------------------------------------------------------------- - // Native methods - //-------------------------------------------------------------------------------------------- + @NativeMethods + interface Natives { + long init(long browserContextPointer); - private static native long nativeInit(long browserContextPointer); - private static native void nativeDestroy(long nativeAwContents); - private static native boolean nativeHasRequiredHardwareExtensions(); - private static native void nativeSetAwDrawSWFunctionTable(long functionTablePointer); - private static native void nativeSetAwDrawGLFunctionTable(long functionTablePointer); - private static native int nativeGetNativeInstanceCount(); - private static native void nativeSetShouldDownloadFavicons(); - private static native void nativeUpdateDefaultLocale(String locale, String localeList); - private static native String nativeGetSafeBrowsingLocaleForTesting(); + void destroy(long nativeAwContents); + boolean hasRequiredHardwareExtensions(); + void setAwDrawSWFunctionTable(long functionTablePointer); + void setAwDrawGLFunctionTable(long functionTablePointer); + int getNativeInstanceCount(); + void setShouldDownloadFavicons(); + void updateDefaultLocale(String locale, String localeList); + String getSafeBrowsingLocaleForTesting(); + void evaluateJavaScriptOnInterstitialForTesting(long nativeAwContents, AwContents caller, + String script, JavaScriptCallback jsCallback); + void setJavaPeers(long nativeAwContents, AwContents caller, AwContents awContents, + AwWebContentsDelegate webViewWebContentsDelegate, + AwContentsClientBridge contentsClientBridge, AwContentsNetworkClient ioThreadClient, + InterceptNavigationDelegate navigationInterceptionDelegate, + AutofillProvider autofillProvider); + WebContents getWebContents(long nativeAwContents, AwContents caller); + AwBrowserContext getBrowserContext(long nativeAwContents, AwContents caller); + void setCompositorFrameConsumer( + long nativeAwContents, AwContents caller, long nativeCompositorFrameConsumer); + void documentHasImages(long nativeAwContents, AwContents caller, Message message); + void generateMHTML( + long nativeAwContents, AwContents caller, String path, Callback<String> callback); + void addVisitedLinks(long nativeAwContents, AwContents caller, String[] visitedLinks); + void zoomBy(long nativeAwContents, AwContents caller, float delta); + void onComputeScroll( + long nativeAwContents, AwContents caller, long currentAnimationTimeMillis); + boolean onDraw(long nativeAwContents, AwContents caller, Canvas canvas, + boolean isHardwareAccelerated, int scrollX, int scrollY, int visibleLeft, + int visibleTop, int visibleRight, int visibleBottom, + boolean forceAuxiliaryBitmapRendering); + boolean needToDrawBackgroundColor(long nativeAwContents, AwContents caller); + void findAllAsync(long nativeAwContents, AwContents caller, String searchString); + void findNext(long nativeAwContents, AwContents caller, boolean forward); + void clearMatches(long nativeAwContents, AwContents caller); + void clearCache(long nativeAwContents, AwContents caller, boolean includeDiskFiles); + void killRenderProcess(long nativeAwContents, AwContents caller); + byte[] getCertificate(long nativeAwContents, AwContents caller); + // Coordinates are in physical pixels when --use-zoom-for-dsf is enabled. + // Otherwise, coordinates are in desity independent pixels. + void requestNewHitTestDataAt( + long nativeAwContents, AwContents caller, float x, float y, float touchMajor); - private native void nativeEvaluateJavaScriptOnInterstitialForTesting( - long nativeAwContents, String script, JavaScriptCallback jsCallback); - private native void nativeSetJavaPeers(long nativeAwContents, AwContents awContents, - AwWebContentsDelegate webViewWebContentsDelegate, - AwContentsClientBridge contentsClientBridge, AwContentsNetworkClient ioThreadClient, - InterceptNavigationDelegate navigationInterceptionDelegate, - AutofillProvider autofillProvider); - private native WebContents nativeGetWebContents(long nativeAwContents); - private native AwBrowserContext nativeGetBrowserContext(long nativeAwContents); - private native void nativeSetCompositorFrameConsumer( - long nativeAwContents, long nativeCompositorFrameConsumer); + void updateLastHitTestData(long nativeAwContents, AwContents caller); + void onSizeChanged(long nativeAwContents, AwContents caller, int w, int h, int ow, int oh); + void scrollTo(long nativeAwContents, AwContents caller, int x, int y); + void restoreScrollAfterTransition(long nativeAwContents, AwContents caller, int x, int y); + void smoothScroll(long nativeAwContents, AwContents caller, int targetX, int targetY, + long durationMs); + void setViewVisibility(long nativeAwContents, AwContents caller, boolean visible); + void setWindowVisibility(long nativeAwContents, AwContents caller, boolean visible); + void setIsPaused(long nativeAwContents, AwContents caller, boolean paused); + void onAttachedToWindow(long nativeAwContents, AwContents caller, int w, int h); + void onDetachedFromWindow(long nativeAwContents, AwContents caller); + boolean isVisible(long nativeAwContents, AwContents caller); + void setDipScale(long nativeAwContents, AwContents caller, float dipScale); + // Returns null if save state fails. + byte[] getOpaqueState(long nativeAwContents, AwContents caller); - private native void nativeDocumentHasImages(long nativeAwContents, Message message); - private native void nativeGenerateMHTML( - long nativeAwContents, String path, Callback<String> callback); + // Returns false if restore state fails. + boolean restoreFromOpaqueState(long nativeAwContents, AwContents caller, byte[] state); - private native void nativeAddVisitedLinks(long nativeAwContents, String[] visitedLinks); - private native void nativeZoomBy(long nativeAwContents, float delta); - private native void nativeOnComputeScroll( - long nativeAwContents, long currentAnimationTimeMillis); - private native boolean nativeOnDraw(long nativeAwContents, Canvas canvas, - boolean isHardwareAccelerated, int scrollX, int scrollY, int visibleLeft, - int visibleTop, int visibleRight, int visibleBottom, - boolean forceAuxiliaryBitmapRendering); - private native boolean nativeNeedToDrawBackgroundColor(long nativeAwContents); - private native void nativeFindAllAsync(long nativeAwContents, String searchString); - private native void nativeFindNext(long nativeAwContents, boolean forward); - private native void nativeClearMatches(long nativeAwContents); - private native void nativeClearCache(long nativeAwContents, boolean includeDiskFiles); - private native void nativeKillRenderProcess(long nativeAwContents); - private native byte[] nativeGetCertificate(long nativeAwContents); - - // Coordinates are in physical pixels when --use-zoom-for-dsf is enabled. - // Otherwise, coordinates are in desity independent pixels. - private native void nativeRequestNewHitTestDataAt(long nativeAwContents, float x, float y, - float touchMajor); - private native void nativeUpdateLastHitTestData(long nativeAwContents); - - private native void nativeOnSizeChanged(long nativeAwContents, int w, int h, int ow, int oh); - private native void nativeScrollTo(long nativeAwContents, int x, int y); - private native void nativeRestoreScrollAfterTransition(long nativeAwContents, int x, int y); - private native void nativeSmoothScroll( - long nativeAwContents, int targetX, int targetY, long durationMs); - private native void nativeSetViewVisibility(long nativeAwContents, boolean visible); - private native void nativeSetWindowVisibility(long nativeAwContents, boolean visible); - private native void nativeSetIsPaused(long nativeAwContents, boolean paused); - private native void nativeOnAttachedToWindow(long nativeAwContents, int w, int h); - private native void nativeOnDetachedFromWindow(long nativeAwContents); - private native boolean nativeIsVisible(long nativeAwContents); - private native void nativeSetDipScale(long nativeAwContents, float dipScale); - - // Returns null if save state fails. - private native byte[] nativeGetOpaqueState(long nativeAwContents); - - // Returns false if restore state fails. - private native boolean nativeRestoreFromOpaqueState(long nativeAwContents, byte[] state); - - private native long nativeReleasePopupAwContents(long nativeAwContents); - private native void nativeFocusFirstNode(long nativeAwContents); - private native void nativeSetBackgroundColor(long nativeAwContents, int color); - - private native long nativeCapturePicture(long nativeAwContents, int width, int height); - private native void nativeEnableOnNewPicture(long nativeAwContents, boolean enabled); - private native void nativeInsertVisualStateCallback( - long nativeAwContents, long requestId, VisualStateCallback callback); - private native void nativeClearView(long nativeAwContents); - private native void nativeSetExtraHeadersForUrl(long nativeAwContents, - String url, String extraHeaders); - - private native void nativeInvokeGeolocationCallback( - long nativeAwContents, boolean value, String requestingFrame); - private native int nativeGetEffectivePriority(long nativeAwContents); - - private native void nativeSetJsOnlineProperty(long nativeAwContents, boolean networkUp); - - private native void nativeTrimMemory(long nativeAwContents, int level, boolean visible); - - private native void nativeCreatePdfExporter(long nativeAwContents, AwPdfExporter awPdfExporter); - - private native void nativePreauthorizePermission(long nativeAwContents, String origin, - long resources); - - private native void nativeGrantFileSchemeAccesstoChildProcess(long nativeAwContents); - private native void nativeResumeLoadingCreatedPopupWebContents(long nativeAwContents); - - private native AwRenderProcess nativeGetRenderProcess(long nativeAwContents); - private native String nativeSetJsApiService(long nativeAwContents, boolean needToInjectJsObject, - String jsObjectName, String[] allowedOrigins); + long releasePopupAwContents(long nativeAwContents, AwContents caller); + void focusFirstNode(long nativeAwContents, AwContents caller); + void setBackgroundColor(long nativeAwContents, AwContents caller, int color); + long capturePicture(long nativeAwContents, AwContents caller, int width, int height); + void enableOnNewPicture(long nativeAwContents, AwContents caller, boolean enabled); + void insertVisualStateCallback(long nativeAwContents, AwContents caller, long requestId, + VisualStateCallback callback); + void clearView(long nativeAwContents, AwContents caller); + void setExtraHeadersForUrl( + long nativeAwContents, AwContents caller, String url, String extraHeaders); + void invokeGeolocationCallback( + long nativeAwContents, AwContents caller, boolean value, String requestingFrame); + int getEffectivePriority(long nativeAwContents, AwContents caller); + void setJsOnlineProperty(long nativeAwContents, AwContents caller, boolean networkUp); + void trimMemory(long nativeAwContents, AwContents caller, int level, boolean visible); + void createPdfExporter( + long nativeAwContents, AwContents caller, AwPdfExporter awPdfExporter); + void preauthorizePermission( + long nativeAwContents, AwContents caller, String origin, long resources); + void grantFileSchemeAccesstoChildProcess(long nativeAwContents, AwContents caller); + void resumeLoadingCreatedPopupWebContents(long nativeAwContents, AwContents caller); + AwRenderProcess getRenderProcess(long nativeAwContents, AwContents caller); + String setJsApiService(long nativeAwContents, AwContents caller, + boolean needToInjectJsObject, String jsObjectName, String[] allowedOrigins); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java index 4512ab2..0fcafc28 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java
@@ -14,6 +14,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.CalledByNativeUnchecked; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.task.PostTask; import org.chromium.content_public.browser.UiThreadTaskTraits; @@ -134,8 +135,9 @@ private void provideResponse(PrivateKey privateKey, byte[][] certChain) { if (mNativeContentsClientBridge == 0) return; - nativeProvideClientCertificateResponse(mNativeContentsClientBridge, mId, - certChain, privateKey); + AwContentsClientBridgeJni.get().provideClientCertificateResponse( + mNativeContentsClientBridge, AwContentsClientBridge.this, mId, certChain, + privateKey); } } @@ -178,7 +180,8 @@ private void proceedSslError(boolean proceed, int id) { if (mNativeContentsClientBridge == 0) return; - nativeProceedSslError(mNativeContentsClientBridge, proceed, id); + AwContentsClientBridgeJni.get().proceedSslError( + mNativeContentsClientBridge, AwContentsClientBridge.this, proceed, id); } // Intentionally not private for testing the native peer of this class. @@ -188,13 +191,14 @@ assert mNativeContentsClientBridge != 0; ClientCertLookupTable.Cert cert = mLookupTable.getCertData(host, port); if (mLookupTable.isDenied(host, port)) { - nativeProvideClientCertificateResponse(mNativeContentsClientBridge, id, - null, null); + AwContentsClientBridgeJni.get().provideClientCertificateResponse( + mNativeContentsClientBridge, AwContentsClientBridge.this, id, null, null); return; } if (cert != null) { - nativeProvideClientCertificateResponse(mNativeContentsClientBridge, id, - cert.mCertChain, cert.mPrivateKey); + AwContentsClientBridgeJni.get().provideClientCertificateResponse( + mNativeContentsClientBridge, AwContentsClientBridge.this, id, cert.mCertChain, + cert.mPrivateKey); return; } // Build the list of principals from encoded versions. @@ -206,8 +210,9 @@ principals[n] = new X500Principal(encodedPrincipals[n]); } catch (IllegalArgumentException e) { Log.w(TAG, "Exception while decoding issuers list: " + e); - nativeProvideClientCertificateResponse(mNativeContentsClientBridge, id, - null, null); + AwContentsClientBridgeJni.get().provideClientCertificateResponse( + mNativeContentsClientBridge, AwContentsClientBridge.this, id, null, + null); return; } } @@ -349,7 +354,8 @@ // clang-format off Callback<AwSafeBrowsingResponse> callback = response -> PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, - () -> nativeTakeSafeBrowsingAction(mNativeContentsClientBridge, + () -> AwContentsClientBridgeJni.get().takeSafeBrowsingAction( + mNativeContentsClientBridge, AwContentsClientBridge.this, response.action(), response.reporting(), requestId)); // clang-format on @@ -404,25 +410,28 @@ void confirmJsResult(int id, String prompt) { if (mNativeContentsClientBridge == 0) return; - nativeConfirmJsResult(mNativeContentsClientBridge, id, prompt); + AwContentsClientBridgeJni.get().confirmJsResult( + mNativeContentsClientBridge, AwContentsClientBridge.this, id, prompt); } void cancelJsResult(int id) { if (mNativeContentsClientBridge == 0) return; - nativeCancelJsResult(mNativeContentsClientBridge, id); + AwContentsClientBridgeJni.get().cancelJsResult( + mNativeContentsClientBridge, AwContentsClientBridge.this, id); } - //-------------------------------------------------------------------------------------------- - // Native methods - //-------------------------------------------------------------------------------------------- - private native void nativeTakeSafeBrowsingAction( - long nativeAwContentsClientBridge, int action, boolean reporting, int requestId); - private native void nativeProceedSslError(long nativeAwContentsClientBridge, boolean proceed, - int id); - private native void nativeProvideClientCertificateResponse(long nativeAwContentsClientBridge, - int id, byte[][] certChain, PrivateKey androidKey); + @NativeMethods + interface Natives { + void takeSafeBrowsingAction(long nativeAwContentsClientBridge, + AwContentsClientBridge caller, int action, boolean reporting, int requestId); - private native void nativeConfirmJsResult(long nativeAwContentsClientBridge, int id, - String prompt); - private native void nativeCancelJsResult(long nativeAwContentsClientBridge, int id); + void proceedSslError(long nativeAwContentsClientBridge, AwContentsClientBridge caller, + boolean proceed, int id); + void provideClientCertificateResponse(long nativeAwContentsClientBridge, + AwContentsClientBridge caller, int id, byte[][] certChain, PrivateKey androidKey); + void confirmJsResult(long nativeAwContentsClientBridge, AwContentsClientBridge caller, + int id, String prompt); + void cancelJsResult( + long nativeAwContentsClientBridge, AwContentsClientBridge caller, int id); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java b/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java index 19944a4a..7609815 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java
@@ -12,6 +12,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import org.chromium.base.task.PostTask; import org.chromium.content_public.browser.UiThreadTaskTraits; @@ -50,7 +51,7 @@ public static void clearClientCertPreferences(Runnable callback) { ThreadUtils.assertOnUiThread(); getClientCertLookupTable().clear(); - nativeClearClientCertPreferences(callback); + AwContentsStaticsJni.get().clearClientCertPreferences(callback); } @CalledByNative @@ -65,7 +66,7 @@ // two calls will be running at the same time, this should not cause // any harm. if (sUnreachableWebDataUrl == null) { - sUnreachableWebDataUrl = nativeGetUnreachableWebDataUrl(); + sUnreachableWebDataUrl = AwContentsStaticsJni.get().getUnreachableWebDataUrl(); } return sUnreachableWebDataUrl; } @@ -79,12 +80,12 @@ } public static String getProductVersion() { - return nativeGetProductVersion(); + return AwContentsStaticsJni.get().getProductVersion(); } public static void setServiceWorkerNetworkClient( AwContentsNetworkClient ioThreadClient, AwBrowserContext browserContext) { - nativeSetServiceWorkerNetworkClient(ioThreadClient, browserContext); + AwContentsStaticsJni.get().setServiceWorkerNetworkClient(ioThreadClient, browserContext); } @CalledByNative @@ -99,7 +100,7 @@ callback = b -> { }; } - nativeSetSafeBrowsingWhitelist(urlArray, callback); + AwContentsStaticsJni.get().setSafeBrowsingWhitelist(urlArray, callback); } @SuppressWarnings("NoContextGetApplicationContext") @@ -117,15 +118,15 @@ } public static Uri getSafeBrowsingPrivacyPolicyUrl() { - return Uri.parse(nativeGetSafeBrowsingPrivacyPolicyUrl()); + return Uri.parse(AwContentsStaticsJni.get().getSafeBrowsingPrivacyPolicyUrl()); } public static void setCheckClearTextPermitted(boolean permitted) { - nativeSetCheckClearTextPermitted(permitted); + AwContentsStaticsJni.get().setCheckClearTextPermitted(permitted); } public static void logCommandLineForDebugging() { - nativeLogCommandLineForDebugging(); + AwContentsStaticsJni.get().logCommandLineForDebugging(); } /** @@ -146,21 +147,21 @@ * Returns true if WebView is running in multi process mode. */ public static boolean isMultiProcessEnabled() { - return nativeIsMultiProcessEnabled(); + return AwContentsStaticsJni.get().isMultiProcessEnabled(); } - //-------------------------------------------------------------------------------------------- - // Native methods - //-------------------------------------------------------------------------------------------- - private static native void nativeLogCommandLineForDebugging(); - private static native String nativeGetSafeBrowsingPrivacyPolicyUrl(); - private static native void nativeClearClientCertPreferences(Runnable callback); - private static native String nativeGetUnreachableWebDataUrl(); - private static native String nativeGetProductVersion(); - private static native void nativeSetServiceWorkerNetworkClient( - AwContentsNetworkClient ioThreadClient, AwBrowserContext browserContext); - private static native void nativeSetSafeBrowsingWhitelist( - String[] urls, Callback<Boolean> callback); - private static native void nativeSetCheckClearTextPermitted(boolean permitted); - private static native boolean nativeIsMultiProcessEnabled(); + @NativeMethods + interface Natives { + void logCommandLineForDebugging(); + + String getSafeBrowsingPrivacyPolicyUrl(); + void clearClientCertPreferences(Runnable callback); + String getUnreachableWebDataUrl(); + String getProductVersion(); + void setServiceWorkerNetworkClient( + AwContentsNetworkClient ioThreadClient, AwBrowserContext browserContext); + void setSafeBrowsingWhitelist(String[] urls, Callback<Boolean> callback); + void setCheckClearTextPermitted(boolean permitted); + boolean isMultiProcessEnabled(); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwCookieManager.java b/android_webview/java/src/org/chromium/android_webview/AwCookieManager.java index 157d50e..c0034c0 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwCookieManager.java +++ b/android_webview/java/src/org/chromium/android_webview/AwCookieManager.java
@@ -10,6 +10,7 @@ import org.chromium.base.Callback; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.base.library_loader.ProcessInitException; @@ -24,7 +25,7 @@ private long mNativeCookieManager; public AwCookieManager() { - this(nativeGetDefaultCookieManager()); + this(AwCookieManagerJni.get().getDefaultCookieManager()); } public AwCookieManager(long nativeCookieManager) { @@ -41,7 +42,8 @@ * @param accept TRUE if accept cookie */ public void setAcceptCookie(boolean accept) { - nativeSetShouldAcceptCookies(mNativeCookieManager, accept); + AwCookieManagerJni.get().setShouldAcceptCookies( + mNativeCookieManager, AwCookieManager.this, accept); } /** @@ -49,7 +51,8 @@ * @return TRUE if accept cookie */ public boolean acceptCookie() { - return nativeGetShouldAcceptCookies(mNativeCookieManager); + return AwCookieManagerJni.get().getShouldAcceptCookies( + mNativeCookieManager, AwCookieManager.this); } /** @@ -57,21 +60,23 @@ */ public void setCookie(String url, String value) { UrlValue pair = fixupUrlValue(url, value); - nativeSetCookieSync(mNativeCookieManager, pair.mUrl, pair.mValue); + AwCookieManagerJni.get().setCookieSync( + mNativeCookieManager, AwCookieManager.this, pair.mUrl, pair.mValue); } /** * Deprecated synchronous version of removeSessionCookies. */ public void removeSessionCookies() { - nativeRemoveSessionCookiesSync(mNativeCookieManager); + AwCookieManagerJni.get().removeSessionCookiesSync( + mNativeCookieManager, AwCookieManager.this); } /** * Deprecated synchronous version of removeAllCookies. */ public void removeAllCookies() { - nativeRemoveAllCookiesSync(mNativeCookieManager); + AwCookieManagerJni.get().removeAllCookiesSync(mNativeCookieManager, AwCookieManager.this); } /** @@ -85,8 +90,8 @@ public void setCookie(final String url, final String value, final Callback<Boolean> callback) { try { UrlValue pair = fixupUrlValue(url, value); - nativeSetCookie( - mNativeCookieManager, pair.mUrl, pair.mValue, new CookieCallback(callback)); + AwCookieManagerJni.get().setCookie(mNativeCookieManager, AwCookieManager.this, + pair.mUrl, pair.mValue, new CookieCallback(callback)); } catch (IllegalStateException e) { throw new IllegalStateException( "SetCookie must be called on a thread with a running Looper."); @@ -100,7 +105,8 @@ * @return The cookies in the format of NAME=VALUE [; NAME=VALUE] */ public String getCookie(final String url) { - String cookie = nativeGetCookie(mNativeCookieManager, url.toString()); + String cookie = AwCookieManagerJni.get().getCookie( + mNativeCookieManager, AwCookieManager.this, url.toString()); // Return null if the string is empty to match legacy behavior return cookie == null || cookie.trim().isEmpty() ? null : cookie; } @@ -112,7 +118,8 @@ */ public void removeSessionCookies(Callback<Boolean> callback) { try { - nativeRemoveSessionCookies(mNativeCookieManager, new CookieCallback(callback)); + AwCookieManagerJni.get().removeSessionCookies( + mNativeCookieManager, AwCookieManager.this, new CookieCallback(callback)); } catch (IllegalStateException e) { throw new IllegalStateException( "removeSessionCookies must be called on a thread with a running Looper."); @@ -126,7 +133,8 @@ */ public void removeAllCookies(Callback<Boolean> callback) { try { - nativeRemoveAllCookies(mNativeCookieManager, new CookieCallback(callback)); + AwCookieManagerJni.get().removeAllCookies( + mNativeCookieManager, AwCookieManager.this, new CookieCallback(callback)); } catch (IllegalStateException e) { throw new IllegalStateException( "removeAllCookies must be called on a thread with a running Looper."); @@ -137,25 +145,26 @@ * Return true if there are stored cookies. */ public boolean hasCookies() { - return nativeHasCookies(mNativeCookieManager); + return AwCookieManagerJni.get().hasCookies(mNativeCookieManager, AwCookieManager.this); } /** * Remove all expired cookies */ public void removeExpiredCookies() { - nativeRemoveExpiredCookies(mNativeCookieManager); + AwCookieManagerJni.get().removeExpiredCookies(mNativeCookieManager, AwCookieManager.this); } public void flushCookieStore() { - nativeFlushCookieStore(mNativeCookieManager); + AwCookieManagerJni.get().flushCookieStore(mNativeCookieManager, AwCookieManager.this); } /** * Whether cookies are accepted for file scheme URLs. */ public boolean allowFileSchemeCookies() { - return nativeAllowFileSchemeCookies(mNativeCookieManager); + return AwCookieManagerJni.get().allowFileSchemeCookies( + mNativeCookieManager, AwCookieManager.this); } /** @@ -168,7 +177,8 @@ * instance has been created. */ public void setAcceptFileSchemeCookies(boolean accept) { - nativeSetAcceptFileSchemeCookies(mNativeCookieManager, accept); + AwCookieManagerJni.get().setAcceptFileSchemeCookies( + mNativeCookieManager, AwCookieManager.this, accept); } /** @@ -179,7 +189,7 @@ * the native method |RunBooleanCallbackAndroid| to call CookieCallback#onResult which posts a * Runnable on the handler of the original thread which in turn calls Callback#onResult. */ - private static class CookieCallback implements Callback<Boolean> { + static class CookieCallback implements Callback<Boolean> { @Nullable Callback<Boolean> mCallback; @Nullable @@ -241,26 +251,28 @@ return new UrlValue(url, value); } - private static native long nativeGetDefaultCookieManager(); - - private native void nativeSetShouldAcceptCookies(long nativeCookieManager, boolean accept); - private native boolean nativeGetShouldAcceptCookies(long nativeCookieManager); - - private native void nativeSetCookie( - long nativeCookieManager, String url, String value, CookieCallback callback); - private native void nativeSetCookieSync(long nativeCookieManager, String url, String value); - private native String nativeGetCookie(long nativeCookieManager, String url); - - private native void nativeRemoveSessionCookies( - long nativeCookieManager, CookieCallback callback); - private native void nativeRemoveSessionCookiesSync(long nativeCookieManager); - private native void nativeRemoveAllCookies(long nativeCookieManager, CookieCallback callback); - private native void nativeRemoveAllCookiesSync(long nativeCookieManager); - private native void nativeRemoveExpiredCookies(long nativeCookieManager); - private native void nativeFlushCookieStore(long nativeCookieManager); - - private native boolean nativeHasCookies(long nativeCookieManager); - - private native boolean nativeAllowFileSchemeCookies(long nativeCookieManager); - private native void nativeSetAcceptFileSchemeCookies(long nativeCookieManager, boolean accept); + @NativeMethods + interface Natives { + long getDefaultCookieManager(); + void setShouldAcceptCookies( + long nativeCookieManager, AwCookieManager caller, boolean accept); + boolean getShouldAcceptCookies(long nativeCookieManager, AwCookieManager caller); + void setCookie(long nativeCookieManager, AwCookieManager caller, String url, String value, + CookieCallback callback); + void setCookieSync( + long nativeCookieManager, AwCookieManager caller, String url, String value); + String getCookie(long nativeCookieManager, AwCookieManager caller, String url); + void removeSessionCookies( + long nativeCookieManager, AwCookieManager caller, CookieCallback callback); + void removeSessionCookiesSync(long nativeCookieManager, AwCookieManager caller); + void removeAllCookies( + long nativeCookieManager, AwCookieManager caller, CookieCallback callback); + void removeAllCookiesSync(long nativeCookieManager, AwCookieManager caller); + void removeExpiredCookies(long nativeCookieManager, AwCookieManager caller); + void flushCookieStore(long nativeCookieManager, AwCookieManager caller); + boolean hasCookies(long nativeCookieManager, AwCookieManager caller); + boolean allowFileSchemeCookies(long nativeCookieManager, AwCookieManager caller); + void setAcceptFileSchemeCookies( + long nativeCookieManager, AwCookieManager caller, boolean accept); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwDebug.java b/android_webview/java/src/org/chromium/android_webview/AwDebug.java index a3cd6fd1..adaeda5 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwDebug.java +++ b/android_webview/java/src/org/chromium/android_webview/AwDebug.java
@@ -5,6 +5,7 @@ package org.chromium.android_webview; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import org.chromium.base.annotations.UsedByReflection; import java.io.File; @@ -39,23 +40,26 @@ } catch (IOException e) { return false; } - return nativeDumpWithoutCrashing(dumpPath); + return AwDebugJni.get().dumpWithoutCrashing(dumpPath); } public static void initCrashKeysForTesting() { - nativeInitCrashKeysForWebViewTesting(); + AwDebugJni.get().initCrashKeysForWebViewTesting(); } public static void setWhiteListedKeyForTesting() { - nativeSetWhiteListedKeyForTesting(); + AwDebugJni.get().setWhiteListedKeyForTesting(); } public static void setNonWhiteListedKeyForTesting() { - nativeSetNonWhiteListedKeyForTesting(); + AwDebugJni.get().setNonWhiteListedKeyForTesting(); } - private static native boolean nativeDumpWithoutCrashing(String dumpPath); - private static native void nativeInitCrashKeysForWebViewTesting(); - private static native void nativeSetWhiteListedKeyForTesting(); - private static native void nativeSetNonWhiteListedKeyForTesting(); + @NativeMethods + interface Natives { + boolean dumpWithoutCrashing(String dumpPath); + void initCrashKeysForWebViewTesting(); + void setWhiteListedKeyForTesting(); + void setNonWhiteListedKeyForTesting(); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwDevToolsServer.java b/android_webview/java/src/org/chromium/android_webview/AwDevToolsServer.java index fa61a90..38c5c40 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwDevToolsServer.java +++ b/android_webview/java/src/org/chromium/android_webview/AwDevToolsServer.java
@@ -5,6 +5,7 @@ package org.chromium.android_webview; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; /** * Controller for Remote Web Debugging (Developer Tools). @@ -15,19 +16,26 @@ private long mNativeDevToolsServer; public AwDevToolsServer() { - mNativeDevToolsServer = nativeInitRemoteDebugging(); + mNativeDevToolsServer = + AwDevToolsServerJni.get().initRemoteDebugging(AwDevToolsServer.this); } public void destroy() { - nativeDestroyRemoteDebugging(mNativeDevToolsServer); + AwDevToolsServerJni.get().destroyRemoteDebugging( + AwDevToolsServer.this, mNativeDevToolsServer); mNativeDevToolsServer = 0; } public void setRemoteDebuggingEnabled(boolean enabled) { - nativeSetRemoteDebuggingEnabled(mNativeDevToolsServer, enabled); + AwDevToolsServerJni.get().setRemoteDebuggingEnabled( + AwDevToolsServer.this, mNativeDevToolsServer, enabled); } - private native long nativeInitRemoteDebugging(); - private native void nativeDestroyRemoteDebugging(long devToolsServer); - private native void nativeSetRemoteDebuggingEnabled(long devToolsServer, boolean enabled); + @NativeMethods + interface Natives { + long initRemoteDebugging(AwDevToolsServer caller); + void destroyRemoteDebugging(AwDevToolsServer caller, long devToolsServer); + void setRemoteDebuggingEnabled( + AwDevToolsServer caller, long devToolsServer, boolean enabled); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwFeatureList.java b/android_webview/java/src/org/chromium/android_webview/AwFeatureList.java index bf9eb01b2..60c81c9 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwFeatureList.java +++ b/android_webview/java/src/org/chromium/android_webview/AwFeatureList.java
@@ -10,6 +10,7 @@ import org.chromium.base.ContextUtils; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.MainDex; +import org.chromium.base.annotations.NativeMethods; /** * Java accessor for base/feature_list.h state. @@ -59,12 +60,15 @@ * @return Whether the feature is enabled or not. */ public static boolean isEnabled(String featureName) { - return nativeIsEnabled(featureName); + return AwFeatureListJni.get().isEnabled(featureName); } // Alphabetical: public static final String WEBVIEW_CONNECTIONLESS_SAFE_BROWSING = "WebViewConnectionlessSafeBrowsing"; - private static native boolean nativeIsEnabled(String featureName); + @NativeMethods + interface Natives { + boolean isEnabled(String featureName); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwFormDatabase.java b/android_webview/java/src/org/chromium/android_webview/AwFormDatabase.java index 0ede383d..5091faf 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwFormDatabase.java +++ b/android_webview/java/src/org/chromium/android_webview/AwFormDatabase.java
@@ -5,6 +5,7 @@ package org.chromium.android_webview; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; /** * Exposes a subset of Chromium form database to Webview database for managing autocomplete @@ -14,17 +15,16 @@ public class AwFormDatabase { public static boolean hasFormData() { - return nativeHasFormData(); + return AwFormDatabaseJni.get().hasFormData(); } public static void clearFormData() { - nativeClearFormData(); + AwFormDatabaseJni.get().clearFormData(); } - //-------------------------------------------------------------------------------------------- - // Native methods - //-------------------------------------------------------------------------------------------- - private static native boolean nativeHasFormData(); - - private static native void nativeClearFormData(); + @NativeMethods + interface Natives { + boolean hasFormData(); + void clearFormData(); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwHttpAuthHandler.java b/android_webview/java/src/org/chromium/android_webview/AwHttpAuthHandler.java index ce5de9499..0d0d0e57 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwHttpAuthHandler.java +++ b/android_webview/java/src/org/chromium/android_webview/AwHttpAuthHandler.java
@@ -6,6 +6,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; /** * See {@link android.webkit.HttpAuthHandler}. @@ -18,14 +19,15 @@ public void proceed(String username, String password) { if (mNativeAwHttpAuthHandler != 0) { - nativeProceed(mNativeAwHttpAuthHandler, username, password); + AwHttpAuthHandlerJni.get().proceed( + mNativeAwHttpAuthHandler, AwHttpAuthHandler.this, username, password); mNativeAwHttpAuthHandler = 0; } } public void cancel() { if (mNativeAwHttpAuthHandler != 0) { - nativeCancel(mNativeAwHttpAuthHandler); + AwHttpAuthHandlerJni.get().cancel(mNativeAwHttpAuthHandler, AwHttpAuthHandler.this); mNativeAwHttpAuthHandler = 0; } } @@ -49,7 +51,10 @@ mNativeAwHttpAuthHandler = 0; } - private native void nativeProceed(long nativeAwHttpAuthHandler, - String username, String password); - private native void nativeCancel(long nativeAwHttpAuthHandler); + @NativeMethods + interface Natives { + void proceed(long nativeAwHttpAuthHandler, AwHttpAuthHandler caller, String username, + String password); + void cancel(long nativeAwHttpAuthHandler, AwHttpAuthHandler caller); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java b/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java index 288cc63..01e2202 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java +++ b/android_webview/java/src/org/chromium/android_webview/AwMetricsServiceClient.java
@@ -13,6 +13,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; /** * Determines user consent and app opt-out for metrics. See aw_metrics_service_client.h for more @@ -56,7 +57,7 @@ public static void setConsentSetting(Context ctx, boolean userConsent) { ThreadUtils.assertOnUiThread(); - nativeSetHaveMetricsConsent(userConsent && !isAppOptedOut(ctx)); + AwMetricsServiceClientJni.get().setHaveMetricsConsent(userConsent && !isAppOptedOut(ctx)); } @CalledByNative @@ -65,5 +66,8 @@ return shouldRecordPackageName(ctx) ? ctx.getPackageName() : null; } - public static native void nativeSetHaveMetricsConsent(boolean enabled); + @NativeMethods + interface Natives { + void setHaveMetricsConsent(boolean enabled); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwPdfExporter.java b/android_webview/java/src/org/chromium/android_webview/AwPdfExporter.java index b02945c..26e3819 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwPdfExporter.java +++ b/android_webview/java/src/org/chromium/android_webview/AwPdfExporter.java
@@ -13,6 +13,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; /** * Export the android webview as a PDF. @@ -84,7 +85,8 @@ mResultCallback = resultCallback; mAttributes = attributes; mFd = fd; - nativeExportToPdf(mNativeAwPdfExporter, mFd.getFd(), pages, cancellationSignal); + AwPdfExporterJni.get().exportToPdf( + mNativeAwPdfExporter, AwPdfExporter.this, mFd.getFd(), pages, cancellationSignal); } @CalledByNative @@ -159,6 +161,9 @@ return mAttributes.getMinMargins().getBottomMils(); } - private native void nativeExportToPdf( - long nativeAwPdfExporter, int fd, int[] pages, CancellationSignal cancellationSignal); + @NativeMethods + interface Natives { + void exportToPdf(long nativeAwPdfExporter, AwPdfExporter caller, int fd, int[] pages, + CancellationSignal cancellationSignal); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwProxyController.java b/android_webview/java/src/org/chromium/android_webview/AwProxyController.java index bb2df95..6cfebf9 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwProxyController.java +++ b/android_webview/java/src/org/chromium/android_webview/AwProxyController.java
@@ -4,8 +4,12 @@ package org.chromium.android_webview; +import android.support.annotation.IntDef; + import org.chromium.base.annotations.CalledByNativeUnchecked; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; +import org.chromium.base.metrics.RecordHistogram; import java.util.concurrent.Executor; @@ -14,6 +18,32 @@ */ @JNINamespace("android_webview") public class AwProxyController { + /** + * Represents the scheme used in proxy rules. + * These values are persisted to logs. Entries should not be renumbered + * or reordered and numeric values should never be reused. + */ + @IntDef({ProxySchemeType.HTTP, ProxySchemeType.HTTPS, ProxySchemeType.ALL}) + private @interface ProxySchemeType { + int HTTP = 0; + int HTTPS = 1; + int ALL = 2; + int NUM_ENTRIES = 3; + } + + /** + * Represents the type of proxy url. + * These values are persisted to logs. Entries should not be renumbered + * or reordered and numeric values should never be reused. + */ + @IntDef({ProxyUrlType.HTTP, ProxyUrlType.HTTPS, ProxyUrlType.DIRECT}) + private @interface ProxyUrlType { + int HTTP = 0; + int HTTPS = 1; + int DIRECT = 2; + int NUM_ENTRIES = 3; + } + public AwProxyController() {} public String setProxyOverride( @@ -21,6 +51,8 @@ int length = (proxyRules == null ? 0 : proxyRules.length); String[] urlSchemes = new String[length]; String[] proxyUrls = new String[length]; + boolean schemeHttp = false, schemeHttps = false; + boolean urlHttp = false, urlHttps = false, urlDirect = false; for (int i = 0; i < length; i++) { // URL schemes if (proxyRules[i][0] == null) { @@ -33,6 +65,23 @@ if (proxyUrls[i] == null) { return "Proxy rule " + i + " has a null url"; } + // Check schemes for UMA + if (proxyRules[i][0].equals("http")) { + schemeHttp = true; + } else if (proxyRules[i][0].equals("https")) { + schemeHttps = true; + } else { + schemeHttp = true; + schemeHttps = true; + } + // Check URLs for UMA + if (proxyUrls[i].startsWith("http://")) { + urlHttp = true; + } else if (proxyUrls[i].startsWith("https://")) { + urlHttps = true; + } else if (proxyUrls[i].startsWith("direct://")) { + urlDirect = true; + } } length = (bypassRules == null ? 0 : bypassRules.length); for (int i = 0; i < length; i++) { @@ -44,7 +93,44 @@ return "Executor must not be null"; } - return nativeSetProxyOverride(urlSchemes, proxyUrls, bypassRules, listener, executor); + String result = AwProxyControllerJni.get().setProxyOverride( + AwProxyController.this, urlSchemes, proxyUrls, bypassRules, listener, executor); + if (result.equals("")) { + // In case operation is successful, log UMA data on SetProxyOverride + // Proxy scheme filter + if (schemeHttp && schemeHttps) { + recordProxySchemeType(ProxySchemeType.ALL); + } else if (schemeHttp) { + recordProxySchemeType(ProxySchemeType.HTTP); + } else if (schemeHttps) { + recordProxySchemeType(ProxySchemeType.HTTPS); + } + // Proxy url type + if (urlHttp) { + recordProxyUrlType(ProxyUrlType.HTTP); + } + if (urlHttps) { + recordProxyUrlType(ProxyUrlType.HTTPS); + } + if (urlDirect) { + recordProxyUrlType(ProxyUrlType.DIRECT); + } + // Bypass rules + RecordHistogram.recordBooleanHistogram("Android.WebView.SetProxyOverride.BypassRules", + bypassRules == null || bypassRules.length == 0 ? false : true); + } + return result; + } + + private static void recordProxySchemeType(@ProxySchemeType int proxySchemeType) { + RecordHistogram.recordEnumeratedHistogram( + "Android.WebView.SetProxyOverride.ProxySchemeFilterType", proxySchemeType, + ProxySchemeType.NUM_ENTRIES); + } + + private static void recordProxyUrlType(@ProxyUrlType int proxyUrlType) { + RecordHistogram.recordEnumeratedHistogram("Android.WebView.SetProxyOverride.ProxyUrlType", + proxyUrlType, ProxyUrlType.NUM_ENTRIES); } public String clearProxyOverride(Runnable listener, Executor executor) { @@ -52,7 +138,9 @@ return "Executor must not be null"; } - nativeClearProxyOverride(listener, executor); + AwProxyControllerJni.get().clearProxyOverride(AwProxyController.this, listener, executor); + // Log UMA data on ClearProxyOverride + RecordHistogram.recordBooleanHistogram("Android.WebView.ClearProxyOverride", true); return ""; } @@ -62,7 +150,10 @@ executor.execute(listener); } - private native String nativeSetProxyOverride(String[] urlSchemes, String[] proxyUrls, - String[] bypassRules, Runnable listener, Executor executor); - private native void nativeClearProxyOverride(Runnable listener, Executor executor); + @NativeMethods + interface Natives { + String setProxyOverride(AwProxyController caller, String[] urlSchemes, String[] proxyUrls, + String[] bypassRules, Runnable listener, Executor executor); + void clearProxyOverride(AwProxyController caller, Runnable listener, Executor executor); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwQuotaManagerBridge.java b/android_webview/java/src/org/chromium/android_webview/AwQuotaManagerBridge.java index 82b1120a..6b2de7a 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwQuotaManagerBridge.java +++ b/android_webview/java/src/org/chromium/android_webview/AwQuotaManagerBridge.java
@@ -10,6 +10,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; /** * Bridge between android.webview.WebStorage and native QuotaManager. This object is owned by Java @@ -49,7 +50,7 @@ mPendingGetOriginCallbacks = new SparseArray<Callback<Origins>>(); mPendingGetQuotaForOriginCallbacks = new SparseArray<Callback<Long>>(); mPendingGetUsageForOriginCallbacks = new SparseArray<Callback<Long>>(); - nativeInit(mNativeAwQuotaManagerBridge); + AwQuotaManagerBridgeJni.get().init(mNativeAwQuotaManagerBridge, AwQuotaManagerBridge.this); } private int getNextId() { @@ -72,14 +73,16 @@ * TODO(boliu): Actually clear Web Storage. */ public void deleteAllData() { - nativeDeleteAllData(mNativeAwQuotaManagerBridge); + AwQuotaManagerBridgeJni.get().deleteAllData( + mNativeAwQuotaManagerBridge, AwQuotaManagerBridge.this); } /** * Implements WebStorage.deleteOrigin(). Clear the storage of APIs 2-5 for the given origin. */ public void deleteOrigin(String origin) { - nativeDeleteOrigin(mNativeAwQuotaManagerBridge, origin); + AwQuotaManagerBridgeJni.get().deleteOrigin( + mNativeAwQuotaManagerBridge, AwQuotaManagerBridge.this, origin); } /** @@ -90,7 +93,8 @@ int callbackId = getNextId(); assert mPendingGetOriginCallbacks.get(callbackId) == null; mPendingGetOriginCallbacks.put(callbackId, callback); - nativeGetOrigins(mNativeAwQuotaManagerBridge, callbackId); + AwQuotaManagerBridgeJni.get().getOrigins( + mNativeAwQuotaManagerBridge, AwQuotaManagerBridge.this, callbackId); } /** @@ -101,7 +105,8 @@ int callbackId = getNextId(); assert mPendingGetQuotaForOriginCallbacks.get(callbackId) == null; mPendingGetQuotaForOriginCallbacks.put(callbackId, callback); - nativeGetUsageAndQuotaForOrigin(mNativeAwQuotaManagerBridge, origin, callbackId, true); + AwQuotaManagerBridgeJni.get().getUsageAndQuotaForOrigin( + mNativeAwQuotaManagerBridge, AwQuotaManagerBridge.this, origin, callbackId, true); } /** @@ -112,7 +117,8 @@ int callbackId = getNextId(); assert mPendingGetUsageForOriginCallbacks.get(callbackId) == null; mPendingGetUsageForOriginCallbacks.put(callbackId, callback); - nativeGetUsageAndQuotaForOrigin(mNativeAwQuotaManagerBridge, origin, callbackId, false); + AwQuotaManagerBridgeJni.get().getUsageAndQuotaForOrigin( + mNativeAwQuotaManagerBridge, AwQuotaManagerBridge.this, origin, callbackId, false); } @CalledByNative @@ -137,10 +143,15 @@ } } - private native void nativeInit(long nativeAwQuotaManagerBridge); - private native void nativeDeleteAllData(long nativeAwQuotaManagerBridge); - private native void nativeDeleteOrigin(long nativeAwQuotaManagerBridge, String origin); - private native void nativeGetOrigins(long nativeAwQuotaManagerBridge, int callbackId); - private native void nativeGetUsageAndQuotaForOrigin( - long nativeAwQuotaManagerBridge, String origin, int callbackId, boolean isQuota); + @NativeMethods + interface Natives { + void init(long nativeAwQuotaManagerBridge, AwQuotaManagerBridge caller); + void deleteAllData(long nativeAwQuotaManagerBridge, AwQuotaManagerBridge caller); + void deleteOrigin( + long nativeAwQuotaManagerBridge, AwQuotaManagerBridge caller, String origin); + void getOrigins( + long nativeAwQuotaManagerBridge, AwQuotaManagerBridge caller, int callbackId); + void getUsageAndQuotaForOrigin(long nativeAwQuotaManagerBridge, AwQuotaManagerBridge caller, + String origin, int callbackId, boolean isQuota); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwRenderProcess.java b/android_webview/java/src/org/chromium/android_webview/AwRenderProcess.java index 3290a54d..b6447dc 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwRenderProcess.java +++ b/android_webview/java/src/org/chromium/android_webview/AwRenderProcess.java
@@ -6,6 +6,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; /** */ @@ -18,7 +19,8 @@ public boolean terminate() { if (mNativeRenderProcess == 0) return false; - return nativeTerminateChildProcess(mNativeRenderProcess); + return AwRenderProcessJni.get().terminateChildProcess( + mNativeRenderProcess, AwRenderProcess.this); } @CalledByNative @@ -31,5 +33,8 @@ mNativeRenderProcess = nativeRenderProcess; } - private native boolean nativeTerminateChildProcess(long nativeAwRenderProcess); + @NativeMethods + interface Natives { + boolean terminateChildProcess(long nativeAwRenderProcess, AwRenderProcess caller); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwSettings.java b/android_webview/java/src/org/chromium/android_webview/AwSettings.java index 6da8446..ad54094 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwSettings.java +++ b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
@@ -21,6 +21,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import org.chromium.content_public.browser.WebContents; import java.lang.annotation.Retention; @@ -144,7 +145,7 @@ static class LazyDefaultUserAgent{ // Lazy Holder pattern - private static final String sInstance = nativeGetDefaultUserAgent(); + private static final String sInstance = AwSettingsJni.get().getDefaultUserAgent(); } // Protects access to settings global fields. @@ -306,12 +307,12 @@ void setWebContents(WebContents webContents) { synchronized (mAwSettingsLock) { if (mNativeAwSettings != 0) { - nativeDestroy(mNativeAwSettings); + AwSettingsJni.get().destroy(mNativeAwSettings, AwSettings.this); assert mNativeAwSettings == 0; // nativeAwSettingsGone should have been called. } if (webContents != null) { mEventHandler.bindUiThread(); - mNativeAwSettings = nativeInit(webContents); + mNativeAwSettings = AwSettingsJni.get().init(AwSettings.this, webContents); updateEverythingLocked(); } } @@ -320,7 +321,7 @@ private void updateEverythingLocked() { assert Thread.holdsLock(mAwSettingsLock); assert mNativeAwSettings != 0; - nativeUpdateEverythingLocked(mNativeAwSettings); + AwSettingsJni.get().updateEverythingLocked(mNativeAwSettings, AwSettings.this); onGestureZoomSupportChanged( supportsDoubleTapZoomLocked(), supportsMultiTouchZoomLocked()); } @@ -483,7 +484,8 @@ mInitialPageScalePercent = scaleInPercent; mEventHandler.runOnUiThreadBlockingAndLocked(() -> { if (mNativeAwSettings != 0) { - nativeUpdateInitialPageScaleLocked(mNativeAwSettings); + AwSettingsJni.get().updateInitialPageScaleLocked( + mNativeAwSettings, AwSettings.this); } }); } @@ -579,7 +581,8 @@ mAutoCompleteEnabled = enable; mEventHandler.runOnUiThreadBlockingAndLocked(() -> { if (mNativeAwSettings != 0) { - nativeUpdateFormDataPreferencesLocked(mNativeAwSettings); + AwSettingsJni.get().updateFormDataPreferencesLocked( + mNativeAwSettings, AwSettings.this); } }); } @@ -640,7 +643,8 @@ if (!oldUserAgent.equals(mUserAgent)) { mEventHandler.runOnUiThreadBlockingAndLocked(() -> { if (mNativeAwSettings != 0) { - nativeUpdateUserAgentLocked(mNativeAwSettings); + AwSettingsJni.get().updateUserAgentLocked( + mNativeAwSettings, AwSettings.this); } }); } @@ -673,7 +677,8 @@ mEventHandler.runOnUiThreadBlockingAndLocked(() -> { if (mNativeAwSettings != 0) { updateWebkitPreferencesOnUiThreadLocked(); - nativeResetScrollAndScaleState(mNativeAwSettings); + AwSettingsJni.get().resetScrollAndScaleState( + mNativeAwSettings, AwSettings.this); } }); } @@ -1292,7 +1297,8 @@ mEventHandler.runOnUiThreadBlockingAndLocked(() -> { assert Thread.holdsLock(mAwSettingsLock); assert mNativeAwSettings != 0; - nativeUpdateWillSuppressErrorStateLocked(mNativeAwSettings); + AwSettingsJni.get().updateWillSuppressErrorStateLocked( + mNativeAwSettings, AwSettings.this); }); } @@ -1747,7 +1753,8 @@ mOffscreenPreRaster = enabled; mEventHandler.runOnUiThreadBlockingAndLocked(() -> { if (mNativeAwSettings != 0) { - nativeUpdateOffscreenPreRasterLocked(mNativeAwSettings); + AwSettingsJni.get().updateOffscreenPreRasterLocked( + mNativeAwSettings, AwSettings.this); } }); } @@ -1770,7 +1777,8 @@ synchronized (mAwSettingsLock) { mEventHandler.runOnUiThreadBlockingAndLocked(() -> { if (mNativeAwSettings != 0) { - nativeUpdateRendererPreferencesLocked(mNativeAwSettings); + AwSettingsJni.get().updateRendererPreferencesLocked( + mNativeAwSettings, AwSettings.this); } }); } @@ -1825,7 +1833,8 @@ private void populateWebPreferences(long webPrefsPtr) { synchronized (mAwSettingsLock) { assert mNativeAwSettings != 0; - nativePopulateWebPreferencesLocked(mNativeAwSettings, webPrefsPtr); + AwSettingsJni.get().populateWebPreferencesLocked( + mNativeAwSettings, AwSettings.this, webPrefsPtr); } } @@ -1833,7 +1842,7 @@ assert mEventHandler.mHandler != null; ThreadUtils.assertOnUiThread(); if (mNativeAwSettings != 0) { - nativeUpdateWebkitPreferencesLocked(mNativeAwSettings); + AwSettingsJni.get().updateWebkitPreferencesLocked(mNativeAwSettings, AwSettings.this); } } @@ -1841,35 +1850,26 @@ assert mEventHandler.mHandler != null; ThreadUtils.assertOnUiThread(); if (mNativeAwSettings != 0) { - nativeUpdateCookiePolicyLocked(mNativeAwSettings); + AwSettingsJni.get().updateCookiePolicyLocked(mNativeAwSettings, AwSettings.this); } } - private native long nativeInit(WebContents webContents); - - private native void nativeDestroy(long nativeAwSettings); - - private native void nativePopulateWebPreferencesLocked(long nativeAwSettings, long webPrefsPtr); - - private native void nativeResetScrollAndScaleState(long nativeAwSettings); - - private native void nativeUpdateEverythingLocked(long nativeAwSettings); - - private native void nativeUpdateInitialPageScaleLocked(long nativeAwSettings); - - private native void nativeUpdateUserAgentLocked(long nativeAwSettings); - - private native void nativeUpdateWebkitPreferencesLocked(long nativeAwSettings); - - private static native String nativeGetDefaultUserAgent(); - - private native void nativeUpdateFormDataPreferencesLocked(long nativeAwSettings); - - private native void nativeUpdateRendererPreferencesLocked(long nativeAwSettings); - - private native void nativeUpdateOffscreenPreRasterLocked(long nativeAwSettings); - - private native void nativeUpdateWillSuppressErrorStateLocked(long nativeAwSettings); - - private native void nativeUpdateCookiePolicyLocked(long nativeAwSettings); + @NativeMethods + interface Natives { + long init(AwSettings caller, WebContents webContents); + void destroy(long nativeAwSettings, AwSettings caller); + void populateWebPreferencesLocked( + long nativeAwSettings, AwSettings caller, long webPrefsPtr); + void resetScrollAndScaleState(long nativeAwSettings, AwSettings caller); + void updateEverythingLocked(long nativeAwSettings, AwSettings caller); + void updateInitialPageScaleLocked(long nativeAwSettings, AwSettings caller); + void updateUserAgentLocked(long nativeAwSettings, AwSettings caller); + void updateWebkitPreferencesLocked(long nativeAwSettings, AwSettings caller); + String getDefaultUserAgent(); + void updateFormDataPreferencesLocked(long nativeAwSettings, AwSettings caller); + void updateRendererPreferencesLocked(long nativeAwSettings, AwSettings caller); + void updateOffscreenPreRasterLocked(long nativeAwSettings, AwSettings caller); + void updateWillSuppressErrorStateLocked(long nativeAwSettings, AwSettings caller); + void updateCookiePolicyLocked(long nativeAwSettings, AwSettings caller); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwTracingController.java b/android_webview/java/src/org/chromium/android_webview/AwTracingController.java index 1a47c015..eb1a6d4 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwTracingController.java +++ b/android_webview/java/src/org/chromium/android_webview/AwTracingController.java
@@ -10,6 +10,7 @@ import org.chromium.base.TraceRecordMode; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import java.io.IOException; import java.io.OutputStream; @@ -71,7 +72,7 @@ // boolean mIsTracing; public AwTracingController() { - mNativeAwTracingController = nativeInit(); + mNativeAwTracingController = AwTracingControllerJni.get().init(AwTracingController.this); } // Start tracing @@ -83,7 +84,8 @@ String categoryFilter = constructCategoryFilterString(predefinedCategories, customIncludedCategories); - nativeStart(mNativeAwTracingController, categoryFilter, mode); + AwTracingControllerJni.get().start( + mNativeAwTracingController, AwTracingController.this, categoryFilter, mode); return RESULT_SUCCESS; } @@ -91,12 +93,14 @@ public boolean stopAndFlush(@Nullable OutputStream outputStream) { if (!isTracing()) return false; mOutputStream = outputStream; - nativeStopAndFlush(mNativeAwTracingController); + AwTracingControllerJni.get().stopAndFlush( + mNativeAwTracingController, AwTracingController.this); return true; } public boolean isTracing() { - return nativeIsTracing(mNativeAwTracingController); + return AwTracingControllerJni.get().isTracing( + mNativeAwTracingController, AwTracingController.this); } // Combines configuration bits into a category string usable by chromium. @@ -152,9 +156,13 @@ } private long mNativeAwTracingController; - private native long nativeInit(); - private native boolean nativeStart( - long nativeAwTracingController, String categories, int traceMode); - private native boolean nativeStopAndFlush(long nativeAwTracingController); - private native boolean nativeIsTracing(long nativeAwTracingController); + + @NativeMethods + interface Natives { + long init(AwTracingController caller); + boolean start(long nativeAwTracingController, AwTracingController caller, String categories, + int traceMode); + boolean stopAndFlush(long nativeAwTracingController, AwTracingController caller); + boolean isTracing(long nativeAwTracingController, AwTracingController caller); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java index ec85440..287354d 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java +++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java
@@ -7,6 +7,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid; /** @@ -34,10 +35,6 @@ @CalledByNative public abstract void activateContents(); - // Call in response to a prior runFileChooser call. - protected static native void nativeFilesSelectedInChooser(int processId, int renderId, - int modeFlags, String[] filePath, String[] displayName); - @Override @CalledByNative public abstract void navigationStateChanged(int flags); @@ -46,4 +43,11 @@ // into onLoad{Started|Stopped}. @CalledByNative public abstract void loadingStateChanged(); + + @NativeMethods + interface Natives { + // Call in response to a prior runFileChooser call. + void filesSelectedInChooser(int processId, int renderId, int modeFlags, String[] filePath, + String[] displayName); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java index a57b57f..4c3e4f1 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java +++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
@@ -226,7 +226,7 @@ } mCompleted = true; if (results == null) { - nativeFilesSelectedInChooser( + AwWebContentsDelegateJni.get().filesSelectedInChooser( processId, renderId, modeFlags, null, null); return; } @@ -348,7 +348,8 @@ @Override protected void onPostExecute(String[] result) { - nativeFilesSelectedInChooser(mProcessId, mRenderId, mModeFlags, mFilePaths, result); + AwWebContentsDelegateJni.get().filesSelectedInChooser( + mProcessId, mRenderId, mModeFlags, mFilePaths, result); } /**
diff --git a/android_webview/java/src/org/chromium/android_webview/JsReplyProxy.java b/android_webview/java/src/org/chromium/android_webview/JsReplyProxy.java index 0e89e2ab..d00153b9 100644 --- a/android_webview/java/src/org/chromium/android_webview/JsReplyProxy.java +++ b/android_webview/java/src/org/chromium/android_webview/JsReplyProxy.java
@@ -8,6 +8,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import org.chromium.base.task.PostTask; import org.chromium.content_public.browser.UiThreadTaskTraits; @@ -33,7 +34,7 @@ public void postMessage(@NonNull final String message) { if (mNativeJsReplyProxy == 0) return; PostTask.runOrPostTask(UiThreadTaskTraits.USER_VISIBLE, - () -> nativePostMessage(mNativeJsReplyProxy, message)); + () -> JsReplyProxyJni.get().postMessage(mNativeJsReplyProxy, message)); } @CalledByNative @@ -46,5 +47,8 @@ mNativeJsReplyProxy = 0; } - private static native void nativePostMessage(long nativeJsReplyProxy, String message); + @NativeMethods + interface Natives { + void postMessage(long nativeJsReplyProxy, String message); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/PopupTouchHandleDrawable.java b/android_webview/java/src/org/chromium/android_webview/PopupTouchHandleDrawable.java index cee9af1..08cac61 100644 --- a/android_webview/java/src/org/chromium/android_webview/PopupTouchHandleDrawable.java +++ b/android_webview/java/src/org/chromium/android_webview/PopupTouchHandleDrawable.java
@@ -23,6 +23,7 @@ import org.chromium.base.ObserverList; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import org.chromium.content_public.browser.GestureListenerManager; import org.chromium.content_public.browser.GestureStateListener; import org.chromium.content_public.browser.WebContents; @@ -173,7 +174,8 @@ } }; GestureListenerManager.fromWebContents(mWebContents).addListener(mGestureStateListener); - mNativeDrawable = nativeInit(HandleViewResources.getHandleHorizontalPaddingRatio()); + mNativeDrawable = PopupTouchHandleDrawableJni.get().init(PopupTouchHandleDrawable.this, + HandleViewResources.getHandleHorizontalPaddingRatio()); } public static PopupTouchHandleDrawable create( @@ -632,5 +634,8 @@ mContainerView = newContainerView; } - private native long nativeInit(float horizontalPaddingRatio); + @NativeMethods + interface Natives { + long init(PopupTouchHandleDrawable caller, float horizontalPaddingRatio); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/gfx/AwDrawFnImpl.java b/android_webview/java/src/org/chromium/android_webview/gfx/AwDrawFnImpl.java index 94ca8c4..b2be2e3 100644 --- a/android_webview/java/src/org/chromium/android_webview/gfx/AwDrawFnImpl.java +++ b/android_webview/java/src/org/chromium/android_webview/gfx/AwDrawFnImpl.java
@@ -7,6 +7,7 @@ import android.graphics.Canvas; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; /** * Implementation of draw_fn.h. @@ -22,26 +23,27 @@ public AwDrawFnImpl(DrawFnAccess access) { mAccess = access; - mNativeAwDrawFnImpl = nativeCreate(); - mHandle = nativeGetFunctorHandle(mNativeAwDrawFnImpl); + mNativeAwDrawFnImpl = AwDrawFnImplJni.get().create(); + mHandle = AwDrawFnImplJni.get().getFunctorHandle(mNativeAwDrawFnImpl, AwDrawFnImpl.this); } @Override public void destroy() { assert mNativeAwDrawFnImpl != 0; - nativeReleaseHandle(mNativeAwDrawFnImpl); + AwDrawFnImplJni.get().releaseHandle(mNativeAwDrawFnImpl, AwDrawFnImpl.this); // Native side is free to destroy itself after ReleaseHandle. mNativeAwDrawFnImpl = 0; } public static void setDrawFnFunctionTable(long functionTablePointer) { - nativeSetDrawFnFunctionTable(functionTablePointer); + AwDrawFnImplJni.get().setDrawFnFunctionTable(functionTablePointer); } @Override public long getNativeCompositorFrameConsumer() { assert mNativeAwDrawFnImpl != 0; - return nativeGetCompositorFrameConsumer(mNativeAwDrawFnImpl); + return AwDrawFnImplJni.get().getCompositorFrameConsumer( + mNativeAwDrawFnImpl, AwDrawFnImpl.this); } @Override @@ -54,10 +56,12 @@ @Override public void trimMemory() {} - private native int nativeGetFunctorHandle(long nativeAwDrawFnImpl); - private native long nativeGetCompositorFrameConsumer(long nativeAwDrawFnImpl); - private native void nativeReleaseHandle(long nativeAwDrawFnImpl); - - private static native void nativeSetDrawFnFunctionTable(long functionTablePointer); - private static native long nativeCreate(); + @NativeMethods + interface Natives { + int getFunctorHandle(long nativeAwDrawFnImpl, AwDrawFnImpl caller); + long getCompositorFrameConsumer(long nativeAwDrawFnImpl, AwDrawFnImpl caller); + void releaseHandle(long nativeAwDrawFnImpl, AwDrawFnImpl caller); + void setDrawFnFunctionTable(long functionTablePointer); + long create(); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/gfx/AwGLFunctor.java b/android_webview/java/src/org/chromium/android_webview/gfx/AwGLFunctor.java index 74275918..7f700048 100644 --- a/android_webview/java/src/org/chromium/android_webview/gfx/AwGLFunctor.java +++ b/android_webview/java/src/org/chromium/android_webview/gfx/AwGLFunctor.java
@@ -11,6 +11,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; /** * Manages state associated with the Android render thread and the draw functor @@ -30,7 +31,7 @@ public AwGLFunctor( AwContents.NativeDrawFunctorFactory nativeDrawFunctorFactory, ViewGroup containerView) { - mNativeAwGLFunctor = nativeCreate(this); + mNativeAwGLFunctor = AwGLFunctorJni.get().create(this); mNativeDrawGLFunctor = nativeDrawFunctorFactory.createGLFunctor(mNativeAwGLFunctor); mContainerView = containerView; if (mNativeDrawGLFunctor.supportsDrawGLFunctorReleasedCallback()) { @@ -44,18 +45,20 @@ @Override public void destroy() { assert mRefCount > 0; - nativeRemoveFromCompositorFrameProducer(mNativeAwGLFunctor); + AwGLFunctorJni.get().removeFromCompositorFrameProducer( + mNativeAwGLFunctor, AwGLFunctor.this); removeReference(); } public static long getAwDrawGLFunction() { - return nativeGetAwDrawGLFunction(); + return AwGLFunctorJni.get().getAwDrawGLFunction(); } @Override public long getNativeCompositorFrameConsumer() { assert mRefCount > 0; - return nativeGetCompositorFrameConsumer(mNativeAwGLFunctor); + return AwGLFunctorJni.get().getCompositorFrameConsumer( + mNativeAwGLFunctor, AwGLFunctor.this); } @Override @@ -78,9 +81,9 @@ // When |mRefCount| decreases to zero, the functor is neither attached to a view, nor // referenced from the render tree, and so it is safe to delete the HardwareRenderer // instance to free up resources because the current state will not be drawn again. - nativeDeleteHardwareRenderer(mNativeAwGLFunctor); + AwGLFunctorJni.get().deleteHardwareRenderer(mNativeAwGLFunctor, AwGLFunctor.this); mNativeDrawGLFunctor.destroy(); - nativeDestroy(mNativeAwGLFunctor); + AwGLFunctorJni.get().destroy(mNativeAwGLFunctor); } } @@ -98,7 +101,7 @@ @Override public void trimMemory() { assert mRefCount > 0; - nativeDeleteHardwareRenderer(mNativeAwGLFunctor); + AwGLFunctorJni.get().deleteHardwareRenderer(mNativeAwGLFunctor, AwGLFunctor.this); } /** @@ -107,15 +110,17 @@ */ @VisibleForTesting public static int getNativeInstanceCount() { - return nativeGetNativeInstanceCount(); + return AwGLFunctorJni.get().getNativeInstanceCount(); } - private native void nativeDeleteHardwareRenderer(long nativeAwGLFunctor); - private native void nativeRemoveFromCompositorFrameProducer(long nativeAwGLFunctor); - private native long nativeGetCompositorFrameConsumer(long nativeAwGLFunctor); - - private static native long nativeGetAwDrawGLFunction(); - private static native void nativeDestroy(long nativeAwGLFunctor); - private static native long nativeCreate(AwGLFunctor javaProxy); - private static native int nativeGetNativeInstanceCount(); + @NativeMethods + interface Natives { + void deleteHardwareRenderer(long nativeAwGLFunctor, AwGLFunctor caller); + void removeFromCompositorFrameProducer(long nativeAwGLFunctor, AwGLFunctor caller); + long getCompositorFrameConsumer(long nativeAwGLFunctor, AwGLFunctor caller); + long getAwDrawGLFunction(); + void destroy(long nativeAwGLFunctor); + long create(AwGLFunctor javaProxy); + int getNativeInstanceCount(); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/gfx/AwPicture.java b/android_webview/java/src/org/chromium/android_webview/gfx/AwPicture.java index c05654dc..5415c09 100644 --- a/android_webview/java/src/org/chromium/android_webview/gfx/AwPicture.java +++ b/android_webview/java/src/org/chromium/android_webview/gfx/AwPicture.java
@@ -9,6 +9,7 @@ import org.chromium.android_webview.CleanupReference; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; import java.io.OutputStream; @@ -29,7 +30,7 @@ } @Override public void run() { - nativeDestroy(mNativeAwPicture); + AwPictureJni.get().destroy(mNativeAwPicture); } } @@ -57,17 +58,17 @@ @Override public int getWidth() { - return nativeGetWidth(mNativeAwPicture); + return AwPictureJni.get().getWidth(mNativeAwPicture, AwPicture.this); } @Override public int getHeight() { - return nativeGetHeight(mNativeAwPicture); + return AwPictureJni.get().getHeight(mNativeAwPicture, AwPicture.this); } @Override public void draw(Canvas canvas) { - nativeDraw(mNativeAwPicture, canvas); + AwPictureJni.get().draw(mNativeAwPicture, AwPicture.this, canvas); } @SuppressWarnings("deprecation") @@ -79,8 +80,11 @@ throw new IllegalStateException("Unsupported in AwPicture"); } - private static native void nativeDestroy(long nativeAwPicture); - private native int nativeGetWidth(long nativeAwPicture); - private native int nativeGetHeight(long nativeAwPicture); - private native void nativeDraw(long nativeAwPicture, Canvas canvas); + @NativeMethods + interface Natives { + void destroy(long nativeAwPicture); + int getWidth(long nativeAwPicture, AwPicture caller); + int getHeight(long nativeAwPicture, AwPicture caller); + void draw(long nativeAwPicture, AwPicture caller, Canvas canvas); + } }
diff --git a/android_webview/java/src/org/chromium/android_webview/permission/AwPermissionRequest.java b/android_webview/java/src/org/chromium/android_webview/permission/AwPermissionRequest.java index 839b0ce6..1903b2ab 100644 --- a/android_webview/java/src/org/chromium/android_webview/permission/AwPermissionRequest.java +++ b/android_webview/java/src/org/chromium/android_webview/permission/AwPermissionRequest.java
@@ -10,6 +10,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; /** * This class wraps permission request in Chromium side, and can only be created @@ -42,7 +43,7 @@ } @Override public void run() { - nativeDestroy(mNativeAwPermissionRequest); + AwPermissionRequestJni.get().destroy(mNativeAwPermissionRequest); } } @@ -74,7 +75,8 @@ public void grant() { validate(); if (mNativeAwPermissionRequest != 0) { - nativeOnAccept(mNativeAwPermissionRequest, true); + AwPermissionRequestJni.get().onAccept( + mNativeAwPermissionRequest, AwPermissionRequest.this, true); destroyNative(); } mProcessed = true; @@ -83,7 +85,8 @@ public void deny() { validate(); if (mNativeAwPermissionRequest != 0) { - nativeOnAccept(mNativeAwPermissionRequest, false); + AwPermissionRequestJni.get().onAccept( + mNativeAwPermissionRequest, AwPermissionRequest.this, false); destroyNative(); } mProcessed = true; @@ -97,14 +100,19 @@ } private void validate() { - if (!ThreadUtils.runningOnUiThread()) + if (!ThreadUtils.runningOnUiThread()) { throw new IllegalStateException( "Either grant() or deny() should be called on UI thread"); + } - if (mProcessed) + if (mProcessed) { throw new IllegalStateException("Either grant() or deny() has been already called."); + } } - private native void nativeOnAccept(long nativeAwPermissionRequest, boolean allowed); - private static native void nativeDestroy(long nativeAwPermissionRequest); + @NativeMethods + interface Natives { + void onAccept(long nativeAwPermissionRequest, AwPermissionRequest caller, boolean allowed); + void destroy(long nativeAwPermissionRequest); + } }
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index c483dc6..07101cd 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -2300,6 +2300,7 @@ "//base:i18n", "//base/test:test_support", "//cc:test_support", + "//ui/platform_window/common", # TODO(https://crbug.com/644336): Make CrasAudioHandler Chrome or Ash only. "//chromeos/audio",
diff --git a/ash/host/ash_window_tree_host_platform.cc b/ash/host/ash_window_tree_host_platform.cc index b6e5209..4a8147d 100644 --- a/ash/host/ash_window_tree_host_platform.cc +++ b/ash/host/ash_window_tree_host_platform.cc
@@ -43,7 +43,7 @@ transformer_helper_(this) { CreateCompositor(viz::FrameSinkId(), /* force_software_compositor */ false, - /* external_begin_frame_client */ nullptr, + /* use_external_begin_frame_control */ false, /* are_events_in_pixels */ true); CommonInit(); }
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc index 50effb6..65bd1c68 100644 --- a/ash/login/ui/lock_contents_view.cc +++ b/ash/login/ui/lock_contents_view.cc
@@ -574,21 +574,28 @@ void LockContentsView::RequestSecurityTokenPin( SecurityTokenPinRequest request) { - if (!primary_big_view_ || !primary_big_view_->auth_user() || - primary_big_view_->GetCurrentUser().basic_user_info.account_id != - request.account_id) { - // The PIN request is obsolete. - std::move(request.pin_ui_closed_callback).Run(); - return; + // Find which of the current big users, if any, should handle the request. + for (auto* big_user : {primary_big_view_, opt_secondary_big_view_}) { + if (big_user && big_user->auth_user() && + big_user->GetCurrentUser().basic_user_info.account_id == + request.account_id) { + big_user->auth_user()->RequestSecurityTokenPin(std::move(request)); + return; + } } - primary_big_view_->auth_user()->RequestSecurityTokenPin(std::move(request)); + // The PIN request is obsolete. + std::move(request.pin_ui_closed_callback).Run(); } void LockContentsView::ClearSecurityTokenPinRequest() { - // Note that if the PIN UI used to be shown in a different primary big view, - // then it was already closed while switching the view. + // Try both big users - it's safe since at most one PIN request can happen at + // a time, and as clearing a non-existing PIN request is a no-op. + // Note that if the PIN UI used to be shown in some other big view, then it + // had already been closed while switching the view(s). if (primary_big_view_ && primary_big_view_->auth_user()) primary_big_view_->auth_user()->ClearSecurityTokenPinRequest(); + if (opt_secondary_big_view_ && opt_secondary_big_view_->auth_user()) + opt_secondary_big_view_->auth_user()->ClearSecurityTokenPinRequest(); } void LockContentsView::Layout() {
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc index eea92a0..57e9265 100644 --- a/ash/login/ui/login_auth_user_view.cc +++ b/ash/login/ui/login_auth_user_view.cc
@@ -474,10 +474,9 @@ arrow_button_->SetBackgroundColor(kChallengeResponseArrowBackgroundColor); arrow_button_->SetFocusPainter(nullptr); - auto* arrow_to_icon_spacer = - AddChildView(std::make_unique<NonAccessibleView>()); - arrow_to_icon_spacer->SetPreferredSize( - gfx::Size(0, kSpacingBetweenChallengeResponseArrowAndIconDp)); + arrow_to_icon_spacer_ = AddChildView(std::make_unique<NonAccessibleView>()); + arrow_to_icon_spacer_->SetPreferredSize( + gfx::Size(0, GetArrowToIconSpacerHeight())); icon_ = AddChildView(std::make_unique<views::ImageView>()); icon_->SetImage(GetImageForIcon()); @@ -522,7 +521,9 @@ base::Unretained(this), State::kInitial)); } - arrow_button_->SetEnabled(state_ != State::kAuthenticating); + arrow_button_->SetVisible(state_ != State::kAuthenticating); + arrow_to_icon_spacer_->SetPreferredSize( + gfx::Size(0, GetArrowToIconSpacerHeight())); icon_->SetImage(GetImageForIcon()); label_->SetText(GetTextForLabel()); @@ -530,6 +531,15 @@ } private: + int GetArrowToIconSpacerHeight() const { + int spacer_height = kSpacingBetweenChallengeResponseArrowAndIconDp; + // During authentication, the arrow button is hidden, so the spacer should + // consume this space to avoid moving controls below it. + if (state_ == State::kAuthenticating) + spacer_height += kChallengeResponseArrowSizeDp; + return spacer_height; + } + gfx::ImageSkia GetImageForIcon() const { switch (state_) { case State::kInitial: @@ -559,6 +569,7 @@ base::RepeatingClosure on_start_tap_; State state_ = State::kInitial; ArrowButtonView* arrow_button_ = nullptr; + NonAccessibleView* arrow_to_icon_spacer_ = nullptr; views::ImageView* icon_ = nullptr; views::Label* label_ = nullptr; base::OneShotTimer reset_state_timer_;
diff --git a/ash/multi_user/user_switch_animator.cc b/ash/multi_user/user_switch_animator.cc index e12c831..c462d65 100644 --- a/ash/multi_user/user_switch_animator.cc +++ b/ash/multi_user/user_switch_animator.cc
@@ -9,6 +9,7 @@ #include "ash/shell.h" #include "ash/wallpaper/wallpaper_controller_impl.h" #include "ash/wm/mru_window_tracker.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/window_positioner.h" #include "base/bind.h" #include "ui/aura/client/aura_constants.h" @@ -89,6 +90,7 @@ animation_step_(ANIMATION_STEP_HIDE_OLD_USER), screen_cover_(GetScreenCover(NULL)), windows_by_account_id_() { + Shell::Get()->overview_controller()->EndOverview(); BuildUserToWindowsListMap(); AdvanceUserTransitionAnimation();
diff --git a/ash/session/session_controller_impl.cc b/ash/session/session_controller_impl.cc index 72479d8..7de40e2 100644 --- a/ash/session/session_controller_impl.cc +++ b/ash/session/session_controller_impl.cc
@@ -22,7 +22,6 @@ #include "ash/system/screen_security/screen_switch_check_controller.h" #include "ash/wm/lock_state_controller.h" #include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/overview_controller.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "ash/wm/wm_event.h" @@ -425,9 +424,6 @@ void SessionControllerImpl::CanSwitchActiveUser( CanSwitchActiveUserCallback callback) { - // Cancel overview mode when switching user profiles. - Shell::Get()->overview_controller()->EndOverview(); - ash::Shell::Get() ->screen_switch_check_controller() ->CanSwitchAwayFromActiveUser(std::move(callback));
diff --git a/ash/session/session_controller_impl_unittest.cc b/ash/session/session_controller_impl_unittest.cc index 1f49f738..ce36ef13 100644 --- a/ash/session/session_controller_impl_unittest.cc +++ b/ash/session/session_controller_impl_unittest.cc
@@ -16,7 +16,6 @@ #include "ash/shell.h" #include "ash/system/tray/system_tray_notifier.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/overview_controller.h" #include "ash/wm/window_util.h" #include "base/bind.h" #include "base/callback.h" @@ -612,14 +611,6 @@ switch_callback_hit_count_++; } - // Methods needed to test with overview mode. - bool StartOverview() { - return Shell::Get()->overview_controller()->StartOverview(); - } - bool InOverviewSession() const { - return Shell::Get()->overview_controller()->InOverviewSession(); - } - // Various counter accessors. int stop_capture_callback_hit_count() const { return stop_capture_callback_hit_count_; @@ -766,18 +757,6 @@ EXPECT_EQ(1, stop_share_callback_hit_count()); } -// Test that overview mode is dismissed before switching user profile. -TEST_F(CanSwitchUserTest, OverviewModeDismissed) { - EXPECT_EQ(0, switch_callback_hit_count()); - gfx::Rect bounds(0, 0, 100, 100); - std::unique_ptr<aura::Window> w(CreateTestWindowInShellWithBounds(bounds)); - ASSERT_TRUE(StartOverview()); - ASSERT_TRUE(InOverviewSession()); - SwitchUser(CanSwitchUserTest::NO_DIALOG); - ASSERT_FALSE(InOverviewSession()); - EXPECT_EQ(1, switch_callback_hit_count()); -} - using SessionControllerImplUnblockTest = NoSessionAshTestBase; TEST_F(SessionControllerImplUnblockTest, ActiveWindowAfterUnblocking) {
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc index 8cf21e6..435183f 100644 --- a/ash/test/ash_test_helper.cc +++ b/ash/test/ash_test_helper.cc
@@ -55,7 +55,6 @@ #include "ui/aura/window.h" #include "ui/base/ime/init/input_method_initializer.h" #include "ui/base/material_design/material_design_controller.h" -#include "ui/base/platform_window_defaults.h" #include "ui/base/ui_base_switches_util.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/compositor/test/test_context_factories.h" @@ -64,6 +63,7 @@ #include "ui/display/manager/display_manager.h" #include "ui/display/screen.h" #include "ui/display/test/display_manager_test_api.h" +#include "ui/platform_window/common/platform_window_defaults.h" #include "ui/wm/core/capture_controller.h" #include "ui/wm/core/cursor_manager.h" #include "ui/wm/core/wm_state.h"
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc index 173ac35f..5fb53f8a 100644 --- a/ash/wm/desks/desks_unittests.cc +++ b/ash/wm/desks/desks_unittests.cc
@@ -37,6 +37,7 @@ #include "ash/wm/workspace_controller.h" #include "base/stl_util.h" #include "base/test/scoped_feature_list.h" +#include "components/session_manager/session_manager_types.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/window_parenting_client.h" #include "ui/base/ui_base_types.h" @@ -1930,6 +1931,7 @@ MultiUserWindowManager::Create(this, GetUser1AccountId()); MultiUserWindowManagerImpl::Get()->SetAnimationSpeedForTest( MultiUserWindowManagerImpl::ANIMATION_SPEED_DISABLED); + session_controller->SetSessionState(session_manager::SessionState::ACTIVE); } void TearDown() override { @@ -2115,6 +2117,14 @@ EXPECT_TRUE(win6->IsVisible()); } +TEST_F(DesksMultiUserTest, SwitchingUsersEndsOverview) { + OverviewController* overview_controller = Shell::Get()->overview_controller(); + EXPECT_TRUE(overview_controller->StartOverview()); + EXPECT_TRUE(overview_controller->InOverviewSession()); + SwitchActiveUser(GetUser2AccountId()); + EXPECT_FALSE(overview_controller->InOverviewSession()); +} + } // namespace // Simulates the same behavior of event rewriting that key presses go through.
diff --git a/base/task/task_executor.cc b/base/task/task_executor.cc index 8b527b0..57ca5cd 100644 --- a/base/task/task_executor.cc +++ b/base/task/task_executor.cc
@@ -6,8 +6,10 @@ #include <type_traits> +#include "base/no_destructor.h" #include "base/task/task_traits.h" #include "base/task/task_traits_extension.h" +#include "base/threading/thread_local.h" namespace base { @@ -30,6 +32,21 @@ } // namespace +ThreadLocalPointer<TaskExecutor>* GetTLSForCurrentTaskExecutor() { + static NoDestructor<ThreadLocalPointer<TaskExecutor>> instance; + return instance.get(); +} + +void SetTaskExecutorForCurrentThread(TaskExecutor* task_executor) { + DCHECK(!GetTLSForCurrentTaskExecutor()->Get() || !task_executor || + GetTLSForCurrentTaskExecutor()->Get() == task_executor); + GetTLSForCurrentTaskExecutor()->Set(task_executor); +} + +TaskExecutor* GetTaskExecutorForCurrentThread() { + return GetTLSForCurrentTaskExecutor()->Get(); +} + void RegisterTaskExecutor(uint8_t extension_id, TaskExecutor* task_executor) { DCHECK_NE(extension_id, TaskTraitsExtensionStorage::kInvalidExtensionId); DCHECK_LE(extension_id, TaskTraitsExtensionStorage::kMaxExtensionId);
diff --git a/base/task/task_executor.h b/base/task/task_executor.h index b4e79e14..a062fdc 100644 --- a/base/task/task_executor.h +++ b/base/task/task_executor.h
@@ -74,6 +74,13 @@ TaskExecutor* task_executor); void BASE_EXPORT UnregisterTaskExecutorForTesting(uint8_t extension_id); +// Stores the provided TaskExecutor in TLS for the current thread, to be used by +// tasks with the CurrentThread() trait. +void BASE_EXPORT SetTaskExecutorForCurrentThread(TaskExecutor* task_executor); + +// Returns the task executor registered for the current thread. +BASE_EXPORT TaskExecutor* GetTaskExecutorForCurrentThread(); + // Determines whether a registered TaskExecutor will handle tasks with the given // |traits| and, if so, returns a pointer to it. Otherwise, returns |nullptr|. TaskExecutor* GetRegisteredTaskExecutorForTraits(const TaskTraits& traits);
diff --git a/build/config/linux/pangocairo/pangocairo.gni b/build/config/linux/pangocairo/pangocairo.gni index 65cf4d81..2a922e32 100644 --- a/build/config/linux/pangocairo/pangocairo.gni +++ b/build/config/linux/pangocairo/pangocairo.gni
@@ -4,4 +4,4 @@ import("//build/config/ui.gni") -use_pangocairo = is_linux && !is_chromeos +use_pangocairo = is_linux && !is_chromeos && !is_chromecast
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 1f1d710..555c8e933 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8903375777801368736 \ No newline at end of file +8903349694152909712 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 2cd8899d..d3107dd 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8903376064405861168 \ No newline at end of file +8903356008077591232 \ No newline at end of file
diff --git a/cc/trees/layer_tree_host_unittest_picture.cc b/cc/trees/layer_tree_host_unittest_picture.cc index 1a10b7a..445a263 100644 --- a/cc/trees/layer_tree_host_unittest_picture.cc +++ b/cc/trees/layer_tree_host_unittest_picture.cc
@@ -567,7 +567,8 @@ // Multi-thread only because in single thread you can't pinch zoom on the // compositor thread. -MULTI_THREAD_TEST_F(LayerTreeHostPictureTestRSLLMembershipWithScale); +// TODO(https://crbug.com/997866): Flaky on several platforms. +// MULTI_THREAD_TEST_F(LayerTreeHostPictureTestRSLLMembershipWithScale); class LayerTreeHostPictureTestForceRecalculateScales : public LayerTreeHostPictureTest {
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 61b901a..13468cfe 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -1586,8 +1586,6 @@ # 'android_apk', or 'android_app_bundle_module'. # apk_name: For 'android_apk' target types, name of the final APK without # an .apk suffix (e.g. 'ChromePublic'). -# module_name: For 'android_app_bundle_module' target types, name of the -# module (e.g. 'ChromePublicBase'). # is_base_module: For 'android_app_bundle_module' target types only, # set to true to indicate that this is a base application module # (instead of a feature module). @@ -1603,7 +1601,6 @@ "is_base_module", "jni_registration_header", "is_modern", - "module_name", "target_type", "enable_multidex", ]) @@ -1654,7 +1651,6 @@ chrome_public_apk_or_module_tmpl("chrome_modern_public_base_bundle_module") { target_type = "android_app_bundle_module" - module_name = "ChromeModernPublicBase" is_base_module = true is_modern = true bundle_target = ":chrome_modern_public_bundle" @@ -1683,8 +1679,6 @@ # target_type: Either 'android_apk' or 'android_app_bundle_module'. # apk_name: For APK target types, the final APK name without an .apk # suffix (e.g. "MonochromePublic"). -# module_name: For module target types, the module's name without a -# suffix (e.g. "MonochromePublicBase") # is_base_module: For module target types, a boolean indicating whether # this is a base bundle module (instead of a feature one). # is_64_bit_browser: When compiling in a 64-bit configuration, a boolean @@ -1735,7 +1729,6 @@ "include_32_bit_webview", "is_64_bit_browser", "is_base_module", - "module_name", "proguard_jar_path", "resource_ids_provider_dep", "static_library_provider", @@ -2172,7 +2165,6 @@ chrome_feature_module( "chrome_modern_public_bundle_${_module_desc.name}_bundle_module") { manifest_package = chrome_public_manifest_package - module_name_suffix = "ChromeModernPublic" base_module_target = ":chrome_modern_public_base_bundle_module" uncompress_shared_libraries = chromium_linker_supported is_monochrome_or_trichrome = false @@ -2262,7 +2254,6 @@ "include_32_bit_webview", "use_trichrome_library", ]) - module_name = _bundle_name + "Base" bundle_target = ":${invoker.target_name}" target_type = "android_app_bundle_module" is_base_module = true @@ -2284,7 +2275,6 @@ foreach(_module_desc, _module_descs) { chrome_feature_module("${target_name}_${_module_desc.name}_bundle_module") { manifest_package = chrome_public_manifest_package - module_name_suffix = _bundle_name base_module_target = ":$_base_module_target_name" uncompress_shared_libraries = true is_monochrome_or_trichrome = true
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index 5040865e..65830305f 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -1492,7 +1492,6 @@ "java/src/org/chromium/chrome/browser/suggestions/SuggestionsOfflineModelObserver.java", "java/src/org/chromium/chrome/browser/suggestions/SuggestionsRanker.java", "java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java", - "java/src/org/chromium/chrome/browser/suggestions/SuggestionsSheetVisibilityChangeObserver.java", "java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java", "java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java", "java/src/org/chromium/chrome/browser/suggestions/ThumbnailGradient.java",
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni index 3659b5c..5080fa07 100644 --- a/chrome/android/chrome_public_apk_tmpl.gni +++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -45,8 +45,6 @@ # Variables: # target_type: Either 'android_apk' or 'android_app_bundle_module'. # apk_name: For APK target types, the final APK name without a suffix. -# module_name: For bundle module target types, the module's name without a -# suffix. # is_base_module: For bundle module target types, true iff this is a base # application module, instead of a feature module. # android_manifest: Application manifest path.
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni index b6661b3..0bbbef9a9 100644 --- a/chrome/android/chrome_test_java_sources.gni +++ b/chrome/android/chrome_test_java_sources.gni
@@ -445,7 +445,6 @@ "javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTest.java", "javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTestRule.java", "javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetUiCaptureTest.java", - "javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsSheetVisibilityChangeObserverTest.java", "javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGridLayoutTest.java", "javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupTest.java", "javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java",
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java index 55663a9..d1d7a35 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
@@ -183,6 +183,8 @@ if (!isSoftKeyboardShowing(view)) { if (is(WAITING_TO_REPLACE)) mModel.set(KEYBOARD_EXTENSION_STATE, REPLACING_KEYBOARD); if (is(EXTENDING_KEYBOARD)) mModel.set(KEYBOARD_EXTENSION_STATE, HIDDEN); + // Cancel animations if the keyboard suddenly closes so the bar doesn't linger. + if (is(HIDDEN)) mKeyboardAccessory.skipClosingAnimationOnce(); // Layout changes when entering/resizing/leaving MultiWindow. Ensure a consistent state: updateKeyboard(mModel.get(KEYBOARD_EXTENSION_STATE)); return; @@ -263,11 +265,15 @@ void hide() { mModel.set(SHOW_WHEN_VISIBLE, false); - pause(); + if (!isInitialized()) return; + mModel.set(KEYBOARD_EXTENSION_STATE, HIDDEN); } void pause() { if (!isInitialized()) return; + // When pause is called, the accessory needs to disappear fast since some UI forced it to + // close (e.g. a scene changed or the screen was turned off). + mKeyboardAccessory.skipClosingAnimationOnce(); mModel.set(KEYBOARD_EXTENSION_STATE, HIDDEN); } @@ -382,6 +388,8 @@ if (extensionState == EXTENDING_KEYBOARD) mKeyboardAccessory.prepareUserEducation(); if (requiresVisibleSheet(extensionState)) { mAccessorySheet.show(); + // TODO(crbug.com/853768): Enable animation that works with sheet (if possible). + mKeyboardAccessory.skipClosingAnimationOnce(); } else if (requiresHiddenSheet(extensionState)) { mKeyboardAccessory.closeActiveTab(); mAccessorySheet.hide();
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java index c42c5fce4..cdf273e 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.keyboard_accessory.bar_component; +import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SKIP_CLOSING_ANIMATION; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.VISIBLE; import android.support.annotation.Nullable; @@ -37,6 +38,10 @@ public class KeyboardAccessoryCoordinator { private final KeyboardAccessoryMediator mMediator; private final KeyboardAccessoryTabLayoutCoordinator mTabLayout; + private final PropertyModelChangeProcessor + .ViewBinder<PropertyModel, KeyboardAccessoryView, PropertyKey> mViewBinder; + private final PropertyModel mModel; + private KeyboardAccessoryView mView; /** * The keyboard accessory provides signals when to show or change the accessory sheet below it. @@ -118,24 +123,22 @@ public KeyboardAccessoryCoordinator(KeyboardAccessoryTabLayoutCoordinator tabLayout, VisibilityDelegate visibilityDelegate, ViewProvider<KeyboardAccessoryView> viewProvider) { - PropertyModel model = KeyboardAccessoryProperties.defaultModelBuilder().build(); mTabLayout = tabLayout; - mMediator = new KeyboardAccessoryMediator(model, visibilityDelegate, + mModel = KeyboardAccessoryProperties.defaultModelBuilder().build(); + mMediator = new KeyboardAccessoryMediator(mModel, visibilityDelegate, mTabLayout.getTabSwitchingDelegate(), mTabLayout.getTabLayoutCallbacks()); if (!ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY)) { viewProvider.whenLoaded(barView -> mTabLayout.assignNewView(barView.getTabLayout())); } + viewProvider.whenLoaded(view -> mView = view); mTabLayout.setTabObserver(mMediator); - PropertyModelChangeProcessor - .ViewBinder<PropertyModel, KeyboardAccessoryView, PropertyKey> viewBinder = - KeyboardAccessoryViewBinder::bind; - if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY)) { - viewBinder = KeyboardAccessoryModernViewBinder::bind; - } - LazyConstructionPropertyMcp.create(model, VISIBLE, viewProvider, viewBinder); + mViewBinder = ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY) + ? KeyboardAccessoryModernViewBinder::bind + : KeyboardAccessoryViewBinder::bind; + LazyConstructionPropertyMcp.create(mModel, VISIBLE, viewProvider, mViewBinder); KeyboardAccessoryMetricsRecorder.registerKeyboardAccessoryModelMetricsObserver( - model, mTabLayout.getTabSwitchingDelegate()); + mModel, mTabLayout.getTabSwitchingDelegate()); } /** @@ -213,6 +216,14 @@ mMediator.show(); } + /** Next time the accessory is closed, don't delay the closing animation. */ + public void skipClosingAnimationOnce() { + mMediator.skipClosingAnimationOnce(); + // TODO(fhorschig): Consider allow LazyConstructionPropertyMcp to propagate updates once the + // view exists. Currently it doesn't, so we need this ugly explicit binding. + if (mView != null) mViewBinder.bind(mModel, mView, SKIP_CLOSING_ANIMATION); + } + /** * Returns the visibility of the the accessory. The returned property reflects the latest change * while the view might still be in progress of being updated accordingly.
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java index 1324c79..7693abbc 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java
@@ -6,9 +6,11 @@ import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BOTTOM_OFFSET_PX; +import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.DISABLE_ANIMATIONS_FOR_TESTING; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.KEYBOARD_TOGGLE_VISIBLE; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SHEET_TITLE; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK; +import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SKIP_CLOSING_ANIMATION; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.TAB_LAYOUT_ITEM; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.VISIBLE; @@ -215,9 +217,14 @@ } void show() { + mModel.set(SKIP_CLOSING_ANIMATION, false); mModel.set(VISIBLE, true); } + void skipClosingAnimationOnce() { + mModel.set(SKIP_CLOSING_ANIMATION, true); + } + void dismiss() { mTabSwitcher.closeActiveTab(); mModel.set(VISIBLE, false); @@ -242,7 +249,9 @@ return; } if (propertyKey == BOTTOM_OFFSET_PX || propertyKey == SHOW_KEYBOARD_CALLBACK - || propertyKey == TAB_LAYOUT_ITEM || propertyKey == SHEET_TITLE) { + || propertyKey == TAB_LAYOUT_ITEM || propertyKey == SHEET_TITLE + || propertyKey == SKIP_CLOSING_ANIMATION + || propertyKey == DISABLE_ANIMATIONS_FOR_TESTING) { return; } assert false : "Every property update needs to be handled explicitly!";
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java index ff9e39e..f79d65aa 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java
@@ -73,7 +73,9 @@ if (propertyKey == KeyboardAccessoryProperties.BOTTOM_OFFSET_PX || propertyKey == KeyboardAccessoryProperties.KEYBOARD_TOGGLE_VISIBLE || propertyKey == KeyboardAccessoryProperties.SHEET_TITLE - || propertyKey == KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK) { + || propertyKey == KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK + || propertyKey == KeyboardAccessoryProperties.SKIP_CLOSING_ANIMATION + || propertyKey == KeyboardAccessoryProperties.DISABLE_ANIMATIONS_FOR_TESTING) { return; } assert false : "Every property update needs to be handled explicitly!";
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java index d5b9d12..35e94f30 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java
@@ -9,11 +9,13 @@ import android.support.design.widget.TabLayout; import android.support.v7.widget.RecyclerView; +import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData.Action; import org.chromium.chrome.browser.keyboard_accessory.tab_layout_component.KeyboardAccessoryTabLayoutCoordinator.TabLayoutCallbacks; import org.chromium.components.autofill.AutofillSuggestion; import org.chromium.ui.modelutil.ListModel; import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.modelutil.PropertyModel.ReadableBooleanPropertyKey; import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey; import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey; import org.chromium.ui.modelutil.PropertyModel.WritableIntPropertyKey; @@ -33,6 +35,8 @@ static final ReadableObjectPropertyKey<ListModel<BarItem>> BAR_ITEMS = new ReadableObjectPropertyKey<>("bar_items"); static final WritableBooleanPropertyKey VISIBLE = new WritableBooleanPropertyKey("visible"); + static final WritableBooleanPropertyKey SKIP_CLOSING_ANIMATION = + new WritableBooleanPropertyKey("skip_closing_animation"); static final WritableIntPropertyKey BOTTOM_OFFSET_PX = new WritableIntPropertyKey("offset"); static final WritableObjectPropertyKey<String> SHEET_TITLE = new WritableObjectPropertyKey<>("sheet_title"); @@ -42,14 +46,20 @@ new WritableObjectPropertyKey<>("tab_layout_item"); static final WritableObjectPropertyKey<Runnable> SHOW_KEYBOARD_CALLBACK = new WritableObjectPropertyKey<>("keyboard_callback"); + @VisibleForTesting + static final ReadableBooleanPropertyKey DISABLE_ANIMATIONS_FOR_TESTING = + new WritableBooleanPropertyKey("skip_all_animations_for_testing"); static PropertyModel.Builder defaultModelBuilder() { return new PropertyModel - .Builder(BAR_ITEMS, VISIBLE, BOTTOM_OFFSET_PX, TAB_LAYOUT_ITEM, - KEYBOARD_TOGGLE_VISIBLE, SHEET_TITLE, SHOW_KEYBOARD_CALLBACK) + .Builder(DISABLE_ANIMATIONS_FOR_TESTING, BAR_ITEMS, VISIBLE, SKIP_CLOSING_ANIMATION, + BOTTOM_OFFSET_PX, TAB_LAYOUT_ITEM, KEYBOARD_TOGGLE_VISIBLE, SHEET_TITLE, + SHOW_KEYBOARD_CALLBACK) .with(BAR_ITEMS, new ListModel<>()) .with(VISIBLE, false) - .with(KEYBOARD_TOGGLE_VISIBLE, false); + .with(SKIP_CLOSING_ANIMATION, false) + .with(KEYBOARD_TOGGLE_VISIBLE, false) + .with(DISABLE_ANIMATIONS_FOR_TESTING, false); } /**
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java index 495f18f..586ac52 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java
@@ -14,7 +14,9 @@ import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.View; +import android.view.ViewPropertyAnimator; import android.view.accessibility.AccessibilityEvent; +import android.view.animation.AccelerateInterpolator; import android.widget.LinearLayout; import org.chromium.chrome.browser.ChromeFeatureList; @@ -27,6 +29,9 @@ class KeyboardAccessoryView extends LinearLayout { protected RecyclerView mBarItemsView; protected TabLayout mTabLayout; + private ViewPropertyAnimator mRunningAnimation; + private boolean mShouldSkipClosingAnimation; + private boolean mDisableAnimations; protected static class HorizontalDividerItemDecoration extends RecyclerView.ItemDecoration { private final int mHorizontalMargin; @@ -118,12 +123,41 @@ private void show() { bringToFront(); // Needs to overlay every component and the bottom sheet - like a keyboard. - setVisibility(View.VISIBLE); + if (mRunningAnimation != null) mRunningAnimation.cancel(); + if (mDisableAnimations) { + mRunningAnimation = null; + setVisibility(View.VISIBLE); + return; + } + mRunningAnimation = animate() + .alpha(1.0f) + .setDuration(150) + .setInterpolator(new AccelerateInterpolator()) + .withStartAction(() -> setVisibility(View.VISIBLE)); announceForAccessibility(getContentDescription()); } private void hide() { - setVisibility(View.GONE); + if (mRunningAnimation != null) mRunningAnimation.cancel(); + if (mShouldSkipClosingAnimation || mDisableAnimations) { + mRunningAnimation = null; + setVisibility(View.GONE); + return; + } + mRunningAnimation = animate() + .alpha(0.0f) + .setInterpolator(new AccelerateInterpolator()) + .setStartDelay(150) + .setDuration(150) + .withEndAction(() -> setVisibility(View.GONE)); + } + + void setSkipClosingAnimation(boolean shouldSkipClosingAnimation) { + mShouldSkipClosingAnimation = shouldSkipClosingAnimation; + } + + void disableAnimationsForTesting() { + mDisableAnimations = true; } private void initializeHorizontalRecyclerView(RecyclerView recyclerView) {
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java index 981dff0..563d9fce 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java
@@ -6,9 +6,11 @@ import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BOTTOM_OFFSET_PX; +import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.DISABLE_ANIMATIONS_FOR_TESTING; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.KEYBOARD_TOGGLE_VISIBLE; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SHEET_TITLE; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK; +import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SKIP_CLOSING_ANIMATION; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.TAB_LAYOUT_ITEM; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.VISIBLE; @@ -101,8 +103,13 @@ if (propertyKey == BAR_ITEMS) { view.setBarItemsAdapter( KeyboardAccessoryCoordinator.createBarItemsAdapter(model.get(BAR_ITEMS))); + } else if (propertyKey == DISABLE_ANIMATIONS_FOR_TESTING) { + if (model.get(DISABLE_ANIMATIONS_FOR_TESTING)) view.disableAnimationsForTesting(); } else if (propertyKey == VISIBLE) { view.setVisible(model.get(VISIBLE)); + } else if (propertyKey == SKIP_CLOSING_ANIMATION) { + view.setSkipClosingAnimation(model.get(SKIP_CLOSING_ANIMATION)); + if (!model.get(VISIBLE)) view.setVisible(false); // Update to cancel any animation. } else if (propertyKey == BOTTOM_OFFSET_PX) { view.setBottomOffset(model.get(BOTTOM_OFFSET_PX)); } else if (propertyKey == SHOW_KEYBOARD_CALLBACK || propertyKey == KEYBOARD_TOGGLE_VISIBLE
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java index 282af258..ad7a958b 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
@@ -22,6 +22,7 @@ import static org.chromium.chrome.browser.keyboard_accessory.AccessoryAction.AUTOFILL_SUGGESTION; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS; +import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.DISABLE_ANIMATIONS_FOR_TESTING; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.KEYBOARD_TOGGLE_VISIBLE; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SHEET_TITLE; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.TAB_LAYOUT_ITEM; @@ -162,6 +163,7 @@ public void onTabLayoutUnbound( TabLayout tabs) {} })) + .with(DISABLE_ANIMATIONS_FOR_TESTING, true) .build(); ViewStub viewStub = mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory_stub);
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java index 4210274..0668bb9 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java
@@ -20,6 +20,7 @@ import static org.chromium.chrome.browser.keyboard_accessory.AccessoryAction.AUTOFILL_SUGGESTION; import static org.chromium.chrome.browser.keyboard_accessory.AccessoryAction.GENERATE_PASSWORD_AUTOMATIC; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS; +import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.DISABLE_ANIMATIONS_FOR_TESTING; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.TAB_LAYOUT_ITEM; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.VISIBLE; import static org.chromium.chrome.test.util.ViewUtils.VIEW_GONE; @@ -89,6 +90,7 @@ public void onTabLayoutUnbound( TabLayout tabs) {} })) + .with(DISABLE_ANIMATIONS_FOR_TESTING, true) .build(); ViewStub viewStub = mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory_stub);
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java index be4af9d..9ebe335e 100644 --- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java +++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
@@ -20,6 +20,7 @@ import static org.chromium.chrome.browser.keyboard_accessory.AccessoryAction.GENERATE_PASSWORD_AUTOMATIC; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SHEET_TITLE; +import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SKIP_CLOSING_ANIMATION; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.VISIBLE; import android.support.design.widget.TabLayout; @@ -407,6 +408,15 @@ } @Test + public void testSkipAnimationsOnlyUntilNextShow() { + assertThat(mModel.get(SKIP_CLOSING_ANIMATION), is(false)); + mCoordinator.skipClosingAnimationOnce(); + assertThat(mModel.get(SKIP_CLOSING_ANIMATION), is(true)); + mCoordinator.show(); + assertThat(mModel.get(SKIP_CLOSING_ANIMATION), is(false)); + } + + @Test public void testRecordsOneImpressionForEveryInitialContentOnVisibilityChange() { assertThat(RecordHistogram.getHistogramTotalCountForTesting( KeyboardAccessoryMetricsRecorder.UMA_KEYBOARD_ACCESSORY_BAR_SHOWN),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java index 637705d..d9310b8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -1285,11 +1285,6 @@ mToolbarManager = null; } - if (mBottomSheet != null) { - mBottomSheet.destroy(); - mBottomSheet = null; - } - if (mDidAddPolicyChangeListener) { CombinedPolicyProvider.get().removePolicyChangeListener(this); mDidAddPolicyChangeListener = false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProvider.java index 6e2163a..5c445df4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProvider.java
@@ -113,7 +113,7 @@ static final String ACTION_UPDATE_ALL_WIDGETS = "org.chromium.chrome.browser.searchwidget.UPDATE_ALL_WIDGETS"; - static final String EXTRA_START_VOICE_SEARCH = + public static final String EXTRA_START_VOICE_SEARCH = "org.chromium.chrome.browser.searchwidget.START_VOICE_SEARCH"; private static final String PREF_IS_VOICE_SEARCH_AVAILABLE =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsSheetVisibilityChangeObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsSheetVisibilityChangeObserver.java deleted file mode 100644 index 71c031c9..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsSheetVisibilityChangeObserver.java +++ /dev/null
@@ -1,171 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.suggestions; - -import android.app.Activity; -import android.support.annotation.CallSuper; - -import org.chromium.base.ActivityState; -import org.chromium.base.ApplicationStatus; -import org.chromium.base.VisibleForTesting; -import org.chromium.chrome.browser.ChromeActivity; -import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet; -import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent; -import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.StateChangeReason; -import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver; - -/** - * Notifies of events dedicated to changes in visibility of a - * {@link SuggestionsBottomSheetContent}. - */ -public abstract class SuggestionsSheetVisibilityChangeObserver - extends EmptyBottomSheetObserver implements ApplicationStatus.ActivityStateListener { - @BottomSheet.SheetState - private int mCurrentContentState; - private boolean mCurrentVisibility; - private boolean mWasShownSinceLastOpen; - - private final ChromeActivity mActivity; - private final BottomSheet.BottomSheetContent mContentObserved; - private final BottomSheet mBottomSheet; - - /** - * Creates and register the observer to receive events related to changes to the provided - * {@link BottomSheetContent}'s visibility. - * @param bottomSheetContent BottomSheetContent to observe visibility for. - * @param chromeActivity The BottomSheet the observed content is registered with. Note: the - * constructor does not register the object as observer! - */ - public SuggestionsSheetVisibilityChangeObserver( - BottomSheetContent bottomSheetContent, ChromeActivity chromeActivity) { - mActivity = chromeActivity; - mContentObserved = bottomSheetContent; - mBottomSheet = chromeActivity.getBottomSheet(); - assert mBottomSheet != null; - - ApplicationStatus.registerStateListenerForActivity(this, chromeActivity); - mBottomSheet.addObserver(this); - - // This event is swallowed when the observer is registered after the sheet is opened. - // (e.g. Chrome starts on the NTP). This allows taking it into account. - if (mBottomSheet.isSheetOpen()) onSheetOpened(StateChangeReason.NONE); - } - - public void onDestroy() { - ApplicationStatus.unregisterActivityStateListener(this); - mBottomSheet.removeObserver(this); - } - - /** Called when the observed sheet content becomes visible. - * @param isFirstShown Only {@code true} the first time suggestions are shown each time the - * sheet is opened. - */ - public abstract void onContentShown(boolean isFirstShown); - - /** Called when the observed sheet content becomes invisible. */ - public abstract void onContentHidden(); - - /** - * Called when the visible state of the observed sheet content changes. - * @param contentState The new state, restricted to stable ones: - * {@link BottomSheet#SHEET_STATE_FULL},{@link BottomSheet#SHEET_STATE_HALF} - * or {@link BottomSheet#SHEET_STATE_PEEK} - */ - public abstract void onContentStateChanged(@BottomSheet.SheetState int contentState); - - @Override - @CallSuper - public void onSheetOpened(@StateChangeReason int reason) { - mWasShownSinceLastOpen = false; - onStateChange(); - } - - @Override - @CallSuper - public void onSheetClosed(@StateChangeReason int reason) { - onStateChange(); - } - - @Override - @CallSuper - public void onSheetContentChanged(BottomSheetContent newContent) { - onStateChange(); - } - - @Override - @CallSuper - public void onSheetStateChanged(int newState) { - onStateChange(); - } - - @Override - @CallSuper - public void onActivityStateChange(Activity activity, @ActivityState int newState) { - if (newState == ActivityState.DESTROYED) { - onDestroy(); - return; - } - - if (!mBottomSheet.isSheetOpen()) return; - - onStateChange(); - } - - /** - * @return Whether the observed sheet content is currently visible. - */ - boolean isVisible() { - return mCurrentVisibility; - } - - /** - * Compares the current state of the bottom sheet and activity with the ones recorded at the - * previous call and generates events based on the difference. - * @see #onContentShown(boolean) - * @see #onContentHidden() - * @see #onContentStateChanged(int) - */ - private void onStateChange() { - @ActivityState - int activityState = ApplicationStatus.getStateForActivity(mActivity); - boolean isActivityVisible = - activityState == ActivityState.RESUMED || activityState == ActivityState.PAUSED; - - boolean newVisibility = - isActivityVisible && mBottomSheet.isSheetOpen() && isObservedContentCurrent(); - - // As the visibility we track is the one for a specific sheet content rather than the - // whole BottomSheet, we also need to reflect that in the state, marking it "peeking" here - // even though the BottomSheet itself is not. - @BottomSheet.SheetState - int newContentState = - newVisibility ? mBottomSheet.getSheetState() : BottomSheet.SheetState.PEEK; - - // Flag overall changes to the visible state of the content, while ignoring transient states - // like |STATE_SCROLLING|. - boolean hasMeaningfulStateChange = BottomSheet.isStateStable(newContentState) - && (mCurrentContentState != newContentState || mCurrentVisibility != newVisibility); - - if (newVisibility != mCurrentVisibility) { - if (newVisibility) { - onContentShown(!mWasShownSinceLastOpen); - mWasShownSinceLastOpen = true; - } else { - onContentHidden(); - } - mCurrentVisibility = newVisibility; - } - - if (hasMeaningfulStateChange) { - onContentStateChanged(newContentState); - mCurrentContentState = newContentState; - } - } - - @VisibleForTesting - protected boolean isObservedContentCurrent() { - return mContentObserved == mBottomSheet.getCurrentSheetContent(); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java index d8245b10..a4d2165 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -108,9 +108,6 @@ */ public static final long BASE_ANIMATION_DURATION_MS = 218; - /** The amount of time it takes to transition sheet content in or out. */ - private static final long TRANSITION_DURATION_MS = 150; - /** * The fraction of the way to the next state the sheet must be swiped to animate there when * released. This is the value used when there are 3 active states. A smaller value here means @@ -230,9 +227,6 @@ /** The token used to enable browser controls persistence. */ private int mPersistentControlsToken; - /** Conversion ratio of dp to px. */ - private float mDpToPx; - /** * An interface defining content that can be displayed inside of the bottom sheet for Chrome * Home. @@ -357,27 +351,6 @@ void onSizeChanged(int width, int height, int oldWidth, int oldHeight); } - /** - * Returns whether the provided bottom sheet state is in one of the stable open or closed - * states: {@link #SheetState.FULL}, {@link #SheetState.PEEK} or {@link #SheetState.HALF} - * @param sheetState A {@link SheetState} to test. - */ - public static boolean isStateStable(@SheetState int sheetState) { - switch (sheetState) { - case SheetState.HIDDEN: - case SheetState.PEEK: - case SheetState.HALF: - case SheetState.FULL: - return true; - case SheetState.SCROLLING: - return false; - case SheetState.NONE: // Should never be tested, internal only value. - default: - assert false; - return false; - } - } - @Override public boolean shouldGestureMoveSheet(MotionEvent initialEvent, MotionEvent currentEvent) { // If the sheet is scrolling off-screen or in the process of hiding, gestures should not @@ -418,7 +391,7 @@ /** * Called when the activity containing the {@link BottomSheet} is destroyed. */ - public void destroy() { + void destroy() { mIsDestroyed = true; mIsTouchEnabled = false; mObservers.clear(); @@ -489,7 +462,7 @@ * @return Whether or not the toolbar Android View is hidden due to being scrolled off-screen. */ @VisibleForTesting - public boolean isToolbarAndroidViewHidden() { + boolean isToolbarAndroidViewHidden() { return mFullscreenManager == null || mFullscreenManager.getBottomControlOffset() > 0 || mToolbarHolder.getVisibility() != VISIBLE; } @@ -530,7 +503,6 @@ (TouchRestrictingFrameLayout) findViewById(R.id.bottom_sheet_content); mBottomSheetContentContainer.setBottomSheet(this); setBackground(mBottomSheetContentContainer); - mDpToPx = mActivity.getResources().getDisplayMetrics().density; // Listen to height changes on the root. root.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @@ -775,7 +747,8 @@ * Show content in the bottom sheet's content area. * @param content The {@link BottomSheetContent} to show, or null if no content should be shown. */ - public void showContent(@Nullable final BottomSheetContent content) { + @VisibleForTesting + void showContent(@Nullable final BottomSheetContent content) { // If the desired content is already showing, do nothing. if (mSheetContent == content) return; @@ -1243,7 +1216,7 @@ * @param state The state to get the height from. * @return The height of the sheet at the provided state. */ - public float getSheetHeightForState(@SheetState int state) { + private float getSheetHeightForState(@SheetState int state) { if (mSheetContent != null && mSheetContent.wrapContentEnabled() && state == SheetState.FULL) { ensureContentDesiredHeightIsComputed(); @@ -1365,13 +1338,6 @@ } /** - * @return The height of the toolbar holder. - */ - public int getToolbarContainerHeight() { - return mToolbarHolder != null ? mToolbarHolder.getHeight() : 0; - } - - /** * @return The height of the toolbar shadow. */ public int getToolbarShadowHeight() { @@ -1379,13 +1345,6 @@ } /** - * @return Whether or not the browser is in overview mode. - */ - protected boolean isInOverviewMode() { - return mActivity != null && mActivity.isInOverviewMode(); - } - - /** * Checks whether the sheet can be moved. It cannot be moved when the activity is in overview * mode, when "find in page" is visible, when the toolbar is in the animation to hide, or when * the toolbar is hidden.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java index fc0e544..5d2c151 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
@@ -236,6 +236,7 @@ @Override public void destroy() { VrModuleProvider.unregisterVrModeObserver(mVrModeObserver); + mBottomSheet.destroy(); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedNewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedNewTabPageTest.java index 327765e..346121f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedNewTabPageTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedNewTabPageTest.java
@@ -35,6 +35,7 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; +import org.chromium.base.test.util.FlakyTest; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; @@ -199,6 +200,7 @@ @Test @MediumTest @Feature({"FeedNewTabPage"}) + @FlakyTest(message = "https://crbug.com/996716") @AccountManagerTestRule.BlockGetAccounts public void testSignInPromo_AccountsNotReady() { // Check that the sign-in promo is not shown if accounts are not ready.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PictureInPictureControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PictureInPictureControllerTest.java index fd093d0..6e8400a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PictureInPictureControllerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PictureInPictureControllerTest.java
@@ -18,6 +18,7 @@ import org.junit.runner.RunWith; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.ChromeTabbedActivity; @@ -73,6 +74,7 @@ @Test @MediumTest @MinAndroidSdkLevel(Build.VERSION_CODES.O) + @DisabledTest(message = "https://crbug.com/1000183") public void testFullscreenVideoDetected() throws Throwable { enterFullscreen(); } @@ -81,6 +83,7 @@ @Test @MediumTest @MinAndroidSdkLevel(Build.VERSION_CODES.O) + @DisabledTest(message = "https://crbug.com/1000183") public void testFullscreenVideoDetectedOnlyWhenPlaying() throws Throwable { enterFullscreen(); @@ -93,6 +96,7 @@ @Test @MediumTest @MinAndroidSdkLevel(Build.VERSION_CODES.O) + @DisabledTest(message = "https://crbug.com/1000183") public void testEnterPip() throws Throwable { enterFullscreen(); triggerAutoPiP(); @@ -104,6 +108,7 @@ @Test @MediumTest @MinAndroidSdkLevel(Build.VERSION_CODES.O) + @DisabledTest(message = "https://crbug.com/1000183") public void testExitPipOnNavigation() throws Throwable { testExitOn(() -> JavaScriptUtils.executeJavaScript(getWebContents(), "window.location.href = 'https://www.example.com/';")); @@ -113,6 +118,7 @@ @Test @MediumTest @MinAndroidSdkLevel(Build.VERSION_CODES.O) + @DisabledTest(message = "https://crbug.com/1000183") public void testExitOnLeaveFullscreen() throws Throwable { testExitOn(() -> DOMUtils.exitFullscreen(getWebContents())); } @@ -121,6 +127,7 @@ @Test @MediumTest @MinAndroidSdkLevel(Build.VERSION_CODES.O) + @DisabledTest(message = "https://crbug.com/1000183") public void testExitOnCloseTab() throws Throwable { // We want 2 Tabs so we can close the first without any special behaviour. mActivityTestRule.loadUrlInNewTab(mTestServer.getURL(TEST_PATH)); @@ -132,6 +139,7 @@ @Test @MediumTest @MinAndroidSdkLevel(Build.VERSION_CODES.O) + @DisabledTest(message = "https://crbug.com/1000183") public void testExitOnCrash() throws Throwable { testExitOn(() -> WebContentsUtils.simulateRendererKilled(getWebContents(), false)); } @@ -140,6 +148,7 @@ @Test @MediumTest @MinAndroidSdkLevel(Build.VERSION_CODES.O) + @DisabledTest(message = "https://crbug.com/1000183") public void testExitOnNewForegroundTab() throws Throwable { testExitOn(new Runnable() { @Override @@ -157,6 +166,7 @@ @Test @MediumTest @MinAndroidSdkLevel(Build.VERSION_CODES.O) + @DisabledTest(message = "https://crbug.com/1000183") public void testNoExitOnIframeNavigation() throws Throwable { // Add a TabObserver so we know when the iFrame navigation has occurred before we check that // we are still in PiP. @@ -180,6 +190,7 @@ @Test @MediumTest @MinAndroidSdkLevel(Build.VERSION_CODES.O) + @DisabledTest(message = "https://crbug.com/1000183") public void testReenterPip() throws Throwable { enterFullscreen(); triggerAutoPiP();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsSheetVisibilityChangeObserverTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsSheetVisibilityChangeObserverTest.java deleted file mode 100644 index 892ee33..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsSheetVisibilityChangeObserverTest.java +++ /dev/null
@@ -1,253 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.suggestions; - -import static org.junit.Assert.assertEquals; - -import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; - -import android.support.annotation.IntDef; -import android.support.test.InstrumentationRegistry; -import android.support.test.espresso.Espresso; -import android.support.test.espresso.action.ViewActions; -import android.support.test.espresso.matcher.ViewMatchers; -import android.support.test.filters.MediumTest; -import android.support.test.uiautomator.UiDevice; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.chromium.base.test.util.CallbackHelper; -import org.chromium.base.test.util.DisabledTest; -import org.chromium.base.test.util.Restriction; -import org.chromium.chrome.R; -import org.chromium.chrome.browser.ChromeActivity; -import org.chromium.chrome.browser.ntp.NtpUiCaptureTestData; -import org.chromium.chrome.browser.suggestions.SuggestionsSheetVisibilityChangeObserverTest.TestVisibilityChangeObserver.Event; -import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet; -import org.chromium.chrome.test.BottomSheetTestRule; -import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.chrome.test.util.browser.suggestions.DummySuggestionsEventReporter; -import org.chromium.chrome.test.util.browser.suggestions.SuggestionsDependenciesRule; -import org.chromium.ui.test.util.UiRestriction; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.concurrent.TimeoutException; - -/** - * Instrumentation tests for {@link SuggestionsSheetVisibilityChangeObserver}. - */ -@DisabledTest(message = "https://crbug.com/805160") -@RunWith(ChromeJUnit4ClassRunner.class) -@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) // ChromeHome is only enabled on phones -public class SuggestionsSheetVisibilityChangeObserverTest { - @Rule - public BottomSheetTestRule mActivityRule = new BottomSheetTestRule(); - - @Rule - public SuggestionsDependenciesRule createSuggestions() { - mEventReporter = new SpyEventReporter(); - SuggestionsDependenciesRule.TestFactory depsFactory = NtpUiCaptureTestData.createFactory(); - depsFactory.eventReporter = mEventReporter; - return new SuggestionsDependenciesRule(depsFactory); - } - - private SpyEventReporter mEventReporter; - private TestVisibilityChangeObserver mObserver; - - @Before - public void setUp() throws InterruptedException { - mActivityRule.startMainActivityOnBottomSheet(BottomSheet.SheetState.PEEK); - // The home sheet should not be initialised. - mEventReporter.surfaceOpenedHelper.verifyCallCount(); - - // Register the change observer - mObserver = new TestVisibilityChangeObserver(mActivityRule.getActivity()); - mObserver.expectEvents(); - } - - @Test - @MediumTest - public void testHomeSheetVisibilityOnWebPage() { - // Pull sheet to half. We use the animated variants to be closer to user triggered events. - mActivityRule.setSheetState(BottomSheet.SheetState.HALF, true); - mObserver.expectEvents(Event.INITIAL_REVEAL, Event.STATE_CHANGE); - mEventReporter.surfaceOpenedHelper.waitForCallback(); - - // Pull sheet to full. - mActivityRule.setSheetState(BottomSheet.SheetState.FULL, true); - mObserver.expectEvents(Event.STATE_CHANGE); - - // close - Espresso.pressBack(); - mObserver.expectEvents(Event.HIDDEN, Event.STATE_CHANGE, Event.STATE_CHANGE); - } - - @Test - @MediumTest - public void testHomeSheetVisibilityOnOmnibox() { - // Tap the omnibox. The home sheet content should not be notified it is selected. - Espresso.onView(ViewMatchers.withId(R.id.url_bar)).perform(ViewActions.click()); - waitForWindowUpdates(); - - mObserver.expectEvents(); - assertEquals(BottomSheet.SheetState.FULL, mActivityRule.getBottomSheet().getSheetState()); - - // Back closes the bottom sheet. - Espresso.pressBack(); - waitForWindowUpdates(); - - mObserver.expectEvents(); - assertEquals(BottomSheet.SheetState.PEEK, mActivityRule.getBottomSheet().getSheetState()); - - mEventReporter.surfaceOpenedHelper.verifyCallCount(); - } - - @Test - @MediumTest - public void testHomeSheetVisibilityOnOmniboxAndSwipeToolbar() { - // Tap the omnibox. The home sheet content should not be notified it is selected. - Espresso.onView(ViewMatchers.withId(R.id.url_bar)).perform(ViewActions.click()); - waitForWindowUpdates(); - - mObserver.expectEvents(); - assertEquals(BottomSheet.SheetState.FULL, mActivityRule.getBottomSheet().getSheetState()); - - // Changing the state of the sheet closes the omnibox suggestions and shows the home sheet. - mActivityRule.setSheetState(BottomSheet.SheetState.HALF, true); - mObserver.expectEvents(Event.INITIAL_REVEAL, Event.STATE_CHANGE); - mEventReporter.surfaceOpenedHelper.waitForCallback(); - - // Back closes the bottom sheet. - Espresso.pressBack(); - mObserver.expectEvents(Event.HIDDEN, Event.STATE_CHANGE, Event.STATE_CHANGE); - assertEquals(BottomSheet.SheetState.PEEK, mActivityRule.getBottomSheet().getSheetState()); - - mEventReporter.surfaceOpenedHelper.verifyCallCount(); - } - - static class TestVisibilityChangeObserver extends SuggestionsSheetVisibilityChangeObserver { - @IntDef({Event.INITIAL_REVEAL, Event.SHOWN, Event.HIDDEN, Event.STATE_CHANGE}) - @Retention(RetentionPolicy.SOURCE) - public @interface Event { - int INITIAL_REVEAL = 0; - int SHOWN = 1; - int HIDDEN = 2; - int STATE_CHANGE = 3; - } - - private final ChromeActivity mActivity; - - private SelfVerifyingCallbackHelper mInitialRevealHelper = - new SelfVerifyingCallbackHelper("InitialReveal"); - private SelfVerifyingCallbackHelper mShownHelper = new SelfVerifyingCallbackHelper("Shown"); - private SelfVerifyingCallbackHelper mHiddenHelper = - new SelfVerifyingCallbackHelper("Hidden"); - private SelfVerifyingCallbackHelper mStateChangedHelper = - new SelfVerifyingCallbackHelper("StateChanged"); - - public TestVisibilityChangeObserver(ChromeActivity chromeActivity) { - super(null, chromeActivity); - mActivity = chromeActivity; - } - - @Override - public void onContentShown(boolean isFirstShown) { - if (isFirstShown) { - mInitialRevealHelper.notifyCalled(); - } else { - mShownHelper.notifyCalled(); - } - } - - @Override - public void onContentHidden() { - mHiddenHelper.notifyCalled(); - } - - @Override - public void onContentStateChanged(int contentState) { - mStateChangedHelper.notifyCalled(); - } - - public void expectEvents(@Event int... events) { - for (@Event int e : events) { - switch (e) { - case Event.INITIAL_REVEAL: - mInitialRevealHelper.waitForCallback(); - break; - case Event.SHOWN: - mShownHelper.waitForCallback(); - break; - case Event.HIDDEN: - mHiddenHelper.waitForCallback(); - break; - case Event.STATE_CHANGE: - mStateChangedHelper.waitForCallback(); - break; - } - } - verifyCalls(); - } - - public void verifyCalls() { - mInitialRevealHelper.verifyCallCount(); - mShownHelper.verifyCallCount(); - mHiddenHelper.verifyCallCount(); - mStateChangedHelper.verifyCallCount(); - } - - @Override - protected boolean isObservedContentCurrent() { - BottomSheet.BottomSheetContent currentSheet = - mActivity.getBottomSheet().getCurrentSheetContent(); - return currentSheet != null; - } - } - - private static class SelfVerifyingCallbackHelper extends CallbackHelper { - private final String mName; - private int mVerifiedCallCount; - - public SelfVerifyingCallbackHelper(String name) { - mName = name; - } - - @Override - public void waitForCallback() { - try { - super.waitForCallback(mName + " not called.", mVerifiedCallCount); - mVerifiedCallCount += 1; - } catch (InterruptedException | TimeoutException e) { - throw new AssertionError(e); - } - } - - public void verifyCallCount() { - assertEquals(mName + " call count", mVerifiedCallCount, getCallCount()); - } - } - - private static class SpyEventReporter extends DummySuggestionsEventReporter { - public final SelfVerifyingCallbackHelper surfaceOpenedHelper = - new SelfVerifyingCallbackHelper("onSurfaceOpened"); - - @Override - public void onSurfaceOpened() { - surfaceOpenedHelper.notifyCalled(); - } - } - - // TODO(dgn): Replace with with shared one after merge. - public static void waitForWindowUpdates() { - final long maxWindowUpdateTimeMs = scaleTimeout(1000); - UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - device.waitForWindowUpdate(null, maxWindowUpdateTimeMs); - device.waitForIdle(maxWindowUpdateTimeMs); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ScrimTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ScrimTest.java index ab45313b..87c4e6a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ScrimTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ScrimTest.java
@@ -124,8 +124,10 @@ assertEquals("The scrim alpha should be 0.", 0f, mScrim.getAlpha(), MathUtils.EPSILON); ThreadUtils.runOnUiThreadBlocking(() -> { - mBottomSheet.showContent(new TestBottomSheetContent( - mActivityTestRule.getActivity(), BottomSheet.ContentPriority.HIGH, false)); + mSheetController.requestShowContent( + new TestBottomSheetContent(mActivityTestRule.getActivity(), + BottomSheet.ContentPriority.HIGH, false), + false); mBottomSheet.setSheetState(BottomSheet.SheetState.HALF, false); });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeSmokeTest.java b/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeSmokeTest.java index 156e5fd..dce1023 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeSmokeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeSmokeTest.java
@@ -32,8 +32,8 @@ private static final String DATA_URL = "data:,Hello"; private static final String ACTIVITY_NAME = "org.chromium.chrome.browser.ChromeTabbedActivity"; - public final long mTimeout = ScalableTimeout.scaleTimeout(5000L); - public static final long UI_CHECK_INTERVAL = 200L; + public final long mTimeout = ScalableTimeout.scaleTimeout(20000L); + public static final long UI_CHECK_INTERVAL = 1000L; private String mPackageName; @Before
diff --git a/chrome/android/modules/chrome_feature_module_tmpl.gni b/chrome/android/modules/chrome_feature_module_tmpl.gni index d41be23..54e115c6 100644 --- a/chrome/android/modules/chrome_feature_module_tmpl.gni +++ b/chrome/android/modules/chrome_feature_module_tmpl.gni
@@ -11,7 +11,6 @@ # Supports most attributes of the android_app_bundle_module target, plus: # module_desc: Descriptor of this module. See # //chrome/android/modules/chrome_feature_modules.gni for the format. -# module_name_suffix: Suffix added to the module name. # is_monochrome_or_trichrome: (Optional) Whether this module is packaged into # Monochrome or Trichrome. # is_64_bit_browser: (Optional) Whether Chrome (as opposed to WebView) runs in @@ -20,7 +19,6 @@ # WebView. template("chrome_feature_module") { assert(defined(invoker.module_desc)) - assert(defined(invoker.module_name_suffix)) _module_desc = invoker.module_desc _is_monochrome_or_trichrome = defined(invoker.is_monochrome_or_trichrome) && invoker.is_monochrome_or_trichrome @@ -29,6 +27,11 @@ _include_32_bit_webview = defined(invoker.include_32_bit_webview) && invoker.include_32_bit_webview + # TODO(tiborg): Remove once downstream use removed. + if (defined(invoker.module_name_suffix)) { + not_needed(invoker, [ "module_name_suffix" ]) + } + android_app_bundle_module(target_name) { forward_variables_from(invoker, [ @@ -40,9 +43,6 @@ "version_name", ]) android_manifest = _module_desc.android_manifest - - # TODO(tiborg): Remove module_name flag from android_app_bundle_module. - module_name = "${_module_desc.name}${invoker.module_name_suffix}" target_sdk_version = android_sdk_version deps = [] if (defined(_module_desc.java_deps)) {
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index df184bb..f1c68dbb 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -2093,12 +2093,6 @@ <message name="IDS_EOL_DISMISS_BUTTON" desc="A button label shown in the notification for eol status change to dismiss the notification."> Don't remind me again </message> - <message name="IDS_PENDING_EOL_NOTIFICATION_TITLE" desc="Notification title shown to inform the user that this device will no longer be supported after a certain period of time."> - Updates end <ph name="MONTH_AND_YEAR">$1<ex>June 2020</ex></ph> - </message> - <message name="IDS_PENDING_EOL_NOTIFICATION_MESSAGE" desc="Notification shown to inform the user that this device will no longer receive latest software updates after a certain period of time."> - You'll still be able to use this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> after that time, but it will no longer get automatic software and security updates - </message> <!-- TPM Firmware Update Notification Strings --> <message name="IDS_TPM_FIRMWARE_UPDATE_NOTIFICATION_TITLE" desc="Notification title shown to inform the user that there is a pending TPM firmware update for the device.">
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 2cb6d82..45abccf 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -4483,6 +4483,9 @@ <message name="IDS_SETTINGS_MOUSE_REVERSE_SCROLL_LABEL" desc="In Device Settings, the text next to the checkbox to set reverse scrolling."> Reverse scrolling </message> + <message name="IDS_SETTINGS_POINTER_ACCELERATION_LABEL" desc="In Device Settings, the text next to the checkbox to disable mouse or touchpad acceleration."> + Pointer acceleration + </message> <!-- Keyboard --> <message name="IDS_SETTINGS_KEYBOARD_KEY_SEARCH" desc="In Device Settings, the label and dropdown list item for the Search key."> Search
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index ce15485..23100fe 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -4050,6 +4050,11 @@ FEATURE_VALUE_TYPE(features::kUseSkiaRenderer)}, #if defined(OS_CHROMEOS) + {"allow-disable-mouse-acceleration", + flag_descriptions::kAllowDisableMouseAccelerationName, + flag_descriptions::kAllowDisableMouseAccelerationDescription, kOsCrOS, + FEATURE_VALUE_TYPE(features::kAllowDisableMouseAcceleration)}, + {"enable-streamlined-usb-printer-setup", flag_descriptions::kStreamlinedUsbPrinterSetupName, flag_descriptions::kStreamlinedUsbPrinterSetupDescription, kOsCrOS,
diff --git a/chrome/browser/android/compositor/layer/overlay_panel_layer.cc b/chrome/browser/android/compositor/layer/overlay_panel_layer.cc index c6609a6bc..a7510883 100644 --- a/chrome/browser/android/compositor/layer/overlay_panel_layer.cc +++ b/chrome/browser/android/compositor/layer/overlay_panel_layer.cc
@@ -126,8 +126,10 @@ rounded_bar_top_->SetIsDrawable(true); ui::NinePatchResource* rounded_bar_top_resource = - ui::NinePatchResource::From(resource_manager_->GetResource( - ui::ANDROID_RESOURCE_TYPE_STATIC, rounded_bar_top_resource_id_)); + ui::NinePatchResource::From( + resource_manager_->GetStaticResourceWithTint( + rounded_bar_top_resource_id_, bar_background_color)); + DCHECK(rounded_bar_top_resource); const gfx::Size rounded_bar_top_size(
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc b/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc index 3612e663..ee3b363 100644 --- a/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc +++ b/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc
@@ -132,17 +132,17 @@ IntentPickerAutoDisplayService* ui_auto_display_service, const GURL& url, const std::string& launch_name, - apps::mojom::AppType app_type, + PickerEntryType entry_type, IntentPickerCloseReason close_reason, bool should_persist) { const bool should_launch_app = close_reason == IntentPickerCloseReason::OPEN_APP; - switch (app_type) { - case apps::mojom::AppType::kWeb: + switch (entry_type) { + case PickerEntryType::kWeb: if (should_launch_app) web_app::ReparentWebContentsIntoAppBrowser(web_contents, launch_name); break; - case apps::mojom::AppType::kUnknown: + case PickerEntryType::kUnknown: // We reach here if the picker was closed without an app being chosen, // e.g. due to the tab being closed. Keep count of this scenario so we can // stop the UI from showing after 2+ dismissals. @@ -151,23 +151,21 @@ ui_auto_display_service->IncrementCounter(url); } break; - case apps::mojom::AppType::kArc: - case apps::mojom::AppType::kBuiltIn: - case apps::mojom::AppType::kCrostini: - case apps::mojom::AppType::kExtension: + case PickerEntryType::kArc: NOTREACHED(); } - RecordUma(launch_name, app_type, close_reason, Source::kHttpOrHttps, + RecordUma(launch_name, entry_type, close_reason, Source::kHttpOrHttps, should_persist); } // static void AppsNavigationThrottle::RecordUma(const std::string& selected_app_package, - apps::mojom::AppType app_type, + PickerEntryType entry_type, IntentPickerCloseReason close_reason, Source source, bool should_persist) { - PickerAction action = GetPickerAction(app_type, close_reason, should_persist); + PickerAction action = + GetPickerAction(entry_type, close_reason, should_persist); Platform platform = GetDestinationPlatform(selected_app_package, action); // TODO(crbug.com/985233) For now External Protocol Dialog is only querying @@ -322,7 +320,7 @@ // Prefer the web and place apps of type PWA before apps of type ARC. // TODO(crbug.com/824598): deterministically sort this list. - apps.emplace(apps.begin(), apps::mojom::AppType::kWeb, + apps.emplace(apps.begin(), PickerEntryType::kWeb, menu_manager->GetIconForExtension(extension->id()), extension->id(), extension->name()); } @@ -343,7 +341,7 @@ const std::vector<apps::IntentPickerAppInfo>& apps) { return std::all_of(apps.begin(), apps.end(), [](const apps::IntentPickerAppInfo& app_info) { - return app_info.type == apps::mojom::AppType::kWeb; + return app_info.type == PickerEntryType::kWeb; }); } @@ -422,7 +420,7 @@ // static AppsNavigationThrottle::PickerAction AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType app_type, + PickerEntryType entry_type, IntentPickerCloseReason close_reason, bool should_persist) { switch (close_reason) { @@ -438,18 +436,14 @@ return should_persist ? PickerAction::CHROME_PREFERRED_PRESSED : PickerAction::CHROME_PRESSED; case IntentPickerCloseReason::OPEN_APP: - switch (app_type) { - case apps::mojom::AppType::kUnknown: + switch (entry_type) { + case PickerEntryType::kUnknown: return PickerAction::INVALID; - case apps::mojom::AppType::kArc: + case PickerEntryType::kArc: return should_persist ? PickerAction::ARC_APP_PREFERRED_PRESSED : PickerAction::ARC_APP_PRESSED; - case apps::mojom::AppType::kWeb: + case PickerEntryType::kWeb: return PickerAction::PWA_APP_PRESSED; - case apps::mojom::AppType::kBuiltIn: - case apps::mojom::AppType::kCrostini: - case apps::mojom::AppType::kExtension: - NOTREACHED(); } }
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_throttle.h b/chrome/browser/apps/intent_helper/apps_navigation_throttle.h index ef14b2f7..8e58b3d4 100644 --- a/chrome/browser/apps/intent_helper/apps_navigation_throttle.h +++ b/chrome/browser/apps/intent_helper/apps_navigation_throttle.h
@@ -56,7 +56,7 @@ // Called when the intent picker is closed for |url|, in |web_contents|, with // |launch_name| as the (possibly empty) action to be triggered based on - // |app_type|. |close_reason| gives the reason for the picker being closed, + // |entry_type|. |close_reason| gives the reason for the picker being closed, // and |should_persist| is true if the user indicated they wish to remember // the choice made. |ui_auto_display_service| keeps track of whether or not // the user dismissed the ui without engaging with it. @@ -65,12 +65,12 @@ IntentPickerAutoDisplayService* ui_auto_display_service, const GURL& url, const std::string& launch_name, - apps::mojom::AppType app_type, + PickerEntryType entry_type, IntentPickerCloseReason close_reason, bool should_persist); static void RecordUma(const std::string& selected_app_package, - apps::mojom::AppType app_type, + PickerEntryType entry_type, IntentPickerCloseReason close_reason, Source source, bool should_persist); @@ -221,9 +221,9 @@ FRIEND_TEST_ALL_PREFIXES(chromeos::ChromeOsAppsNavigationThrottleTest, TestGetDestinationPlatform); - // Converts the provided |app_type|, |close_reason| and |should_persist| + // Converts the provided |entry_type|, |close_reason| and |should_persist| // boolean to a PickerAction value for recording in UMA. - static PickerAction GetPickerAction(apps::mojom::AppType app_type, + static PickerAction GetPickerAction(PickerEntryType entry_type, IntentPickerCloseReason close_reason, bool should_persist);
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_throttle_unittest.cc b/chrome/browser/apps/intent_helper/apps_navigation_throttle_unittest.cc index 9433cc3..808cbd3 100644 --- a/chrome/browser/apps/intent_helper/apps_navigation_throttle_unittest.cc +++ b/chrome/browser/apps/intent_helper/apps_navigation_throttle_unittest.cc
@@ -106,152 +106,148 @@ TEST(AppsNavigationThrottleTest, TestGetPickerAction) { EXPECT_EQ(AppsNavigationThrottle::PickerAction::ERROR_BEFORE_PICKER, AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kUnknown, + PickerEntryType::kUnknown, IntentPickerCloseReason::ERROR_BEFORE_PICKER, /*should_persist=*/true)); + EXPECT_EQ( + AppsNavigationThrottle::PickerAction::ERROR_BEFORE_PICKER, + AppsNavigationThrottle::GetPickerAction( + PickerEntryType::kArc, IntentPickerCloseReason::ERROR_BEFORE_PICKER, + /*should_persist=*/true)); + EXPECT_EQ(AppsNavigationThrottle::PickerAction::ERROR_BEFORE_PICKER, AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kArc, - IntentPickerCloseReason::ERROR_BEFORE_PICKER, - /*should_persist=*/true)); - - EXPECT_EQ(AppsNavigationThrottle::PickerAction::ERROR_BEFORE_PICKER, - AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kUnknown, + PickerEntryType::kUnknown, IntentPickerCloseReason::ERROR_BEFORE_PICKER, /*should_persist=*/false)); - EXPECT_EQ(AppsNavigationThrottle::PickerAction::ERROR_BEFORE_PICKER, - AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kArc, - IntentPickerCloseReason::ERROR_BEFORE_PICKER, - /*should_persist=*/false)); + EXPECT_EQ( + AppsNavigationThrottle::PickerAction::ERROR_BEFORE_PICKER, + AppsNavigationThrottle::GetPickerAction( + PickerEntryType::kArc, IntentPickerCloseReason::ERROR_BEFORE_PICKER, + /*should_persist=*/false)); EXPECT_EQ(AppsNavigationThrottle::PickerAction::ERROR_AFTER_PICKER, AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kUnknown, + PickerEntryType::kUnknown, IntentPickerCloseReason::ERROR_AFTER_PICKER, /*should_persist=*/true)); - EXPECT_EQ(AppsNavigationThrottle::PickerAction::ERROR_AFTER_PICKER, - AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kArc, - IntentPickerCloseReason::ERROR_AFTER_PICKER, - /*should_persist=*/true)); + EXPECT_EQ( + AppsNavigationThrottle::PickerAction::ERROR_AFTER_PICKER, + AppsNavigationThrottle::GetPickerAction( + PickerEntryType::kArc, IntentPickerCloseReason::ERROR_AFTER_PICKER, + /*should_persist=*/true)); EXPECT_EQ(AppsNavigationThrottle::PickerAction::ERROR_AFTER_PICKER, AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kUnknown, + PickerEntryType::kUnknown, IntentPickerCloseReason::ERROR_AFTER_PICKER, /*should_persist=*/false)); - EXPECT_EQ(AppsNavigationThrottle::PickerAction::ERROR_AFTER_PICKER, - AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kArc, - IntentPickerCloseReason::ERROR_AFTER_PICKER, - /*should_persist=*/false)); + EXPECT_EQ( + AppsNavigationThrottle::PickerAction::ERROR_AFTER_PICKER, + AppsNavigationThrottle::GetPickerAction( + PickerEntryType::kArc, IntentPickerCloseReason::ERROR_AFTER_PICKER, + /*should_persist=*/false)); // Expect PickerAction::DIALOG_DEACTIVATED if the close_reason is // DIALOG_DEACTIVATED. EXPECT_EQ(AppsNavigationThrottle::PickerAction::DIALOG_DEACTIVATED, AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kUnknown, + PickerEntryType::kUnknown, IntentPickerCloseReason::DIALOG_DEACTIVATED, /*should_persist=*/true)); - EXPECT_EQ(AppsNavigationThrottle::PickerAction::DIALOG_DEACTIVATED, - AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kArc, - IntentPickerCloseReason::DIALOG_DEACTIVATED, - /*should_persist=*/true)); + EXPECT_EQ( + AppsNavigationThrottle::PickerAction::DIALOG_DEACTIVATED, + AppsNavigationThrottle::GetPickerAction( + PickerEntryType::kArc, IntentPickerCloseReason::DIALOG_DEACTIVATED, + /*should_persist=*/true)); EXPECT_EQ(AppsNavigationThrottle::PickerAction::DIALOG_DEACTIVATED, AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kUnknown, + PickerEntryType::kUnknown, IntentPickerCloseReason::DIALOG_DEACTIVATED, /*should_persist=*/false)); - EXPECT_EQ(AppsNavigationThrottle::PickerAction::DIALOG_DEACTIVATED, - AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kArc, - IntentPickerCloseReason::DIALOG_DEACTIVATED, - /*should_persist=*/false)); + EXPECT_EQ( + AppsNavigationThrottle::PickerAction::DIALOG_DEACTIVATED, + AppsNavigationThrottle::GetPickerAction( + PickerEntryType::kArc, IntentPickerCloseReason::DIALOG_DEACTIVATED, + /*should_persist=*/false)); // Expect PickerAction::PREFERRED_ACTIVITY_FOUND if the close_reason is // PREFERRED_APP_FOUND. EXPECT_EQ(AppsNavigationThrottle::PickerAction::PREFERRED_ACTIVITY_FOUND, AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kUnknown, + PickerEntryType::kUnknown, IntentPickerCloseReason::PREFERRED_APP_FOUND, /*should_persist=*/true)); - EXPECT_EQ(AppsNavigationThrottle::PickerAction::PREFERRED_ACTIVITY_FOUND, - AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kArc, - IntentPickerCloseReason::PREFERRED_APP_FOUND, - /*should_persist=*/true)); - - EXPECT_EQ(AppsNavigationThrottle::PickerAction::PREFERRED_ACTIVITY_FOUND, - AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kUnknown, - IntentPickerCloseReason::PREFERRED_APP_FOUND, - /*should_persist=*/false)); - - EXPECT_EQ(AppsNavigationThrottle::PickerAction::PREFERRED_ACTIVITY_FOUND, - AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kArc, - IntentPickerCloseReason::PREFERRED_APP_FOUND, - /*should_persist=*/false)); - - // Expect PREFERRED depending on the value of |should_persist|, and |app_type| - // to be ignored if reason is STAY_IN_CHROME. - EXPECT_EQ(AppsNavigationThrottle::PickerAction::CHROME_PREFERRED_PRESSED, - AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kUnknown, - IntentPickerCloseReason::STAY_IN_CHROME, - /*should_persist=*/true)); - EXPECT_EQ( - AppsNavigationThrottle::PickerAction::CHROME_PREFERRED_PRESSED, + AppsNavigationThrottle::PickerAction::PREFERRED_ACTIVITY_FOUND, AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kArc, IntentPickerCloseReason::STAY_IN_CHROME, + PickerEntryType::kArc, IntentPickerCloseReason::PREFERRED_APP_FOUND, /*should_persist=*/true)); - EXPECT_EQ(AppsNavigationThrottle::PickerAction::CHROME_PRESSED, + EXPECT_EQ(AppsNavigationThrottle::PickerAction::PREFERRED_ACTIVITY_FOUND, AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kUnknown, - IntentPickerCloseReason::STAY_IN_CHROME, + PickerEntryType::kUnknown, + IntentPickerCloseReason::PREFERRED_APP_FOUND, /*should_persist=*/false)); EXPECT_EQ( + AppsNavigationThrottle::PickerAction::PREFERRED_ACTIVITY_FOUND, + AppsNavigationThrottle::GetPickerAction( + PickerEntryType::kArc, IntentPickerCloseReason::PREFERRED_APP_FOUND, + /*should_persist=*/false)); + + // Expect PREFERRED depending on the value of |should_persist|, and + // |entry_type| to be ignored if reason is STAY_IN_CHROME. + EXPECT_EQ( + AppsNavigationThrottle::PickerAction::CHROME_PREFERRED_PRESSED, + AppsNavigationThrottle::GetPickerAction( + PickerEntryType::kUnknown, IntentPickerCloseReason::STAY_IN_CHROME, + /*should_persist=*/true)); + + EXPECT_EQ(AppsNavigationThrottle::PickerAction::CHROME_PREFERRED_PRESSED, + AppsNavigationThrottle::GetPickerAction( + PickerEntryType::kArc, IntentPickerCloseReason::STAY_IN_CHROME, + /*should_persist=*/true)); + + EXPECT_EQ( AppsNavigationThrottle::PickerAction::CHROME_PRESSED, AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kArc, IntentPickerCloseReason::STAY_IN_CHROME, + PickerEntryType::kUnknown, IntentPickerCloseReason::STAY_IN_CHROME, /*should_persist=*/false)); + EXPECT_EQ(AppsNavigationThrottle::PickerAction::CHROME_PRESSED, + AppsNavigationThrottle::GetPickerAction( + PickerEntryType::kArc, IntentPickerCloseReason::STAY_IN_CHROME, + /*should_persist=*/false)); + // Expect PREFERRED depending on the value of |should_persist|, and // INVALID/ARC to be chosen if reason is OPEN_APP. - EXPECT_EQ( - AppsNavigationThrottle::PickerAction::INVALID, - AppsNavigationThrottle::GetPickerAction(apps::mojom::AppType::kUnknown, - IntentPickerCloseReason::OPEN_APP, - /*should_persist=*/true)); + EXPECT_EQ(AppsNavigationThrottle::PickerAction::INVALID, + AppsNavigationThrottle::GetPickerAction( + PickerEntryType::kUnknown, IntentPickerCloseReason::OPEN_APP, + /*should_persist=*/true)); EXPECT_EQ(AppsNavigationThrottle::PickerAction::ARC_APP_PREFERRED_PRESSED, AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kArc, IntentPickerCloseReason::OPEN_APP, + PickerEntryType::kArc, IntentPickerCloseReason::OPEN_APP, /*should_persist=*/true)); - EXPECT_EQ( - AppsNavigationThrottle::PickerAction::INVALID, - AppsNavigationThrottle::GetPickerAction(apps::mojom::AppType::kUnknown, - IntentPickerCloseReason::OPEN_APP, - /*should_persist=*/false)); + EXPECT_EQ(AppsNavigationThrottle::PickerAction::INVALID, + AppsNavigationThrottle::GetPickerAction( + PickerEntryType::kUnknown, IntentPickerCloseReason::OPEN_APP, + /*should_persist=*/false)); EXPECT_EQ(AppsNavigationThrottle::PickerAction::ARC_APP_PRESSED, AppsNavigationThrottle::GetPickerAction( - apps::mojom::AppType::kArc, IntentPickerCloseReason::OPEN_APP, + PickerEntryType::kArc, IntentPickerCloseReason::OPEN_APP, /*should_persist=*/false)); }
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_types.cc b/chrome/browser/apps/intent_helper/apps_navigation_types.cc index 52a1169..8a6b83ed 100644 --- a/chrome/browser/apps/intent_helper/apps_navigation_types.cc +++ b/chrome/browser/apps/intent_helper/apps_navigation_types.cc
@@ -6,7 +6,7 @@ namespace apps { -IntentPickerAppInfo::IntentPickerAppInfo(apps::mojom::AppType type, +IntentPickerAppInfo::IntentPickerAppInfo(PickerEntryType type, const gfx::Image& icon, const std::string& launch_name, const std::string& display_name)
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_types.h b/chrome/browser/apps/intent_helper/apps_navigation_types.h index 34f0a96..eb350683 100644 --- a/chrome/browser/apps/intent_helper/apps_navigation_types.h +++ b/chrome/browser/apps/intent_helper/apps_navigation_types.h
@@ -67,9 +67,16 @@ kMaxValue = kExternalProtocol }; +// The type of an entry in the intent picker for the user to choose from. +enum class PickerEntryType { + kUnknown = 0, + kArc, + kWeb, +}; + // Represents the data required to display an app in a picker to the user. struct IntentPickerAppInfo { - IntentPickerAppInfo(apps::mojom::AppType type, + IntentPickerAppInfo(PickerEntryType type, const gfx::Image& icon, const std::string& launch_name, const std::string& display_name); @@ -79,7 +86,7 @@ IntentPickerAppInfo& operator=(IntentPickerAppInfo&& other); // The type of app that this object represents. - apps::mojom::AppType type; + PickerEntryType type; // The icon to be displayed for this app in the picker. gfx::Image icon; @@ -114,7 +121,7 @@ // values of the launch name, app type, and persistence boolean are all ignored. using IntentPickerResponse = base::OnceCallback<void(const std::string& launch_name, - apps::mojom::AppType app_type, + apps::PickerEntryType entry_type, apps::IntentPickerCloseReason close_reason, bool should_persist)>;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 907a8ec..86225a0 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1508,6 +1508,8 @@ "login/users/user_manager_interface.h", "login/version_info_updater.cc", "login/version_info_updater.h", + "login/version_updater/version_updater.cc", + "login/version_updater/version_updater.h", "login/wizard_controller.cc", "login/wizard_controller.h", "mobile/mobile_activator.cc", @@ -2197,6 +2199,10 @@ "extensions/login_screen/login_screen_ui/login_screen_extension_ui_handler.h", "extensions/login_screen/login_screen_ui/login_screen_ui_api.cc", "extensions/login_screen/login_screen_ui/login_screen_ui_api.h", + "extensions/login_screen/login_state/login_state_api.cc", + "extensions/login_screen/login_state/login_state_api.h", + "extensions/login_screen/login_state/session_state_changed_event_dispatcher.cc", + "extensions/login_screen/login_state/session_state_changed_event_dispatcher.h", "extensions/media_player_api.cc", "extensions/media_player_api.h", "extensions/quick_unlock_private/quick_unlock_private_api.cc", @@ -2322,6 +2328,8 @@ "login/test/test_condition_waiter.h", "login/test/test_predicate_waiter.cc", "login/test/test_predicate_waiter.h", + "login/version_updater/mock_version_updater_delegate.cc", + "login/version_updater/mock_version_updater_delegate.h", "printing/printing_stubs.cc", "printing/printing_stubs.h", "scoped_set_running_on_chromeos_for_testing.cc", @@ -2482,7 +2490,6 @@ "drive/fileapi/fileapi_worker_unittest.cc", "drive/fileapi/webkit_file_stream_reader_impl_unittest.cc", "drive/write_on_cache_file_unittest.cc", - "eol_notification_unittest.cc", "events/event_rewriter_unittest.cc", "extensions/active_tab_permission_granter_delegate_chromeos_unittest.cc", "extensions/default_app_order_unittest.cc", @@ -2498,6 +2505,8 @@ "extensions/install_limiter_unittest.cc", "extensions/login_screen/login/login_api_unittest.cc", "extensions/login_screen/login_screen_ui/login_screen_extension_ui_handler_unittest.cc", + "extensions/login_screen/login_state/login_state_api_unittest.cc", + "extensions/login_screen/login_state/session_state_changed_event_dispatcher_unittest.cc", "extensions/permissions_updater_delegate_chromeos_unittest.cc", "extensions/public_session_permission_helper_unittest.cc", "extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc", @@ -2612,6 +2621,7 @@ "login/users/affiliation_unittest.cc", "login/users/multi_profile_user_controller_unittest.cc", "login/users/user_manager_unittest.cc", + "login/version_updater/version_updater_unittest.cc", "mobile/mobile_activator_unittest.cc", "net/client_cert_store_chromeos_unittest.cc", "net/network_portal_detector_impl_unittest.cc",
diff --git a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc index dfe82b56..786a212 100644 --- a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc +++ b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc
@@ -63,23 +63,23 @@ IntentPickerAutoDisplayService* ui_auto_display_service, const GURL& url, const std::string& launch_name, - apps::mojom::AppType app_type, + apps::PickerEntryType entry_type, apps::IntentPickerCloseReason close_reason, bool should_persist) { const bool should_launch_app = close_reason == apps::IntentPickerCloseReason::OPEN_APP; - switch (app_type) { - case apps::mojom::AppType::kArc: + switch (entry_type) { + case apps::PickerEntryType::kArc: if (arc::ArcIntentPickerAppFetcher::MaybeLaunchOrPersistArcApp( url, launch_name, should_launch_app, should_persist)) { CloseOrGoBack(web_contents); } else { close_reason = apps::IntentPickerCloseReason::ERROR_AFTER_PICKER; } - RecordUma(launch_name, app_type, close_reason, apps::Source::kHttpOrHttps, - should_persist); + RecordUma(launch_name, entry_type, close_reason, + apps::Source::kHttpOrHttps, should_persist); return; - case apps::mojom::AppType::kUnknown: + case apps::PickerEntryType::kUnknown: // TODO(crbug.com/826982): This workaround can be removed when preferences // are no longer persisted within the ARC container, it was necessary // since chrome browser is neither a PWA or ARC app. @@ -91,31 +91,28 @@ } // Fall through to super class method to increment counter. break; - case apps::mojom::AppType::kWeb: - case apps::mojom::AppType::kBuiltIn: - case apps::mojom::AppType::kCrostini: - case apps::mojom::AppType::kExtension: + case apps::PickerEntryType::kWeb: break; } apps::AppsNavigationThrottle::OnIntentPickerClosed( - web_contents, ui_auto_display_service, url, launch_name, app_type, + web_contents, ui_auto_display_service, url, launch_name, entry_type, close_reason, should_persist); } // static void ChromeOsAppsNavigationThrottle::RecordUma( const std::string& selected_app_package, - apps::mojom::AppType app_type, + apps::PickerEntryType entry_type, apps::IntentPickerCloseReason close_reason, apps::Source source, bool should_persist) { - if (app_type == apps::mojom::AppType::kArc && + if (entry_type == apps::PickerEntryType::kArc && (close_reason == apps::IntentPickerCloseReason::PREFERRED_APP_FOUND || close_reason == apps::IntentPickerCloseReason::OPEN_APP)) { UMA_HISTOGRAM_ENUMERATION("Arc.UserInteraction", arc::UserInteractionType::APP_STARTED_FROM_LINK); } - apps::AppsNavigationThrottle::RecordUma(selected_app_package, app_type, + apps::AppsNavigationThrottle::RecordUma(selected_app_package, entry_type, close_reason, source, should_persist); }
diff --git a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h index e38fcb19..ce344e4b 100644 --- a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h +++ b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h
@@ -45,7 +45,7 @@ // Called when the intent picker is closed for |url|, in |web_contents|, with // |launch_name| as the (possibly empty) action to be triggered based on - // |app_type|. |close_reason| gives the reason for the picker being closed, + // |entry_type|. |close_reason| gives the reason for the picker being closed, // and |should_persist| is true if the user indicated they wish to remember // the choice made. |ui_auto_display_service| keeps track of whether or not // the user dismissed the ui without engaging with it. @@ -54,12 +54,12 @@ IntentPickerAutoDisplayService* ui_auto_display_service, const GURL& url, const std::string& launch_name, - apps::mojom::AppType app_type, + apps::PickerEntryType entry_type, apps::IntentPickerCloseReason close_reason, bool should_persist); static void RecordUma(const std::string& selected_app_package, - apps::mojom::AppType app_type, + apps::PickerEntryType entry_type, apps::IntentPickerCloseReason close_reason, apps::Source source, bool should_persist);
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc b/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc index a824ef8..ef437415 100644 --- a/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc +++ b/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc
@@ -359,7 +359,7 @@ bool safe_to_bypass_ui, std::vector<mojom::IntentHandlerInfoPtr> handlers, const std::string& selected_app_package, - apps::mojom::AppType app_type, + apps::PickerEntryType entry_type, apps::IntentPickerCloseReason reason, bool should_persist) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -402,7 +402,7 @@ case apps::IntentPickerCloseReason::OPEN_APP: // Only ARC apps are offered in the external protocol intent picker, so if // the user decided to open in app the type must be ARC. - DCHECK_EQ(apps::mojom::AppType::kArc, app_type); + DCHECK_EQ(apps::PickerEntryType::kArc, entry_type); DCHECK(arc_service_manager); if (should_persist) { @@ -464,7 +464,7 @@ RecordUmaDialogAction(url_scheme, protocol_accepted, should_persist); chromeos::ChromeOsAppsNavigationThrottle::RecordUma( - selected_app_package, app_type, reason, apps::Source::kExternalProtocol, + selected_app_package, entry_type, reason, apps::Source::kExternalProtocol, should_persist); } @@ -485,7 +485,7 @@ const ArcIntentHelperBridge::ActivityName activity(handler->package_name, handler->activity_name); const auto it = icons->find(activity); - app_info.emplace_back(apps::mojom::AppType::kArc, + app_info.emplace_back(apps::PickerEntryType::kArc, it != icons->end() ? it->second.icon16 : gfx::Image(), handler->package_name, handler->name); } @@ -547,7 +547,7 @@ handlers.size(), &result, safe_to_bypass_ui)) { if (result == GetActionResult::HANDLE_URL_IN_ARC) { chromeos::ChromeOsAppsNavigationThrottle::RecordUma( - std::string(), apps::mojom::AppType::kArc, + std::string(), apps::PickerEntryType::kArc, apps::IntentPickerCloseReason::PREFERRED_APP_FOUND, apps::Source::kExternalProtocol, /*should_persist=*/false);
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_intent_picker_app_fetcher.cc b/chrome/browser/chromeos/arc/intent_helper/arc_intent_picker_app_fetcher.cc index be5a02805..43aa383 100644 --- a/chrome/browser/chromeos/arc/intent_helper/arc_intent_picker_app_fetcher.cc +++ b/chrome/browser/chromeos/arc/intent_helper/arc_intent_picker_app_fetcher.cc
@@ -235,7 +235,7 @@ // created iff there are ARC apps which can actually handle the given URL. DVLOG(1) << "There are no app candidates for this URL: " << url; chromeos::ChromeOsAppsNavigationThrottle::RecordUma( - /*selected_app_package=*/std::string(), apps::mojom::AppType::kUnknown, + /*selected_app_package=*/std::string(), apps::PickerEntryType::kUnknown, apps::IntentPickerCloseReason::ERROR_BEFORE_PICKER, apps::Source::kHttpOrHttps, /*should_persist=*/false); @@ -294,7 +294,7 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); apps::PreferredPlatform preferred_platform = apps::PreferredPlatform::NONE; - apps::mojom::AppType app_type = apps::mojom::AppType::kUnknown; + apps::PickerEntryType entry_type = apps::PickerEntryType::kUnknown; const size_t index = FindPreferredApp(app_candidates, url); if (index != app_candidates.size()) { @@ -318,10 +318,10 @@ } else { instance->HandleUrl(url.spec(), package_name); preferred_platform = apps::PreferredPlatform::ARC; - app_type = apps::mojom::AppType::kArc; + entry_type = apps::PickerEntryType::kArc; } chromeos::ChromeOsAppsNavigationThrottle::RecordUma( - package_name, app_type, close_reason, apps::Source::kHttpOrHttps, + package_name, entry_type, close_reason, apps::Source::kHttpOrHttps, /*should_persist=*/false); } @@ -340,7 +340,7 @@ if (!intent_helper_bridge) { LOG(ERROR) << "Cannot get an instance of ArcIntentHelperBridge"; chromeos::ChromeOsAppsNavigationThrottle::RecordUma( - /*selected_app_package=*/std::string(), apps::mojom::AppType::kUnknown, + /*selected_app_package=*/std::string(), apps::PickerEntryType::kUnknown, apps::IntentPickerCloseReason::ERROR_BEFORE_PICKER, apps::Source::kHttpOrHttps, /*should_persist=*/false); std::move(callback).Run({}); @@ -374,7 +374,7 @@ candidate->package_name, candidate->activity_name); const auto it = icons->find(activity); - app_info.emplace_back(apps::mojom::AppType::kArc, + app_info.emplace_back(apps::PickerEntryType::kArc, it != icons->end() ? it->second.icon16 : gfx::Image(), candidate->package_name, candidate->name); }
diff --git a/chrome/browser/chromeos/eol_notification.cc b/chrome/browser/chromeos/eol_notification.cc index ee986cf..7831e00 100644 --- a/chrome/browser/chromeos/eol_notification.cc +++ b/chrome/browser/chromeos/eol_notification.cc
@@ -6,9 +6,6 @@ #include "ash/public/cpp/notification_utils.h" #include "base/bind.h" -#include "base/i18n/time_formatting.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/default_clock.h" #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" @@ -23,7 +20,6 @@ #include "chromeos/dbus/update_engine_client.h" #include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" -#include "components/vector_icons/vector_icons.h" #include "ui/base/l10n/l10n_util.h" #include "ui/chromeos/devicetype_utils.h" #include "ui/gfx/color_palette.h" @@ -37,25 +33,6 @@ const char kEolNotificationId[] = "chrome://product_eol"; -base::string16 PredictedMonthAndYearOfEol(base::Time current_time, - int32_t number_of_milestones) { - // The average number of weeks between automatic updates to the OS. There is - // an 8 week cycle every 6 months, so the worst case earliest predicted date - // can be 4 weeks/year behind the actual final release date. Since the date - // of the first release milestone out of the |number_of_milestones| remaining - // is not provided, the worst case latest prediction could be up to but not - // including 6 weeks ahead of the actual final release date. Underestimation - // is preferred, so 6 week intervals are used. - constexpr int kAverageNumWeeksInMilestone = 6; - constexpr int kNumDaysInOneWeek = 7; - - base::Time predicted_eol_date = - current_time + - base::TimeDelta::FromDays(kAverageNumWeeksInMilestone * - kNumDaysInOneWeek * number_of_milestones); - return base::TimeFormatMonthAndYear(predicted_eol_date); -} - // Buttons that appear in notifications. enum ButtonIndex { BUTTON_MORE_INFO = 0, @@ -117,9 +94,7 @@ } EolNotification::EolNotification(Profile* profile) - : clock_(base::DefaultClock::GetInstance()), - profile_(profile), - status_(update_engine::EndOfLifeStatus::kSupported) {} + : profile_(profile), status_(update_engine::EndOfLifeStatus::kSupported) {} EolNotification::~EolNotification() {} @@ -142,11 +117,9 @@ profile_->GetPrefs()->GetInteger(prefs::kEolStatus); profile_->GetPrefs()->SetInteger(prefs::kEolStatus, status_); - // Security only state is no longer supported. If |number_of_milestones_| is - // non-empty, a notification should appear regardless of |status_| alone. - if (!number_of_milestones_ && - (status_ == update_engine::EndOfLifeStatus::kSupported || - status_ == update_engine::EndOfLifeStatus::kSecurityOnly)) { + // Security only state is no longer supported. + if (status_ == update_engine::EndOfLifeStatus::kSupported || + status_ == update_engine::EndOfLifeStatus::kSecurityOnly) { return; } @@ -166,43 +139,26 @@ void EolNotification::Update() { message_center::RichNotificationData data; - std::unique_ptr<message_center::Notification> notification; DCHECK_EQ(BUTTON_MORE_INFO, data.buttons.size()); data.buttons.emplace_back(GetStringUTF16(IDS_LEARN_MORE)); - if (number_of_milestones_ && number_of_milestones_.value() > 0) { - // Notifies user that updates will stop occurring at a month and year. - notification = ash::CreateSystemNotification( - message_center::NOTIFICATION_TYPE_SIMPLE, kEolNotificationId, - l10n_util::GetStringFUTF16( - IDS_PENDING_EOL_NOTIFICATION_TITLE, - PredictedMonthAndYearOfEol(clock_->Now(), - number_of_milestones_.value())), - l10n_util::GetStringFUTF16(IDS_PENDING_EOL_NOTIFICATION_MESSAGE, - ui::GetChromeOSDeviceName()), - base::string16() /* display_source */, GURL(kEolNotificationId), - message_center::NotifierId( - message_center::NotifierType::SYSTEM_COMPONENT, kEolNotificationId), - data, new EolNotificationDelegate(profile_), - vector_icons::kBusinessIcon, - message_center::SystemNotificationWarningLevel::NORMAL); - } else { - // Notifies user that updates will no longer occur after this final update. - DCHECK_EQ(BUTTON_DISMISS, data.buttons.size()); - data.buttons.emplace_back(GetStringUTF16(IDS_EOL_DISMISS_BUTTON)); - notification = ash::CreateSystemNotification( - message_center::NOTIFICATION_TYPE_SIMPLE, kEolNotificationId, - GetStringUTF16(IDS_EOL_NOTIFICATION_TITLE), - l10n_util::GetStringFUTF16(IDS_EOL_NOTIFICATION_EOL, - ui::GetChromeOSDeviceName()), - base::string16() /* display_source */, GURL(kEolNotificationId), - message_center::NotifierId( - message_center::NotifierType::SYSTEM_COMPONENT, kEolNotificationId), - data, new EolNotificationDelegate(profile_), - kNotificationEndOfSupportIcon, - message_center::SystemNotificationWarningLevel::NORMAL); - } + DCHECK_EQ(BUTTON_DISMISS, data.buttons.size()); + data.buttons.emplace_back(GetStringUTF16(IDS_EOL_DISMISS_BUTTON)); + + std::unique_ptr<message_center::Notification> notification = + ash::CreateSystemNotification( + message_center::NOTIFICATION_TYPE_SIMPLE, kEolNotificationId, + GetStringUTF16(IDS_EOL_NOTIFICATION_TITLE), + l10n_util::GetStringFUTF16(IDS_EOL_NOTIFICATION_EOL, + ui::GetChromeOSDeviceName()), + base::string16() /* display_source */, GURL(kEolNotificationId), + message_center::NotifierId( + message_center::NotifierType::SYSTEM_COMPONENT, + kEolNotificationId), + data, new EolNotificationDelegate(profile_), + kNotificationEndOfSupportIcon, + message_center::SystemNotificationWarningLevel::NORMAL); NotificationDisplayServiceFactory::GetForProfile(profile_)->Display( NotificationHandler::Type::TRANSIENT, *notification,
diff --git a/chrome/browser/chromeos/eol_notification.h b/chrome/browser/chromeos/eol_notification.h index 7923e7c..4053bbe1 100644 --- a/chrome/browser/chromeos/eol_notification.h +++ b/chrome/browser/chromeos/eol_notification.h
@@ -12,10 +12,6 @@ #include "chrome/browser/profiles/profile.h" #include "third_party/cros_system_api/dbus/update_engine/dbus-constants.h" -namespace base { -class Clock; -} // namespace base - namespace chromeos { // EolNotification is created when user logs in. It is @@ -33,11 +29,6 @@ void CheckEolStatus(); private: - friend class EolNotificationTest; - - // Overridden for testing Milestones until EOL notifications. - base::Clock* clock_; - // Callback invoked when |GetEolStatus()| has finished. // - EndOfLife status: the end of life status of the device. // - Optional<int32_t> number_of_milestones: the number of milestones before
diff --git a/chrome/browser/chromeos/eol_notification_unittest.cc b/chrome/browser/chromeos/eol_notification_unittest.cc deleted file mode 100644 index 325cb5a..0000000 --- a/chrome/browser/chromeos/eol_notification_unittest.cc +++ /dev/null
@@ -1,126 +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. - -#include "chrome/browser/chromeos/eol_notification.h" - -#include "base/test/simple_test_clock.h" -#include "chrome/browser/notifications/notification_display_service_tester.h" -#include "chrome/browser/notifications/system_notification_helper.h" -#include "chrome/grit/generated_resources.h" -#include "chrome/test/base/browser_with_test_window_test.h" -#include "chrome/test/base/testing_browser_process.h" -#include "chrome/test/base/testing_profile.h" -#include "chrome/test/base/testing_profile_manager.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/fake_update_engine_client.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/chromeos/devicetype_utils.h" - -namespace chromeos { - -class EolNotificationTest : public BrowserWithTestWindowTest { - public: - EolNotificationTest() = default; - ~EolNotificationTest() override = default; - - void SetUp() override { - BrowserWithTestWindowTest::SetUp(); - - TestingBrowserProcess::GetGlobal()->SetSystemNotificationHelper( - std::make_unique<SystemNotificationHelper>()); - tester_ = std::make_unique<NotificationDisplayServiceTester>(profile()); - - fake_update_engine_client_ = new FakeUpdateEngineClient(); - DBusThreadManager::GetSetterForTesting()->SetUpdateEngineClient( - base::WrapUnique<UpdateEngineClient>(fake_update_engine_client_)); - - eol_notification_ = std::make_unique<EolNotification>(profile()); - clock_ = std::make_unique<base::SimpleTestClock>(); - eol_notification_->clock_ = clock_.get(); - } - - void TearDown() override { - eol_notification_.reset(); - tester_.reset(); - BrowserWithTestWindowTest::TearDown(); - } - - protected: - FakeUpdateEngineClient* fake_update_engine_client_; - std::unique_ptr<NotificationDisplayServiceTester> tester_; - std::unique_ptr<EolNotification> eol_notification_; - std::unique_ptr<base::SimpleTestClock> clock_; -}; - -TEST_F(EolNotificationTest, TestMilestonesUntilEolNotification) { - base::Time fake_time; - ASSERT_TRUE(base::Time::FromString("1 Jan 2019 12:00:00", &fake_time)); - clock_->SetNow(fake_time); - - fake_update_engine_client_->set_number_of_milestones(2); - fake_update_engine_client_->set_end_of_life_status( - update_engine::EndOfLifeStatus::kEol); - eol_notification_->CheckEolStatus(); - - // The callback passed from |eol_notification_| to - // |fake_update_engine_client_| should be invoked before a notification can - // appear. - base::RunLoop().RunUntilIdle(); - - auto notification = tester_->GetNotification("chrome://product_eol"); - ASSERT_TRUE(notification); - - base::string16 expected_title = base::ASCIIToUTF16("Updates end March 2019"); - base::string16 expected_message = base::ASCIIToUTF16( - "You'll still be able to use this Chrome device after that time, but it " - "will no longer get automatic software and security updates"); - EXPECT_EQ(notification->title(), expected_title); - EXPECT_EQ(notification->message(), expected_message); -} - -TEST_F(EolNotificationTest, TestZeroMilestonesUntilEolNotification) { - fake_update_engine_client_->set_number_of_milestones(0); - fake_update_engine_client_->set_end_of_life_status( - update_engine::EndOfLifeStatus::kEol); - eol_notification_->CheckEolStatus(); - - // The callback passed from |eol_notification_| to - // |fake_update_engine_client_| should be invoked before a notification can - // appear. - base::RunLoop().RunUntilIdle(); - - auto notification = tester_->GetNotification("chrome://product_eol"); - ASSERT_TRUE(notification); - - base::string16 expected_title = base::ASCIIToUTF16("Final software update"); - base::string16 expected_message = base::ASCIIToUTF16( - "This is the last automatic software and security update for this Chrome " - "device. To get future updates, upgrade to a newer model."); - EXPECT_EQ(notification->title(), expected_title); - EXPECT_EQ(notification->message(), expected_message); -} - -TEST_F(EolNotificationTest, TestEolNotificationWithoutMilestonesSet) { - fake_update_engine_client_->set_end_of_life_status( - update_engine::EndOfLifeStatus::kEol); - eol_notification_->CheckEolStatus(); - - // The callback passed from |eol_notification_| to - // |fake_update_engine_client_| should be invoked before a notification can - // appear. - base::RunLoop().RunUntilIdle(); - - auto notification = tester_->GetNotification("chrome://product_eol"); - ASSERT_TRUE(notification); - - base::string16 expected_title = base::ASCIIToUTF16("Final software update"); - base::string16 expected_message = base::ASCIIToUTF16( - "This is the last automatic software and security update for this Chrome " - "device. To get future updates, upgrade to a newer model."); - EXPECT_EQ(notification->title(), expected_title); - EXPECT_EQ(notification->message(), expected_message); -} - -} // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api.cc b/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api.cc new file mode 100644 index 0000000..77ac761 --- /dev/null +++ b/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api.cc
@@ -0,0 +1,65 @@ +// 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 "chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api.h" + +#include <memory> + +#include "base/values.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "components/session_manager/core/session_manager.h" +#include "content/public/browser/browser_context.h" + +namespace extensions { + +// Not all session states are exposed to the extension. Session states which +// are not exposed will be mapped to the nearest logical state. The mapping is +// as follows: +// UNKNOWN -> UNKNOWN +// OOBE -> IN_OOBE_SCREEN +// LOGIN_PRIMARY -> IN_LOGIN_SCREEN +// LOGIN_SECONDARY -> IN_LOGIN_SCREEN +// LOGGED_IN_NOT_ACTIVE -> IN_LOGIN_SCREEN +// ACTIVE -> IN_SESSION +// LOCKED -> IN_LOCK_SCREEN +api::login_state::SessionState SessionStateToApiEnum( + session_manager::SessionState state) { + switch (state) { + case session_manager::SessionState::UNKNOWN: + return api::login_state::SessionState::SESSION_STATE_UNKNOWN; + case session_manager::SessionState::OOBE: + return api::login_state::SessionState::SESSION_STATE_IN_OOBE_SCREEN; + case session_manager::SessionState::LOGIN_PRIMARY: + case session_manager::SessionState::LOGIN_SECONDARY: + case session_manager::SessionState::LOGGED_IN_NOT_ACTIVE: + return api::login_state::SessionState::SESSION_STATE_IN_LOGIN_SCREEN; + case session_manager::SessionState::ACTIVE: + return api::login_state::SessionState::SESSION_STATE_IN_SESSION; + case session_manager::SessionState::LOCKED: + return api::login_state::SessionState::SESSION_STATE_IN_LOCK_SCREEN; + } + NOTREACHED(); + return api::login_state::SessionState::SESSION_STATE_UNKNOWN; +} + +ExtensionFunction::ResponseAction LoginStateGetProfileTypeFunction::Run() { + bool is_signin_profile = chromeos::ProfileHelper::IsSigninProfile( + Profile::FromBrowserContext(browser_context())); + api::login_state::ProfileType profile_type = + is_signin_profile + ? api::login_state::ProfileType::PROFILE_TYPE_SIGNIN_PROFILE + : api::login_state::ProfileType::PROFILE_TYPE_USER_PROFILE; + return RespondNow(ArgumentList( + api::login_state::GetProfileType::Results::Create(profile_type))); +} + +ExtensionFunction::ResponseAction LoginStateGetSessionStateFunction::Run() { + session_manager::SessionState state = + session_manager::SessionManager::Get()->session_state(); + return RespondNow( + ArgumentList(api::login_state::GetSessionState::Results::Create( + SessionStateToApiEnum(state)))); +} + +} // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api.h b/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api.h new file mode 100644 index 0000000..a62d367 --- /dev/null +++ b/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api.h
@@ -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. + +#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_LOGIN_SCREEN_LOGIN_STATE_LOGIN_STATE_API_H_ +#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_LOGIN_SCREEN_LOGIN_STATE_LOGIN_STATE_API_H_ + +#include "chrome/common/extensions/api/login_state.h" +#include "extensions/browser/extension_function.h" +#include "extensions/browser/extension_function_histogram_value.h" + +namespace session_manager { +enum class SessionState; +} // namespace session_manager + +namespace extensions { + +api::login_state::SessionState SessionStateToApiEnum( + session_manager::SessionState state); + +class LoginStateGetProfileTypeFunction : public ExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("loginState.getProfileType", + LOGINSTATE_GETPROFILETYPE) + + protected: + ~LoginStateGetProfileTypeFunction() override {} + ResponseAction Run() override; +}; + +class LoginStateGetSessionStateFunction : public ExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("loginState.getSessionState", + LOGINSTATE_GETSESSIONSTATE) + + protected: + ~LoginStateGetSessionStateFunction() override {} + ResponseAction Run() override; +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_LOGIN_SCREEN_LOGIN_STATE_LOGIN_STATE_API_H_
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api_unittest.cc b/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api_unittest.cc new file mode 100644 index 0000000..a761866e --- /dev/null +++ b/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api_unittest.cc
@@ -0,0 +1,106 @@ +// 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 "chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api.h" + +#include <memory> + +#include "base/memory/scoped_refptr.h" +#include "base/values.h" +#include "chrome/browser/extensions/extension_api_unittest.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/test/base/testing_profile.h" +#include "components/session_manager/core/session_manager.h" +#include "components/session_manager/session_manager_types.h" +#include "extensions/browser/api_test_utils.h" +#include "extensions/common/extension.h" +#include "extensions/common/extension_builder.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +constexpr char kExtensionName[] = "loginState API extension"; +constexpr char kExtensionId[] = "abcdefghijklmnopqrstuvwxyzabcdef"; + +} // namespace + +namespace extensions { + +class LoginStateApiUnittest : public ExtensionApiUnittest { + public: + LoginStateApiUnittest() {} + ~LoginStateApiUnittest() override = default; + + void SetUp() override { + ExtensionApiUnittest::SetUp(); + + // |session_manager::SessionManager| is not initialized by default. + // This sets up the static instance of |SessionManager| so + // |session_manager::SessionManager::Get()| will return this particular + // instance. + session_manager_ = std::make_unique<session_manager::SessionManager>(); + + scoped_refptr<const Extension> extension = + ExtensionBuilder(kExtensionName).SetID(kExtensionId).Build(); + set_extension(extension); + } + + protected: + std::unique_ptr<session_manager::SessionManager> session_manager_; + + private: + DISALLOW_COPY_AND_ASSIGN(LoginStateApiUnittest); +}; + +// Test that calling |loginState.getSessionState()| returns the correctly mapped +// session state. +TEST_F(LoginStateApiUnittest, GetSessionState) { + const struct { + const session_manager::SessionState session_state; + const std::string expected; + } kTestCases[] = { + {session_manager::SessionState::UNKNOWN, "UNKNOWN"}, + {session_manager::SessionState::OOBE, "IN_OOBE_SCREEN"}, + {session_manager::SessionState::LOGIN_PRIMARY, "IN_LOGIN_SCREEN"}, + {session_manager::SessionState::LOGGED_IN_NOT_ACTIVE, "IN_LOGIN_SCREEN"}, + {session_manager::SessionState::LOGIN_SECONDARY, "IN_LOGIN_SCREEN"}, + {session_manager::SessionState::ACTIVE, "IN_SESSION"}, + {session_manager::SessionState::LOCKED, "IN_LOCK_SCREEN"}, + }; + + for (const auto& test : kTestCases) { + session_manager_->SetSessionState(test.session_state); + auto function = base::MakeRefCounted<LoginStateGetSessionStateFunction>(); + std::unique_ptr<base::Value> result = + RunFunctionAndReturnValue(function.get(), "[]"); + EXPECT_EQ(test.expected, result->GetString()); + } +} + +// Test that |loginState.getProfileType()| returns |USER_PROFILE| for +// extensions not running in the signin profile. +TEST_F(LoginStateApiUnittest, GetProfileType_UserProfile) { + auto function = base::MakeRefCounted<LoginStateGetProfileTypeFunction>(); + EXPECT_EQ("USER_PROFILE", + RunFunctionAndReturnValue(function.get(), "[]")->GetString()); +} + +// Test that |loginState.getProfileType()| returns |SIGNIN_PROFILE| for +// extensions running in the signin profile. +TEST_F(LoginStateApiUnittest, GetProfileType_SigninProfile) { + // |chromeos::ProfileHelper::GetSigninProfile()| cannot be used as the + // |TestingProfileManager| set up by |BrowserWithTestWindowTest| has an empty + // user data directory. + TestingProfile::Builder builder; + builder.SetPath(base::FilePath(FILE_PATH_LITERAL(chrome::kInitialProfile))); + std::unique_ptr<Profile> profile = builder.Build(); + + auto function = base::MakeRefCounted<LoginStateGetProfileTypeFunction>(); + EXPECT_EQ("SIGNIN_PROFILE", api_test_utils::RunFunctionAndReturnSingleResult( + function.get(), "[]", profile.get()) + ->GetString()); +} + +} // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_apitest.cc b/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_apitest.cc new file mode 100644 index 0000000..a2af3d9c --- /dev/null +++ b/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_apitest.cc
@@ -0,0 +1,21 @@ +// 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 "chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api.h" + +#include "chrome/browser/extensions/extension_apitest.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace extensions { + +using LoginStateApitest = ExtensionApiTest; + +// Test that |loginState.getProfileType()| returns |USER_PROFILE| for +// extensions not running in the signin profile. +IN_PROC_BROWSER_TEST_F(LoginStateApitest, GetProfileType_UserProfile) { + EXPECT_TRUE(RunExtensionTestWithArg( + "login_screen_apis/login_state/get_profile_type", "USER_PROFILE")); +} + +} // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher.cc b/chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher.cc new file mode 100644 index 0000000..2e11f66a --- /dev/null +++ b/chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher.cc
@@ -0,0 +1,67 @@ +// 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 "chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher.h" + +#include "base/logging.h" +#include "base/no_destructor.h" +#include "chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api.h" +#include "chrome/common/extensions/api/login_state.h" +#include "components/session_manager/core/session_manager.h" +#include "components/session_manager/session_manager_types.h" +#include "content/public/browser/browser_context.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/extension_event_histogram_value.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/extension_set.h" + +namespace extensions { + +BrowserContextKeyedAPIFactory<SessionStateChangedEventDispatcher>* +SessionStateChangedEventDispatcher::GetFactoryInstance() { + static base::NoDestructor< + BrowserContextKeyedAPIFactory<SessionStateChangedEventDispatcher>> + instance; + return instance.get(); +} + +SessionStateChangedEventDispatcher::SessionStateChangedEventDispatcher( + content::BrowserContext* browser_context) + : session_manager_observer_(this), + browser_context_(browser_context), + event_router_(EventRouter::Get(browser_context)), + session_state_(api::login_state::SESSION_STATE_UNKNOWN) { + session_manager_observer_.Add(session_manager::SessionManager::Get()); +} + +SessionStateChangedEventDispatcher::~SessionStateChangedEventDispatcher() = + default; + +void SessionStateChangedEventDispatcher::Shutdown() {} + +void SessionStateChangedEventDispatcher::OnSessionStateChanged() { + api::login_state::SessionState new_state = SessionStateToApiEnum( + session_manager::SessionManager::Get()->session_state()); + + // |session_manager::SessionState| changed but the mapped + // |api::login_state::SessionState| did not. + if (session_state_ == new_state) + return; + + session_state_ = new_state; + + std::unique_ptr<Event> event = std::make_unique<Event>( + events::LOGIN_STATE_ON_SESSION_STATE_CHANGED, + api::login_state::OnSessionStateChanged::kEventName, + api::login_state::OnSessionStateChanged::Create(new_state)); + + event_router_->BroadcastEvent(std::move(event)); +} + +void SessionStateChangedEventDispatcher::SetEventRouterForTesting( + EventRouter* event_router) { + event_router_ = event_router; +} + +} // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher.h b/chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher.h new file mode 100644 index 0000000..dad82be8 --- /dev/null +++ b/chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher.h
@@ -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. + +#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_LOGIN_SCREEN_LOGIN_STATE_SESSION_STATE_CHANGED_EVENT_DISPATCHER_H_ +#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_LOGIN_SCREEN_LOGIN_STATE_SESSION_STATE_CHANGED_EVENT_DISPATCHER_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/scoped_observer.h" +#include "chrome/common/extensions/api/login_state.h" +#include "components/session_manager/core/session_manager.h" +#include "components/session_manager/core/session_manager_observer.h" +#include "extensions/browser/browser_context_keyed_api_factory.h" +#include "extensions/browser/event_router_factory.h" + +namespace content { +class BrowserContext; +} // namespace content + +namespace extensions { + +class EventRouter; + +// |SessionStateChangedEventDispatcher| observes changes in the session state +// and dispatches them to extensions listening on the +// |loginState.onSessionStateChanged| event. +class SessionStateChangedEventDispatcher + : public session_manager::SessionManagerObserver, + public BrowserContextKeyedAPI { + public: + // BrowserContextKeyedAPI implementation. + static BrowserContextKeyedAPIFactory<SessionStateChangedEventDispatcher>* + GetFactoryInstance(); + void Shutdown() override; + + explicit SessionStateChangedEventDispatcher( + content::BrowserContext* browser_context_); + ~SessionStateChangedEventDispatcher() override; + + // SessionManagerObserver implementation. + void OnSessionStateChanged() override; + + void SetEventRouterForTesting(EventRouter* event_router); + + private: + // Needed for BrowserContextKeyedAPI implementation. + friend class BrowserContextKeyedAPIFactory< + SessionStateChangedEventDispatcher>; + + // BrowserContextKeyedAPI implementation. + static const char* service_name() { + return "SessionStateChangedEventDispatcher"; + } + static const bool kServiceIsNULLWhileTesting = true; + + ScopedObserver<session_manager::SessionManager, + session_manager::SessionManagerObserver> + session_manager_observer_; + content::BrowserContext* browser_context_; + EventRouter* event_router_; + api::login_state::SessionState session_state_; + + DISALLOW_COPY_AND_ASSIGN(SessionStateChangedEventDispatcher); +}; + +template <> +struct BrowserContextFactoryDependencies<SessionStateChangedEventDispatcher> { + static void DeclareFactoryDependencies( + BrowserContextKeyedAPIFactory<SessionStateChangedEventDispatcher>* + factory) { + factory->DependsOn(EventRouterFactory::GetInstance()); + } +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_LOGIN_SCREEN_LOGIN_STATE_SESSION_STATE_CHANGED_EVENT_DISPATCHER_H_
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher_apitest.cc b/chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher_apitest.cc new file mode 100644 index 0000000..72f99a2b --- /dev/null +++ b/chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher_apitest.cc
@@ -0,0 +1,45 @@ +// 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 "chrome/browser/extensions/extension_apitest.h" +#include "components/session_manager/core/session_manager.h" +#include "components/session_manager/session_manager_types.h" +#include "extensions/test/extension_test_message_listener.h" +#include "extensions/test/result_catcher.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace extensions { + +using SessionStateChangedEventDispatcherApitest = ExtensionApiTest; + +IN_PROC_BROWSER_TEST_F(SessionStateChangedEventDispatcherApitest, + OnSessionStateDetailsChanged) { + session_manager::SessionManager* session_manager = + session_manager::SessionManager::Get(); + ASSERT_TRUE(RunExtensionTest( + "login_screen_apis/login_state/on_session_state_changed")); + + // Test cases are rearranged as the event is not fired if the mapped session + // state is the same. + const struct { + const session_manager::SessionState session_state; + const char* expected; + } kTestCases[] = { + {session_manager::SessionState::OOBE, "IN_OOBE_SCREEN"}, + {session_manager::SessionState::LOGIN_PRIMARY, "IN_LOGIN_SCREEN"}, + {session_manager::SessionState::LOCKED, "IN_LOCK_SCREEN"}, + {session_manager::SessionState::LOGGED_IN_NOT_ACTIVE, "IN_LOGIN_SCREEN"}, + {session_manager::SessionState::ACTIVE, "IN_SESSION"}, + {session_manager::SessionState::LOGIN_SECONDARY, "IN_LOGIN_SCREEN"}, + {session_manager::SessionState::UNKNOWN, "UNKNOWN"}, + }; + + for (const auto& test : kTestCases) { + ExtensionTestMessageListener listener(test.expected, /*will_reply=*/false); + session_manager->SetSessionState(test.session_state); + ASSERT_TRUE(listener.WaitUntilSatisfied()); + } +} + +} // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher_unittest.cc b/chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher_unittest.cc new file mode 100644 index 0000000..6d6e2cd --- /dev/null +++ b/chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher_unittest.cc
@@ -0,0 +1,124 @@ +// 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 "chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher.h" + +#include <memory> +#include <string> + +#include "base/logging.h" +#include "base/values.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile.h" +#include "chrome/test/base/testing_profile_manager.h" +#include "components/session_manager/session_manager_types.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_service_manager_context.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/test_event_router_observer.h" +#include "testing/gtest/include/gtest/gtest.h" + +using extensions::api::login_state::OnSessionStateChanged::kEventName; + +namespace { + +bool WasSessionStateChangedEventDispatched( + const extensions::TestEventRouterObserver* observer, + extensions::api::login_state::SessionState expected_state) { + const auto& event_map = observer->events(); + auto iter = event_map.find(kEventName); + if (iter == event_map.end()) { + return false; + } + + const extensions::Event& event = *iter->second; + CHECK(event.event_args); + CHECK_EQ(1u, event.event_args->GetList().size()); + std::string session_state = (event.event_args->GetList())[0].GetString(); + return extensions::api::login_state::ParseSessionState(session_state) == + expected_state; +} + +} // namespace + +namespace extensions { + +class SessionStateChangedEventDispatcherUnittest : public testing::Test { + public: + SessionStateChangedEventDispatcherUnittest() {} + ~SessionStateChangedEventDispatcherUnittest() override = default; + + void SetUp() override { + // |session_manager::SessionManager| is not initialized by default. This + // sets up the static instance of |SessionManager| so + // |session_manager::SessionManager::Get()| will return this particular + // instance. + session_manager_ = std::make_unique<session_manager::SessionManager>(); + profile_manager_ = std::make_unique<TestingProfileManager>( + TestingBrowserProcess::GetGlobal()); + ASSERT_TRUE(profile_manager_->SetUp()); + testing_profile_ = + profile_manager_->CreateTestingProfile(chrome::kInitialProfile); + dispatcher_ = + std::make_unique<SessionStateChangedEventDispatcher>(testing_profile_); + event_router_ = std::make_unique<EventRouter>(testing_profile_, nullptr); + dispatcher_->SetEventRouterForTesting(event_router_.get()); + observer_ = std::make_unique<TestEventRouterObserver>(event_router_.get()); + } + + void TearDown() override { + observer_.reset(); + event_router_.reset(); + testing_profile_ = nullptr; + profile_manager_->DeleteTestingProfile(chrome::kInitialProfile); + } + + protected: + content::TestBrowserThreadBundle thread_bundle_; + content::TestServiceManagerContext service_manager_context_; + TestingProfile* testing_profile_; + std::unique_ptr<session_manager::SessionManager> session_manager_; + std::unique_ptr<SessionStateChangedEventDispatcher> dispatcher_; + std::unique_ptr<TestingProfileManager> profile_manager_; + std::unique_ptr<EventRouter> event_router_; + std::unique_ptr<TestEventRouterObserver> observer_; + + private: + DISALLOW_COPY_AND_ASSIGN(SessionStateChangedEventDispatcherUnittest); +}; + +// Test that |OnSessionStateChanged| is dispatched when the session state +// changes. +TEST_F(SessionStateChangedEventDispatcherUnittest, EventIsDispatched) { + session_manager_->SetSessionState(session_manager::SessionState::ACTIVE); + EXPECT_TRUE(WasSessionStateChangedEventDispatched( + observer_.get(), + api::login_state::SessionState::SESSION_STATE_IN_SESSION)); + + session_manager_->SetSessionState(session_manager::SessionState::LOCKED); + EXPECT_TRUE(WasSessionStateChangedEventDispatched( + observer_.get(), + api::login_state::SessionState::SESSION_STATE_IN_LOCK_SCREEN)); +} + +// Test that the event is not dispatched when the mapped +// |api::login_state::SessionState| is the same even when the +// |session_manager::SessionState| is different. +TEST_F(SessionStateChangedEventDispatcherUnittest, + EventIsNotDispatchedWhenSessionStateIsSame) { + session_manager_->SetSessionState( + session_manager::SessionState::LOGIN_PRIMARY); + + EXPECT_TRUE(WasSessionStateChangedEventDispatched( + observer_.get(), + api::login_state::SessionState::SESSION_STATE_IN_LOGIN_SCREEN)); + observer_->ClearEvents(); + + session_manager_->SetSessionState( + session_manager::SessionState::LOGGED_IN_NOT_ACTIVE); + EXPECT_TRUE(observer_->events().empty()); +} + +} // namespace extensions
diff --git a/chrome/browser/chromeos/login/screens/update_screen.cc b/chrome/browser/chromeos/login/screens/update_screen.cc index 7c917442..5609dd51 100644 --- a/chrome/browser/chromeos/login/screens/update_screen.cc +++ b/chrome/browser/chromeos/login/screens/update_screen.cc
@@ -8,29 +8,12 @@ #include "base/bind.h" #include "base/files/file_util.h" -#include "base/location.h" #include "base/logging.h" -#include "base/no_destructor.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/sequenced_task_runner_handle.h" -#include "base/threading/thread_restrictions.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/default_tick_clock.h" #include "chrome/browser/chromeos/login/error_screens_histogram_helper.h" #include "chrome/browser/chromeos/login/screen_manager.h" -#include "chrome/browser/chromeos/login/screens/error_screen.h" #include "chrome/browser/chromeos/login/screens/network_error.h" -#include "chrome/browser/chromeos/login/startup_utils.h" -#include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/ui/webui/chromeos/login/update_screen_handler.h" -#include "chrome/grit/chromium_strings.h" -#include "chrome/grit/generated_resources.h" -#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/network/network_state.h" -#include "content/public/browser/browser_thread.h" -#include "ui/base/l10n/l10n_util.h" - -using content::BrowserThread; namespace chromeos { @@ -41,49 +24,18 @@ constexpr const char kUserActionRejectUpdateOverCellular[] = "update-reject-cellular"; -#if !defined(OFFICIAL_BUILD) constexpr const char kUserActionCancelUpdateShortcut[] = "cancel-update"; -#endif - -// If reboot didn't happen, ask user to reboot device manually. -const int kWaitForRebootTimeSec = 3; - -// Progress bar stages. Each represents progress bar value -// at the beginning of each stage. -// TODO(nkostylev): Base stage progress values on approximate time. -// TODO(nkostylev): Animate progress during each state. -const int kBeforeUpdateCheckProgress = 7; -const int kBeforeDownloadProgress = 14; -const int kBeforeVerifyingProgress = 74; -const int kBeforeFinalizingProgress = 81; -const int kProgressComplete = 100; - -// Defines what part of update progress does download part takes. -const int kDownloadProgressIncrement = 60; const char kUpdateDeadlineFile[] = "/tmp/update-check-response-deadline"; -// Minimum timestep between two consecutive measurements for the download rates. -const int kMinTimeStepInSeconds = 1; - -// Smooth factor that is used for the average downloading speed -// estimation. -// avg_speed = smooth_factor * cur_speed + (1.0 - smooth_factor) * -// avg_speed. -const double kDownloadSpeedSmoothFactor = 0.1; - -// Minumum allowed value for the average downloading speed. -const double kDownloadAverageSpeedDropBound = 1e-8; - -// An upper bound for possible downloading time left estimations. -const double kMaxTimeLeft = 24 * 60 * 60; - // Delay before showing error message if captive portal is detected. // We wait for this delay to let captive portal to perform redirect and show // its login page before error message appears. -const int kDelayErrorMessageSec = 10; +constexpr const base::TimeDelta kDelayErrorMessage = + base::TimeDelta::FromSeconds(10); -const int kShowDelayMs = 400; +constexpr const base::TimeDelta kShowDelay = + base::TimeDelta::FromMicroseconds(400); } // anonymous namespace @@ -96,12 +48,12 @@ ErrorScreen* error_screen, const ScreenExitCallback& exit_callback) : BaseScreen(UpdateView::kScreenId), - tick_clock_(base::DefaultTickClock::GetInstance()), - reboot_check_delay_(kWaitForRebootTimeSec), view_(view), error_screen_(error_screen), exit_callback_(exit_callback), - histogram_helper_(new ErrorScreensHistogramHelper("Update")) { + histogram_helper_( + std::make_unique<ErrorScreensHistogramHelper>("Update")), + version_updater_(std::make_unique<VersionUpdater>(this)) { if (view_) view_->Bind(this); } @@ -109,9 +61,6 @@ UpdateScreen::~UpdateScreen() { if (view_) view_->Unbind(); - - DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); - network_portal_detector::GetInstance()->RemoveObserver(this); } void UpdateScreen::OnViewDestroyed(UpdateView* view) { @@ -119,253 +68,19 @@ view_ = nullptr; } -void UpdateScreen::StartNetworkCheck() { - // If portal detector is enabled and portal detection before AU is - // allowed, initiate network state check. Otherwise, directly - // proceed to update. - if (!network_portal_detector::GetInstance()->IsEnabled()) { - StartUpdateCheck(); - return; - } - state_ = State::STATE_FIRST_PORTAL_CHECK; - is_first_detection_notification_ = true; - is_first_portal_notification_ = true; - network_portal_detector::GetInstance()->AddAndFireObserver(this); -} - -void UpdateScreen::SetIgnoreIdleStatus(bool ignore_idle_status) { - ignore_idle_status_ = ignore_idle_status; -} - -void UpdateScreen::ExitUpdate(Result result) { - DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); - network_portal_detector::GetInstance()->RemoveObserver(this); - show_timer_.Stop(); - - exit_callback_.Run(result); -} - -void UpdateScreen::UpdateStatusChanged( - const UpdateEngineClient::Status& status) { - if (is_checking_for_update_ && - status.status > UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE && - status.status != UpdateEngineClient::UPDATE_STATUS_ERROR && - status.status != - UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT) { - is_checking_for_update_ = false; - } - if (ignore_idle_status_ && - status.status > UpdateEngineClient::UPDATE_STATUS_IDLE) { - ignore_idle_status_ = false; - } - - switch (status.status) { - case UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE: - // Do nothing in these cases, we don't want to notify the user of the - // check unless there is an update. - break; - case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE: - MakeSureScreenIsShown(); - if (view_) { - view_->SetProgress(kBeforeDownloadProgress); - view_->SetShowEstimatedTimeLeft(false); - } - if (!HasCriticalUpdate()) { - VLOG(1) << "Noncritical update available: " << status.new_version; - ExitUpdate(Result::UPDATE_NOT_REQUIRED); - } else { - VLOG(1) << "Critical update available: " << status.new_version; - if (view_) { - view_->SetProgressMessage( - l10n_util::GetStringUTF16(IDS_UPDATE_AVAILABLE)); - view_->SetShowCurtain(false); - } - } - break; - case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING: - MakeSureScreenIsShown(); - if (!is_downloading_update_) { - // Because update engine doesn't send UPDATE_STATUS_UPDATE_AVAILABLE - // we need to is update critical on first downloading notification. - is_downloading_update_ = true; - download_start_time_ = download_last_time_ = tick_clock_->NowTicks(); - download_start_progress_ = status.download_progress; - download_last_progress_ = status.download_progress; - is_download_average_speed_computed_ = false; - download_average_speed_ = 0.0; - if (!HasCriticalUpdate()) { - VLOG(1) << "Non-critical update available: " << status.new_version; - ExitUpdate(Result::UPDATE_NOT_REQUIRED); - } else { - VLOG(1) << "Critical update available: " << status.new_version; - if (view_) { - view_->SetProgressMessage( - l10n_util::GetStringUTF16(IDS_INSTALLING_UPDATE)); - view_->SetShowCurtain(false); - } - } - } - UpdateDownloadingStats(status); - break; - case UpdateEngineClient::UPDATE_STATUS_VERIFYING: - MakeSureScreenIsShown(); - if (view_) { - view_->SetProgress(kBeforeVerifyingProgress); - view_->SetProgressMessage( - l10n_util::GetStringUTF16(IDS_UPDATE_VERIFYING)); - } - break; - case UpdateEngineClient::UPDATE_STATUS_FINALIZING: - MakeSureScreenIsShown(); - if (view_) { - view_->SetProgress(kBeforeFinalizingProgress); - view_->SetProgressMessage( - l10n_util::GetStringUTF16(IDS_UPDATE_FINALIZING)); - } - break; - case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT: - MakeSureScreenIsShown(); - if (view_) { - view_->SetProgress(kProgressComplete); - view_->SetShowEstimatedTimeLeft(false); - } - if (HasCriticalUpdate()) { - if (view_) - view_->SetShowCurtain(false); - VLOG(1) << "Initiate reboot after update"; - DBusThreadManager::Get()->GetUpdateEngineClient()->RebootAfterUpdate(); - reboot_timer_.Start(FROM_HERE, - base::TimeDelta::FromSeconds(reboot_check_delay_), - this, &UpdateScreen::OnWaitForRebootTimeElapsed); - } else { - ExitUpdate(Result::UPDATE_NOT_REQUIRED); - } - break; - case UpdateEngineClient::UPDATE_STATUS_NEED_PERMISSION_TO_UPDATE: - VLOG(1) << "Update requires user permission to proceed."; - state_ = State::STATE_REQUESTING_USER_PERMISSION; - pending_update_version_ = status.new_version; - pending_update_size_ = status.new_size; - - DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); - - MakeSureScreenIsShown(); - if (view_) { - view_->SetRequiresPermissionForCellular(true); - view_->SetShowCurtain(false); - } - break; - case UpdateEngineClient::UPDATE_STATUS_ATTEMPTING_ROLLBACK: - VLOG(1) << "Attempting rollback"; - break; - case UpdateEngineClient::UPDATE_STATUS_IDLE: - // Exit update only if update engine was in non-idle status before. - // Otherwise, it's possible that the update request has not yet been - // started. - if (!ignore_idle_status_) - ExitUpdate(Result::UPDATE_NOT_REQUIRED); - break; - case UpdateEngineClient::UPDATE_STATUS_ERROR: - case UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT: - // Ignore update errors for non-critical updates to prevent blocking the - // user from getting to login screen during OOBE if the pending update is - // not critical. - if (is_checking_for_update_ || !HasCriticalUpdate()) { - ExitUpdate(Result::UPDATE_NOT_REQUIRED); - } else { - ExitUpdate(Result::UPDATE_ERROR); - } - break; - } -} - -void UpdateScreen::OnPortalDetectionCompleted( - const NetworkState* network, - const NetworkPortalDetector::CaptivePortalState& state) { - VLOG(1) << "UpdateScreen::OnPortalDetectionCompleted(): " - << "network=" << (network ? network->path() : "") << ", " - << "state.status=" << state.status << ", " - << "state.response_code=" << state.response_code; - - // Wait for sane detection results. - if (network && - state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN) { - return; - } - - // Restart portal detection for the first notification about offline state. - if ((!network || - state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE) && - is_first_detection_notification_) { - is_first_detection_notification_ = false; - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce([]() { - network_portal_detector::GetInstance()->StartPortalDetection( - false /* force */); - })); - return; - } - is_first_detection_notification_ = false; - - NetworkPortalDetector::CaptivePortalStatus status = state.status; - if (state_ == State::STATE_ERROR) { - // In the case of online state hide error message and proceed to - // the update stage. Otherwise, update error message content. - if (status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) - StartUpdateCheck(); - else - UpdateErrorMessage(network, status); - } else if (state_ == State::STATE_FIRST_PORTAL_CHECK) { - // In the case of online state immediately proceed to the update - // stage. Otherwise, prepare and show error message. - if (status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) { - StartUpdateCheck(); - } else { - UpdateErrorMessage(network, status); - - // StartUpdateCheck, which gets called when the error clears up, will add - // the update engine observer back. - DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); - - if (status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL) - DelayErrorMessage(); - else - ShowErrorMessage(); - } - } -} - -void UpdateScreen::CancelUpdate() { - VLOG(1) << "Forced update cancel"; - ExitUpdate(Result::UPDATE_NOT_REQUIRED); -} - -base::OneShotTimer* UpdateScreen::GetShowTimerForTesting() { - return &show_timer_; -} - -base::OneShotTimer* UpdateScreen::GetErrorMessageTimerForTesting() { - return &error_message_timer_; -} - -base::OneShotTimer* UpdateScreen::GetRebootTimerForTesting() { - return &reboot_timer_; -} - void UpdateScreen::Show() { - if (view_) { #if !defined(OFFICIAL_BUILD) + if (view_) { view_->SetCancelUpdateShortcutEnabled(true); -#endif - view_->SetProgress(kBeforeUpdateCheckProgress); - view_->SetRequiresPermissionForCellular(false); } +#endif + RefreshView(version_updater_->update_info()); - show_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kShowDelayMs), + show_timer_.Start(FROM_HERE, kShowDelay, base::BindOnce(&UpdateScreen::MakeSureScreenIsShown, weak_factory_.GetWeakPtr())); - StartNetworkCheck(); + version_updater_->StartNetworkCheck(); } void UpdateScreen::Hide() { @@ -376,97 +91,174 @@ } void UpdateScreen::OnUserAction(const std::string& action_id) { -#if !defined(OFFICIAL_BUILD) - if (action_id == kUserActionCancelUpdateShortcut) - CancelUpdate(); - else + bool is_official_build = false; +#if defined(OFFICIAL_BUILD) + is_official_build = true; #endif - if (action_id == kUserActionAcceptUpdateOverCellular) { - DBusThreadManager::Get() - ->GetUpdateEngineClient() - ->SetUpdateOverCellularOneTimePermission( - pending_update_version_, pending_update_size_, - base::BindRepeating( - &UpdateScreen::RetryUpdateWithUpdateOverCellularPermissionSet, - weak_factory_.GetWeakPtr())); + + if (!is_official_build && action_id == kUserActionCancelUpdateShortcut) { + // Skip update UI, usually used only in debug builds/tests. + VLOG(1) << "Forced update cancel"; + ExitUpdate(Result::UPDATE_NOT_REQUIRED); + } else if (action_id == kUserActionAcceptUpdateOverCellular) { + version_updater_->SetUpdateOverCellularOneTimePermission(); } else if (action_id == kUserActionRejectUpdateOverCellular) { - // Reset UI context to show curtain again when the user goes back to the - // update screen. - if (view_) { - view_->SetShowCurtain(true); - view_->SetRequiresPermissionForCellular(false); - } + version_updater_->RejectUpdateOverCellular(); ExitUpdate(Result::UPDATE_ERROR); } else { BaseScreen::OnUserAction(action_id); } } -void UpdateScreen::RetryUpdateWithUpdateOverCellularPermissionSet( - bool success) { - if (success) { - if (view_) - view_->SetRequiresPermissionForCellular(false); - StartUpdateCheck(); - } else { - // Reset UI context to show curtain again when the user goes back to the - // update screen. - if (view_) { - view_->SetShowCurtain(true); - view_->SetRequiresPermissionForCellular(false); +base::OneShotTimer* UpdateScreen::GetShowTimerForTesting() { + return &show_timer_; +} + +base::OneShotTimer* UpdateScreen::GetErrorMessageTimerForTesting() { + return &error_message_timer_; +} + +VersionUpdater* UpdateScreen::GetVersionUpdaterForTesting() { + return version_updater_.get(); +} + +void UpdateScreen::ExitUpdate(Result result) { + version_updater_->StartExitUpdate(result); +} + +void UpdateScreen::OnWaitForRebootTimeElapsed() { + LOG(ERROR) << "Unable to reboot - asking user for a manual reboot."; + MakeSureScreenIsShown(); + if (view_) + view_->SetUpdateCompleted(true); +} + +void UpdateScreen::PrepareForUpdateCheck() { + error_message_timer_.Stop(); + error_screen_->HideCaptivePortal(); + + connect_request_subscription_.reset(); + if (version_updater_->update_info().state == + VersionUpdater::State::STATE_ERROR) + HideErrorMessage(); +} + +void UpdateScreen::ShowErrorMessage() { + LOG(WARNING) << "UpdateScreen::ShowErrorMessage()"; + + error_message_timer_.Stop(); + + is_shown_ = false; + show_timer_.Stop(); + + connect_request_subscription_ = + error_screen_->RegisterConnectRequestCallback(base::BindRepeating( + &UpdateScreen::OnConnectRequested, weak_factory_.GetWeakPtr())); + error_screen_->SetUIState(NetworkError::UI_STATE_UPDATE); + error_screen_->SetParentScreen(UpdateView::kScreenId); + error_screen_->SetHideCallback(base::BindRepeating( + &UpdateScreen::OnErrorScreenHidden, weak_factory_.GetWeakPtr())); + error_screen_->Show(); + histogram_helper_->OnErrorShow(error_screen_->GetErrorState()); +} + +void UpdateScreen::UpdateErrorMessage( + const NetworkPortalDetector::CaptivePortalStatus status, + const NetworkError::ErrorState& error_state, + const std::string& network_name) { + error_screen_->SetErrorState(error_state, network_name); + if (status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL) { + if (is_first_portal_notification_) { + is_first_portal_notification_ = false; + error_screen_->FixCaptivePortal(); } - ExitUpdate(Result::UPDATE_ERROR); } } -void UpdateScreen::UpdateDownloadingStats( - const UpdateEngineClient::Status& status) { - base::TimeTicks download_current_time = tick_clock_->NowTicks(); - if (download_current_time >= - download_last_time_ + - base::TimeDelta::FromSeconds(kMinTimeStepInSeconds)) { - // Estimate downloading rate. - double progress_delta = - std::max(status.download_progress - download_last_progress_, 0.0); - double time_delta = - (download_current_time - download_last_time_).InSecondsF(); - double download_rate = status.new_size * progress_delta / time_delta; +void UpdateScreen::DelayErrorMessage() { + if (error_message_timer_.IsRunning()) + return; - download_last_time_ = download_current_time; - download_last_progress_ = status.download_progress; + error_message_timer_.Start(FROM_HERE, kDelayErrorMessage, this, + &UpdateScreen::ShowErrorMessage); +} - // Estimate time left. - double progress_left = std::max(1.0 - status.download_progress, 0.0); - if (!is_download_average_speed_computed_) { - download_average_speed_ = download_rate; - is_download_average_speed_computed_ = true; - } - download_average_speed_ = - kDownloadSpeedSmoothFactor * download_rate + - (1.0 - kDownloadSpeedSmoothFactor) * download_average_speed_; - if (download_average_speed_ < kDownloadAverageSpeedDropBound) { - time_delta = (download_current_time - download_start_time_).InSecondsF(); - download_average_speed_ = - status.new_size * - (status.download_progress - download_start_progress_) / time_delta; - } - double work_left = progress_left * status.new_size; - // time_left is in seconds. - double time_left = work_left / download_average_speed_; - // |time_left| may be large enough or even +infinity. So we must - // |bound possible estimations. - time_left = std::min(time_left, kMaxTimeLeft); - - if (view_) { - view_->SetShowEstimatedTimeLeft(true); - view_->SetEstimatedTimeLeft(static_cast<int>(time_left)); - } +void UpdateScreen::UpdateInfoChanged( + const VersionUpdater::UpdateInfo& update_info) { + const UpdateEngineClient::Status& status = update_info.status; + hide_progress_on_exit_ = false; + bool need_refresh_view = true; + switch (status.status) { + case UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE: + // Do nothing in this case, we don't want to notify the user of the + // check unless there is an update. + case UpdateEngineClient::UPDATE_STATUS_ATTEMPTING_ROLLBACK: + case UpdateEngineClient::UPDATE_STATUS_IDLE: + need_refresh_view = false; + break; + case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE: + case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING: + MakeSureScreenIsShown(); + if (!is_critical_checked_) { + // Because update engine doesn't send UPDATE_STATUS_UPDATE_AVAILABLE we + // need to check if update is critical on first downloading + // notification. + is_critical_checked_ = true; + if (!HasCriticalUpdate()) { + VLOG(1) << "Non-critical update available: " << status.new_version; + hide_progress_on_exit_ = true; + ExitUpdate(Result::UPDATE_NOT_REQUIRED); + } else { + VLOG(1) << "Critical update available: " << status.new_version; + } + } + break; + case UpdateEngineClient::UPDATE_STATUS_VERIFYING: + case UpdateEngineClient::UPDATE_STATUS_FINALIZING: + case UpdateEngineClient::UPDATE_STATUS_NEED_PERMISSION_TO_UPDATE: + MakeSureScreenIsShown(); + break; + case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT: + MakeSureScreenIsShown(); + if (HasCriticalUpdate()) { + version_updater_->RebootAfterUpdate(); + } else { + hide_progress_on_exit_ = true; + ExitUpdate(Result::UPDATE_NOT_REQUIRED); + } + break; + case UpdateEngineClient::UPDATE_STATUS_ERROR: + case UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT: + // Ignore update errors for non-critical updates to prevent blocking the + // user from getting to login screen during OOBE if the pending update is + // not critical. + if (update_info.is_checking_for_update || !HasCriticalUpdate()) { + ExitUpdate(Result::UPDATE_NOT_REQUIRED); + } else { + ExitUpdate(Result::UPDATE_ERROR); + } + need_refresh_view = false; + break; } + if (need_refresh_view) + RefreshView(update_info); +} +void UpdateScreen::FinishExitUpdate(Result result) { + show_timer_.Stop(); + exit_callback_.Run(result); +} + +void UpdateScreen::RefreshView(const VersionUpdater::UpdateInfo& update_info) { if (view_) { - int download_progress = - static_cast<int>(status.download_progress * kDownloadProgressIncrement); - view_->SetProgress(kBeforeDownloadProgress + download_progress); + view_->SetProgress(update_info.progress); + view_->SetProgressMessage(update_info.progress_message); + view_->SetEstimatedTimeLeft(update_info.estimated_time_left_in_secs); + view_->SetShowEstimatedTimeLeft(update_info.show_estimated_time_left); + view_->SetShowCurtain(update_info.progress_unavailable || + hide_progress_on_exit_); + view_->SetRequiresPermissionForCellular( + update_info.requires_permission_for_cellular); } } @@ -489,13 +281,6 @@ return true; } -void UpdateScreen::OnWaitForRebootTimeElapsed() { - LOG(ERROR) << "Unable to reboot - asking user for a manual reboot."; - MakeSureScreenIsShown(); - if (view_) - view_->SetUpdateCompleted(true); -} - void UpdateScreen::MakeSureScreenIsShown() { show_timer_.Stop(); @@ -508,104 +293,17 @@ view_->Show(); } -void UpdateScreen::StartUpdateCheck() { - error_message_timer_.Stop(); - error_screen_->HideCaptivePortal(); - - network_portal_detector::GetInstance()->RemoveObserver(this); - connect_request_subscription_.reset(); - if (state_ == State::STATE_ERROR) - HideErrorMessage(); - - pending_update_version_ = std::string(); - pending_update_size_ = 0; - - state_ = State::STATE_UPDATE; - DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this); - VLOG(1) << "Initiate update check"; - DBusThreadManager::Get()->GetUpdateEngineClient()->RequestUpdateCheck( - base::BindRepeating(&UpdateScreen::OnUpdateCheckStarted, - weak_factory_.GetWeakPtr())); -} - -void UpdateScreen::ShowErrorMessage() { - LOG(WARNING) << "UpdateScreen::ShowErrorMessage()"; - - error_message_timer_.Stop(); - - is_shown_ = false; - show_timer_.Stop(); - - state_ = State::STATE_ERROR; - connect_request_subscription_ = - error_screen_->RegisterConnectRequestCallback(base::BindRepeating( - &UpdateScreen::OnConnectRequested, base::Unretained(this))); - error_screen_->SetUIState(NetworkError::UI_STATE_UPDATE); - error_screen_->SetParentScreen(UpdateView::kScreenId); - error_screen_->SetHideCallback(base::BindRepeating( - &UpdateScreen::OnErrorScreenHidden, weak_factory_.GetWeakPtr())); - error_screen_->Show(); - histogram_helper_->OnErrorShow(error_screen_->GetErrorState()); -} - void UpdateScreen::HideErrorMessage() { LOG(WARNING) << "UpdateScreen::HideErrorMessage()"; error_screen_->Hide(); histogram_helper_->OnErrorHide(); } -void UpdateScreen::UpdateErrorMessage( - const NetworkState* network, - const NetworkPortalDetector::CaptivePortalStatus status) { - switch (status) { - case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE: - NOTREACHED(); - break; - case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN: - case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE: - error_screen_->SetErrorState(NetworkError::ERROR_STATE_OFFLINE, - std::string()); - break; - case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL: - DCHECK(network); - error_screen_->SetErrorState(NetworkError::ERROR_STATE_PORTAL, - network->name()); - if (is_first_portal_notification_) { - is_first_portal_notification_ = false; - error_screen_->FixCaptivePortal(); - } - break; - case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED: - error_screen_->SetErrorState(NetworkError::ERROR_STATE_PROXY, - std::string()); - break; - default: - NOTREACHED(); - break; - } -} - -void UpdateScreen::DelayErrorMessage() { - if (error_message_timer_.IsRunning()) - return; - - state_ = State::STATE_ERROR; - error_message_timer_.Start( - FROM_HERE, base::TimeDelta::FromSeconds(kDelayErrorMessageSec), this, - &UpdateScreen::ShowErrorMessage); -} - -void UpdateScreen::OnUpdateCheckStarted( - UpdateEngineClient::UpdateCheckResult result) { - VLOG(1) << "Callback from RequestUpdateCheck, result " << result; - if (result != UpdateEngineClient::UPDATE_RESULT_SUCCESS) - ExitUpdate(Result::UPDATE_NOT_REQUIRED); -} - void UpdateScreen::OnConnectRequested() { - if (state_ == State::STATE_ERROR) { + if (version_updater_->update_info().state == + VersionUpdater::State::STATE_ERROR) { LOG(WARNING) << "Hiding error message since AP was reselected"; - StartUpdateCheck(); + version_updater_->StartUpdateCheck(); } }
diff --git a/chrome/browser/chromeos/login/screens/update_screen.h b/chrome/browser/chromeos/login/screens/update_screen.h index 663f7f5..7279b4de 100644 --- a/chrome/browser/chromeos/login/screens/update_screen.h +++ b/chrome/browser/chromeos/login/screens/update_screen.h
@@ -5,17 +5,17 @@ #ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_SCREEN_H_ #define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_SCREEN_H_ +#include <memory> +#include <string> + #include "base/callback.h" -#include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/time/time.h" #include "base/timer/timer.h" #include "chrome/browser/chromeos/login/screens/base_screen.h" #include "chrome/browser/chromeos/login/screens/error_screen.h" -#include "chromeos/dbus/update_engine_client.h" -#include "chromeos/network/portal_detector/network_portal_detector.h" +#include "chrome/browser/chromeos/login/version_updater/version_updater.h" namespace base { class TickClock; @@ -23,9 +23,7 @@ namespace chromeos { -class ErrorScreen; class ErrorScreensHistogramHelper; -class NetworkState; class ScreenManager; class UpdateView; @@ -55,16 +53,11 @@ // has network connectivity - if the current network is not online (e.g. behind // a protal), it will request an ErrorScreen to be shown. Update check will be // delayed until the Internet connectivity is established. -class UpdateScreen : public BaseScreen, - public UpdateEngineClient::Observer, - public NetworkPortalDetector::Observer { +class UpdateScreen : public BaseScreen, public VersionUpdater::Delegate { public: - static UpdateScreen* Get(ScreenManager* manager); + using Result = VersionUpdater::Result; - enum class Result { - UPDATE_NOT_REQUIRED, - UPDATE_ERROR, - }; + static UpdateScreen* Get(ScreenManager* manager); using ScreenExitCallback = base::RepeatingCallback<void(Result result)>; UpdateScreen(UpdateView* view, @@ -76,19 +69,6 @@ // associated View if this class is destroyed before it. void OnViewDestroyed(UpdateView* view); - void SetIgnoreIdleStatus(bool ignore_idle_status); - - // UpdateEngineClient::Observer implementation: - void UpdateStatusChanged(const UpdateEngineClient::Status& status) override; - - // NetworkPortalDetector::Observer implementation: - void OnPortalDetectionCompleted( - const NetworkState* network, - const NetworkPortalDetector::CaptivePortalState& state) override; - - // Skip update UI, usually used only in debug builds/tests. - void CancelUpdate(); - // BaseScreen: void Show() override; void Hide() override; @@ -96,18 +76,26 @@ base::OneShotTimer* GetShowTimerForTesting(); base::OneShotTimer* GetErrorMessageTimerForTesting(); - base::OneShotTimer* GetRebootTimerForTesting(); + VersionUpdater* GetVersionUpdaterForTesting(); void set_ignore_update_deadlines_for_testing(bool ignore_update_deadlines) { ignore_update_deadlines_ = ignore_update_deadlines; } - void set_tick_clock_for_testing(const base::TickClock* tick_clock) { - tick_clock_ = tick_clock; - } + // VersionUpdater::Delegate: + void OnWaitForRebootTimeElapsed() override; + void PrepareForUpdateCheck() override; + void ShowErrorMessage() override; + void UpdateErrorMessage( + const NetworkPortalDetector::CaptivePortalStatus status, + const NetworkError::ErrorState& error_state, + const std::string& network_name) override; + void DelayErrorMessage() override; + void UpdateInfoChanged( + const VersionUpdater::UpdateInfo& update_info) override; + void FinishExitUpdate(VersionUpdater::Result result) override; protected: - // Reports update results. void ExitUpdate(Result result); private: @@ -116,49 +104,16 @@ FRIEND_TEST_ALL_PREFIXES(UpdateScreenTest, TestAPReselection); friend class UpdateScreenUnitTest; - enum class State { - STATE_IDLE = 0, - STATE_FIRST_PORTAL_CHECK, - STATE_REQUESTING_USER_PERMISSION, - STATE_UPDATE, - STATE_ERROR - }; - - // Starts network check. - void StartNetworkCheck(); - - // Callback to UpdateEngineClient::SetUpdateOverCellularOneTimePermission - // called in response to user confirming that the OS update can proceed - // despite being over cellular charges. - // |success|: whether the update engine accepted the user permission. - void RetryUpdateWithUpdateOverCellularPermissionSet(bool success); - - // Updates downloading stats (remaining time and downloading - // progress) on the AU screen. - void UpdateDownloadingStats(const UpdateEngineClient::Status& status); + void RefreshView(const VersionUpdater::UpdateInfo& update_info); // Returns true if there is critical system update that requires installation // and immediate reboot. bool HasCriticalUpdate(); - // Timer notification handlers. - void OnWaitForRebootTimeElapsed(); - // Checks that screen is shown, shows if not. void MakeSureScreenIsShown(); - void StartUpdateCheck(); - void ShowErrorMessage(); void HideErrorMessage(); - void UpdateErrorMessage( - const NetworkState* network, - const NetworkPortalDetector::CaptivePortalStatus status); - - void DelayErrorMessage(); - - // Callback for UpdateEngineClient::RequestUpdateCheck() called fomr - // StartUpdateCheck(). - void OnUpdateCheckStarted(UpdateEngineClient::UpdateCheckResult result); // The user requested an attempt to connect to the network should be made. void OnConnectRequested(); @@ -167,64 +122,33 @@ // screen gets hidden. void OnErrorScreenHidden(); - // Timer for the interval to wait for the reboot. - // If reboot didn't happen - ask user to reboot manually. - base::OneShotTimer reboot_timer_; + UpdateView* view_; + ErrorScreen* error_screen_; + ScreenExitCallback exit_callback_; - // Current state of the update screen. - State state_ = State::STATE_IDLE; - - const base::TickClock* tick_clock_; - - // Time in seconds after which we decide that the device has not rebooted - // automatically. If reboot didn't happen during this interval, ask user to - // reboot device manually. - int reboot_check_delay_ = 0; - - // True if in the process of checking for update. - bool is_checking_for_update_ = true; - // Flag that is used to detect when update download has just started. - bool is_downloading_update_ = false; // If true, update deadlines are ignored. // Note, this is false by default. bool ignore_update_deadlines_ = false; // Whether the update screen is shown. bool is_shown_ = false; - // Ignore fist IDLE status that is sent before update screen initiated check. - bool ignore_idle_status_ = true; - - UpdateView* view_; - ErrorScreen* error_screen_; - ScreenExitCallback exit_callback_; - - // Time of the first notification from the downloading stage. - base::TimeTicks download_start_time_; - double download_start_progress_ = 0; - - // Time of the last notification from the downloading stage. - base::TimeTicks download_last_time_; - double download_last_progress_ = 0; - - bool is_download_average_speed_computed_ = false; - double download_average_speed_ = 0; - - // True if there was no notification from NetworkPortalDetector - // about state for the default network. - bool is_first_detection_notification_ = true; // True if there was no notification about captive portal state for // the default network. bool is_first_portal_notification_ = true; - // Information about a pending update. Set if a user permission is required to - // proceed with the update. The values have to be passed to the update engine - // in SetUpdateOverCellularOneTimePermission method in order to enable update - // over cellular network. - std::string pending_update_version_; - int64_t pending_update_size_ = 0; + // True if already checked that update is critical. + bool is_critical_checked_ = false; + + // True if the update progress should be hidden even if update_info suggests + // the opposite. + bool hide_progress_on_exit_ = false; + // True if it is possible for user to skip update check. + bool cancel_update_shortcut_enabled_ = false; std::unique_ptr<ErrorScreensHistogramHelper> histogram_helper_; + std::unique_ptr<VersionUpdater> version_updater_; + // Showing the update screen view will be delayed for a small amount of time // after UpdateScreen::Show() is called. If the screen determines that an // update is not required before the delay expires, the UpdateScreen will exit
diff --git a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc index 1ffc66f..90eb7c9 100644 --- a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
@@ -15,11 +15,11 @@ #include "base/time/time.h" #include "chrome/browser/chromeos/login/login_wizard.h" #include "chrome/browser/chromeos/login/screens/error_screen.h" -#include "chrome/browser/chromeos/login/screens/update_screen.h" #include "chrome/browser/chromeos/login/test/js_checker.h" #include "chrome/browser/chromeos/login/test/network_portal_detector_mixin.h" #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h" +#include "chrome/browser/chromeos/login/version_updater/version_updater.h" #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" @@ -75,7 +75,8 @@ GetOobeUI()->GetView<UpdateScreenHandler>(), error_screen_, base::BindRepeating(&UpdateScreenTest::HandleScreenExit, base::Unretained(this))); - update_screen_->set_tick_clock_for_testing(&tick_clock_); + version_updater_ = update_screen_->GetVersionUpdaterForTesting(); + version_updater_->set_tick_clock_for_testing(&tick_clock_); MixinBasedInProcessBrowserTest::SetUpOnMainThread(); } @@ -103,6 +104,8 @@ NetworkPortalDetectorMixin network_portal_detector_{&mixin_host_}; std::unique_ptr<UpdateScreen> update_screen_; + // Version updater - owned by |update_screen_|. + VersionUpdater* version_updater_ = nullptr; // Error screen - owned by OobeUI. ErrorScreen* error_screen_ = nullptr; @@ -358,8 +361,8 @@ EXPECT_EQ(1, fake_update_engine_client_->reboot_after_update_call_count()); // Simulate the situation where reboot does not happen in time. - ASSERT_TRUE(update_screen_->GetRebootTimerForTesting()->IsRunning()); - update_screen_->GetRebootTimerForTesting()->FireNow(); + ASSERT_TRUE(version_updater_->GetRebootTimerForTesting()->IsRunning()); + version_updater_->GetRebootTimerForTesting()->FireNow(); test::OobeJS().ExpectHiddenPath({"oobe-update-md", "updating-progress"}); test::OobeJS().ExpectEQ("$('oobe-update-md').$$('#updating-progress').value", @@ -389,7 +392,7 @@ // GetLastStatus() will be called via ExitUpdate() called from // UpdateStatusChanged(). fake_update_engine_client_->set_default_status(status); - update_screen_->UpdateStatusChanged(status); + version_updater_->UpdateStatusChangedForTesting(status); ASSERT_TRUE(last_screen_result_.has_value()); EXPECT_EQ(UpdateScreen::Result::UPDATE_NOT_REQUIRED, @@ -606,7 +609,7 @@ {"oobe-update-md", "checking-for-updates-dialog"}); status.status = UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT; - update_screen_->UpdateStatusChanged(status); + version_updater_->UpdateStatusChangedForTesting(status); // UpdateStatusChanged(status) calls RebootAfterUpdate(). EXPECT_EQ(1, fake_update_engine_client_->reboot_after_update_call_count());
diff --git a/chrome/browser/chromeos/login/test/oobe_screens_utils.cc b/chrome/browser/chromeos/login/test/oobe_screens_utils.cc index 44368e751..983de3e 100644 --- a/chrome/browser/chromeos/login/test/oobe_screens_utils.cc +++ b/chrome/browser/chromeos/login/test/oobe_screens_utils.cc
@@ -72,7 +72,7 @@ UpdateScreen* screen = UpdateScreen::Get( WizardController::default_controller()->screen_manager()); - screen->UpdateStatusChanged(status); + screen->GetVersionUpdaterForTesting()->UpdateStatusChangedForTesting(status); } void WaitForFingerprintScreen() {
diff --git a/chrome/browser/chromeos/login/version_updater/mock_version_updater_delegate.cc b/chrome/browser/chromeos/login/version_updater/mock_version_updater_delegate.cc new file mode 100644 index 0000000..2d240ee0 --- /dev/null +++ b/chrome/browser/chromeos/login/version_updater/mock_version_updater_delegate.cc
@@ -0,0 +1,13 @@ +// 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 "chrome/browser/chromeos/login/version_updater/mock_version_updater_delegate.h" + +namespace chromeos { + +MockVersionUpdaterDelegate::MockVersionUpdaterDelegate() {} + +MockVersionUpdaterDelegate::~MockVersionUpdaterDelegate() {} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/version_updater/mock_version_updater_delegate.h b/chrome/browser/chromeos/login/version_updater/mock_version_updater_delegate.h new file mode 100644 index 0000000..cd0759b --- /dev/null +++ b/chrome/browser/chromeos/login/version_updater/mock_version_updater_delegate.h
@@ -0,0 +1,35 @@ +// 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 CHROME_BROWSER_CHROMEOS_LOGIN_VERSION_UPDATER_MOCK_VERSION_UPDATER_DELEGATE_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_VERSION_UPDATER_MOCK_VERSION_UPDATER_DELEGATE_H_ + +#include <string> + +#include "chrome/browser/chromeos/login/version_updater/version_updater.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace chromeos { + +class MockVersionUpdaterDelegate : public VersionUpdater::Delegate { + public: + MockVersionUpdaterDelegate(); + virtual ~MockVersionUpdaterDelegate(); + + MOCK_METHOD1(UpdateInfoChanged, + void(const VersionUpdater::UpdateInfo& update_info)); + MOCK_METHOD1(FinishExitUpdate, void(VersionUpdater::Result result)); + MOCK_METHOD0(OnWaitForRebootTimeElapsed, void()); + MOCK_METHOD0(PrepareForUpdateCheck, void()); + MOCK_METHOD3(UpdateErrorMessage, + void(const NetworkPortalDetector::CaptivePortalStatus status, + const NetworkError::ErrorState& error_state, + const std::string& network_name)); + MOCK_METHOD0(ShowErrorMessage, void()); + MOCK_METHOD0(DelayErrorMessage, void()); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_VERSION_UPDATER_MOCK_VERSION_UPDATER_DELEGATE_H_
diff --git a/chrome/browser/chromeos/login/version_updater/version_updater.cc b/chrome/browser/chromeos/login/version_updater/version_updater.cc new file mode 100644 index 0000000..082588f9 --- /dev/null +++ b/chrome/browser/chromeos/login/version_updater/version_updater.cc
@@ -0,0 +1,384 @@ +// 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 "chrome/browser/chromeos/login/version_updater/version_updater.h" + +#include <algorithm> +#include <string> + +#include "base/bind.h" +#include "base/time/default_tick_clock.h" +#include "chrome/grit/chromium_strings.h" +#include "chrome/grit/generated_resources.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/network/network_state.h" +#include "ui/base/l10n/l10n_util.h" + +namespace chromeos { + +namespace { + +// Time in seconds after which we decide that the device has not rebooted +// automatically. If reboot didn't happen during this interval, ask user to +// reboot device manually. +constexpr const base::TimeDelta kWaitForRebootTime = + base::TimeDelta::FromSeconds(3); + +// Progress bar stages. Each represents progress bar value +// at the beginning of each stage. +// TODO(nkostylev): Base stage progress values on approximate time. +// TODO(nkostylev): Animate progress during each state. +const int kBeforeUpdateCheckProgress = 7; +const int kBeforeDownloadProgress = 14; +const int kBeforeVerifyingProgress = 74; +const int kBeforeFinalizingProgress = 81; +const int kProgressComplete = 100; + +// Minimum timestep between two consecutive measurements for the download rates. +constexpr const base::TimeDelta kMinTimeStep = base::TimeDelta::FromSeconds(1); + +// Defines what part of update progress does download part takes. +const int kDownloadProgressIncrement = 60; + +// Smooth factor that is used for the average downloading speed +// estimation. +// avg_speed = smooth_factor * cur_speed + (1.0 - smooth_factor) * +// avg_speed. +const double kDownloadSpeedSmoothFactor = 0.1; + +// Minimum allowed value for the average downloading speed. +const double kDownloadAverageSpeedDropBound = 1e-8; + +// An upper bound for possible downloading time left estimations. +constexpr const base::TimeDelta kMaxTimeLeft = base::TimeDelta::FromDays(1); + +} // anonymous namespace + +VersionUpdater::UpdateInfo::UpdateInfo() {} + +VersionUpdater::VersionUpdater(VersionUpdater::Delegate* delegate) + : delegate_(delegate), tick_clock_(base::DefaultTickClock::GetInstance()) {} + +VersionUpdater::~VersionUpdater() { + DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); + network_portal_detector::GetInstance()->RemoveObserver(this); +} + +void VersionUpdater::StartNetworkCheck() { + // If portal detector is enabled and portal detection before AU is + // allowed, initiate network state check. Otherwise, directly + // proceed to update. + if (!network_portal_detector::GetInstance()->IsEnabled()) { + StartUpdateCheck(); + return; + } + update_info_.state = State::STATE_FIRST_PORTAL_CHECK; + delegate_->UpdateInfoChanged(update_info_); + + is_first_detection_notification_ = true; + network_portal_detector::GetInstance()->AddAndFireObserver(this); +} + +void VersionUpdater::StartUpdateCheck() { + delegate_->PrepareForUpdateCheck(); + RequestUpdateCheck(); +} + +void VersionUpdater::SetUpdateOverCellularOneTimePermission() { + DBusThreadManager::Get() + ->GetUpdateEngineClient() + ->SetUpdateOverCellularOneTimePermission( + update_info_.update_version, update_info_.update_size, + base::BindRepeating( + &VersionUpdater::OnSetUpdateOverCellularOneTimePermission, + weak_ptr_factory_.GetWeakPtr())); +} + +void VersionUpdater::RejectUpdateOverCellular() { + // Reset UI context to show curtain again when the user goes back to the + // screen. + update_info_.progress_unavailable = true; + update_info_.requires_permission_for_cellular = false; + delegate_->UpdateInfoChanged(update_info_); +} + +void VersionUpdater::RebootAfterUpdate() { + VLOG(1) << "Initiate reboot after update"; + DBusThreadManager::Get()->GetUpdateEngineClient()->RebootAfterUpdate(); + reboot_timer_.Start(FROM_HERE, kWaitForRebootTime, this, + &VersionUpdater::OnWaitForRebootTimeElapsed); +} + +void VersionUpdater::StartExitUpdate(Result result) { + DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); + network_portal_detector::GetInstance()->RemoveObserver(this); + delegate_->FinishExitUpdate(result); +} + +base::OneShotTimer* VersionUpdater::GetRebootTimerForTesting() { + return &reboot_timer_; +} + +void VersionUpdater::UpdateStatusChangedForTesting( + const UpdateEngineClient::Status& status) { + UpdateStatusChanged(status); +} + +void VersionUpdater::RequestUpdateCheck() { + update_info_.state = State::STATE_UPDATE; + update_info_.progress = kBeforeUpdateCheckProgress; + update_info_.update_version = std::string(); + update_info_.update_size = 0; + delegate_->UpdateInfoChanged(update_info_); + + network_portal_detector::GetInstance()->RemoveObserver(this); + DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this); + VLOG(1) << "Initiate update check"; + DBusThreadManager::Get()->GetUpdateEngineClient()->RequestUpdateCheck( + base::BindRepeating(&VersionUpdater::OnUpdateCheckStarted, + weak_ptr_factory_.GetWeakPtr())); +} + +void VersionUpdater::UpdateStatusChanged( + const UpdateEngineClient::Status& status) { + update_info_.status = status; + + if (update_info_.is_checking_for_update && + status.status > UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE && + status.status != UpdateEngineClient::UPDATE_STATUS_ERROR && + status.status != + UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT) { + update_info_.is_checking_for_update = false; + } + if (ignore_idle_status_ && + status.status > UpdateEngineClient::UPDATE_STATUS_IDLE) { + ignore_idle_status_ = false; + } + + switch (status.status) { + case UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE: + break; + case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE: + update_info_.progress = kBeforeDownloadProgress; + update_info_.progress_message = + l10n_util::GetStringUTF16(IDS_UPDATE_AVAILABLE); + update_info_.show_estimated_time_left = false; + update_info_.progress_unavailable = false; + break; + case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING: + if (!is_downloading_update_) { + is_downloading_update_ = true; + + download_start_time_ = download_last_time_ = tick_clock_->NowTicks(); + download_start_progress_ = status.download_progress; + download_last_progress_ = status.download_progress; + is_download_average_speed_computed_ = false; + download_average_speed_ = 0.0; + update_info_.progress_message = + l10n_util::GetStringUTF16(IDS_INSTALLING_UPDATE); + update_info_.progress_unavailable = false; + } + UpdateDownloadingStats(status); + break; + case UpdateEngineClient::UPDATE_STATUS_VERIFYING: + update_info_.progress = kBeforeVerifyingProgress; + update_info_.progress_message = + l10n_util::GetStringUTF16(IDS_UPDATE_VERIFYING); + update_info_.show_estimated_time_left = false; + break; + case UpdateEngineClient::UPDATE_STATUS_FINALIZING: + update_info_.progress = kBeforeFinalizingProgress; + update_info_.progress_message = + l10n_util::GetStringUTF16(IDS_UPDATE_FINALIZING); + update_info_.show_estimated_time_left = false; + break; + case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT: + update_info_.progress = kProgressComplete; + update_info_.show_estimated_time_left = false; + update_info_.progress_unavailable = false; + break; + case UpdateEngineClient::UPDATE_STATUS_NEED_PERMISSION_TO_UPDATE: + VLOG(1) << "Update requires user permission to proceed."; + update_info_.state = State::STATE_REQUESTING_USER_PERMISSION; + update_info_.update_version = status.new_version; + update_info_.update_size = status.new_size; + update_info_.requires_permission_for_cellular = true; + update_info_.progress_unavailable = false; + + DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); + break; + case UpdateEngineClient::UPDATE_STATUS_ATTEMPTING_ROLLBACK: + VLOG(1) << "Attempting rollback"; + break; + case UpdateEngineClient::UPDATE_STATUS_IDLE: + // Exit update only if update engine was in non-idle status before. + // Otherwise, it's possible that the update request has not yet been + // started. + if (!ignore_idle_status_) + StartExitUpdate(Result::UPDATE_NOT_REQUIRED); + break; + case UpdateEngineClient::UPDATE_STATUS_ERROR: + case UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT: + break; + } + + delegate_->UpdateInfoChanged(update_info_); +} + +void VersionUpdater::UpdateDownloadingStats( + const UpdateEngineClient::Status& status) { + base::TimeTicks download_current_time = tick_clock_->NowTicks(); + if (download_current_time >= download_last_time_ + kMinTimeStep) { + // Estimate downloading rate. + double progress_delta = + std::max(status.download_progress - download_last_progress_, 0.0); + double time_delta = + (download_current_time - download_last_time_).InSecondsF(); + double download_rate = status.new_size * progress_delta / time_delta; + + download_last_time_ = download_current_time; + download_last_progress_ = status.download_progress; + + // Estimate time left. + double progress_left = std::max(1.0 - status.download_progress, 0.0); + if (!is_download_average_speed_computed_) { + download_average_speed_ = download_rate; + is_download_average_speed_computed_ = true; + } + download_average_speed_ = + kDownloadSpeedSmoothFactor * download_rate + + (1.0 - kDownloadSpeedSmoothFactor) * download_average_speed_; + if (download_average_speed_ < kDownloadAverageSpeedDropBound) { + time_delta = (download_current_time - download_start_time_).InSecondsF(); + download_average_speed_ = + status.new_size * + (status.download_progress - download_start_progress_) / time_delta; + } + double work_left = progress_left * status.new_size; + // time_left is in seconds. + double time_left = work_left / download_average_speed_; + // |time_left| may be large enough or even +infinity. So we must + // |bound possible estimations. + time_left = std::min(time_left, kMaxTimeLeft.InSecondsF()); + + update_info_.show_estimated_time_left = true; + update_info_.estimated_time_left_in_secs = static_cast<int>(time_left); + } + + int download_progress = + static_cast<int>(status.download_progress * kDownloadProgressIncrement); + update_info_.progress = kBeforeDownloadProgress + download_progress; +} + +void VersionUpdater::OnPortalDetectionCompleted( + const NetworkState* network, + const NetworkPortalDetector::CaptivePortalState& state) { + VLOG(1) << "VersionUpdater::OnPortalDetectionCompleted(): " + << "network=" << (network ? network->path() : "") << ", " + << "state.status=" << state.status << ", " + << "state.response_code=" << state.response_code; + + // Wait for sane detection results. + if (network && + state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN) { + return; + } + + // Restart portal detection for the first notification about offline state. + if ((!network || + state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE) && + is_first_detection_notification_) { + is_first_detection_notification_ = false; + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce([]() { + network_portal_detector::GetInstance()->StartPortalDetection( + false /* force */); + })); + return; + } + is_first_detection_notification_ = false; + + NetworkPortalDetector::CaptivePortalStatus status = state.status; + if (update_info_.state == State::STATE_ERROR) { + // In the case of online state hide error message and proceed to + // the update stage. Otherwise, update error message content. + if (status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) + StartUpdateCheck(); + else + UpdateErrorMessage(network, status); + } else if (update_info_.state == State::STATE_FIRST_PORTAL_CHECK) { + // In the case of online state immediately proceed to the update + // stage. Otherwise, prepare and show error message. + if (status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) { + StartUpdateCheck(); + } else { + UpdateErrorMessage(network, status); + + // StartUpdateCheck, which gets called when the error clears up, will add + // the update engine observer back. + DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); + + update_info_.state = State::STATE_ERROR; + delegate_->UpdateInfoChanged(update_info_); + if (status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL) + delegate_->DelayErrorMessage(); + else + delegate_->ShowErrorMessage(); + } + } +} + +void VersionUpdater::OnWaitForRebootTimeElapsed() { + delegate_->OnWaitForRebootTimeElapsed(); +} + +void VersionUpdater::UpdateErrorMessage( + const NetworkState* network, + const NetworkPortalDetector::CaptivePortalStatus status) { + std::string network_name = std::string(); + NetworkError::ErrorState error_state; + switch (status) { + case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN: + case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE: + error_state = NetworkError::ERROR_STATE_OFFLINE; + break; + case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL: + DCHECK(network); + error_state = NetworkError::ERROR_STATE_PORTAL; + network_name = network->name(); + break; + case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED: + error_state = NetworkError::ERROR_STATE_PROXY; + break; + default: + NOTREACHED(); + return; + } + delegate_->UpdateErrorMessage(status, error_state, network_name); +} + +void VersionUpdater::OnSetUpdateOverCellularOneTimePermission(bool success) { + update_info_.requires_permission_for_cellular = false; + if (!success) { + // Reset UI context to show curtain again when the user goes back to the + // screen. + update_info_.progress_unavailable = true; + } + delegate_->UpdateInfoChanged(update_info_); + + if (success) { + StartUpdateCheck(); + } else { + StartExitUpdate(Result::UPDATE_ERROR); + } +} + +void VersionUpdater::OnUpdateCheckStarted( + UpdateEngineClient::UpdateCheckResult result) { + VLOG(1) << "Callback from RequestUpdateCheck, result " << result; + if (result != UpdateEngineClient::UPDATE_RESULT_SUCCESS) + StartExitUpdate(Result::UPDATE_NOT_REQUIRED); +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/version_updater/version_updater.h b/chrome/browser/chromeos/login/version_updater/version_updater.h new file mode 100644 index 0000000..8c73f6c --- /dev/null +++ b/chrome/browser/chromeos/login/version_updater/version_updater.h
@@ -0,0 +1,191 @@ +// 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 CHROME_BROWSER_CHROMEOS_LOGIN_VERSION_UPDATER_VERSION_UPDATER_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_VERSION_UPDATER_VERSION_UPDATER_H_ + +#include <string> + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "base/timer/timer.h" +#include "chrome/browser/chromeos/login/screens/network_error.h" +#include "chromeos/dbus/update_engine_client.h" +#include "chromeos/network/portal_detector/network_portal_detector.h" + +namespace base { +class DefaultTickClock; +} + +namespace chromeos { + +// Tries to update system, interacting with UpdateEnglineClient and +// NetworkPortalDetector. Uses callbacks - methods of |delegate_|, which may +// interact with user, change UI etc. +class VersionUpdater : public UpdateEngineClient::Observer, + public NetworkPortalDetector::Observer { + public: + enum class Result { + UPDATE_NOT_REQUIRED, + UPDATE_ERROR, + }; + + enum class State { + STATE_IDLE = 0, + STATE_FIRST_PORTAL_CHECK, + STATE_REQUESTING_USER_PERMISSION, + STATE_UPDATE, + STATE_ERROR + }; + + // Stores information about current downloading process, update progress and + // state. + struct UpdateInfo { + UpdateInfo(); + + UpdateEngineClient::Status status = UpdateEngineClient::Status(); + + // Estimated time left, in seconds. + int estimated_time_left_in_secs = 0; + bool show_estimated_time_left = false; + + // True if VersionUpdater in such a state that progress is not available or + // applicable (e.g. checking for updates) + bool progress_unavailable = true; + base::string16 progress_message = base::string16(); + // Percent of update progress, between 0 and 100. + int progress = 0; + + bool requires_permission_for_cellular = false; + + // Information about a pending update. Set if a user permission is required + // to proceed with the update. The values have to be passed to the update + // engine in SetUpdateOverCellularOneTimePermission method in order to + // enable update over cellular network. + int64_t update_size = 0; + std::string update_version = std::string(); + + // True if in the process of checking for update. + bool is_checking_for_update = true; + + // Current state. + State state = State::STATE_IDLE; + }; + + // Interface for callbacks that are called when corresponding events occur + // during update process. + class Delegate { + public: + // Called when update info changes + virtual void UpdateInfoChanged( + const VersionUpdater::UpdateInfo& update_info) = 0; + // Reports update results. + virtual void FinishExitUpdate(VersionUpdater::Result result) = 0; + // Timer notification handler. + virtual void OnWaitForRebootTimeElapsed() = 0; + // Called before update check starts. + virtual void PrepareForUpdateCheck() = 0; + virtual void UpdateErrorMessage( + const NetworkPortalDetector::CaptivePortalStatus status, + const NetworkError::ErrorState& error_state, + const std::string& network_name) = 0; + virtual void ShowErrorMessage() = 0; + virtual void DelayErrorMessage() = 0; + }; + + explicit VersionUpdater(VersionUpdater::Delegate* delegate); + ~VersionUpdater() override; + + // Starts network check. If success, starts update check. + void StartNetworkCheck(); + void StartUpdateCheck(); + + void SetUpdateOverCellularOneTimePermission(); + void RejectUpdateOverCellular(); + void RebootAfterUpdate(); + void StartExitUpdate(Result result); + + const UpdateInfo& update_info() { return update_info_; } + + void set_tick_clock_for_testing(const base::TickClock* tick_clock) { + tick_clock_ = tick_clock; + } + + base::OneShotTimer* GetRebootTimerForTesting(); + void UpdateStatusChangedForTesting(const UpdateEngineClient::Status& status); + + private: + void RequestUpdateCheck(); + + // UpdateEngineClient::Observer implementation: + void UpdateStatusChanged(const UpdateEngineClient::Status& status) override; + + // Updates downloading stats (remaining time and downloading + // progress), which are stored in update_info_. + void UpdateDownloadingStats(const UpdateEngineClient::Status& status); + + // NetworkPortalDetector::Observer implementation: + void OnPortalDetectionCompleted( + const NetworkState* network, + const NetworkPortalDetector::CaptivePortalState& state) override; + + void OnWaitForRebootTimeElapsed(); + + void UpdateErrorMessage( + const NetworkState* network, + const NetworkPortalDetector::CaptivePortalStatus status); + + // Callback to UpdateEngineClient::SetUpdateOverCellularOneTimePermission + // called in response to user confirming that the OS update can proceed + // despite being over cellular charges. + // |success|: whether the update engine accepted the user permission. + void OnSetUpdateOverCellularOneTimePermission(bool success); + + // Callback for UpdateEngineClient::RequestUpdateCheck() called from + // StartUpdateCheck(). + void OnUpdateCheckStarted(UpdateEngineClient::UpdateCheckResult result); + + // Pointer to delegate that owns this VersionUpdater instance. + Delegate* delegate_; + + // Time of the first notification from the downloading stage. + base::TimeTicks download_start_time_; + double download_start_progress_ = 0; + + // Time of the last notification from the downloading stage. + base::TimeTicks download_last_time_; + double download_last_progress_ = 0; + + bool is_download_average_speed_computed_ = false; + double download_average_speed_ = 0; + + // Flag that is used to detect when update download has just started. + bool is_downloading_update_ = false; + // Ignore fist IDLE status that is sent before VersionUpdater initiated check. + bool ignore_idle_status_ = true; + + // Timer for the interval to wait for the reboot. + // If reboot didn't happen - ask user to reboot manually. + base::OneShotTimer reboot_timer_; + + // True if there was no notification from NetworkPortalDetector + // about state for the default network. + bool is_first_detection_notification_ = true; + + // Stores information about current downloading process, update progress and + // state. It is sent to Delegate on each UpdateInfoChanged call, and also can + // be obtained with corresponding getter. + UpdateInfo update_info_; + + const base::TickClock* tick_clock_; + + base::WeakPtrFactory<VersionUpdater> weak_ptr_factory_{this}; + + DISALLOW_COPY_AND_ASSIGN(VersionUpdater); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_VERSION_UPDATER_VERSION_UPDATER_H_
diff --git a/chrome/browser/chromeos/login/version_updater/version_updater_unittest.cc b/chrome/browser/chromeos/login/version_updater/version_updater_unittest.cc new file mode 100644 index 0000000..8c8b850 --- /dev/null +++ b/chrome/browser/chromeos/login/version_updater/version_updater_unittest.cc
@@ -0,0 +1,281 @@ +// 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 "chrome/browser/chromeos/login/version_updater/version_updater.h" + +#include <memory> + +#include "base/command_line.h" +#include "base/optional.h" +#include "base/test/scoped_mock_time_message_loop_task_runner.h" +#include "chrome/browser/chromeos/login/startup_utils.h" +#include "chrome/browser/chromeos/login/version_updater/mock_version_updater_delegate.h" +#include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/device_settings_service.h" +#include "chrome/test/base/scoped_testing_local_state.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chromeos/constants/chromeos_switches.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/fake_update_engine_client.h" +#include "chromeos/dbus/update_engine_client.h" +#include "chromeos/network/network_handler.h" +#include "chromeos/network/portal_detector/mock_network_portal_detector.h" +#include "chromeos/network/portal_detector/network_portal_detector.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::AnyNumber; +using testing::Return; + +namespace chromeos { + +namespace { +constexpr const char kNetworkGuid[] = "test_network"; +} // anonymous namespace + +class VersionUpdaterUnitTest : public testing::Test { + public: + VersionUpdaterUnitTest() : local_state_(TestingBrowserProcess::GetGlobal()) {} + + void SetUpdateEngineStatus(UpdateEngineClient::UpdateStatusOperation status) { + UpdateEngineClient::Status update_engine_status; + update_engine_status.status = status; + fake_update_engine_client_->NotifyObserversThatStatusChanged( + update_engine_status); + } + + void SetStatusWithChecks(UpdateEngineClient::UpdateStatusOperation status) { + testing::MockFunction<void(int check_point_name)> check; + { + testing::InSequence s; + + EXPECT_CALL(*mock_delegate_, UpdateInfoChanged(_)); + EXPECT_CALL(check, Call(checks_count_)); + } + + SetUpdateEngineStatus(status); + check.Call(checks_count_); + ++checks_count_; + } + + void SetUpMockNetworkPortalDetector() { + network_portal_detector::SetNetworkPortalDetector( + mock_network_portal_detector_.get()); + } + + void SetUpFakeNetworkPortalDetector() { + fake_network_portal_detector_->SetDefaultNetworkForTesting(kNetworkGuid); + network_portal_detector::SetNetworkPortalDetector( + fake_network_portal_detector_.get()); + } + + // testing::Test: + void SetUp() override { + // Initialize objects needed by VersionUpdater. + fake_update_engine_client_ = new FakeUpdateEngineClient(); + DBusThreadManager::GetSetterForTesting()->SetUpdateEngineClient( + std::unique_ptr<UpdateEngineClient>(fake_update_engine_client_)); + + NetworkHandler::Initialize(); + + // |mock_network_portal_detector_->IsEnabled()| will always return false. + mock_network_portal_detector_ = + std::make_unique<MockNetworkPortalDetector>(); + EXPECT_CALL(*mock_network_portal_detector_, IsEnabled()) + .Times(AnyNumber()) + .WillRepeatedly(Return(false)); + + // |fake_network_portal_detector_->IsEnabled()| will always return true. + fake_network_portal_detector_ = + std::make_unique<NetworkPortalDetectorTestImpl>(); + + mock_delegate_ = std::make_unique<MockVersionUpdaterDelegate>(); + version_updater_ = std::make_unique<VersionUpdater>(mock_delegate_.get()); + + checks_count_ = 0; + } + + void TearDown() override { + TestingBrowserProcess::GetGlobal()->SetShuttingDown(true); + // We need to stop observing |NetworkPortalDetector| before call + // |DBusThreadManager::Shutdown()|, so destroy |version_updater_| now. + version_updater_.reset(); + mock_delegate_.reset(); + + network_portal_detector::InitializeForTesting(nullptr); + NetworkHandler::Shutdown(); + + // It will delete |fake_update_engine_client_|. + DBusThreadManager::Shutdown(); + } + + protected: + std::unique_ptr<VersionUpdater> version_updater_; + + // Accessory objects needed by VersionUpdater. + std::unique_ptr<MockVersionUpdaterDelegate> mock_delegate_; + std::unique_ptr<MockNetworkPortalDetector> mock_network_portal_detector_; + std::unique_ptr<NetworkPortalDetectorTestImpl> fake_network_portal_detector_; + FakeUpdateEngineClient* fake_update_engine_client_; + + private: + // Test versions of core browser infrastructure. + content::BrowserTaskEnvironment task_environment_; + ScopedTestingLocalState local_state_; + + int checks_count_ = 0; + + DISALLOW_COPY_AND_ASSIGN(VersionUpdaterUnitTest); +}; + +TEST_F(VersionUpdaterUnitTest, HandlesNoUpdate) { + SetUpMockNetworkPortalDetector(); + + EXPECT_CALL(*mock_delegate_, PrepareForUpdateCheck()).Times(1); + version_updater_->StartNetworkCheck(); + // Verify that the DUT checks for an update. + EXPECT_EQ(fake_update_engine_client_->request_update_check_call_count(), 1); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE); + + // No updates are available. + EXPECT_CALL(*mock_delegate_, + FinishExitUpdate(VersionUpdater::Result::UPDATE_NOT_REQUIRED)) + .Times(1); + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_IDLE); +} + +TEST_F(VersionUpdaterUnitTest, HandlesAvailableUpdate) { + SetUpMockNetworkPortalDetector(); + + EXPECT_CALL(*mock_delegate_, PrepareForUpdateCheck()).Times(1); + version_updater_->StartNetworkCheck(); + // Verify that the DUT checks for an update. + EXPECT_EQ(fake_update_engine_client_->request_update_check_call_count(), 1); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_IDLE); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_DOWNLOADING); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_VERIFYING); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_FINALIZING); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT); + + EXPECT_EQ(fake_update_engine_client_->reboot_after_update_call_count(), 0); + version_updater_->RebootAfterUpdate(); + EXPECT_EQ(fake_update_engine_client_->reboot_after_update_call_count(), 1); +} + +TEST_F(VersionUpdaterUnitTest, HandlesCancelUpdateOnUpdateAvailable) { + SetUpMockNetworkPortalDetector(); + + EXPECT_CALL(*mock_delegate_, PrepareForUpdateCheck()).Times(1); + version_updater_->StartNetworkCheck(); + + // Verify that the DUT checks for an update. + EXPECT_EQ(fake_update_engine_client_->request_update_check_call_count(), 1); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_IDLE); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE); + + EXPECT_CALL(*mock_delegate_, + FinishExitUpdate(VersionUpdater::Result::UPDATE_NOT_REQUIRED)) + .Times(1); + version_updater_->StartExitUpdate( + VersionUpdater::Result::UPDATE_NOT_REQUIRED); +} + +TEST_F(VersionUpdaterUnitTest, HandlesCancelUpdateOnDownloading) { + SetUpMockNetworkPortalDetector(); + + EXPECT_CALL(*mock_delegate_, PrepareForUpdateCheck()).Times(1); + version_updater_->StartNetworkCheck(); + + // Verify that the DUT checks for an update. + EXPECT_EQ(fake_update_engine_client_->request_update_check_call_count(), 1); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_IDLE); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_DOWNLOADING); + + EXPECT_CALL(*mock_delegate_, + FinishExitUpdate(VersionUpdater::Result::UPDATE_NOT_REQUIRED)) + .Times(1); + version_updater_->StartExitUpdate( + VersionUpdater::Result::UPDATE_NOT_REQUIRED); +} + +TEST_F(VersionUpdaterUnitTest, HandleUpdateError) { + SetUpMockNetworkPortalDetector(); + + EXPECT_CALL(*mock_delegate_, PrepareForUpdateCheck()).Times(1); + version_updater_->StartNetworkCheck(); + + // Verify that the DUT checks for an update. + EXPECT_EQ(fake_update_engine_client_->request_update_check_call_count(), 1); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_IDLE); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE); + + SetStatusWithChecks(UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT); + + EXPECT_CALL(*mock_delegate_, + FinishExitUpdate(VersionUpdater::Result::UPDATE_ERROR)) + .Times(1); + version_updater_->StartExitUpdate(VersionUpdater::Result::UPDATE_ERROR); +} + +TEST_F(VersionUpdaterUnitTest, HandlesPortalOnline) { + SetUpFakeNetworkPortalDetector(); + + version_updater_->StartNetworkCheck(); + + NetworkPortalDetector::CaptivePortalState state; + state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE; + + EXPECT_CALL(*mock_delegate_, PrepareForUpdateCheck()).Times(1); + fake_network_portal_detector_->SetDetectionResultsForTesting(kNetworkGuid, + state); + fake_network_portal_detector_->NotifyObserversForTesting(); +} + +TEST_F(VersionUpdaterUnitTest, HandlesPortalError) { + SetUpFakeNetworkPortalDetector(); + + version_updater_->StartNetworkCheck(); + + NetworkPortalDetector::CaptivePortalState state; + state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL; + + // Name of the network is empty because of implementation + // SetDefaultNetworkForTesting (and it's not easy to fix it). + EXPECT_CALL( + *mock_delegate_, + UpdateErrorMessage(state.status, NetworkError::ERROR_STATE_PORTAL, "")) + .Times(1); + EXPECT_CALL(*mock_delegate_, DelayErrorMessage()).Times(1); + fake_network_portal_detector_->SetDetectionResultsForTesting(kNetworkGuid, + state); + fake_network_portal_detector_->NotifyObserversForTesting(); +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc index 74f485a..8d2ad3b7 100644 --- a/chrome/browser/chromeos/preferences.cc +++ b/chrome/browser/chromeos/preferences.cc
@@ -15,6 +15,7 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/i18n/time_formatting.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -228,6 +229,12 @@ registry->RegisterBooleanPref( prefs::kMouseReverseScroll, false, user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); + registry->RegisterBooleanPref( + prefs::kMouseAcceleration, true, + user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); + registry->RegisterBooleanPref( + prefs::kTouchpadAcceleration, true, + user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); registry->RegisterBooleanPref(prefs::kLabsMediaplayerEnabled, false); registry->RegisterBooleanPref(prefs::kLabsAdvancedFilesystemEnabled, false); registry->RegisterBooleanPref(prefs::kAppReinstallRecommendationEnabled, @@ -597,6 +604,8 @@ primary_mouse_button_right_.Init(prefs::kPrimaryMouseButtonRight, prefs, callback); mouse_reverse_scroll_.Init(prefs::kMouseReverseScroll, prefs, callback); + mouse_acceleration_.Init(prefs::kMouseAcceleration, prefs, callback); + touchpad_acceleration_.Init(prefs::kTouchpadAcceleration, prefs, callback); download_default_directory_.Init(prefs::kDownloadDefaultDirectory, prefs, callback); preload_engines_.Init(prefs::kLanguagePreloadEngines, prefs, callback); @@ -835,6 +844,25 @@ else if (reason == REASON_INITIALIZATION) UMA_HISTOGRAM_BOOLEAN("Mouse.ReverseScroll.Started", enabled); } + if (reason != REASON_PREF_CHANGED || pref_name == prefs::kMouseAcceleration) { + const bool enabled = mouse_acceleration_.GetValue(); + if (user_is_active) + mouse_settings.SetAcceleration(enabled); + if (reason == REASON_PREF_CHANGED) + base::UmaHistogramBoolean("Mouse.Acceleration.Changed", enabled); + else if (reason == REASON_INITIALIZATION) + base::UmaHistogramBoolean("Mouse.Acceleration.Started", enabled); + } + if (reason != REASON_PREF_CHANGED || + pref_name == prefs::kTouchpadAcceleration) { + const bool enabled = touchpad_acceleration_.GetValue(); + if (user_is_active) + touchpad_settings.SetAcceleration(enabled); + if (reason == REASON_PREF_CHANGED) + base::UmaHistogramBoolean("Touchpad.Acceleration.Changed", enabled); + else if (reason == REASON_INITIALIZATION) + base::UmaHistogramBoolean("Touchpad.Acceleration.Started", enabled); + } if (reason != REASON_PREF_CHANGED || pref_name == prefs::kDownloadDefaultDirectory) { const bool default_download_to_drive = drive::util::IsUnderDriveMountPoint(
diff --git a/chrome/browser/chromeos/preferences.h b/chrome/browser/chromeos/preferences.h index cd4486b..f9056e1 100644 --- a/chrome/browser/chromeos/preferences.h +++ b/chrome/browser/chromeos/preferences.h
@@ -123,6 +123,8 @@ IntegerPrefMember touchpad_sensitivity_; BooleanPrefMember primary_mouse_button_right_; BooleanPrefMember mouse_reverse_scroll_; + BooleanPrefMember mouse_acceleration_; + BooleanPrefMember touchpad_acceleration_; FilePathPrefMember download_default_directory_; StringListPrefMember allowed_languages_;
diff --git a/chrome/browser/chromeos/preferences_chromeos_browsertest.cc b/chrome/browser/chromeos/preferences_chromeos_browsertest.cc index e8da9f8..3e77db75 100644 --- a/chrome/browser/chromeos/preferences_chromeos_browsertest.cc +++ b/chrome/browser/chromeos/preferences_chromeos_browsertest.cc
@@ -66,6 +66,8 @@ prefs->SetBoolean(prefs::kTapToClickEnabled, variant); prefs->SetBoolean(prefs::kPrimaryMouseButtonRight, !variant); prefs->SetBoolean(prefs::kMouseReverseScroll, variant); + prefs->SetBoolean(prefs::kMouseAcceleration, variant); + prefs->SetBoolean(prefs::kTouchpadAcceleration, variant); prefs->SetBoolean(prefs::kEnableTouchpadThreeFingerClick, !variant); prefs->SetBoolean(prefs::kNaturalScroll, variant); prefs->SetInteger(prefs::kMouseSensitivity, !variant); @@ -86,6 +88,10 @@ .GetPrimaryButtonRight()); EXPECT_EQ(prefs->GetBoolean(prefs::kMouseReverseScroll), input_settings_->current_mouse_settings().GetReverseScroll()); + EXPECT_EQ(prefs->GetBoolean(prefs::kMouseAcceleration), + input_settings_->current_mouse_settings().GetAcceleration()); + EXPECT_EQ(prefs->GetBoolean(prefs::kTouchpadAcceleration), + input_settings_->current_touchpad_settings().GetAcceleration()); EXPECT_EQ(prefs->GetBoolean(prefs::kEnableTouchpadThreeFingerClick), input_settings_->current_touchpad_settings() .GetThreeFingerClick());
diff --git a/chrome/browser/chromeos/system/fake_input_device_settings.cc b/chrome/browser/chromeos/system/fake_input_device_settings.cc index 4bbc76c..7160d46 100644 --- a/chrome/browser/chromeos/system/fake_input_device_settings.cc +++ b/chrome/browser/chromeos/system/fake_input_device_settings.cc
@@ -82,6 +82,18 @@ UpdateMouseSettings(settings); } +void FakeInputDeviceSettings::SetMouseAcceleration(bool enabled) { + MouseSettings settings; + settings.SetAcceleration(enabled); + UpdateMouseSettings(settings); +} + +void FakeInputDeviceSettings::SetTouchpadAcceleration(bool enabled) { + TouchpadSettings settings; + settings.SetAcceleration(enabled); + UpdateTouchpadSettings(settings); +} + void FakeInputDeviceSettings::ReapplyTouchpadSettings() { }
diff --git a/chrome/browser/chromeos/system/fake_input_device_settings.h b/chrome/browser/chromeos/system/fake_input_device_settings.h index 9f715b07..3111e96 100644 --- a/chrome/browser/chromeos/system/fake_input_device_settings.h +++ b/chrome/browser/chromeos/system/fake_input_device_settings.h
@@ -31,6 +31,8 @@ void SetMouseSensitivity(int value) override; void SetPrimaryButtonRight(bool right) override; void SetMouseReverseScroll(bool enabled) override; + void SetMouseAcceleration(bool enabled) override; + void SetTouchpadAcceleration(bool enabled) override; void SetNaturalScroll(bool enabled) override; void ReapplyTouchpadSettings() override; void ReapplyMouseSettings() override;
diff --git a/chrome/browser/chromeos/system/input_device_settings.cc b/chrome/browser/chromeos/system/input_device_settings.cc index 36a7547..413470d6 100644 --- a/chrome/browser/chromeos/system/input_device_settings.cc +++ b/chrome/browser/chromeos/system/input_device_settings.cc
@@ -39,6 +39,7 @@ three_finger_click_ = other.three_finger_click_; tap_dragging_ = other.tap_dragging_; natural_scroll_ = other.natural_scroll_; + acceleration_ = other.acceleration_; } return *this; } @@ -103,6 +104,18 @@ return tap_dragging_.has_value(); } +void TouchpadSettings::SetAcceleration(bool enabled) { + acceleration_ = enabled; +} + +bool TouchpadSettings::GetAcceleration() const { + return *acceleration_; +} + +bool TouchpadSettings::IsAccelerationSet() const { + return acceleration_.has_value(); +} + bool TouchpadSettings::Update(const TouchpadSettings& settings) { bool updated = false; if (UpdateIfHasValue(settings.sensitivity_, &sensitivity_)) @@ -113,6 +126,8 @@ updated = true; if (UpdateIfHasValue(settings.tap_dragging_, &tap_dragging_)) updated = true; + if (UpdateIfHasValue(settings.acceleration_, &acceleration_)) + updated = true; UpdateIfHasValue(settings.natural_scroll_, &natural_scroll_); // Always send natural scrolling to the shell command, as a workaround. // See crbug.com/406480 @@ -146,6 +161,10 @@ input_device_settings->SetNaturalScroll( touchpad_settings.natural_scroll_.value()); } + if (touchpad_settings.acceleration_.has_value()) { + input_device_settings->SetTouchpadAcceleration( + touchpad_settings.acceleration_.value()); + } } MouseSettings::MouseSettings() = default; @@ -157,6 +176,7 @@ sensitivity_ = other.sensitivity_; primary_button_right_ = other.primary_button_right_; reverse_scroll_ = other.reverse_scroll_; + acceleration_ = other.acceleration_; } return *this; } @@ -197,6 +217,18 @@ return reverse_scroll_.has_value(); } +void MouseSettings::SetAcceleration(bool enabled) { + acceleration_ = enabled; +} + +bool MouseSettings::GetAcceleration() const { + return *acceleration_; +} + +bool MouseSettings::IsAccelerationSet() const { + return acceleration_.has_value(); +} + bool MouseSettings::Update(const MouseSettings& settings) { bool updated = false; if (UpdateIfHasValue(settings.sensitivity_, &sensitivity_)) @@ -208,6 +240,9 @@ if (UpdateIfHasValue(settings.reverse_scroll_, &reverse_scroll_)) { updated = true; } + if (UpdateIfHasValue(settings.acceleration_, &acceleration_)) { + updated = true; + } return updated; } @@ -228,6 +263,10 @@ input_device_settings->SetMouseReverseScroll( mouse_settings.reverse_scroll_.value()); } + if (mouse_settings.acceleration_.has_value()) { + input_device_settings->SetMouseAcceleration( + mouse_settings.acceleration_.value()); + } } // static
diff --git a/chrome/browser/chromeos/system/input_device_settings.h b/chrome/browser/chromeos/system/input_device_settings.h index ec33073..bb08298a 100644 --- a/chrome/browser/chromeos/system/input_device_settings.h +++ b/chrome/browser/chromeos/system/input_device_settings.h
@@ -49,6 +49,10 @@ bool GetNaturalScroll() const; bool IsNaturalScrollSet() const; + void SetAcceleration(bool enabled); + bool GetAcceleration() const; + bool IsAccelerationSet() const; + // Updates |this| with |settings|. If at least one setting was updated returns // true. bool Update(const TouchpadSettings& settings); @@ -63,6 +67,7 @@ base::Optional<bool> three_finger_click_; base::Optional<bool> tap_dragging_; base::Optional<bool> natural_scroll_; + base::Optional<bool> acceleration_; }; // Auxiliary class used to update several mouse settings at a time. User @@ -89,6 +94,10 @@ bool GetReverseScroll() const; bool IsReverseScrollSet() const; + void SetAcceleration(bool enabled); + bool GetAcceleration() const; + bool IsAccelerationSet() const; + // Updates |this| with |settings|. If at least one setting was updated returns // true. bool Update(const MouseSettings& settings); @@ -101,6 +110,7 @@ base::Optional<int> sensitivity_; base::Optional<bool> primary_button_right_; base::Optional<bool> reverse_scroll_; + base::Optional<bool> acceleration_; }; // Interface for configuring input device settings. @@ -171,6 +181,12 @@ // Turns mouse reverse scrolling on/off. virtual void SetMouseReverseScroll(bool enabled) = 0; + // Turns mouse acceleration on/off. + virtual void SetMouseAcceleration(bool enabled) = 0; + + // Turns touchpad acceleration on/off. + virtual void SetTouchpadAcceleration(bool enabled) = 0; + // Reapplies previously set touchpad settings. virtual void ReapplyTouchpadSettings() = 0;
diff --git a/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc b/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc index 0a64967..baf1fb9c 100644 --- a/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc +++ b/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc
@@ -42,6 +42,8 @@ void SetMouseSensitivity(int value) override; void SetPrimaryButtonRight(bool right) override; void SetMouseReverseScroll(bool enabled) override; + void SetMouseAcceleration(bool enabled) override; + void SetTouchpadAcceleration(bool enabled) override; void ReapplyTouchpadSettings() override; void ReapplyMouseSettings() override; InputDeviceSettings::FakeInterface* GetFakeInterface() override; @@ -127,6 +129,16 @@ input_controller()->SetMouseReverseScroll(enabled); } +void InputDeviceSettingsImplOzone::SetMouseAcceleration(bool enabled) { + current_mouse_settings_.SetAcceleration(enabled); + input_controller()->SetMouseAcceleration(enabled); +} + +void InputDeviceSettingsImplOzone::SetTouchpadAcceleration(bool enabled) { + current_touchpad_settings_.SetAcceleration(enabled); + input_controller()->SetTouchpadAcceleration(enabled); +} + void InputDeviceSettingsImplOzone::ReapplyTouchpadSettings() { TouchpadSettings::Apply(current_touchpad_settings_, this); }
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc index 52eb6c9..ae6d1bf 100644 --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -553,6 +553,10 @@ settings_api::PrefType::PREF_TYPE_BOOLEAN; (*s_whitelist)[::prefs::kMouseReverseScroll] = settings_api::PrefType::PREF_TYPE_BOOLEAN; + (*s_whitelist)[::prefs::kMouseAcceleration] = + settings_api::PrefType::PREF_TYPE_BOOLEAN; + (*s_whitelist)[::prefs::kTouchpadAcceleration] = + settings_api::PrefType::PREF_TYPE_BOOLEAN; (*s_whitelist)[::prefs::kMouseSensitivity] = settings_api::PrefType::PREF_TYPE_NUMBER; (*s_whitelist)[::prefs::kLanguageRemapSearchKeyTo] =
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc index a908dfec55..6c950b9 100644 --- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -2527,7 +2527,10 @@ // An extension should be able to modify the request header for service worker // script by using WebRequest API. -IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, ServiceWorkerScript) { +// +// Disabled due to https://crbug.com/995763. +IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, + DISABLED_ServiceWorkerScript) { // The extension to be used in this test adds foo=bar request header. const char kScriptPath[] = "/echoheader_service_worker.js"; int served_service_worker_count = 0;
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 7433228..7a62605 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -39,6 +39,11 @@ "expiry_milestone": 81 }, { + "name": "allow-disable-mouse-acceleration", + "owners": [ "zentaro" ], + "expiry_milestone": 82 + }, + { "name": "allow-insecure-localhost", "owners": [ "security-dev" ], "expiry_milestone": 82 @@ -2075,7 +2080,7 @@ { "name": "fill-on-account-select-http", "owners": [ "jdoerrie" ], - "expiry_milestone": 76 + "expiry_milestone": 80 }, { "name": "focus-mode", @@ -2187,7 +2192,7 @@ { "name": "google-password-manager", "owners": [ "ioanap", "jdoerrie" ], - "expiry_milestone": 76 + "expiry_milestone": 82 }, { "name": "grid-layout-for-ntp-shortcuts",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 87d4934..b381081c 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -3061,6 +3061,11 @@ const char kAggregatedMlAppRankingDescription[] = "Use the aggregated ML model to rank the suggested apps."; +const char kAllowDisableMouseAccelerationName[] = + "Allow disabling mouse acceleration"; +const char kAllowDisableMouseAccelerationDescription[] = + "Shows a setting to disable mouse acceleration."; + const char kAppServiceAshName[] = "App Service Ash"; const char kAppServiceAshDescription[] = "Use the App Service to provide data to the Ash UI, such as the app list.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 1b73f59..b9b3f38 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1820,6 +1820,9 @@ extern const char kAggregatedMlAppRankingName[]; extern const char kAggregatedMlAppRankingDescription[]; +extern const char kAllowDisableMouseAccelerationName[]; +extern const char kAllowDisableMouseAccelerationDescription[]; + extern const char kAppServiceAshName[]; extern const char kAppServiceAshDescription[];
diff --git a/chrome/browser/notifications/scheduler/internal/impression_history_tracker.h b/chrome/browser/notifications/scheduler/internal/impression_history_tracker.h index 28ca55b..a49e3ad0 100644 --- a/chrome/browser/notifications/scheduler/internal/impression_history_tracker.h +++ b/chrome/browser/notifications/scheduler/internal/impression_history_tracker.h
@@ -38,6 +38,8 @@ virtual ~Delegate() = default; // Called when the impression data is updated. + // TODO(xingliu): Rename this, only need to call this when the background + // task needs to reschedule to another time. virtual void OnImpressionUpdated() = 0; private:
diff --git a/chrome/browser/notifications/scheduler/internal/impression_history_tracker_unittest.cc b/chrome/browser/notifications/scheduler/internal/impression_history_tracker_unittest.cc index 473de39..efc3ed3 100644 --- a/chrome/browser/notifications/scheduler/internal/impression_history_tracker_unittest.cc +++ b/chrome/browser/notifications/scheduler/internal/impression_history_tracker_unittest.cc
@@ -42,7 +42,14 @@ Impression CreateImpression(const base::Time& create_time, const std::string& guid) { Impression impression(SchedulerClientType::kTest1, guid, create_time); - impression.task_start_time = SchedulerTaskTime::kMorning; + return impression; +} + +Impression CreateImpression(const base::Time& create_time, + const std::string& guid, + UserFeedback feedback) { + Impression impression(SchedulerClientType::kTest1, guid, create_time); + impression.feedback = feedback; return impression; } @@ -152,8 +159,6 @@ } } - void SetNow(const char* now_str) { clock_.SetNow(now_str); } - const SchedulerConfig& config() const { return config_; } MockImpressionStore* store() { return store_; } MockDelegate* delegate() { return delegate_.get(); } @@ -232,7 +237,7 @@ Impression::CustomData()); VerifyClientStates(test_case); - SetNow(kTimeStr); + clock()->SetNow(kTimeStr); Impression::ImpressionResultMap impression_mapping = { {UserFeedback::kDismiss, ImpressionResult::kNegative}}; @@ -273,6 +278,40 @@ VerifyClientStates(test_case); } +// Verifies a consecutive dismiss will generate impression result. +TEST_F(ImpressionHistoryTrackerTest, ConsecutiveDismisses) { + TestCase test_case = CreateDefaultTestCase(); + clock()->SetNow(kTimeStr); + + // Construct 3 dismisses in a row, which will generate neutral impression + // result. + auto dismiss_0 = + CreateImpression(clock()->Now() - base::TimeDelta::FromDays(1), "guid0", + UserFeedback::kDismiss); + auto dismiss_1 = + CreateImpression(clock()->Now() - base::TimeDelta::FromMinutes(30), + "guid1", UserFeedback::kDismiss); + auto dismiss_2 = + CreateImpression(clock()->Now() - base::TimeDelta::FromMinutes(15), + "guid2", UserFeedback::kDismiss); + test_case.input.front().impressions = {dismiss_0, dismiss_1, dismiss_2}; + test_case.expected.front().impressions = test_case.input.front().impressions; + for (auto& impression : test_case.expected.front().impressions) { + impression.feedback = UserFeedback::kDismiss; + impression.impression = ImpressionResult::kNeutral; + impression.integrated = true; + } + + CreateTracker(test_case); + InitTrackerWithData(test_case); + EXPECT_CALL(*delegate(), OnImpressionUpdated()); + EXPECT_CALL(*store(), Update(_, _, _)); + UserActionData action_data(SchedulerClientType::kTest1, + UserActionType::kDismiss, "guid2"); + tracker()->OnUserAction(action_data); + VerifyClientStates(test_case); +} + // Defines the expected state of impression data after certain user action. struct UserActionTestParam { ImpressionResult impression_result = ImpressionResult::kInvalid;
diff --git a/chrome/browser/notifications/scheduler/public/notification_scheduler_types.h b/chrome/browser/notifications/scheduler/public/notification_scheduler_types.h index 6d54cbb..3b69178a 100644 --- a/chrome/browser/notifications/scheduler/public/notification_scheduler_types.h +++ b/chrome/browser/notifications/scheduler/public/notification_scheduler_types.h
@@ -49,29 +49,33 @@ enum class UserFeedback { // No user feedback yet. kNoFeedback = 0, - // The user taps the helpful button, potentially a strong indicator of user's - // positive preference on the notification. + // The user taps the helpful button. By default, generates positive + // ImpressionResult and may increase the notification display frequency. kHelpful = 1, - // The user taps the unhelpful button, potentially a strong indicator of - // user's negative preference on the notification. + // The user taps the unhelpful button. By default, generates negative + // ImpressionResult and may decrease the notification display frequency. kNotHelpful = 2, - // The user clicks the notification. + // The user clicks the notification. By default, generates positive + // ImpressionResult and may increase the notification display frequency. kClick = 3, - // The user clicks the body of the notification. + // The user dismisses notification. Only consecutive dismisses generates + // ImpressionResult. + // By default, generates neutral impression result and will not change the + // notification display frequency. kDismiss = 4, // The user has no interaction with the notification for a while. kIgnore = 5, kMaxValue = kIgnore }; -// The user impression of a particular notification, which may impact the +// The user impression result of a particular notification, which may impact the // notification display frenquency. enum class ImpressionResult { // Invalid user impression. kInvalid = 0, // Positive user impression that the user may like the notification. kPositive = 1, - // Positive user impression that the user may dislike the notification. + // Negative user impression that the user may dislike the notification. kNegative = 2, // The feedback is neutral to the user. kNeutral = 3,
diff --git a/chrome/browser/notifications/scheduler/test/test_utils.cc b/chrome/browser/notifications/scheduler/test/test_utils.cc index 0c9d3d0..0e66694 100644 --- a/chrome/browser/notifications/scheduler/test/test_utils.cc +++ b/chrome/browser/notifications/scheduler/test/test_utils.cc
@@ -125,7 +125,8 @@ for (const auto& impression : client_state->impressions) { std::ostringstream stream; - stream << "Impression, create_time:" << impression.create_time << "\n" + stream << "\n" + << "Impression, create_time:" << impression.create_time << "\n" << " create_time in microseconds:" << impression.create_time.ToDeltaSinceWindowsEpoch().InMicroseconds() << "\n"
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index 2e321e4..2fbc6d4 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -333,9 +333,6 @@ if (!CanShowBubbleOnURL(web_contents()->GetLastCommittedURL())) return false; #if defined(OS_ANDROID) - if (form_to_save->IsBlacklisted()) { - return false; - } // This class will delete itself after the dialog is dismissed. (new OnboardingDialogView(this, std::move(form_to_save)))->Show(); return true;
diff --git a/chrome/browser/password_manager/password_store_x_unittest.cc b/chrome/browser/password_manager/password_store_x_unittest.cc index 9dfcfe3..241c0ed1 100644 --- a/chrome/browser/password_manager/password_store_x_unittest.cc +++ b/chrome/browser/password_manager/password_store_x_unittest.cc
@@ -122,14 +122,14 @@ // Add existing credential into loginDB. It should be the only thing that's // available in the store. auto login_db = std::make_unique<password_manager::LoginDatabase>( - test_login_db_file_path()); + test_login_db_file_path(), /*is_account_store=*/false); ASSERT_TRUE(login_db->Init()); ignore_result(login_db->AddLogin(MakePasswordForm())); login_db.reset(); // Create the store. login_db = std::make_unique<password_manager::LoginDatabase>( - test_login_db_file_path()); + test_login_db_file_path(), /*is_account_store=*/false); scoped_refptr<PasswordStoreX> store = new PasswordStoreX(std::move(login_db), fake_pref_service()); store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); @@ -146,7 +146,8 @@ WaitForPasswordStore(); // Check if the database is encrypted. - password_manager::LoginDatabase login_db2(test_login_db_file_path()); + password_manager::LoginDatabase login_db2(test_login_db_file_path(), + /*is_account_store=*/false); // Disable encryption. login_db2.disable_encryption(); EXPECT_TRUE(login_db2.Init()); @@ -172,7 +173,7 @@ // Create the store with an empty database. auto login_db = std::make_unique<password_manager::LoginDatabase>( - test_login_db_file_path()); + test_login_db_file_path(), /*is_account_store=*/false); password_manager::LoginDatabase* login_db_ptr = login_db.get(); scoped_refptr<PasswordStoreX> store = @@ -189,7 +190,8 @@ WaitForPasswordStore(); // Check if the database is encrypted. - password_manager::LoginDatabase login_db2(test_login_db_file_path()); + password_manager::LoginDatabase login_db2(test_login_db_file_path(), + /*is_account_store=*/false); login_db2.disable_encryption(); EXPECT_TRUE(login_db2.Init()); // Read the password again. @@ -218,7 +220,7 @@ // Add existing credential into loginDB. auto existing_login = MakePasswordForm(); auto login_db = std::make_unique<password_manager::LoginDatabase>( - test_login_db_file_path()); + test_login_db_file_path(), /*is_account_store=*/false); login_db->disable_encryption(); ASSERT_TRUE(login_db->Init()); ignore_result(login_db->AddLogin(existing_login)); @@ -226,7 +228,7 @@ // Create the store with a non-empty database. login_db = std::make_unique<password_manager::LoginDatabase>( - test_login_db_file_path()); + test_login_db_file_path(), /*is_account_store=*/false); password_manager::LoginDatabase* login_db_ptr = login_db.get(); scoped_refptr<PasswordStoreX> store = @@ -245,7 +247,8 @@ WaitForPasswordStore(); // Check that the database is encrypted. - password_manager::LoginDatabase login_db2(test_login_db_file_path()); + password_manager::LoginDatabase login_db2(test_login_db_file_path(), + /*is_account_store=*/false); // Disable encryption and get the raw values. An encrypted database would have // read both encrypted and unencrypted entries. login_db2.disable_encryption();
diff --git a/chrome/browser/performance_manager/graph/policies/dynamic_tcmalloc_policy_linux_unittest.cc b/chrome/browser/performance_manager/graph/policies/dynamic_tcmalloc_policy_linux_unittest.cc index 5e8c3938..fdfbff0 100644 --- a/chrome/browser/performance_manager/graph/policies/dynamic_tcmalloc_policy_linux_unittest.cc +++ b/chrome/browser/performance_manager/graph/policies/dynamic_tcmalloc_policy_linux_unittest.cc
@@ -5,8 +5,6 @@ #include "chrome/browser/performance_manager/graph/policies/dynamic_tcmalloc_policy_linux.h" #include "base/allocator/buildflags.h" -#include "base/metrics/field_trial.h" -#include "base/metrics/field_trial_params.h" #include "base/task/post_task.h" #include "base/test/scoped_feature_list.h" #include "base/test/simple_test_tick_clock.h" @@ -78,40 +76,6 @@ DISALLOW_COPY_AND_ASSIGN(MockTcmallocTunablesImpl); }; -// ScopedExperimentalStateToggle allows us to set our experimental state so we -// can tweak params for testing. -class ScopedExperimentalStateToggle { - public: - ScopedExperimentalStateToggle(const std::string& feature_name, - base::FeatureList::OverrideState feature_state, - base::FieldTrialParams variation_params) - : field_trial_list_(nullptr /* entropy_provider */) { - constexpr const char kTestFieldTrialName[] = - "FieldTrialNameShouldNotMatter"; - constexpr const char kTestExperimentGroupName[] = - "GroupNameShouldNotMatter"; - - EXPECT_TRUE(base::AssociateFieldTrialParams( - kTestFieldTrialName, kTestExperimentGroupName, variation_params)); - base::FieldTrial* field_trial = base::FieldTrialList::CreateFieldTrial( - kTestFieldTrialName, kTestExperimentGroupName); - - std::unique_ptr<base::FeatureList> feature_list = - std::make_unique<base::FeatureList>(); - feature_list->RegisterFieldTrialOverride(feature_name, feature_state, - field_trial); - scoped_feature_list_.InitWithFeatureList(std::move(feature_list)); - } - - ~ScopedExperimentalStateToggle() {} - - private: - base::FieldTrialList field_trial_list_; - base::test::ScopedFeatureList scoped_feature_list_; - - DISALLOW_COPY_AND_ASSIGN(ScopedExperimentalStateToggle); -}; - class DynamicTcmallocPolicyTest : public ::testing::Test { public: DynamicTcmallocPolicyTest() @@ -277,9 +241,9 @@ // the frame has been invisible for longer than the cutoff time. TEST_F(DynamicTcmallocPolicyTest, OnlyApplyInvisibleScaleFactorAfterCutoff) { // Switch our experimental state so we can test certain behavior. - ScopedExperimentalStateToggle experimental_state_( - features::kDynamicTcmallocTuning.name, - base::FeatureList::OVERRIDE_ENABLE_FEATURE, + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + features::kDynamicTcmallocTuning, {{"DynamicTcmallocScaleInvisibleTimeSec", "240"}, {"DynamicTcmallocTuneTimeSec", "120"}});
diff --git a/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos.cc b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos.cc index 5bc234de..e08b80b2 100644 --- a/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos.cc +++ b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos.cc
@@ -50,16 +50,22 @@ void WorkingSetTrimmerPolicyChromeOS::TrimNodesOnGraph() { const base::TimeTicks now_ticks = base::TimeTicks::Now(); - for (const PageNode* node : graph_->GetAllPageNodes()) { - if (!node->IsVisible() && - node->GetTimeSinceLastVisibilityChange() > + for (const PageNode* page_node : graph_->GetAllPageNodes()) { + if (!page_node->IsVisible() && + page_node->GetTimeSinceLastVisibilityChange() > trim_on_memory_pressure_params_.node_invisible_time) { // Get the process node and if it has not been // trimmed within the backoff period, we will do that // now. - const ProcessNode* process_node = - node->GetMainFrameNode()->GetProcessNode(); - if (process_node->GetProcess().IsValid()) { + + // Check that we have a main frame. + const FrameNode* frame_node = page_node->GetMainFrameNode(); + if (!frame_node) { + continue; + } + + const ProcessNode* process_node = frame_node->GetProcessNode(); + if (process_node && process_node->GetProcess().IsValid()) { base::TimeTicks last_trim = GetLastTrimTime(process_node); if (now_ticks - last_trim > trim_on_memory_pressure_params_.node_trim_backoff_time) {
diff --git a/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos_unittest.cc b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos_unittest.cc index 6e68d77a..e49986d 100644 --- a/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos_unittest.cc +++ b/chrome/browser/performance_manager/graph/policies/working_set_trimmer_policy_chromeos_unittest.cc
@@ -173,6 +173,27 @@ EXPECT_NE(current_walk_time, initial_walk_time); } +// This test will validate that we skip a page node that doesn't have a main +// frame node. +TEST_F(WorkingSetTrimmerPolicyChromeOSTest, DontTrimIfNoMainFrame) { + // Create a lone page node. + auto page_node = CreateNode<PageNodeImpl>(); + + // Make sure the node is not visible for 1 day. + page_node->SetIsVisible(true); // Reset visibility and set invisible Now. + page_node->SetIsVisible(false); // Uses the testing clock. + FastForwardBy(base::TimeDelta::FromDays(1)); + + // We should not be called because we don't have a frame node or process node. + EXPECT_CALL(*policy(), TrimWorkingSet(testing::_)).Times(0); + + // Triger memory pressure and we should observe the walk. + policy()->listener().SimulatePressureNotification( + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE); + + FastForwardBy(base::TimeDelta::FromDays(1)); +} + // This test will validate that we WILL trim the working set if it has been // invisible long enough. TEST_F(WorkingSetTrimmerPolicyChromeOSTest, TrimIfInvisibleLongEnough) {
diff --git a/chrome/browser/performance_manager/graph/properties.h b/chrome/browser/performance_manager/graph/properties.h index 0ecdc2e4..72fe1a4 100644 --- a/chrome/browser/performance_manager/graph/properties.h +++ b/chrome/browser/performance_manager/graph/properties.h
@@ -78,6 +78,38 @@ private: PropertyType value_; }; + + // Same as NotifiesOnlyOnChanges, but provides the previous value when + // notifying observers. + template <typename PropertyType, + void (ObserverType::*NotifyFunctionPtr)( + const NodeType*, + PropertyType previous_value)> + class NotifiesOnlyOnChangesWithPreviousValue { + public: + NotifiesOnlyOnChangesWithPreviousValue() {} + explicit NotifiesOnlyOnChangesWithPreviousValue(PropertyType initial_value) + : value_(initial_value) {} + + ~NotifiesOnlyOnChangesWithPreviousValue() {} + + // Sets the property and sends a notification if needed. Returns true if a + // notification was sent, false otherwise. + bool SetAndMaybeNotify(NodeImplType* node, PropertyType value) { + if (value_ == value) + return false; + PropertyType previous_value = value_; + value_ = std::forward<PropertyType>(value); + for (auto* observer : node->GetObservers()) + ((observer)->*(NotifyFunctionPtr))(node, previous_value); + return true; + } + + const PropertyType& value() const { return value_; } + + private: + PropertyType value_; + }; }; } // namespace performance_manager
diff --git a/chrome/browser/performance_manager/graph/properties_unittest.cc b/chrome/browser/performance_manager/graph/properties_unittest.cc index 463e5985..5ad4e51 100644 --- a/chrome/browser/performance_manager/graph/properties_unittest.cc +++ b/chrome/browser/performance_manager/graph/properties_unittest.cc
@@ -21,6 +21,8 @@ MOCK_METHOD1(NotifyAlwaysConst, void(const DummyNode*)); MOCK_METHOD1(NotifyOnlyOnChangesConst, void(const DummyNode*)); + MOCK_METHOD2(NotifyOnlyOnChangesWithPreviousValueConst, + void(const DummyNode*, bool)); }; class DummyNode { @@ -43,6 +45,9 @@ bool observed_only_on_changes() const { return observed_only_on_changes_.value(); } + bool observed_only_on_changes_with_previous_value() const { + return observed_only_on_changes_with_previous_value_.value(); + } void SetObservedAlways(bool value) { observed_always_.SetAndNotify(this, value); @@ -50,18 +55,24 @@ bool SetObservedOnlyOnChanges(bool value) { return observed_only_on_changes_.SetAndMaybeNotify(this, value); } + bool SetObservedOnlyOnChangesWithPreviousValue(bool value) { + return observed_only_on_changes_with_previous_value_.SetAndMaybeNotify( + this, value); + } private: using ObservedProperty = ObservedPropertyImpl<DummyNode, DummyNode, DummyObserver>; - ObservedProperty::NotifiesAlways<bool, - &DummyObserver::NotifyAlwaysConst> + ObservedProperty::NotifiesAlways<bool, &DummyObserver::NotifyAlwaysConst> observed_always_{false}; - ObservedProperty::NotifiesOnlyOnChanges< + ObservedProperty:: + NotifiesOnlyOnChanges<bool, &DummyObserver::NotifyOnlyOnChangesConst> + observed_only_on_changes_{false}; + ObservedProperty::NotifiesOnlyOnChangesWithPreviousValue< bool, - &DummyObserver::NotifyOnlyOnChangesConst> - observed_only_on_changes_{false}; + &DummyObserver::NotifyOnlyOnChangesWithPreviousValueConst> + observed_only_on_changes_with_previous_value_{false}; base::ObserverList<DummyObserver>::Unchecked observers_; std::vector<DummyObserver*> new_observers_; @@ -121,4 +132,22 @@ testing::Mock::VerifyAndClear(&observer_); } +TEST_F(GraphPropertiesTest, ObservedOnlyOnChangesWithPreviousValueProperty) { + EXPECT_FALSE(node_.observed_only_on_changes_with_previous_value()); + + EXPECT_FALSE(node_.SetObservedOnlyOnChanges(false)); + EXPECT_EQ(false, node_.observed_only_on_changes_with_previous_value()); + + EXPECT_CALL(observer_, + NotifyOnlyOnChangesWithPreviousValueConst(&node_, false)); + EXPECT_TRUE(node_.SetObservedOnlyOnChangesWithPreviousValue(true)); + testing::Mock::VerifyAndClear(&observer_); + EXPECT_EQ(true, node_.observed_only_on_changes_with_previous_value()); + + EXPECT_FALSE(node_.SetObservedOnlyOnChangesWithPreviousValue(true)); + EXPECT_EQ(true, node_.observed_only_on_changes_with_previous_value()); + + testing::Mock::VerifyAndClear(&observer_); +} + } // namespace performance_manager
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc index 4a2aaef..888f9e3 100644 --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -110,6 +110,7 @@ #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/android_sms/android_sms_service_factory.h" #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h" +#include "chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher.h" #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h" #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h" #include "chrome/browser/chromeos/policy/user_cloud_policy_token_forwarder_factory.h" @@ -271,8 +272,9 @@ chromeos::SyncedPrintersManagerFactory::GetInstance(); chromeos::smb_client::SmbServiceFactory::GetInstance(); crostini::CrostiniRegistryServiceFactory::GetInstance(); - TetherServiceFactory::GetInstance(); + extensions::SessionStateChangedEventDispatcher::GetFactoryInstance(); extensions::VerifyTrustAPI::GetFactoryInstance(); + TetherServiceFactory::GetInstance(); #endif FaviconServiceFactory::GetInstance(); HistoryUiFaviconRequestHandlerFactory::GetInstance();
diff --git a/chrome/browser/resources/chromeos/camera/src/js/mojo/device_operator.js b/chrome/browser/resources/chromeos/camera/src/js/mojo/device_operator.js index 1343ce5..ae99b9f 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/mojo/device_operator.js +++ b/chrome/browser/resources/chromeos/camera/src/js/mojo/device_operator.js
@@ -235,6 +235,19 @@ } /** + * Sets the intent for the upcoming capture session. + * @param {string} deviceId The renderer-facing device id of the target camera + * which could be retrieved from MediaDeviceInfo.deviceId. + * @param {cros.mojom.CaptureIntent} captureIntent The purpose of this + * capture, to help the camera device decide optimal configurations. + * @return {!Promise} Promise for the operation. + */ + async setCaptureIntent(deviceId, captureIntent) { + const device = this.getDevice(deviceId); + await device.setCaptureIntent(captureIntent); + } + + /** * Checks if portrait mode is supported. * @param {string} deviceId The id for target device. * @return {!Promise<boolean>} Promise of the boolean result.
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js index 6765c76..4a577a7 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js
@@ -305,6 +305,8 @@ try { if (deviceOperator) { await deviceOperator.setFpsRange(deviceId, constraints); + await deviceOperator.setCaptureIntent( + deviceId, this.modes_.getCaptureIntent(mode)); } const stream = await navigator.mediaDevices.getUserMedia(constraints); if (!supportedModes) {
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js index fd97e99..b5bac6e 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js
@@ -128,6 +128,7 @@ resolutionConfig: videoPreferrer, v1Config: cca.views.camera.Modes.getV1Constraints.bind(this, true), nextMode: 'photo-mode', + captureIntent: cros.mojom.CaptureIntent.VIDEO_RECORD, }, 'photo-mode': { captureFactory: () => new cca.views.camera.Photo( @@ -136,6 +137,7 @@ resolutionConfig: photoResolPreferrer, v1Config: cca.views.camera.Modes.getV1Constraints.bind(this, false), nextMode: 'square-mode', + captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE, }, 'square-mode': { captureFactory: () => new cca.views.camera.Square( @@ -144,6 +146,7 @@ resolutionConfig: photoResolPreferrer, v1Config: cca.views.camera.Modes.getV1Constraints.bind(this, false), nextMode: 'portrait-mode', + captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE, }, 'portrait-mode': { captureFactory: () => new cca.views.camera.Portrait( @@ -159,6 +162,7 @@ resolutionConfig: photoResolPreferrer, v1Config: cca.views.camera.Modes.getV1Constraints.bind(this, false), nextMode: 'photo-mode', + captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE, }, }; @@ -291,6 +295,15 @@ }; /** + * Gets capture intent for the given mode. + * @param {string} mode + * @return {cros.mojom.CaptureIntent} Capture intent for the given mode. + */ +cca.views.camera.Modes.prototype.getCaptureIntent = function(mode) { + return this.allModes_[mode].captureIntent; +}; + +/** * Gets supported modes for video device of the given stream. * @param {MediaStream} stream Stream of the video device. * @return {Array<string>} Names of all supported mode for the video device.
diff --git a/chrome/browser/resources/chromeos/login/oobe_network.js b/chrome/browser/resources/chromeos/login/oobe_network.js index 597e8f6..683a8ade 100644 --- a/chrome/browser/resources/chromeos/login/oobe_network.js +++ b/chrome/browser/resources/chromeos/login/oobe_network.js
@@ -66,6 +66,10 @@ this.$.networkDialog.show(); }, + focus: function() { + this.$.networkDialog.focus(); + }, + /** Updates localized elements of the UI. */ updateLocalizedContent: function() { this.$.networkSelectLogin.setCrOncStrings();
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 3b7d3b42..67fc314 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
@@ -113,7 +113,7 @@ <div class="start"> <span>$i18nRaw{browserSettingsBannerText}</span> <!-- Use role="presentation" because the <span> has an accessible - link to settings.--> + link to settings.--> <a href="chrome://settings" target="_blank" tabindex="-1" role="presentation"> </a>
diff --git a/chrome/browser/resources/settings/device_page/pointers.html b/chrome/browser/resources/settings/device_page/pointers.html index 95301b1..fff070d 100644 --- a/chrome/browser/resources/settings/device_page/pointers.html +++ b/chrome/browser/resources/settings/device_page/pointers.html
@@ -22,8 +22,8 @@ .subsection > settings-toggle-button, .subsection > .settings-box { - padding-left: 0; - padding-right: 0; + padding-inline-end: 0; + padding-inline-start: 0; } </style> <div id="mouse" hidden$="[[!hasMouse]]"> @@ -43,6 +43,12 @@ pref="{{prefs.settings.mouse.reverse_scroll}}" label="$i18n{mouseReverseScroll}"> </settings-toggle-button> + <template is="dom-if" if="[[allowDisableAcceleration_]]"> + <settings-toggle-button id="mouseAcceleration" + pref="{{prefs.settings.mouse.acceleration}}" + label="$i18n{pointerAccelerationLabel}"> + </settings-toggle-button> + </template> <div class="settings-box"> <div class="start" id="mouseSpeedLabel">$i18n{mouseSpeed}</div> <settings-slider pref="{{prefs.settings.mouse.sensitivity2}}" @@ -66,6 +72,12 @@ pref="{{prefs.settings.touchpad.enable_tap_dragging}}" label="$i18n{tapDraggingLabel}"> </settings-toggle-button> + <template is="dom-if" if="[[allowDisableAcceleration_]]"> + <settings-toggle-button id="touchpadAcceleration" + pref="{{prefs.settings.touchpad.acceleration}}" + label="$i18n{pointerAccelerationLabel}"> + </settings-toggle-button> + </template> <div class="settings-box"> <div class="start" id="touchpadSpeedLabel">$i18n{touchpadSpeed}</div> <settings-slider id="touchpadSensitivity"
diff --git a/chrome/browser/resources/settings/device_page/pointers.js b/chrome/browser/resources/settings/device_page/pointers.js index 4414214..1db8739 100644 --- a/chrome/browser/resources/settings/device_page/pointers.js +++ b/chrome/browser/resources/settings/device_page/pointers.js
@@ -30,6 +30,17 @@ value: [1, 2, 3, 4, 5], readOnly: true, }, + + /** + * TODO(zentaro): Remove this conditional once the feature is launched. + * @private + */ + allowDisableAcceleration_: { + type: Boolean, + value: function() { + return loadTimeData.getBoolean('allowDisableMouseAcceleration'); + }, + }, }, // Used to correctly identify when the mouse button has been released.
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win_unittest.cc b/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win_unittest.cc index 6166e88..ba74f1e 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win_unittest.cc +++ b/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win_unittest.cc
@@ -8,46 +8,25 @@ #include <string> #include "base/metrics/field_trial.h" +#include "base/test/scoped_feature_list.h" #include "base/win/windows_version.h" -#include "components/variations/variations_params_manager.h" #include "testing/gtest/include/gtest/gtest.h" namespace safe_browsing { class SRTDownloadURLTest : public ::testing::Test { protected: - void CreatePromptTrial(const std::string& experiment_name) { - // Assigned trials will go out of scope when variations_ goes out of scope. - constexpr char kTrialName[] = "SRTPromptFieldTrial"; - base::FieldTrialList::CreateFieldTrial(kTrialName, experiment_name); - } - void CreateDownloadFeature(const std::string& download_group_name) { - constexpr char kFeatureName[] = "ChromeCleanupDistribution"; - std::map<std::string, std::string> params; + base::FieldTrialParams params; params["cleaner_download_group"] = download_group_name; - variations_.SetVariationParamsWithFeatureAssociations( - "A trial name", params, {kFeatureName}); + scoped_feature_list_.InitAndEnableFeatureWithParameters( + kChromeCleanupDistributionFeature, params); } private: - variations::testing::VariationParamsManager variations_; + base::test::ScopedFeatureList scoped_feature_list_; }; -TEST_F(SRTDownloadURLTest, Stable) { - CreatePromptTrial("On"); - std::string expected_path; - if (base::win::OSInfo::GetArchitecture() == - base::win::OSInfo::X86_ARCHITECTURE) { - expected_path = - "/dl/softwareremovaltool/win/x86/stable/chrome_cleanup_tool.exe"; - } else { - expected_path = - "/dl/softwareremovaltool/win/x64/stable/chrome_cleanup_tool.exe"; - } - EXPECT_EQ(expected_path, GetSRTDownloadURL().path()); -} - TEST_F(SRTDownloadURLTest, Experiment) { CreateDownloadFeature("experiment"); std::string expected_path;
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc index e44f73d..4c515e5 100644 --- a/chrome/browser/sync/chrome_sync_client.cc +++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -14,7 +14,6 @@ #include "base/syslog_logging.h" #include "base/task/post_task.h" #include "build/build_config.h" -#include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/consent_auditor/consent_auditor_factory.h" #include "chrome/browser/dom_distiller/dom_distiller_service_factory.h" @@ -272,11 +271,6 @@ return SessionSyncServiceFactory::GetForProfile(profile_); } -autofill::PersonalDataManager* ChromeSyncClient::GetPersonalDataManager() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - return autofill::PersonalDataManagerFactory::GetForProfile(profile_); -} - base::Closure ChromeSyncClient::GetPasswordStateChangedCallback() { return base::Bind( &PasswordStoreFactory::OnPasswordsSyncedStatePotentiallyChanged,
diff --git a/chrome/browser/sync/chrome_sync_client.h b/chrome/browser/sync/chrome_sync_client.h index 5282d0f..a85b52e 100644 --- a/chrome/browser/sync/chrome_sync_client.h +++ b/chrome/browser/sync/chrome_sync_client.h
@@ -51,7 +51,6 @@ base::Closure GetPasswordStateChangedCallback() override; syncer::DataTypeController::TypeVector CreateDataTypeControllers( syncer::SyncService* sync_service) override; - autofill::PersonalDataManager* GetPersonalDataManager() override; invalidation::InvalidationService* GetInvalidationService() override; BookmarkUndoService* GetBookmarkUndoService() override; scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index a72290f9..381a060 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1199,6 +1199,8 @@ "webui/constrained_web_dialog_delegate_base.h", "webui/devtools_ui.cc", "webui/devtools_ui.h", + "webui/devtools_ui_data_source.cc", + "webui/devtools_ui_data_source.h", "webui/downloads/downloads_dom_handler.cc", "webui/downloads/downloads_dom_handler.h", "webui/downloads/downloads_list_tracker.cc", @@ -2479,6 +2481,7 @@ "views/frame/browser_desktop_window_tree_host_platform.h", "views/frame/native_browser_frame_factory_ozone.cc", ] + deps += [ "//ui/platform_window" ] } if (use_gtk) { # This is the only component that can interact with gtk.
diff --git a/chrome/browser/ui/android/passwords/onboarding_dialog_view.cc b/chrome/browser/ui/android/passwords/onboarding_dialog_view.cc index 86fa328c..c930aef 100644 --- a/chrome/browser/ui/android/passwords/onboarding_dialog_view.cc +++ b/chrome/browser/ui/android/passwords/onboarding_dialog_view.cc
@@ -6,6 +6,7 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" +#include "base/metrics/field_trial_params.h" #include "base/strings/string16.h" #include "chrome/android/chrome_jni_headers/OnboardingDialogBridge_jni.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h" @@ -14,11 +15,51 @@ #include "components/password_manager/core/browser/password_form_manager_for_ui.h" #include "components/password_manager/core/browser/password_manager_metrics_util.h" #include "components/password_manager/core/browser/password_manager_onboarding.h" +#include "components/password_manager/core/common/password_manager_features.h" #include "components/password_manager/core/common/password_manager_pref_names.h" #include "components/prefs/pref_service.h" #include "ui/android/window_android.h" #include "ui/base/l10n/l10n_util.h" +namespace { + +// Story centered on your password being available on multiple devices. +constexpr char kStoryB[] = "access"; +// Story centered on password safety and leak detection. +constexpr char kStoryC[] = "safety"; + +// Retrieve the title and explanation strings that will be used for the +// dialog from the |story| parameter of the |kPasswordManagerOnboardingAndroid| +// feature, which will be provided when running experiments. +// The first story is run if the parameter isn't provided. +std::pair<base::string16, base::string16> GetOnboardingTitleAndDetails() { + std::string story = base::GetFieldTrialParamValueByFeature( + password_manager::features::kPasswordManagerOnboardingAndroid, "story"); + + // By default the story centered on not having to remember your password is + // shown. + base::string16 onboarding_title = + l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_ONBOARDING_TITLE_A); + base::string16 onboarding_details = + l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_ONBOARDING_DETAILS_A); + + if (story == kStoryB) { + onboarding_title = + l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_ONBOARDING_TITLE_B); + onboarding_details = + l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_ONBOARDING_DETAILS_B); + } else if (story == kStoryC) { + onboarding_title = + l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_ONBOARDING_TITLE_C); + onboarding_details = + l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_ONBOARDING_DETAILS_C); + } + + return {onboarding_title, onboarding_details}; +} + +} // namespace + OnboardingDialogView::OnboardingDialogView( ChromePasswordManagerClient* client, std::unique_ptr<password_manager::PasswordFormManagerForUI> form_to_save) @@ -36,10 +77,9 @@ java_object_.Reset(Java_OnboardingDialogBridge_create( env, window_android->GetJavaObject(), reinterpret_cast<intptr_t>(this))); - base::string16 onboarding_title = - l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_ONBOARDING_TITLE_A); - base::string16 onboarding_details = - l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_ONBOARDING_DETAILS_A); + base::string16 onboarding_title, onboarding_details; + std::tie(onboarding_title, onboarding_details) = + GetOnboardingTitleAndDetails(); Java_OnboardingDialogBridge_showDialog( env, java_object_,
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc index a5b0001..7fb95c0 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -77,7 +77,6 @@ #include "ui/events/event_constants.h" #include "ui/gfx/animation/slide_animation.h" #include "ui/gfx/canvas.h" -#include "ui/gfx/color_utils.h" #include "ui/gfx/favicon_size.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/rect.h" @@ -947,7 +946,9 @@ ui::PaintRecorder recorder(paint_info.context(), size()); // TODO(sky/glen): make me pretty! - recorder.canvas()->FillRect(indicator_bounds, GetBookmarkBarTextColor()); + recorder.canvas()->FillRect( + indicator_bounds, + GetThemeProvider()->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)); } } @@ -1559,13 +1560,14 @@ button->SetAccessibleName(node->GetTitle()); button->SetID(VIEW_ID_BOOKMARK_BAR_ELEMENT); // We don't always have a theme provider (ui tests, for example). + SkColor text_color = gfx::kPlaceholderColor; const ui::ThemeProvider* const tp = GetThemeProvider(); if (tp) { - SkColor color = GetBookmarkBarTextColor(); - button->SetEnabledTextColors(color); + text_color = tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT); + button->SetEnabledTextColors(text_color); if (node->is_folder()) { button->SetImage(views::Button::STATE_NORMAL, - chrome::GetBookmarkFolderIcon(color)); + chrome::GetBookmarkFolderIcon(text_color)); } } @@ -1581,8 +1583,8 @@ // This favicon currently does not match the default favicon icon used // elsewhere in the codebase. // See https://crbug/814447 - const gfx::ImageSkia icon = gfx::CreateVectorIcon( - kDefaultTouchFaviconIcon, GetBookmarkBarTextColor()); + const gfx::ImageSkia icon = + gfx::CreateVectorIcon(kDefaultTouchFaviconIcon, text_color); const gfx::ImageSkia mask = gfx::CreateVectorIcon(kDefaultTouchFaviconMaskIcon, SK_ColorBLACK); favicon = gfx::ImageSkiaOperations::CreateMaskedImage(icon, mask); @@ -1592,12 +1594,10 @@ themify_icon = true; } - if (themify_icon && GetThemeProvider() && - GetThemeProvider()->HasCustomColor( - ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON)) { + if (themify_icon && tp && + tp->HasCustomColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON)) { favicon = gfx::ImageSkiaOperations::CreateColorMask( - favicon, GetThemeProvider()->GetColor( - ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON)); + favicon, tp->GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON)); } button->SetImage(views::Button::STATE_NORMAL, favicon); @@ -1911,7 +1911,8 @@ bookmark_buttons_[i]); } - const SkColor color = GetBookmarkBarTextColor(); + const SkColor color = + theme_provider->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT); other_bookmarks_button_->SetEnabledTextColors(color); other_bookmarks_button_->SetImage(views::Button::STATE_NORMAL, chrome::GetBookmarkFolderIcon(color)); @@ -2011,11 +2012,3 @@ return size_t{it - bookmark_buttons_.cbegin()}; } - -SkColor BookmarkBarView::GetBookmarkBarTextColor() { - const ui::ThemeProvider* theme_provider = GetThemeProvider(); - return color_utils::BlendForMinContrast( - theme_provider->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT), - theme_provider->GetColor(ThemeProperties::COLOR_TOOLBAR)) - .color; -}
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h index f474142..e7a41fa 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h
@@ -370,9 +370,6 @@ // or size_t{-1} if |button| is not a bookmark button from this bar. size_t GetIndexForButton(views::View* button); - // Returns the color that should be used to draw text on the bookmark bar. - SkColor GetBookmarkBarTextColor(); - // Needed to react to kShowAppsShortcutInBookmarkBar changes. PrefChangeRegistrar profile_pref_registrar_;
diff --git a/chrome/browser/ui/views/frame/browser_view_unittest.cc b/chrome/browser/ui/views/frame/browser_view_unittest.cc index b8a4bc09..bc7e78bb 100644 --- a/chrome/browser/ui/views/frame/browser_view_unittest.cc +++ b/chrome/browser/ui/views/frame/browser_view_unittest.cc
@@ -211,7 +211,14 @@ #endif // !defined(OS_MACOSX) // Test that bookmark bar view becomes invisible when closing the browser. -TEST_F(BrowserViewTest, BookmarkBarInvisibleOnShutdown) { +// TODO(https://crbug.com/1000251): Flaky on Linux. +#if defined(OS_LINUX) +#define MAYBE_BookmarkBarInvisibleOnShutdown \ + DISABLED_BookmarkBarInvisibleOnShutdown +#else +#define MAYBE_BookmarkBarInvisibleOnShutdown BookmarkBarInvisibleOnShutdown +#endif +TEST_F(BrowserViewTest, MAYBE_BookmarkBarInvisibleOnShutdown) { BookmarkBarView::DisableAnimationsForTesting(true); Browser* browser = browser_view()->browser();
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc index 9ea74ab..c40f06c3 100644 --- a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc +++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
@@ -160,8 +160,9 @@ DISALLOW_COPY_AND_ASSIGN(MediaDialogViewBrowserTest); }; -#if defined(OS_MACOSX) +#if defined(OS_MACOSX) || defined(OS_WIN) // TODO(https://crbug.com/998342): Fix these on Mac. +// Deterministic Failures on Windows: https://crbug.com/1000215 #define MAYBE_ShowsMetadataAndControlsMedia \ DISABLED_ShowsMetadataAndControlsMedia #else
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view.cc b/chrome/browser/ui/views/intent_picker_bubble_view.cc index 53aa438..14eebe1e 100644 --- a/chrome/browser/ui/views/intent_picker_bubble_view.cc +++ b/chrome/browser/ui/views/intent_picker_bubble_view.cc
@@ -131,7 +131,7 @@ Browser* browser = chrome::FindBrowserWithWebContents(web_contents); if (!browser || !BrowserView::GetBrowserViewForBrowser(browser)) { std::move(intent_picker_cb) - .Run(kInvalidLaunchName, apps::mojom::AppType::kUnknown, + .Run(kInvalidLaunchName, apps::PickerEntryType::kUnknown, apps::IntentPickerCloseReason::ERROR_BEFORE_PICKER, false); return nullptr; } @@ -208,7 +208,7 @@ #endif bool should_persist = remember_selection_checkbox_ && remember_selection_checkbox_->GetChecked(); - RunCallback(launch_name, apps::mojom::AppType::kUnknown, + RunCallback(launch_name, apps::PickerEntryType::kUnknown, apps::IntentPickerCloseReason::STAY_IN_CHROME, should_persist); return true; } @@ -216,7 +216,7 @@ bool IntentPickerBubbleView::Close() { // Whenever closing the bubble without pressing |Just once| or |Always| we // need to report back that the user didn't select anything. - RunCallback(kInvalidLaunchName, apps::mojom::AppType::kUnknown, + RunCallback(kInvalidLaunchName, apps::PickerEntryType::kUnknown, apps::IntentPickerCloseReason::DIALOG_DEACTIVATED, false); return true; } @@ -267,7 +267,7 @@ // If the widget gets closed without an app being selected we still need to use // the callback so the caller can Resume the navigation. void IntentPickerBubbleView::OnWidgetDestroying(views::Widget* widget) { - RunCallback(kInvalidLaunchName, apps::mojom::AppType::kUnknown, + RunCallback(kInvalidLaunchName, apps::PickerEntryType::kUnknown, apps::IntentPickerCloseReason::DIALOG_DEACTIVATED, false); } @@ -403,13 +403,13 @@ void IntentPickerBubbleView::RunCallback( const std::string& launch_name, - apps::mojom::AppType app_type, + apps::PickerEntryType entry_type, apps::IntentPickerCloseReason close_reason, bool should_persist) { if (!intent_picker_cb_.is_null()) { // Calling Run() will make |intent_picker_cb_| null. std::move(intent_picker_cb_) - .Run(launch_name, app_type, close_reason, should_persist); + .Run(launch_name, entry_type, close_reason, should_persist); } intent_picker_bubble_ = nullptr; @@ -451,7 +451,7 @@ // TODO(crbug.com/826982): allow PWAs to have their decision persisted when // there is a central Chrome OS apps registry to store persistence. const bool should_enable = - app_info_[selected_app_tag_].type != apps::mojom::AppType::kWeb; + app_info_[selected_app_tag_].type != apps::PickerEntryType::kWeb; // Reset the checkbox state to the default unchecked if becomes disabled. if (!should_enable)
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view.h b/chrome/browser/ui/views/intent_picker_bubble_view.h index 267e601..ca6c998 100644 --- a/chrome/browser/ui/views/intent_picker_bubble_view.h +++ b/chrome/browser/ui/views/intent_picker_bubble_view.h
@@ -134,7 +134,7 @@ // the internal ScrollView. IntentPickerLabelButton* GetIntentPickerLabelButtonAt(size_t index); void RunCallback(const std::string& launch_name, - apps::mojom::AppType app_type, + apps::PickerEntryType entry_type, apps::IntentPickerCloseReason close_reason, bool should_persist);
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc b/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc index 3202fee..e6fb3f15 100644 --- a/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc +++ b/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc
@@ -64,13 +64,13 @@ anchor_view_ = std::make_unique<views::View>(); // Pushing a couple of fake apps just to check they are created on the UI. - app_info_.emplace_back(apps::mojom::AppType::kArc, gfx::Image(), + app_info_.emplace_back(apps::PickerEntryType::kArc, gfx::Image(), "package_1", "dank app 1"); - app_info_.emplace_back(apps::mojom::AppType::kArc, gfx::Image(), + app_info_.emplace_back(apps::PickerEntryType::kArc, gfx::Image(), "package_2", "dank_app_2"); // Also adding the corresponding Chrome's package name on ARC, even if this // is given to the picker UI as input it should be ignored. - app_info_.emplace_back(apps::mojom::AppType::kArc, gfx::Image(), + app_info_.emplace_back(apps::PickerEntryType::kArc, gfx::Image(), kArcIntentHelperPackageName, "legit_chrome"); if (use_icons) @@ -109,7 +109,7 @@ // Dummy method to be called upon bubble closing. void OnBubbleClosed(const std::string& selected_app_package, - apps::mojom::AppType app_type, + apps::PickerEntryType entry_type, apps::IntentPickerCloseReason close_reason, bool should_persist) {}
diff --git a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc index c5c66ca..a80858e0 100644 --- a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc +++ b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
@@ -36,7 +36,7 @@ namespace { const int kHorizontalMargin = 10; -const float kWindowAlphaValue = 0.85f; +const float kWindowAlphaValue = 0.96f; const int kPaddingVertical = 5; const int kPaddingHorizontal = 10;
diff --git a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.cc b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.cc index 8cecf26..64c27eb8 100644 --- a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.cc +++ b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/sad_tab_helper.h" #include "chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "components/infobars/core/infobar.h" @@ -208,6 +209,33 @@ } } +void TabSharingUIViews::TabChangedAt(content::WebContents* contents, + int index, + TabChangeType change_type) { + // Sad tab cannot be shared so don't create an infobar for it. + auto* sad_tab_helper = SadTabHelper::FromWebContents(contents); + if (sad_tab_helper && sad_tab_helper->sad_tab()) + return; + + if (infobars_.find(contents) == infobars_.end()) + CreateInfobarForWebContents(contents); +} + +void TabSharingUIViews::OnInfoBarRemoved(infobars::InfoBar* info_bar, + bool animate) { + auto infobars_entry = std::find_if(infobars_.begin(), infobars_.end(), + [info_bar](const auto& infobars_entry) { + return infobars_entry.second == info_bar; + }); + if (infobars_entry == infobars_.end()) + return; + + info_bar->owner()->RemoveObserver(this); + infobars_.erase(infobars_entry); + if (infobars_entry->first == shared_tab_) + StopSharing(); +} + void TabSharingUIViews::CreateInfobarsForAllTabs() { BrowserList* browser_list = BrowserList::GetInstance(); for (auto* browser : *browser_list) { @@ -223,8 +251,10 @@ void TabSharingUIViews::CreateInfobarForWebContents( content::WebContents* contents) { + auto* infobar_service = InfoBarService::FromWebContents(contents); + infobar_service->AddObserver(this); infobars_[contents] = TabSharingInfoBarDelegate::Create( - InfoBarService::FromWebContents(contents), + infobar_service, shared_tab_ == contents ? base::string16() : shared_tab_name_, app_name_, !source_callback_.is_null() /*is_sharing_allowed*/, this); } @@ -233,8 +263,10 @@ BrowserList::GetInstance()->RemoveObserver(this); TabStripModelObserver::StopObservingAll(this); - for (const auto& infobars_entry : infobars_) + for (const auto& infobars_entry : infobars_) { + infobars_entry.second->owner()->RemoveObserver(this); infobars_entry.second->RemoveSelf(); + } infobars_.clear(); }
diff --git a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.h b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.h index 68210f2..c28f98a 100644 --- a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.h +++ b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.h
@@ -30,7 +30,8 @@ class TabSharingUIViews : public TabSharingUI, public BrowserListObserver, - public TabStripModelObserver { + public TabStripModelObserver, + public infobars::InfoBarManager::Observer { public: TabSharingUIViews(const content::DesktopMediaID& media_id, base::string16 app_name); @@ -61,6 +62,12 @@ TabStripModel* tab_strip_model, const TabStripModelChange& change, const TabStripSelectionChange& selection) override; + void TabChangedAt(content::WebContents* contents, + int index, + TabChangeType change_type) override; + + // InfoBarManager::Observer: + void OnInfoBarRemoved(infobars::InfoBar* infobar, bool animate) override; private: void CreateInfobarsForAllTabs();
diff --git a/chrome/browser/ui/views/tabs/tab_style_views.cc b/chrome/browser/ui/views/tabs/tab_style_views.cc index 37c1ee9..df96f7b 100644 --- a/chrome/browser/ui/views/tabs/tab_style_views.cc +++ b/chrome/browser/ui/views/tabs/tab_style_views.cc
@@ -31,6 +31,15 @@ // Opacity of the active tab background painted over inactive selected tabs. constexpr float kSelectedTabOpacity = 0.75f; +// How the tab shape path is modified for selected tabs. +using ShapeModifier = int; +// No modification should be done. +constexpr ShapeModifier kNone = 0x00; +// Exclude the lower left arc. +constexpr ShapeModifier kNoLowerLeftArc = 0x01; +// Exclude the lower right arc. +constexpr ShapeModifier kNoLowerRightArc = 0x02; + // Tab style implementation for the GM2 refresh (Chrome 69). class GM2TabStyle : public TabStyleViews { public: @@ -87,6 +96,12 @@ SkColor GetTabBackgroundColor(TabActive active) const; + // When selected, non-active, non-hovered tabs are adjacent to each other, + // there are anti-aliasing artifacts in the overlapped lower arc region. This + // returns how to modify the tab shape to eliminate the lower arcs on the + // right or left based on the state of the adjacent tab(s). + ShapeModifier GetShapeModifier(PathType path_type) const; + // Painting helper functions: void PaintInactiveTabBackground(gfx::Canvas* canvas, const SkPath& clip) const; @@ -223,8 +238,11 @@ tab_bottom -= stroke_adjustment; bottom_radius -= stroke_adjustment; } + const ShapeModifier shape_modifier = GetShapeModifier(path_type); const bool extend_to_top = (path_type == PathType::kHitTest) && ShouldExtendHitTest(); + const bool extend_left_to_bottom = shape_modifier & kNoLowerLeftArc; + const bool extend_right_to_bottom = shape_modifier & kNoLowerRightArc; // When the radius shrinks, it leaves a gap between the bottom corners and the // edge of the tab. Make sure we account for this - and for any adjustment we @@ -262,14 +280,18 @@ // ┏━╯ ╰─┐ path.moveTo(left, extended_bottom); path.lineTo(left, tab_bottom); - path.lineTo(left + corner_gap, tab_bottom); - // Draw the bottom-left arc. + // Draw the bottom-left arc if not excluded. // ╭─────────╮ // │ Content │ // ┌─╝ ╰─┐ - path.arcTo(bottom_radius, bottom_radius, 0, SkPath::kSmall_ArcSize, - SkPath::kCCW_Direction, tab_left, tab_bottom - bottom_radius); + if (extend_left_to_bottom) { + path.lineTo(left + corner_gap + bottom_radius, tab_bottom); + } else { + path.lineTo(left + corner_gap, tab_bottom); + path.arcTo(bottom_radius, bottom_radius, 0, SkPath::kSmall_ArcSize, + SkPath::kCCW_Direction, tab_left, tab_bottom - bottom_radius); + } // Draw the ascender and top arc, if present. if (extend_to_top) { @@ -306,9 +328,13 @@ // ╭─────────╮ // │ Content ┃ // ┌─╯ ╚─┐ - path.lineTo(tab_right, tab_bottom - bottom_radius); - path.arcTo(bottom_radius, bottom_radius, 0, SkPath::kSmall_ArcSize, - SkPath::kCCW_Direction, right - corner_gap, tab_bottom); + if (extend_right_to_bottom) { + path.lineTo(tab_right, tab_bottom); + } else { + path.lineTo(tab_right, tab_bottom - bottom_radius); + path.arcTo(bottom_radius, bottom_radius, 0, SkPath::kSmall_ArcSize, + SkPath::kCCW_Direction, right - corner_gap, tab_bottom); + } // Draw everything right of the bottom-right corner of the tab. // ╭─────────╮ @@ -632,6 +658,24 @@ return color; } +ShapeModifier GM2TabStyle::GetShapeModifier(PathType path_type) const { + ShapeModifier shape_modifier = kNone; + if (path_type == PathType::kFill && tab_->IsSelected() && !IsHoverActive() && + !tab_->IsActive()) { + auto check_adjacent_tab = [](const Tab* tab, int offset, + ShapeModifier modifier) { + const Tab* adjacent_tab = tab->controller()->GetAdjacentTab(tab, offset); + if (adjacent_tab && adjacent_tab->IsSelected() && + !adjacent_tab->IsMouseHovered()) + return modifier; + return kNone; + }; + shape_modifier |= check_adjacent_tab(tab_, -1, kNoLowerLeftArc); + shape_modifier |= check_adjacent_tab(tab_, 1, kNoLowerRightArc); + } + return shape_modifier; +} + void GM2TabStyle::PaintInactiveTabBackground(gfx::Canvas* canvas, const SkPath& clip) const { PaintTabBackground(canvas, TabActive::kInactive,
diff --git a/chrome/browser/ui/webui/devtools_ui.cc b/chrome/browser/ui/webui/devtools_ui.cc index 6f16167..5217a31 100644 --- a/chrome/browser/ui/webui/devtools_ui.cc +++ b/chrome/browser/ui/webui/devtools_ui.cc
@@ -4,419 +4,16 @@ #include "chrome/browser/ui/webui/devtools_ui.h" -#include <list> -#include <utility> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/files/file_util.h" -#include "base/macros.h" -#include "base/memory/ref_counted_memory.h" -#include "base/path_service.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/task/post_task.h" #include "chrome/browser/devtools/url_constants.h" -#include "chrome/common/chrome_paths.h" +#include "chrome/browser/ui/webui/devtools_ui_data_source.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/url_constants.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/devtools_frontend_host.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/url_data_source.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" #include "content/public/common/user_agent.h" -#include "net/base/filename_util.h" #include "net/base/load_flags.h" -#include "net/traffic_annotation/network_traffic_annotation.h" -#include "services/network/public/cpp/resource_request.h" -#include "services/network/public/cpp/simple_url_loader.h" -#include "third_party/blink/public/public_buildflags.h" - -using content::BrowserThread; -using content::WebContents; - -namespace { - -std::string PathWithoutParams(const std::string& path) { - return GURL(std::string("devtools://devtools/") + path).path().substr(1); -} - -scoped_refptr<base::RefCountedMemory> CreateNotFoundResponse() { - const char kHttpNotFound[] = "HTTP/1.1 404 Not Found\n\n"; - return base::MakeRefCounted<base::RefCountedStaticMemory>( - kHttpNotFound, strlen(kHttpNotFound)); -} - -// DevToolsDataSource --------------------------------------------------------- - -std::string GetMimeTypeForPath(const std::string& path) { - std::string filename = PathWithoutParams(path); - if (base::EndsWith(filename, ".html", base::CompareCase::INSENSITIVE_ASCII)) { - return "text/html"; - } else if (base::EndsWith(filename, ".css", - base::CompareCase::INSENSITIVE_ASCII)) { - return "text/css"; - } else if (base::EndsWith(filename, ".js", - base::CompareCase::INSENSITIVE_ASCII)) { - return "application/javascript"; - } else if (base::EndsWith(filename, ".png", - base::CompareCase::INSENSITIVE_ASCII)) { - return "image/png"; - } else if (base::EndsWith(filename, ".gif", - base::CompareCase::INSENSITIVE_ASCII)) { - return "image/gif"; - } else if (base::EndsWith(filename, ".svg", - base::CompareCase::INSENSITIVE_ASCII)) { - return "image/svg+xml"; - } else if (base::EndsWith(filename, ".manifest", - base::CompareCase::INSENSITIVE_ASCII)) { - return "text/cache-manifest"; - } - return "text/html"; -} - -// An URLDataSource implementation that handles devtools://devtools/ -// requests. Three types of requests could be handled based on the URL path: -// 1. /bundled/: bundled DevTools frontend is served. -// when built with debug_devtools=true, the path can be provided via -// --custom-devtools-frontend. -// 2. /remote/: remote DevTools frontend is served from App Engine. -// 3. /custom/: custom DevTools frontend is served from the server as specified -// by the --custom-devtools-frontend flag. -class DevToolsDataSource : public content::URLDataSource { - public: - using GotDataCallback = content::URLDataSource::GotDataCallback; - - explicit DevToolsDataSource( - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) - : url_loader_factory_(std::move(url_loader_factory)) {} - ~DevToolsDataSource() override = default; - - // content::URLDataSource implementation. - std::string GetSource() override; - - void StartDataRequest(const std::string& path, - const content::WebContents::Getter& wc_getter, - const GotDataCallback& callback) override; - - private: - struct PendingRequest; - - // content::URLDataSource overrides. - std::string GetMimeType(const std::string& path) override; - bool ShouldAddContentSecurityPolicy() override; - bool ShouldDenyXFrameOptions() override; - bool ShouldServeMimeTypeAsContentTypeHeader() override; - - void OnLoadComplete(std::list<PendingRequest>::iterator request_iter, - std::unique_ptr<std::string> response_body); - - // Serves bundled DevTools frontend from ResourceBundle. - void StartBundledDataRequest(const std::string& path, - const GotDataCallback& callback); - - // Serves remote DevTools frontend from hard-coded App Engine domain. - void StartRemoteDataRequest(const GURL& url, const GotDataCallback& callback); - - // Serves remote DevTools frontend from any endpoint, passed through - // command-line flag. - void StartCustomDataRequest(const GURL& url, - const GotDataCallback& callback); - - void StartNetworkRequest( - const GURL& url, - const net::NetworkTrafficAnnotationTag& traffic_annotation, - int load_flags, - const GotDataCallback& callback); - -#if BUILDFLAG(DEBUG_DEVTOOLS) - void StartFileRequestForDebugDevtools(const std::string& path, - const GotDataCallback& callback); -#endif - - struct PendingRequest { - PendingRequest() = default; - PendingRequest(PendingRequest&& other) = default; - PendingRequest& operator=(PendingRequest&& other) = default; - - ~PendingRequest() { - if (callback) - callback.Run(CreateNotFoundResponse()); - } - - GotDataCallback callback; - std::unique_ptr<network::SimpleURLLoader> loader; - - DISALLOW_COPY_AND_ASSIGN(PendingRequest); - }; - - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; - std::list<PendingRequest> pending_requests_; - - DISALLOW_COPY_AND_ASSIGN(DevToolsDataSource); -}; - -std::string DevToolsDataSource::GetSource() { - return chrome::kChromeUIDevToolsHost; -} - -void DevToolsDataSource::StartDataRequest( - const std::string& path, - const content::WebContents::Getter& wc_getter, - const content::URLDataSource::GotDataCallback& callback) { - // Serve request from local bundle. - std::string bundled_path_prefix(chrome::kChromeUIDevToolsBundledPath); - bundled_path_prefix += "/"; - if (base::StartsWith(path, bundled_path_prefix, - base::CompareCase::INSENSITIVE_ASCII)) { - std::string path_without_params = PathWithoutParams(path); - - DCHECK(base::StartsWith(path_without_params, bundled_path_prefix, - base::CompareCase::INSENSITIVE_ASCII)); - std::string path_under_bundled = - path_without_params.substr(bundled_path_prefix.length()); -#if BUILDFLAG(DEBUG_DEVTOOLS) - StartFileRequestForDebugDevtools(path_under_bundled, callback); -#else - StartBundledDataRequest(path_under_bundled, callback); -#endif - return; - } - - // Serve empty page. - std::string empty_path_prefix(chrome::kChromeUIDevToolsBlankPath); - if (base::StartsWith(path, empty_path_prefix, - base::CompareCase::INSENSITIVE_ASCII)) { - callback.Run(new base::RefCountedStaticMemory()); - return; - } - - // Serve request from remote location. - std::string remote_path_prefix(chrome::kChromeUIDevToolsRemotePath); - remote_path_prefix += "/"; - if (base::StartsWith(path, remote_path_prefix, - base::CompareCase::INSENSITIVE_ASCII)) { - GURL url(kRemoteFrontendBase + path.substr(remote_path_prefix.length())); - - CHECK_EQ(url.host(), kRemoteFrontendDomain); - if (url.is_valid() && DevToolsUIBindings::IsValidRemoteFrontendURL(url)) { - StartRemoteDataRequest(url, callback); - } else { - DLOG(ERROR) << "Refusing to load invalid remote front-end URL"; - callback.Run(CreateNotFoundResponse()); - } - return; - } - - std::string custom_frontend_url = - base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kCustomDevtoolsFrontend); - - if (custom_frontend_url.empty()) { - callback.Run(NULL); - return; - } - - // Serve request from custom location. - std::string custom_path_prefix(chrome::kChromeUIDevToolsCustomPath); - custom_path_prefix += "/"; - - if (base::StartsWith(path, custom_path_prefix, - base::CompareCase::INSENSITIVE_ASCII)) { - GURL url = GURL(custom_frontend_url + - path.substr(custom_path_prefix.length())); - DCHECK(url.is_valid()); - StartCustomDataRequest(url, callback); - return; - } - - callback.Run(NULL); -} - -std::string DevToolsDataSource::GetMimeType(const std::string& path) { - return GetMimeTypeForPath(path); -} - -bool DevToolsDataSource::ShouldAddContentSecurityPolicy() { - return false; -} - -bool DevToolsDataSource::ShouldDenyXFrameOptions() { - return false; -} - -bool DevToolsDataSource::ShouldServeMimeTypeAsContentTypeHeader() { - return true; -} - -void DevToolsDataSource::StartBundledDataRequest( - const std::string& path, - const content::URLDataSource::GotDataCallback& callback) { - base::StringPiece resource = - content::DevToolsFrontendHost::GetFrontendResource(path); - - DLOG_IF(WARNING, resource.empty()) - << "Unable to find dev tool resource: " << path - << ". If you compiled with debug_devtools=1, try running with " - "--debug-devtools."; - scoped_refptr<base::RefCountedStaticMemory> bytes( - new base::RefCountedStaticMemory(resource.data(), resource.length())); - callback.Run(bytes.get()); -} - -void DevToolsDataSource::StartRemoteDataRequest( - const GURL& url, - const content::URLDataSource::GotDataCallback& callback) { - CHECK(url.is_valid()); - net::NetworkTrafficAnnotationTag traffic_annotation = - net::DefineNetworkTrafficAnnotation("devtools_hard_coded_data_source", R"( - semantics { - sender: "Developer Tools Remote Data Request From Google" - description: - "This service fetches Chromium DevTools front-end files from the " - "cloud for the remote debugging scenario." - trigger: - "When user attaches to mobile phone for debugging." - data: "None" - destination: GOOGLE_OWNED_SERVICE - } - policy { - cookies_allowed: YES - cookies_store: "user" - setting: "This feature cannot be disabled by settings." - chrome_policy { - DeveloperToolsAvailability { - policy_options {mode: MANDATORY} - DeveloperToolsAvailability: 2 - } - } - })"); - - StartNetworkRequest(url, traffic_annotation, net::LOAD_NORMAL, callback); -} - -void DevToolsDataSource::StartCustomDataRequest( - const GURL& url, - const content::URLDataSource::GotDataCallback& callback) { - if (!url.is_valid()) { - callback.Run(CreateNotFoundResponse()); - return; - } - net::NetworkTrafficAnnotationTag traffic_annotation = - net::DefineNetworkTrafficAnnotation("devtools_free_data_source", R"( - semantics { - sender: "Developer Tools Remote Data Request" - description: - "This service fetches Chromium DevTools front-end files from the " - "cloud for the remote debugging scenario. This can only happen if " - "a URL was passed on the commandline via flag " - "'--custom-devtools-frontend'. This URL overrides the default " - "fetching from a Google website, see " - "devtools_hard_coded_data_source." - trigger: - "When command line flag --custom-devtools-frontend is specified " - "and DevTools is opened." - data: "None" - destination: WEBSITE - } - policy { - cookies_allowed: YES - cookies_store: "user" - setting: "This feature cannot be disabled by settings." - chrome_policy { - DeveloperToolsAvailability { - policy_options {mode: MANDATORY} - DeveloperToolsAvailability: 2 - } - } - })"); - - StartNetworkRequest(url, traffic_annotation, net::LOAD_DISABLE_CACHE, - callback); -} - -void DevToolsDataSource::StartNetworkRequest( - const GURL& url, - const net::NetworkTrafficAnnotationTag& traffic_annotation, - int load_flags, - const GotDataCallback& callback) { - auto request = std::make_unique<network::ResourceRequest>(); - request->url = url; - request->load_flags = load_flags; - - auto request_iter = pending_requests_.emplace(pending_requests_.begin()); - request_iter->callback = callback; - request_iter->loader = - network::SimpleURLLoader::Create(std::move(request), traffic_annotation); - request_iter->loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( - url_loader_factory_.get(), - base::BindOnce(&DevToolsDataSource::OnLoadComplete, - base::Unretained(this), request_iter)); -} - -#if BUILDFLAG(DEBUG_DEVTOOLS) -scoped_refptr<base::RefCountedMemory> ReadFile(const base::FilePath& path) { - std::string buffer; - if (!base::ReadFileToString(path, &buffer)) { - LOG(ERROR) << "Failed to read " << path; - return CreateNotFoundResponse(); - } - return base::RefCountedString::TakeString(&buffer); -} - -void DevToolsDataSource::StartFileRequestForDebugDevtools( - const std::string& path, - const GotDataCallback& callback) { - base::FilePath inspector_debug_dir; - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kCustomDevtoolsFrontend)) { - inspector_debug_dir = - command_line->GetSwitchValuePath(switches::kCustomDevtoolsFrontend); - // --custom-devtools-frontend may already be used to specify an URL. - // In that case, fall back to the default debug-devtools bundle. - if (!base::PathExists(inspector_debug_dir)) - inspector_debug_dir.clear(); - } - if (inspector_debug_dir.empty() && - !base::PathService::Get(chrome::DIR_INSPECTOR_DEBUG, - &inspector_debug_dir)) { - callback.Run(CreateNotFoundResponse()); - return; - } - - DCHECK(!inspector_debug_dir.empty()); - - base::FilePath full_path = inspector_debug_dir.AppendASCII(path); - - base::PostTaskAndReplyWithResult( - FROM_HERE, - {base::MayBlock(), base::ThreadPool(), - base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN, - base::TaskPriority::USER_VISIBLE}, - // The usage of BindRepeating below is only because the type of - // task callback needs to match that of response callback, which - // is currently a repeating callback. - base::BindRepeating(ReadFile, std::move(full_path)), callback); -} - -#endif // BUILDFLAG(DEBUG_DEVTOOLS) - -void DevToolsDataSource::OnLoadComplete( - std::list<PendingRequest>::iterator request_iter, - std::unique_ptr<std::string> response_body) { - std::move(request_iter->callback) - .Run(response_body - ? base::RefCountedString::TakeString(response_body.get()) - : CreateNotFoundResponse()); - pending_requests_.erase(request_iter); -} - -} // namespace - -// DevToolsUI ----------------------------------------------------------------- // static GURL DevToolsUI::GetProxyURL(const std::string& frontend_url) {
diff --git a/chrome/browser/ui/webui/devtools_ui_data_source.cc b/chrome/browser/ui/webui/devtools_ui_data_source.cc new file mode 100644 index 0000000..95e73c5 --- /dev/null +++ b/chrome/browser/ui/webui/devtools_ui_data_source.cc
@@ -0,0 +1,348 @@ +// 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 "chrome/browser/ui/webui/devtools_ui_data_source.h" + +#include <list> +#include <utility> + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/files/file_util.h" +#include "base/memory/ref_counted_memory.h" +#include "base/path_service.h" +#include "base/strings/strcat.h" +#include "base/task/post_task.h" +#include "chrome/browser/devtools/devtools_ui_bindings.h" +#include "chrome/browser/devtools/url_constants.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/url_constants.h" +#include "chrome/common/webui_url_constants.h" +#include "content/public/browser/devtools_frontend_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/url_constants.h" +#include "net/base/load_flags.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/public/cpp/resource_request.h" +#include "url/url_constants.h" + +namespace { + +std::string PathWithoutParams(const std::string& path) { + return GURL(base::StrCat({content::kChromeDevToolsScheme, + url::kStandardSchemeSeparator, + chrome::kChromeUIDevToolsHost})) + .Resolve(path) + .path() + .substr(1); +} + +scoped_refptr<base::RefCountedMemory> CreateNotFoundResponse() { + const char kHttpNotFound[] = "HTTP/1.1 404 Not Found\n\n"; + return base::MakeRefCounted<base::RefCountedStaticMemory>( + kHttpNotFound, strlen(kHttpNotFound)); +} + +// DevToolsDataSource --------------------------------------------------------- + +std::string GetMimeTypeForPath(const std::string& path) { + std::string filename = PathWithoutParams(path); + if (base::EndsWith(filename, ".html", base::CompareCase::INSENSITIVE_ASCII)) { + return "text/html"; + } else if (base::EndsWith(filename, ".css", + base::CompareCase::INSENSITIVE_ASCII)) { + return "text/css"; + } else if (base::EndsWith(filename, ".js", + base::CompareCase::INSENSITIVE_ASCII)) { + return "application/javascript"; + } else if (base::EndsWith(filename, ".png", + base::CompareCase::INSENSITIVE_ASCII)) { + return "image/png"; + } else if (base::EndsWith(filename, ".gif", + base::CompareCase::INSENSITIVE_ASCII)) { + return "image/gif"; + } else if (base::EndsWith(filename, ".svg", + base::CompareCase::INSENSITIVE_ASCII)) { + return "image/svg+xml"; + } else if (base::EndsWith(filename, ".manifest", + base::CompareCase::INSENSITIVE_ASCII)) { + return "text/cache-manifest"; + } + return "text/html"; +} +} // namespace + +DevToolsDataSource::DevToolsDataSource( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) + : url_loader_factory_(std::move(url_loader_factory)) {} + +DevToolsDataSource::~DevToolsDataSource() {} + +std::string DevToolsDataSource::GetSource() { + return chrome::kChromeUIDevToolsHost; +} + +void DevToolsDataSource::StartDataRequest( + const std::string& path, + const content::WebContents::Getter& wc_getter, + const GotDataCallback& callback) { + // Serve request from local bundle. + std::string bundled_path_prefix(chrome::kChromeUIDevToolsBundledPath); + bundled_path_prefix += "/"; + if (base::StartsWith(path, bundled_path_prefix, + base::CompareCase::INSENSITIVE_ASCII)) { + std::string path_without_params = PathWithoutParams(path); + + DCHECK(base::StartsWith(path_without_params, bundled_path_prefix, + base::CompareCase::INSENSITIVE_ASCII)); + std::string path_under_bundled = + path_without_params.substr(bundled_path_prefix.length()); +#if BUILDFLAG(DEBUG_DEVTOOLS) + StartFileRequestForDebugDevtools(path_under_bundled, callback); +#else + StartBundledDataRequest(path_under_bundled, callback); +#endif + return; + } + + // Serve empty page. + std::string empty_path_prefix(chrome::kChromeUIDevToolsBlankPath); + if (base::StartsWith(path, empty_path_prefix, + base::CompareCase::INSENSITIVE_ASCII)) { + callback.Run(new base::RefCountedStaticMemory()); + return; + } + + // Serve request from remote location. + std::string remote_path_prefix(chrome::kChromeUIDevToolsRemotePath); + remote_path_prefix += "/"; + if (base::StartsWith(path, remote_path_prefix, + base::CompareCase::INSENSITIVE_ASCII)) { + GURL url(kRemoteFrontendBase + path.substr(remote_path_prefix.length())); + + CHECK_EQ(url.host(), kRemoteFrontendDomain); + if (url.is_valid() && DevToolsUIBindings::IsValidRemoteFrontendURL(url)) { + StartRemoteDataRequest(url, callback); + } else { + DLOG(ERROR) << "Refusing to load invalid remote front-end URL"; + callback.Run(CreateNotFoundResponse()); + } + return; + } + + std::string custom_frontend_url = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kCustomDevtoolsFrontend); + + if (custom_frontend_url.empty()) { + callback.Run(nullptr); + return; + } + + // Serve request from custom location. + std::string custom_path_prefix(chrome::kChromeUIDevToolsCustomPath); + custom_path_prefix += "/"; + + if (base::StartsWith(path, custom_path_prefix, + base::CompareCase::INSENSITIVE_ASCII)) { + GURL url = + GURL(custom_frontend_url + path.substr(custom_path_prefix.length())); + DCHECK(url.is_valid()); + StartCustomDataRequest(url, callback); + return; + } + + callback.Run(nullptr); +} + +std::string DevToolsDataSource::GetMimeType(const std::string& path) { + return GetMimeTypeForPath(path); +} + +bool DevToolsDataSource::ShouldAddContentSecurityPolicy() { + return false; +} + +bool DevToolsDataSource::ShouldDenyXFrameOptions() { + return false; +} + +bool DevToolsDataSource::ShouldServeMimeTypeAsContentTypeHeader() { + return true; +} + +void DevToolsDataSource::StartBundledDataRequest( + const std::string& path, + const content::URLDataSource::GotDataCallback& callback) { + base::StringPiece resource = + content::DevToolsFrontendHost::GetFrontendResource(path); + + DLOG_IF(WARNING, resource.empty()) + << "Unable to find dev tool resource: " << path + << ". If you compiled with debug_devtools=1, try running with " + "--debug-devtools."; + scoped_refptr<base::RefCountedStaticMemory> bytes( + new base::RefCountedStaticMemory(resource.data(), resource.length())); + callback.Run(bytes.get()); +} + +void DevToolsDataSource::StartRemoteDataRequest( + const GURL& url, + const content::URLDataSource::GotDataCallback& callback) { + CHECK(url.is_valid()); + net::NetworkTrafficAnnotationTag traffic_annotation = + net::DefineNetworkTrafficAnnotation("devtools_hard_coded_data_source", + R"( + semantics { + sender: "Developer Tools Remote Data Request From Google" + description: + "This service fetches Chromium DevTools front-end files from the " + "cloud for the remote debugging scenario." + trigger: + "When user attaches to mobile phone for debugging." + data: "None" + destination: GOOGLE_OWNED_SERVICE + } + policy { + cookies_allowed: YES + cookies_store: "user" + setting: "This feature cannot be disabled by settings." + chrome_policy { + DeveloperToolsAvailability { + policy_options {mode: MANDATORY} + DeveloperToolsAvailability: 2 + } + } + })"); + + StartNetworkRequest(url, traffic_annotation, net::LOAD_NORMAL, callback); +} + +void DevToolsDataSource::StartCustomDataRequest( + const GURL& url, + const content::URLDataSource::GotDataCallback& callback) { + if (!url.is_valid()) { + callback.Run(CreateNotFoundResponse()); + return; + } + net::NetworkTrafficAnnotationTag traffic_annotation = + net::DefineNetworkTrafficAnnotation("devtools_free_data_source", R"( + semantics { + sender: "Developer Tools Remote Data Request" + description: + "This service fetches Chromium DevTools front-end files from the " + "cloud for the remote debugging scenario. This can only happen if " + "a URL was passed on the commandline via flag " + "'--custom-devtools-frontend'. This URL overrides the default " + "fetching from a Google website, see " + "devtools_hard_coded_data_source." + trigger: + "When command line flag --custom-devtools-frontend is specified " + "and DevTools is opened." + data: "None" + destination: WEBSITE + } + policy { + cookies_allowed: YES + cookies_store: "user" + setting: "This feature cannot be disabled by settings." + chrome_policy { + DeveloperToolsAvailability { + policy_options {mode: MANDATORY} + DeveloperToolsAvailability: 2 + } + } + })"); + + StartNetworkRequest(url, traffic_annotation, net::LOAD_DISABLE_CACHE, + callback); +} + +void DevToolsDataSource::StartNetworkRequest( + const GURL& url, + const net::NetworkTrafficAnnotationTag& traffic_annotation, + int load_flags, + const GotDataCallback& callback) { + auto request = std::make_unique<network::ResourceRequest>(); + request->url = url; + request->load_flags = load_flags; + + auto request_iter = pending_requests_.emplace(pending_requests_.begin()); + request_iter->callback = callback; + request_iter->loader = + network::SimpleURLLoader::Create(std::move(request), traffic_annotation); + request_iter->loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( + url_loader_factory_.get(), + base::BindOnce(&DevToolsDataSource::OnLoadComplete, + base::Unretained(this), request_iter)); +} + +#if BUILDFLAG(DEBUG_DEVTOOLS) +scoped_refptr<base::RefCountedMemory> ReadFileForDebugDevTools( + const base::FilePath& path) { + std::string buffer; + if (!base::ReadFileToString(path, &buffer)) { + LOG(ERROR) << "Failed to read " << path; + return CreateNotFoundResponse(); + } + return base::RefCountedString::TakeString(&buffer); +} + +void DevToolsDataSource::StartFileRequestForDebugDevtools( + const std::string& path, + const GotDataCallback& callback) { + base::FilePath inspector_debug_dir; + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kCustomDevtoolsFrontend)) { + inspector_debug_dir = + command_line->GetSwitchValuePath(switches::kCustomDevtoolsFrontend); + // --custom-devtools-frontend may already be used to specify an URL. + // In that case, fall back to the default debug-devtools bundle. + if (!base::PathExists(inspector_debug_dir)) + inspector_debug_dir.clear(); + } + if (inspector_debug_dir.empty() && + !base::PathService::Get(chrome::DIR_INSPECTOR_DEBUG, + &inspector_debug_dir)) { + callback.Run(CreateNotFoundResponse()); + return; + } + + DCHECK(!inspector_debug_dir.empty()); + + base::FilePath full_path = inspector_debug_dir.AppendASCII(path); + + base::PostTaskAndReplyWithResult( + FROM_HERE, + {base::MayBlock(), base::ThreadPool(), + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN, + base::TaskPriority::USER_VISIBLE}, + // The usage of BindRepeating below is only because the type of + // task callback needs to match that of response callback, which + // is currently a repeating callback. + base::BindRepeating(ReadFileForDebugDevTools, std::move(full_path)), + callback); +} +#endif // BUILDFLAG(DEBUG_DEVTOOLS) + +void DevToolsDataSource::OnLoadComplete( + std::list<PendingRequest>::iterator request_iter, + std::unique_ptr<std::string> response_body) { + std::move(request_iter->callback) + .Run(response_body + ? base::RefCountedString::TakeString(response_body.get()) + : CreateNotFoundResponse()); + pending_requests_.erase(request_iter); +} + +DevToolsDataSource::PendingRequest::PendingRequest() = default; + +DevToolsDataSource::PendingRequest::PendingRequest(PendingRequest&& other) = + default; + +DevToolsDataSource::PendingRequest::~PendingRequest() { + if (callback) + callback.Run(CreateNotFoundResponse()); +}
diff --git a/chrome/browser/ui/webui/devtools_ui_data_source.h b/chrome/browser/ui/webui/devtools_ui_data_source.h new file mode 100644 index 0000000..dddecbc --- /dev/null +++ b/chrome/browser/ui/webui/devtools_ui_data_source.h
@@ -0,0 +1,101 @@ +// 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 CHROME_BROWSER_UI_WEBUI_DEVTOOLS_UI_DATA_SOURCE_H_ +#define CHROME_BROWSER_UI_WEBUI_DEVTOOLS_UI_DATA_SOURCE_H_ + +#include <list> +#include <memory> + +#include "content/public/browser/url_data_source.h" + +#include "base/macros.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/simple_url_loader.h" +#include "third_party/blink/public/public_buildflags.h" + +class GURL; + +namespace net { +struct NetworkTrafficAnnotationTag; +} + +// An URLDataSource implementation that handles devtools://devtools/ +// requests. Three types of requests could be handled based on the URL path: +// 1. /bundled/: bundled DevTools frontend is served. +// when built with debug_devtools=true, the path can be provided via +// --custom-devtools-frontend. +// 2. /remote/: remote DevTools frontend is served from App Engine. +// 3. /custom/: custom DevTools frontend is served from the server as specified +// by the --custom-devtools-frontend flag. +class DevToolsDataSource : public content::URLDataSource { + public: + using GotDataCallback = content::URLDataSource::GotDataCallback; + + explicit DevToolsDataSource( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); + ~DevToolsDataSource() override; + + // content::URLDataSource implementation. + std::string GetSource() override; + + void StartDataRequest(const std::string& path, + const content::WebContents::Getter& wc_getter, + const GotDataCallback& callback) override; + + private: + friend class DevToolsUIDataSourceTest; + + struct PendingRequest; + + // content::URLDataSource overrides. + std::string GetMimeType(const std::string& path) override; + bool ShouldAddContentSecurityPolicy() override; + bool ShouldDenyXFrameOptions() override; + bool ShouldServeMimeTypeAsContentTypeHeader() override; + + void OnLoadComplete(std::list<PendingRequest>::iterator request_iter, + std::unique_ptr<std::string> response_body); + + // Serves bundled DevTools frontend from ResourceBundle. + void StartBundledDataRequest(const std::string& path, + const GotDataCallback& callback); + + // Serves remote DevTools frontend from hard-coded App Engine domain. + void StartRemoteDataRequest(const GURL& url, const GotDataCallback& callback); + + // Serves remote DevTools frontend from any endpoint, passed through + // command-line flag. + void StartCustomDataRequest(const GURL& url, const GotDataCallback& callback); + + virtual void StartNetworkRequest( + const GURL& url, + const net::NetworkTrafficAnnotationTag& traffic_annotation, + int load_flags, + const GotDataCallback& callback); + +#if BUILDFLAG(DEBUG_DEVTOOLS) + void StartFileRequestForDebugDevtools(const std::string& path, + const GotDataCallback& callback); +#endif + + struct PendingRequest { + PendingRequest(); + PendingRequest(PendingRequest&& other); + PendingRequest& operator=(PendingRequest&& other) = default; + ~PendingRequest(); + + GotDataCallback callback; + std::unique_ptr<network::SimpleURLLoader> loader; + + DISALLOW_COPY_AND_ASSIGN(PendingRequest); + }; + + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; + std::list<PendingRequest> pending_requests_; + + DISALLOW_COPY_AND_ASSIGN(DevToolsDataSource); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_DEVTOOLS_UI_DATA_SOURCE_H_
diff --git a/chrome/browser/ui/webui/devtools_ui_data_source_unittest.cc b/chrome/browser/ui/webui/devtools_ui_data_source_unittest.cc new file mode 100644 index 0000000..323ce84e --- /dev/null +++ b/chrome/browser/ui/webui/devtools_ui_data_source_unittest.cc
@@ -0,0 +1,235 @@ +// 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 "chrome/browser/ui/webui/devtools_ui_data_source.h" + +#include <memory> + +#include "base/bind.h" +#include "base/memory/ref_counted_memory.h" +#include "base/strings/strcat.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/url_constants.h" +#include "content/public/browser/url_data_source.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +constexpr char kDevToolsUITestFrontEndUrl[] = "/devtools_app.html"; +constexpr char kDevToolsUITest404Response[] = "HTTP/1.1 404 Not Found"; + +GURL DevToolsUrl() { + return GURL(base::StrCat({content::kChromeDevToolsScheme, + url::kStandardSchemeSeparator, + chrome::kChromeUIDevToolsHost})); +} + +std::string DevToolsBundledPath(const std::string& path) { + return base::StrCat({chrome::kChromeUIDevToolsBundledPath, path}); +} + +std::string DevToolsRemotePath(const std::string& path) { + return base::StrCat({chrome::kChromeUIDevToolsRemotePath, path}); +} + +std::string DevToolsCustomPath(const std::string& path) { + return base::StrCat({chrome::kChromeUIDevToolsCustomPath, path}); +} + +} // namespace + +class TestDevToolsDataSource : public DevToolsDataSource { + public: + TestDevToolsDataSource() : DevToolsDataSource(nullptr) {} + ~TestDevToolsDataSource() override {} + + void StartNetworkRequest( + const GURL& url, + const net::NetworkTrafficAnnotationTag& traffic_annotation, + int load_flags, + const GotDataCallback& callback) override { + std::string copy_of_url = url.spec(); + callback.Run(base::RefCountedString::TakeString(©_of_url)); + } +}; + +class DevToolsUIDataSourceTest : public testing::Test { + protected: + DevToolsUIDataSourceTest() {} + ~DevToolsUIDataSourceTest() override = default; + + void SetUp() override { + devtools_data_source_ = std::make_unique<TestDevToolsDataSource>(); + } + + void TearDown() override { devtools_data_source_.reset(); } + + TestDevToolsDataSource* data_source() const { + return devtools_data_source_.get(); + } + + bool data_received() const { return data_received_; } + + std::string data() const { return data_; } + + void StartRequest(const std::string& path) { + data_received_ = false; + data_.clear(); + std::string trimmed_path = path.substr(1); + content::WebContents::Getter wc_getter; + data_source()->StartDataRequest( + trimmed_path, std::move(wc_getter), + base::BindRepeating(&DevToolsUIDataSourceTest::OnDataReceived, + base::Unretained(this))); + } + + private: + void OnDataReceived(scoped_refptr<base::RefCountedMemory> bytes) { + data_received_ = true; + if (bytes.get() != nullptr) { + data_ = base::StringPiece(reinterpret_cast<const char*>(bytes->front()), + bytes->size()) + .as_string(); + } + } + + std::unique_ptr<TestDevToolsDataSource> devtools_data_source_; + bool data_received_ = false; + std::string data_; + + DISALLOW_COPY_AND_ASSIGN(DevToolsUIDataSourceTest); +}; + +// devtools/bundled path. + +TEST_F(DevToolsUIDataSourceTest, TestDevToolsBundledURL) { + const GURL path = + DevToolsUrl().Resolve(DevToolsBundledPath(kDevToolsUITestFrontEndUrl)); + StartRequest(path.path()); + EXPECT_TRUE(data_received()); + EXPECT_FALSE(data().empty()); +} + +TEST_F(DevToolsUIDataSourceTest, TestDevToolsBundledURLWithQueryParam) { + const GURL path = + DevToolsUrl().Resolve(DevToolsBundledPath(kDevToolsUITestFrontEndUrl)); + StartRequest(path.path() + "?foo"); + EXPECT_TRUE(data_received()); + EXPECT_FALSE(data().empty()); +} + +TEST_F(DevToolsUIDataSourceTest, TestDevToolsInvalidBundledURL) { + const GURL path = + DevToolsUrl().Resolve(DevToolsBundledPath("invalid_devtools_app.html")); + StartRequest(path.path()); + EXPECT_TRUE(data_received()); + EXPECT_TRUE(data().empty()); +} + +TEST_F(DevToolsUIDataSourceTest, TestDevToolsInvalidBundledURLWithQueryParam) { + const GURL path = + DevToolsUrl().Resolve(DevToolsBundledPath("invalid_devtools_app.html")); + StartRequest(path.path() + "?foo"); + EXPECT_TRUE(data_received()); + EXPECT_TRUE(data().empty()); +} + +// devtools/blank path + +TEST_F(DevToolsUIDataSourceTest, TestDevToolsBlankURL) { + const GURL path = DevToolsUrl().Resolve(chrome::kChromeUIDevToolsBlankPath); + StartRequest(path.path()); + EXPECT_TRUE(data_received()); + EXPECT_TRUE(data().empty()); +} + +TEST_F(DevToolsUIDataSourceTest, TestDevToolsBlankURLWithQueryParam) { + const GURL path = DevToolsUrl().Resolve(chrome::kChromeUIDevToolsBlankPath); + StartRequest(path.path() + "?foo"); + EXPECT_TRUE(data_received()); + EXPECT_TRUE(data().empty()); +} + +// devtools/remote path + +TEST_F(DevToolsUIDataSourceTest, TestDevToolsRemoteURL) { + const GURL path = + DevToolsUrl().Resolve(DevToolsRemotePath(kDevToolsUITestFrontEndUrl)); + StartRequest(path.path()); + EXPECT_TRUE(data_received()); + EXPECT_EQ(data(), + "https://chrome-devtools-frontend.appspot.com/devtools_app.html"); +} + +TEST_F(DevToolsUIDataSourceTest, TestDevToolsRemoteURLWithQueryParam) { + const GURL path = + DevToolsUrl().Resolve(DevToolsRemotePath(kDevToolsUITestFrontEndUrl)); + StartRequest(path.path() + "?foo"); + EXPECT_TRUE(data_received()); + ASSERT_TRUE(base::StartsWith(data(), kDevToolsUITest404Response, + base::CompareCase::SENSITIVE)); +} + +// devtools/custom path. + +TEST_F(DevToolsUIDataSourceTest, TestDevToolsCustomURLWithNoSwitch) { + const GURL path = + DevToolsUrl().Resolve(DevToolsCustomPath(kDevToolsUITestFrontEndUrl)); + StartRequest(path.path()); + EXPECT_TRUE(data_received()); + EXPECT_TRUE(data().empty()); +} + +TEST_F(DevToolsUIDataSourceTest, TestDevToolsCustomURLWithSwitch) { + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kCustomDevtoolsFrontend, "http://localhost:8090/front_end/"); + const GURL path = + DevToolsUrl().Resolve(DevToolsCustomPath(kDevToolsUITestFrontEndUrl)); + StartRequest(path.path()); + EXPECT_TRUE(data_received()); + EXPECT_EQ(data(), "http://localhost:8090/front_end/devtools_app.html"); +} + +TEST_F(DevToolsUIDataSourceTest, TestDevToolsCustomURLWithSwitchAndQueryParam) { + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kCustomDevtoolsFrontend, "http://localhost:8090/front_end/"); + const GURL path = + DevToolsUrl().Resolve(DevToolsCustomPath(kDevToolsUITestFrontEndUrl)); + StartRequest(path.path() + "?foo"); + EXPECT_TRUE(data_received()); + EXPECT_EQ(data(), "http://localhost:8090/front_end/devtools_app.html?foo"); +} + +#if !DCHECK_IS_ON() +TEST_F(DevToolsUIDataSourceTest, + TestDevToolsCustomURLWithSwitchAndInvalidServerURL) { + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kCustomDevtoolsFrontend, "invalid-server-url"); + const GURL path = + DevToolsUrl().Resolve(DevToolsCustomPath(kDevToolsUITestFrontEndUrl)); + StartRequest(path.path()); + EXPECT_TRUE(data_received()); + ASSERT_TRUE(base::StartsWith(data(), kDevToolsUITest404Response, + base::CompareCase::SENSITIVE)); +} +#endif + +// devtools path (i.e. no route specified). + +TEST_F(DevToolsUIDataSourceTest, TestDevToolsNoRoute) { + const GURL path = DevToolsUrl().Resolve(kDevToolsUITestFrontEndUrl); + StartRequest(path.path()); + EXPECT_TRUE(data_received()); + EXPECT_TRUE(data().empty()); +} + +TEST_F(DevToolsUIDataSourceTest, TestDevToolsNoRouteWithSwitch) { + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kCustomDevtoolsFrontend, "invalid-server-url"); + const GURL path = DevToolsUrl().Resolve(kDevToolsUITestFrontEndUrl); + StartRequest(path.path()); + EXPECT_TRUE(data_received()); + EXPECT_TRUE(data().empty()); +}
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 9b93ae3..3385fe0 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -883,6 +883,7 @@ {"mouseSpeed", IDS_SETTINGS_MOUSE_SPEED_LABEL}, {"mouseSwapButtons", IDS_SETTINGS_MOUSE_SWAP_BUTTONS_LABEL}, {"mouseReverseScroll", IDS_SETTINGS_MOUSE_REVERSE_SCROLL_LABEL}, + {"pointerAccelerationLabel", IDS_SETTINGS_POINTER_ACCELERATION_LABEL}, }; AddLocalizedStringsBulk(html_source, kPointersStrings, base::size(kPointersStrings)); @@ -1029,6 +1030,10 @@ html_source->AddBoolean("hasExternalTouchDevice", display::HasExternalTouchscreenDevice()); + html_source->AddBoolean( + "allowDisableMouseAcceleration", + base::FeatureList::IsEnabled(features::kAllowDisableMouseAcceleration)); + static constexpr LocalizedString kStorageStrings[] = { {"storageTitle", IDS_SETTINGS_STORAGE_TITLE}, {"storageItemInUse", IDS_SETTINGS_STORAGE_ITEM_IN_USE},
diff --git a/chrome/browser/vr/service/vr_service_impl.cc b/chrome/browser/vr/service/vr_service_impl.cc index 8918a6a..88bddf5 100644 --- a/chrome/browser/vr/service/vr_service_impl.cc +++ b/chrome/browser/vr/service/vr_service_impl.cc
@@ -546,8 +546,13 @@ } void VRServiceImpl::SetListeningForActivate( - device::mojom::VRDisplayClientPtr display_client) { - display_client_ = std::move(display_client); + mojo::PendingRemote<device::mojom::VRDisplayClient> display_client) { + // TODO(crbug.com/999745): Remove the check if the condition to check if + // |display_client| is nullptr is not required. + if (display_client) + display_client_.Bind(std::move(display_client)); + else + display_client_.reset(); BrowserXRRuntime* immersive_runtime = runtime_manager_->GetImmersiveRuntime(); if (immersive_runtime && display_client_) { immersive_runtime->UpdateListeningForActivate(this);
diff --git a/chrome/browser/vr/service/vr_service_impl.h b/chrome/browser/vr/service/vr_service_impl.h index f009f49..6a47928 100644 --- a/chrome/browser/vr/service/vr_service_impl.h +++ b/chrome/browser/vr/service/vr_service_impl.h
@@ -96,7 +96,8 @@ content::WebContents* GetWebContents(); void SetListeningForActivate( - device::mojom::VRDisplayClientPtr display_client) override; + mojo::PendingRemote<device::mojom::VRDisplayClient> display_client) + override; private: // content::WebContentsObserver implementation @@ -159,7 +160,7 @@ std::vector<base::OnceCallback<void()>> pending_requests_; // This is required for WebVR 1.1 backwards compatibility. - device::mojom::VRDisplayClientPtr display_client_; + mojo::Remote<device::mojom::VRDisplayClient> display_client_; bool initialization_complete_ = false; bool in_focused_frame_ = false;
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 009b60b..cbec662 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -163,6 +163,10 @@ #endif #if defined(OS_CHROMEOS) +// Shows a setting that allows disabling mouse acceleration. +const base::Feature kAllowDisableMouseAcceleration{ + "AllowDisableMouseAcceleration", base::FEATURE_DISABLED_BY_DEFAULT}; + // Enable project Crostini, Linux VMs on Chrome OS. const base::Feature kCrostini{"Crostini", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index e23d509..96081a93 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -109,6 +109,8 @@ #endif #if defined(OS_CHROMEOS) +COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kAllowDisableMouseAcceleration; COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kCrostini; COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kCrostiniAdditionalEnterpriseReporting;
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json index e4ff297..3a24e6d 100644 --- a/chrome/common/extensions/api/_api_features.json +++ b/chrome/common/extensions/api/_api_features.json
@@ -59,8 +59,10 @@ }, "action": { "dependencies": ["manifest:action"], - "contexts": ["blessed_extension"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension"] + }, + "action.setIcon": { + "disallow_for_service_workers": true }, "activityLogPrivate": [{ "dependencies": ["permission:activityLogPrivate"], @@ -159,8 +161,7 @@ }, "browserAction": { "dependencies": ["manifest:browser_action"], - "contexts": ["blessed_extension"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension"] }, // This API is whitelisted on stable and should not be enabled for a wider // audience without resolving security issues raised in API proposal and @@ -265,8 +266,7 @@ }, "contextMenus": { "dependencies": ["permission:contextMenus"], - "contexts": ["blessed_extension"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension"] }, "contextMenusInternal": { "internal": true, @@ -365,12 +365,14 @@ }, "enterprise.platformKeys": { "dependencies": ["permission:enterprise.platformKeys"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "enterprise.platformKeysInternal": { "dependencies": ["permission:enterprise.platformKeys"], "internal": true, - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "enterprise.platformKeysPrivate": { "dependencies": ["permission:enterprise.platformKeysPrivate"], @@ -395,15 +397,23 @@ "extension_types": ["extension", "legacy_packaged_app"], "contexts": ["blessed_extension"] }, + "extension.getBackgroundPage": { + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true + }, + "extension.getExtensionTabs": { + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true + }, "extension.getURL": { - "contexts": ["blessed_extension", "unblessed_extension", "content_script"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension", "unblessed_extension", "content_script"] }, "extension.getViews": [ { "channel": "stable", "contexts": ["blessed_extension"], - "extension_types": ["extension", "legacy_packaged_app"] + "extension_types": ["extension", "legacy_packaged_app"], + "disallow_for_service_workers": true }, { // TODO(yoz): Eliminate this usage. @@ -412,7 +422,8 @@ "extension_types": ["platform_app"], "whitelist": [ "A948368FC53BE437A55FEB414106E207925482F5" // File manager - ] + ], + "disallow_for_service_workers": true } ], "extension.inIncognitoContext": { @@ -446,12 +457,14 @@ }, "fileBrowserHandler": { "dependencies": ["permission:fileBrowserHandler"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "fileBrowserHandlerInternal": { "internal": true, "dependencies": ["permission:fileBrowserHandler"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "fileManagerPrivate": { "dependencies": ["permission:fileManagerPrivate"], @@ -464,12 +477,14 @@ }, "fileSystemProvider": { "dependencies": ["permission:fileSystemProvider"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "fileSystemProviderInternal": { "internal": true, "dependencies": ["permission:fileSystemProvider"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "fontSettings": { "dependencies": ["permission:fontSettings"], @@ -487,7 +502,11 @@ "channel": "stable", "extension_types": ["extension", "legacy_packaged_app", "platform_app"], "contexts": ["blessed_extension", "unblessed_extension", "content_script", - "lock_screen_extension"] + "lock_screen_extension"], + "disallow_for_service_workers": true + }, + "i18n.getAcceptLanguages": { + "disallow_for_service_workers": false }, "identity": { "dependencies": ["permission:identity"], @@ -546,7 +565,8 @@ }, "login": { "dependencies": ["permission:login"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "loginScreenStorage": { "dependencies": ["permission:loginScreenStorage"], @@ -556,6 +576,10 @@ "dependencies": ["permission:loginScreenUi"], "contexts": ["blessed_extension"] }, + "loginState": { + "dependencies": ["permission:loginState"], + "contexts": ["blessed_extension"] + }, "webcamPrivate": { "dependencies": ["permission:webcamPrivate"], "contexts": ["blessed_extension"] @@ -596,11 +620,13 @@ }, "pageAction": { "dependencies": ["manifest:page_action"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "pageCapture": { "dependencies": ["permission:pageCapture"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "passwordsPrivate": [{ "dependencies": ["permission:passwordsPrivate"], @@ -618,21 +644,23 @@ "permissions": { "channel": "stable", "extension_types": ["extension", "legacy_packaged_app", "platform_app"], - "contexts": ["blessed_extension"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension"] }, "platformKeys": { "dependencies": ["permission:platformKeys"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "platformKeysInternal": [{ "dependencies": ["permission:platformKeys"], "internal": true, - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true },{ "dependencies": ["permission:enterprise.platformKeys"], "internal": true, - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }], "privacy": { "dependencies": ["permission:privacy"], @@ -712,13 +740,13 @@ }, "tabCapture": { "dependencies": ["permission:tabCapture"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "tabs": [{ "channel": "stable", "extension_types": ["extension", "legacy_packaged_app"], - "contexts": ["blessed_extension"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension"] }, { "channel": "stable", "contexts": ["webui"], @@ -780,8 +808,7 @@ }, "webNavigation": { "dependencies": ["permission:webNavigation"], - "contexts": ["blessed_extension"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension"] }, "webrtcAudioPrivate": { "dependencies": ["permission:webrtcAudioPrivate"], @@ -821,8 +848,7 @@ }, "windows": [{ "dependencies": ["api:tabs"], - "contexts": ["blessed_extension"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension"] }, { "channel": "stable", "contexts": ["webui"],
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json index a8b5dcf..eb95198 100644 --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json
@@ -479,6 +479,11 @@ "4DBFC1C52D6660DD90791976DF7FEF7B3D360509" // Imprivata (login screen) DEV ] }, + "loginState": { + "channel": "dev", + "extension_types": ["login_screen_extension", "extension"], + "platforms": ["chromeos"] + }, "webcamPrivate": { "channel": "stable", "extension_types": ["extension", "platform_app"],
diff --git a/chrome/common/extensions/api/api_sources.gni b/chrome/common/extensions/api/api_sources.gni index 6652939f..67e412b 100644 --- a/chrome/common/extensions/api/api_sources.gni +++ b/chrome/common/extensions/api/api_sources.gni
@@ -100,6 +100,7 @@ "login.idl", "login_screen_storage.idl", "login_screen_ui.idl", + "login_state.idl", "platform_keys.idl", "platform_keys_internal.idl", "quick_unlock_private.idl",
diff --git a/chrome/common/extensions/api/login_state.idl b/chrome/common/extensions/api/login_state.idl new file mode 100644 index 0000000..c8195e4 --- /dev/null +++ b/chrome/common/extensions/api/login_state.idl
@@ -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. + +// Use the <code>chrome.loginState</code> API to read and monitor the login +// state. +[platforms=("chromeos"), + implemented_in="chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api.h"] +namespace loginState { + enum ProfileType { + // The extension is in the signin profile. + SIGNIN_PROFILE, + + // The extension is in the user profile. + USER_PROFILE + }; + + enum SessionState { + // The session state is unknown. + UNKNOWN, + + // The user is in the out-of-box-experience screen. + IN_OOBE_SCREEN, + + // The user is in the login screen. + IN_LOGIN_SCREEN, + + // The user is in the session. + IN_SESSION, + + // The user is in the lock screen. + IN_LOCK_SCREEN + }; + + callback ProfileTypeCallback = void (ProfileType result); + callback SessionStateCallback = void (SessionState result); + + interface Functions { + // Gets the type of the profile the extension is in. + static void getProfileType(ProfileTypeCallback callback); + + // Gets the current session state. + static void getSessionState(SessionStateCallback callback); + }; + + interface Events { + // Dispatched when the session state changes. <code>sessionState</code> + // is the new session state. + static void onSessionStateChanged(SessionState sessionState); + }; +};
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc index fe26ddd..e43cd3f 100644 --- a/chrome/common/extensions/permissions/permission_set_unittest.cc +++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -772,6 +772,7 @@ skip.insert(APIPermission::kIdle); skip.insert(APIPermission::kImeWindowEnabled); skip.insert(APIPermission::kIdltest); + skip.insert(APIPermission::kLoginState); skip.insert(APIPermission::kOverrideEscFullscreen); skip.insert(APIPermission::kPointerLock); skip.insert(APIPermission::kPower);
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 161a186..62902d11 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -504,6 +504,14 @@ // result in scrolling up instead of the more common scrolling down. const char kMouseReverseScroll[] = "settings.mouse.reverse_scroll"; +// A boolean pref set to true if mouse acceleration is enabled. When disabled +// only simple linear scaling is applied based on sensitivity. +const char kMouseAcceleration[] = "settings.mouse.acceleration"; + +// A boolean pref set to true if touchpad acceleration is enabled. When +// disabled only simple linear scaling is applied based on sensitivity. +const char kTouchpadAcceleration[] = "settings.touchpad.acceleration"; + // A integer pref for the touchpad sensitivity. const char kMouseSensitivity[] = "settings.mouse.sensitivity2";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 65da4f5..881dd6e 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -204,6 +204,8 @@ extern const char kNaturalScroll[]; extern const char kPrimaryMouseButtonRight[]; extern const char kMouseReverseScroll[]; +extern const char kMouseAcceleration[]; +extern const char kTouchpadAcceleration[]; extern const char kMouseSensitivity[]; extern const char kTouchpadSensitivity[]; extern const char kUse24HourClock[];
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index f71cc6f..7d1c395 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2004,6 +2004,8 @@ "../browser/chromeos/extensions/login_screen/login_screen_apitest_base.cc", "../browser/chromeos/extensions/login_screen/login_screen_apitest_base.h", "../browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_ui_apitest.cc", + "../browser/chromeos/extensions/login_screen/login_state/login_state_apitest.cc", + "../browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher_apitest.cc", "../browser/chromeos/extensions/login_screen/storage_apitest.cc", "../browser/chromeos/extensions/users_private/users_private_apitest.cc", "../browser/chromeos/extensions/wallpaper_apitest.cc", @@ -3325,6 +3327,7 @@ "../browser/ui/sync/sync_promo_ui_unittest.cc", "../browser/ui/thumbnails/thumbnail_utils_unittest.cc", "../browser/ui/toolbar/app_menu_icon_controller_unittest.cc", + "../browser/ui/webui/devtools_ui_data_source_unittest.cc", "../browser/ui/webui/favicon_source_unittest.cc", "../browser/webauthn/authenticator_request_scheduler_unittest.cc", "../browser/webauthn/chrome_authenticator_request_delegate_unittest.cc",
diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_profile_type/manifest.json b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_profile_type/manifest.json new file mode 100644 index 0000000..bdd9ebb --- /dev/null +++ b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_profile_type/manifest.json
@@ -0,0 +1,12 @@ +{ + "name": "Get Profile Type", + "version": "0.1", + "manifest_version": 2, + "description": "Browser test for chrome.loginState.getProfileType()", + "background": { + "scripts": ["test.js"] + }, + "permissions": [ + "loginState" + ] +}
diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_profile_type/test.js b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_profile_type/test.js new file mode 100644 index 0000000..bea3f95 --- /dev/null +++ b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/get_profile_type/test.js
@@ -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. + +function testGetProfileType(expected) { + chrome.test.runTests([() => { + chrome.loginState.getProfileType(profileType => { + chrome.test.assertNoLastError(); + chrome.test.assertEq(expected, profileType); + chrome.test.succeed(); + }); + }]); +} + +chrome.test.getConfig(config => { + testGetProfileType(config.customArg); +});
diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/login_state/on_session_state_changed/manifest.json b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/on_session_state_changed/manifest.json new file mode 100644 index 0000000..f299e1a9 --- /dev/null +++ b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/on_session_state_changed/manifest.json
@@ -0,0 +1,12 @@ +{ + "name": "On Session State Changed", + "version": "0.1", + "manifest_version": 2, + "description": "Browser test for chrome.loginState.onSessionStateChanged()", + "background": { + "scripts": ["test.js"] + }, + "permissions": [ + "loginState" + ] +}
diff --git a/chrome/test/data/extensions/api_test/login_screen_apis/login_state/on_session_state_changed/test.js b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/on_session_state_changed/test.js new file mode 100644 index 0000000..99a2e4e4 --- /dev/null +++ b/chrome/test/data/extensions/api_test/login_screen_apis/login_state/on_session_state_changed/test.js
@@ -0,0 +1,13 @@ +// 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. + +chrome.test.runTests([ + function testOnSessionStateChanged() { + chrome.loginState.onSessionStateChanged.addListener(sessionState => { + chrome.test.assertNoLastError(); + chrome.test.sendMessage(sessionState); + }); + chrome.test.succeed(); + }, +]);
diff --git a/chrome/test/data/extensions/api_test/stubs/content_script.js b/chrome/test/data/extensions/api_test/stubs/content_script.js index 6398c7d8..6c20448f 100644 --- a/chrome/test/data/extensions/api_test/stubs/content_script.js +++ b/chrome/test/data/extensions/api_test/stubs/content_script.js
@@ -15,30 +15,64 @@ console.log("asking for api ..."); chrome.extension.sendRequest("getApi", function(apis) { var apiFeatures = chrome.test.getApiFeatures(); + // TODO(crbug.com/998971): This really should support more than two levels of + // inheritance. function isAvailableToContentScripts(namespace, path) { - function checkContexts(contextList) { - return contextList == 'all' || - contextList.indexOf('content_script') != -1; + const results = { + NULL: 'null', + NOT_FOUND: 'not_found', + FOUND: 'found' + }; + function searchContexts(contexts) { + // This is tricky because the context can be either: + // 1. Undefined, so return results.NULL. + // 2. The string value 'all', so return results.FOUND. + // 3. An array of string values, which cannot be empty. + // Return results.FOUND if 'content_script' is in the array. + if (!contexts) { + return results.NULL; + } + if (contexts == 'all' || contexts.includes('content_script')) { + return results.FOUND; + } + return results.NOT_FOUND; } - function checkFeature(feature) { - if (feature.contexts) { - // Simple features. - return checkContexts(feature.contexts); - } else { - // Complex features. - for (var i = 0; i < feature.length; i++) { - if (checkContexts(feature[i].contexts)) - return true; + + function searchFeature(feature) { + if (!feature.length) { + // Simple feature, not an array. Can return results.NULL, + // because feature.context may be undefined. + return searchContexts(feature.contexts); + } + // Complex feature. We need to return results.NULL if we didn't + // find any contexts. + var foundContext = false; + for (var i = 0; i < feature.length; ++i) { + var currentResult = searchContexts(feature[i].contexts); + if (currentResult === results.FOUND) { + return results.FOUND; } - return false; + foundContext = currentResult !== results.NULL; + } + return foundContext ? results.NOT_FOUND : results.NULL; + } + + var pathFeature = apiFeatures[path]; + if (!!pathFeature) { + const result = searchFeature(pathFeature); + // If we found something, use that result. + if (result !== results.NULL) { + return result === results.FOUND; } } - if (apiFeatures.hasOwnProperty(path)) - return checkFeature(apiFeatures[path]); - return apiFeatures.hasOwnProperty(namespace) && - checkFeature(apiFeatures[namespace]); - } + var namespaceFeature = apiFeatures[namespace]; + // Check the namespace, if it's defined. + if (!!namespaceFeature) { + return searchFeature(namespaceFeature) === results.FOUND; + } + return false; + } /* isAvailableToContentScripts */ console.log("got api response"); var privilegedPaths = [];
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js index 1c3bc7b4..930db92 100644 --- a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js +++ b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
@@ -118,7 +118,13 @@ ]), }; -TEST_F('CrElementsInputTest', 'All', function() { +// https://crbug.com/997943: Flaky on Mac +GEN('#if defined(OS_MACOSX)'); +GEN('#define MAYBE_All DISABLED_All'); +GEN('#else'); +GEN('#define MAYBE_All All'); +GEN('#endif'); +TEST_F('CrElementsInputTest', 'MAYBE_All', function() { mocha.run(); });
diff --git a/chrome/test/data/webui/settings/chromeos/device_page_tests.js b/chrome/test/data/webui/settings/chromeos/device_page_tests.js index ea34ee2..24b1a9b6 100644 --- a/chrome/test/data/webui/settings/chromeos/device_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/device_page_tests.js
@@ -278,6 +278,11 @@ type: chrome.settingsPrivate.PrefType.BOOLEAN, value: false, }, + acceleration: { + key: 'settings.touchpad.acceleration', + type: chrome.settingsPrivate.PrefType.BOOLEAN, + value: true, + }, sensitivity2: { key: 'settings.touchpad.sensitivity2', type: chrome.settingsPrivate.PrefType.NUMBER, @@ -295,6 +300,11 @@ type: chrome.settingsPrivate.PrefType.BOOLEAN, value: false, }, + acceleration: { + key: 'settings.mouse.acceleration', + type: chrome.settingsPrivate.PrefType.BOOLEAN, + value: true, + }, sensitivity2: { key: 'settings.mouse.sensitivity2', type: chrome.settingsPrivate.PrefType.NUMBER,
diff --git a/chromecast/common/extensions_api/_api_features.json b/chromecast/common/extensions_api/_api_features.json index 7cf1009..12b07352 100644 --- a/chromecast/common/extensions_api/_api_features.json +++ b/chromecast/common/extensions_api/_api_features.json
@@ -27,8 +27,7 @@ "contexts": ["blessed_extension"] }, "extension.getURL": { - "contexts": ["blessed_extension", "unblessed_extension", "content_script"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension", "unblessed_extension", "content_script"] }, "extension.getViews": [ { @@ -98,8 +97,7 @@ "tabs": [{ "channel": "stable", "extension_types": ["extension", "legacy_packaged_app"], - "contexts": ["blessed_extension"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension"] }, { "channel": "stable", "contexts": ["webui"],
diff --git a/chromecast/graphics/BUILD.gn b/chromecast/graphics/BUILD.gn index 0ef718f..54324d06 100644 --- a/chromecast/graphics/BUILD.gn +++ b/chromecast/graphics/BUILD.gn
@@ -45,8 +45,8 @@ "accessibility/partial_magnification_controller.h", "cast_display_util.cc", "cast_display_util.h", - "cast_external_begin_frame_client.cc", - "cast_external_begin_frame_client.h", + "cast_external_begin_frame_source.cc", + "cast_external_begin_frame_source.h", "cast_focus_client_aura.cc", "cast_focus_client_aura.h", "cast_touch_event_gate.cc",
diff --git a/chromecast/graphics/DEPS b/chromecast/graphics/DEPS index 9067975..25819e5e 100644 --- a/chromecast/graphics/DEPS +++ b/chromecast/graphics/DEPS
@@ -1,4 +1,5 @@ include_rules = [ + "+components/viz/common/frame_sinks", "+ui/aura", "+ui/base", "+ui/base/ime",
diff --git a/chromecast/graphics/cast_external_begin_frame_client.cc b/chromecast/graphics/cast_external_begin_frame_client.cc deleted file mode 100644 index ce9cca7..0000000 --- a/chromecast/graphics/cast_external_begin_frame_client.cc +++ /dev/null
@@ -1,52 +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. - -#include "chromecast/graphics/cast_external_begin_frame_client.h" - -#include "base/time/time.h" -#include "chromecast/graphics/cast_window_manager_aura.h" - -namespace chromecast { - -CastExternalBeginFrameClient::CastExternalBeginFrameClient( - CastWindowManagerAura* cast_window_manager_aura) - : cast_window_manager_aura_(cast_window_manager_aura), - sequence_number_(viz::BeginFrameArgs::kStartingFrameNumber), - source_id_(viz::BeginFrameArgs::kManualSourceId), - interval_(base::TimeDelta::FromMilliseconds(250)), - frame_in_flight_(false) {} - -CastExternalBeginFrameClient::~CastExternalBeginFrameClient() {} - -void CastExternalBeginFrameClient::OnDisplayDidFinishFrame( - const viz::BeginFrameAck& ack) { - if (ack.source_id == source_id_) - frame_in_flight_ = false; -} - -void CastExternalBeginFrameClient::OnNeedsExternalBeginFrames( - bool needs_begin_frames) { - if (needs_begin_frames) - timer_.Start(FROM_HERE, interval_, this, - &CastExternalBeginFrameClient::IssueExternalBeginFrame); - else - timer_.Stop(); -} - -void CastExternalBeginFrameClient::IssueExternalBeginFrame() { - if (!frame_in_flight_) { - viz::BeginFrameArgs args = viz::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, source_id_, sequence_number_, - base::TimeTicks::Now(), base::TimeTicks::Now() + interval_, interval_, - viz::BeginFrameArgs::NORMAL); - ui::Compositor* compositor = - cast_window_manager_aura_->window_tree_host()->compositor(); - compositor->context_factory_private()->IssueExternalBeginFrame(compositor, - args); - sequence_number_++; - frame_in_flight_ = true; - } -} - -} // namespace chromecast
diff --git a/chromecast/graphics/cast_external_begin_frame_client.h b/chromecast/graphics/cast_external_begin_frame_client.h deleted file mode 100644 index a474f4f9..0000000 --- a/chromecast/graphics/cast_external_begin_frame_client.h +++ /dev/null
@@ -1,41 +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. - -#ifndef CHROMECAST_GRAPHICS_CAST_EXTERNAL_BEGIN_FRAME_CLIENT_H_ -#define CHROMECAST_GRAPHICS_CAST_EXTERNAL_BEGIN_FRAME_CLIENT_H_ - -#include "ui/compositor/external_begin_frame_client.h" - -#include "base/time/time.h" -#include "base/timer/timer.h" - -namespace chromecast { - -class CastWindowManagerAura; - -class CastExternalBeginFrameClient : public ui::ExternalBeginFrameClient { - public: - CastExternalBeginFrameClient(CastWindowManagerAura* cast_window_manager_aura); - ~CastExternalBeginFrameClient() override; - - // ui::ExternalBeginFrameClient implementation: - void OnDisplayDidFinishFrame(const viz::BeginFrameAck& ack) override; - void OnNeedsExternalBeginFrames(bool needs_begin_frames) override; - - private: - void IssueExternalBeginFrame(); - - CastWindowManagerAura* cast_window_manager_aura_; - uint64_t sequence_number_; - const uint64_t source_id_; - const base::TimeDelta interval_; - bool frame_in_flight_; - base::RepeatingTimer timer_; - - DISALLOW_COPY_AND_ASSIGN(CastExternalBeginFrameClient); -}; - -} // namespace chromecast - -#endif // CHROMECAST_GRAPHICS_CAST_EXTERNAL_BEGIN_FRAME_CLIENT_H_
diff --git a/chromecast/graphics/cast_external_begin_frame_source.cc b/chromecast/graphics/cast_external_begin_frame_source.cc new file mode 100644 index 0000000..5d305d76 --- /dev/null +++ b/chromecast/graphics/cast_external_begin_frame_source.cc
@@ -0,0 +1,50 @@ +// 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 "chromecast/graphics/cast_external_begin_frame_source.h" + +#include "base/time/time.h" +#include "chromecast/graphics/cast_window_manager_aura.h" + +namespace chromecast { +namespace { +constexpr base::TimeDelta kFrameInterval = + base::TimeDelta::FromMilliseconds(250); +constexpr uint64_t kSourceId = viz::BeginFrameArgs::kManualSourceId; +} // namespace + +CastExternalBeginFrameSource::CastExternalBeginFrameSource( + CastWindowManagerAura* cast_window_manager_aura) + : cast_window_manager_aura_(cast_window_manager_aura), + sequence_number_(viz::BeginFrameArgs::kStartingFrameNumber), + weak_factory_(this) { + IssueExternalBeginFrame(); +} + +CastExternalBeginFrameSource::~CastExternalBeginFrameSource() {} + +void CastExternalBeginFrameSource::OnFrameComplete( + const viz::BeginFrameAck& ack) { + DCHECK_EQ(kSourceId, ack.source_id); + timer_.Start( + FROM_HERE, kFrameInterval, + base::BindOnce(&CastExternalBeginFrameSource::IssueExternalBeginFrame, + base::Unretained(this))); +} + +void CastExternalBeginFrameSource::IssueExternalBeginFrame() { + const auto now = base::TimeTicks::Now(); + viz::BeginFrameArgs args = viz::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, kSourceId, sequence_number_, now, + now + kFrameInterval, kFrameInterval, viz::BeginFrameArgs::NORMAL); + ui::Compositor* compositor = + cast_window_manager_aura_->window_tree_host()->compositor(); + compositor->context_factory_private()->IssueExternalBeginFrame( + compositor, args, false, + base::BindOnce(&CastExternalBeginFrameSource::OnFrameComplete, + weak_factory_.GetWeakPtr())); + sequence_number_++; +} + +} // namespace chromecast
diff --git a/chromecast/graphics/cast_external_begin_frame_source.h b/chromecast/graphics/cast_external_begin_frame_source.h new file mode 100644 index 0000000..b264bac1 --- /dev/null +++ b/chromecast/graphics/cast_external_begin_frame_source.h
@@ -0,0 +1,37 @@ +// 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 CHROMECAST_GRAPHICS_CAST_EXTERNAL_BEGIN_FRAME_SOURCE_H_ +#define CHROMECAST_GRAPHICS_CAST_EXTERNAL_BEGIN_FRAME_SOURCE_H_ + +#include "base/memory/weak_ptr.h" +#include "base/timer/timer.h" +#include "components/viz/common/frame_sinks/begin_frame_args.h" + +namespace chromecast { + +class CastWindowManagerAura; + +class CastExternalBeginFrameSource { + public: + explicit CastExternalBeginFrameSource( + CastWindowManagerAura* cast_window_manager_aura); + ~CastExternalBeginFrameSource(); + + private: + void OnFrameComplete(const viz::BeginFrameAck& ack); + void IssueExternalBeginFrame(); + + CastWindowManagerAura* cast_window_manager_aura_; + uint64_t sequence_number_; + base::OneShotTimer timer_; + + base::WeakPtrFactory<CastExternalBeginFrameSource> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(CastExternalBeginFrameSource); +}; + +} // namespace chromecast + +#endif // CHROMECAST_GRAPHICS_CAST_EXTERNAL_BEGIN_FRAME_SOURCE_H_
diff --git a/chromecast/graphics/cast_window_manager_aura.cc b/chromecast/graphics/cast_window_manager_aura.cc index 23a03c8..61089a9 100644 --- a/chromecast/graphics/cast_window_manager_aura.cc +++ b/chromecast/graphics/cast_window_manager_aura.cc
@@ -85,11 +85,11 @@ CastWindowTreeHost::CastWindowTreeHost( bool enable_input, ui::PlatformWindowInitProperties properties, - ui::ExternalBeginFrameClient* external_begin_frame_client) + bool use_external_frame_control) : WindowTreeHostPlatform(std::move(properties), nullptr, nullptr, - external_begin_frame_client), + use_external_frame_control), enable_input_(enable_input) { if (!enable_input) window()->SetEventTargeter(std::make_unique<aura::NullWindowTargeter>());
diff --git a/chromecast/graphics/cast_window_manager_aura.h b/chromecast/graphics/cast_window_manager_aura.h index 876b76c..b593c2a 100644 --- a/chromecast/graphics/cast_window_manager_aura.h +++ b/chromecast/graphics/cast_window_manager_aura.h
@@ -19,10 +19,6 @@ } // namespace client } // namespace aura -namespace ui { -class ExternalBeginFrameClient; -} // namespace ui - namespace chromecast { class CastTouchEventGate; @@ -35,10 +31,9 @@ // An aura::WindowTreeHost that correctly converts input events. class CastWindowTreeHost : public aura::WindowTreeHostPlatform { public: - CastWindowTreeHost( - bool enable_input, - ui::PlatformWindowInitProperties properties, - ui::ExternalBeginFrameClient* external_begin_frame_client = nullptr); + CastWindowTreeHost(bool enable_input, + ui::PlatformWindowInitProperties properties, + bool use_external_frame_control = false); ~CastWindowTreeHost() override; // aura::WindowTreeHostPlatform implementation:
diff --git a/chromecast/media/audio/cast_audio_output_stream.cc b/chromecast/media/audio/cast_audio_output_stream.cc index 97ad131..92ad089 100644 --- a/chromecast/media/audio/cast_audio_output_stream.cc +++ b/chromecast/media/audio/cast_audio_output_stream.cc
@@ -385,18 +385,11 @@ // The rendering delay to account for buffering is not included in // rendering_delay.delay_microseconds but is in delay_timestamp which isn't // used by AudioOutputStreamImpl. - if (is_audio_prefetch_) { - // Only account for this when prefetch is enabled or else video will - // stutter (b/123999757). - delay = base::TimeDelta::FromMicroseconds( - rendering_delay.delay_microseconds + - rendering_delay.timestamp_microseconds - MonotonicClockNow()); - if (delay.InMicroseconds() < 0) { - delay = base::TimeDelta(); - } - } else { - delay = - base::TimeDelta::FromMicroseconds(rendering_delay.delay_microseconds); + delay = base::TimeDelta::FromMicroseconds( + rendering_delay.delay_microseconds + + rendering_delay.timestamp_microseconds - MonotonicClockNow()); + if (delay.InMicroseconds() < 0) { + delay = base::TimeDelta(); } } last_rendering_delay_ = delay;
diff --git a/chromecast/media/audio/cast_audio_output_stream_unittest.cc b/chromecast/media/audio/cast_audio_output_stream_unittest.cc index 3e6b625..6f26df409 100644 --- a/chromecast/media/audio/cast_audio_output_stream_unittest.cc +++ b/chromecast/media/audio/cast_audio_output_stream_unittest.cc
@@ -19,6 +19,7 @@ #include "chromecast/common/mojom/multiroom.mojom.h" #include "chromecast/media/audio/cast_audio_manager.h" #include "chromecast/media/audio/cast_audio_mixer.h" +#include "chromecast/media/base/monotonic_clock.h" #include "chromecast/media/cma/backend/cma_backend.h" #include "chromecast/media/cma/base/decoder_buffer_base.h" #include "chromecast/media/cma/test/mock_cma_backend_factory.h" @@ -56,7 +57,6 @@ namespace { const char kDefaultDeviceId[] = ""; const int64_t kDelayUs = 123; -const int64_t kDelayTimestampUs = 123456789; const double kDefaultVolume = 1.0f; int on_more_data_call_count_ = 0; @@ -919,11 +919,12 @@ FakeAudioDecoder* audio_decoder = GetAudioDecoder(); ASSERT_TRUE(audio_decoder); audio_decoder->set_rendering_delay( - CmaBackend::AudioDecoder::RenderingDelay(kDelayUs, kDelayTimestampUs)); - + CmaBackend::AudioDecoder::RenderingDelay(kDelayUs, MonotonicClockNow())); ::media::MockAudioSourceCallback source_callback; const base::TimeDelta delay(base::TimeDelta::FromMicroseconds(kDelayUs)); - EXPECT_CALL(source_callback, OnMoreData(delay, _, _, _)) + // OnMoreData can be called with a shorter delay than the rendering delay in + // order to prefetch audio data faster. + EXPECT_CALL(source_callback, OnMoreData(testing::Le(delay), _, _, _)) .WillRepeatedly(Invoke(OnMoreData)); stream->Start(&source_callback);
diff --git a/chromeos/dbus/fake_update_engine_client.cc b/chromeos/dbus/fake_update_engine_client.cc index 4b77dd06..d3d64342 100644 --- a/chromeos/dbus/fake_update_engine_client.cc +++ b/chromeos/dbus/fake_update_engine_client.cc
@@ -15,8 +15,7 @@ reboot_after_update_call_count_(0), request_update_check_call_count_(0), rollback_call_count_(0), - can_rollback_call_count_(0), - end_of_life_status_(update_engine::EndOfLifeStatus::kSupported) {} + can_rollback_call_count_(0) {} FakeUpdateEngineClient::~FakeUpdateEngineClient() = default; @@ -89,8 +88,9 @@ void FakeUpdateEngineClient::GetEolStatus(GetEolStatusCallback callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, - base::BindOnce(base::BindOnce(std::move(callback), end_of_life_status_), - number_of_milestones_)); + base::BindOnce(base::BindOnce(std::move(callback), + update_engine::EndOfLifeStatus::kSupported), + base::nullopt /* number_of_milestones */)); } void FakeUpdateEngineClient::SetUpdateOverCellularPermission( @@ -106,4 +106,14 @@ callback.Run(true); } +void FakeUpdateEngineClient::set_default_status( + const UpdateEngineClient::Status& status) { + default_status_ = status; +} + +void FakeUpdateEngineClient::set_update_check_result( + const UpdateEngineClient::UpdateCheckResult& result) { + update_check_result_ = result; +} + } // namespace chromeos
diff --git a/chromeos/dbus/fake_update_engine_client.h b/chromeos/dbus/fake_update_engine_client.h index 29c5cc1b..e60a1b4 100644 --- a/chromeos/dbus/fake_update_engine_client.h +++ b/chromeos/dbus/fake_update_engine_client.h
@@ -60,25 +60,11 @@ // Sets the default UpdateEngineClient::Status. GetLastStatus() returns the // value set here if |status_queue_| is empty. - void set_default_status(const UpdateEngineClient::Status& status) { - default_status_ = status; - } - - // Sets the EOL status. - void set_end_of_life_status(const update_engine::EndOfLifeStatus& status) { - end_of_life_status_ = status; - } - - // Sets the number of milestones until EOL. - void set_number_of_milestones(const int32_t& number_of_milestones) { - number_of_milestones_ = number_of_milestones; - } + void set_default_status(const UpdateEngineClient::Status& status); // Sets a value returned by RequestUpdateCheck(). void set_update_check_result( - const UpdateEngineClient::UpdateCheckResult& result) { - update_check_result_ = result; - } + const UpdateEngineClient::UpdateCheckResult& result); void set_can_rollback_check_result(bool result) { can_rollback_stub_result_ = result; @@ -110,8 +96,6 @@ int request_update_check_call_count_; int rollback_call_count_; int can_rollback_call_count_; - update_engine::EndOfLifeStatus end_of_life_status_; - base::Optional<int32_t> number_of_milestones_; }; } // namespace chromeos
diff --git a/chromeos/services/device_sync/BUILD.gn b/chromeos/services/device_sync/BUILD.gn index 4780dbc..d71d27c 100644 --- a/chromeos/services/device_sync/BUILD.gn +++ b/chromeos/services/device_sync/BUILD.gn
@@ -243,6 +243,7 @@ "cryptauth_key_unittest.cc", "cryptauth_metadata_syncer_impl_unittest.cc", "cryptauth_scheduler_impl_unittest.cc", + "cryptauth_v2_device_manager_impl_unittest.cc", "cryptauth_v2_enroller_impl_unittest.cc", "cryptauth_v2_enrollment_manager_impl_unittest.cc", "device_sync_service_unittest.cc",
diff --git a/chromeos/services/device_sync/cryptauth_device_sync_result.cc b/chromeos/services/device_sync/cryptauth_device_sync_result.cc index 931ea924..a1e67cc 100644 --- a/chromeos/services/device_sync/cryptauth_device_sync_result.cc +++ b/chromeos/services/device_sync/cryptauth_device_sync_result.cc
@@ -72,6 +72,10 @@ case ResultCode::kFinishedWithNonFatalErrors: stream << "[Finished with non-fatal errors]"; break; + case ResultCode::kErrorClientAppMetadataFetchFailed: + stream << "[Error: Could not retrieve ClientAppMetadata from " + << "ClientAppMetadataProvider]"; + break; case ResultCode::kErrorMissingUserKeyPair: stream << "[Error: No user key pair in registry]"; break; @@ -168,6 +172,9 @@ case ResultCode::kErrorShareGroupPrivateKeyApiCallUnknownError: stream << "[ShareGroupPrivateKey API call failed: Unknown error]"; break; + case ResultCode::kErrorTimeoutWaitingForClientAppMetadata: + stream << "[Error: Timeout waiting for ClientAppMetadata]"; + break; case ResultCode::kErrorTimeoutWaitingForGroupKeyCreation: stream << "[Error: Timeout waiting for group key creation]"; break;
diff --git a/chromeos/services/device_sync/cryptauth_device_sync_result.h b/chromeos/services/device_sync/cryptauth_device_sync_result.h index a2c48fd..b45418d 100644 --- a/chromeos/services/device_sync/cryptauth_device_sync_result.h +++ b/chromeos/services/device_sync/cryptauth_device_sync_result.h
@@ -25,6 +25,7 @@ enum class ResultCode { kSuccess, kFinishedWithNonFatalErrors, + kErrorClientAppMetadataFetchFailed, kErrorMissingUserKeyPair, kErrorEncryptingDeviceMetadata, kErrorEstablishingGroupPublicKey, @@ -57,6 +58,7 @@ kErrorShareGroupPrivateKeyApiCallInternalServerError, kErrorShareGroupPrivateKeyApiCallUnknownError, kErrorTimeoutWaitingForGroupKeyCreation, + kErrorTimeoutWaitingForClientAppMetadata, kErrorTimeoutWaitingForLocalDeviceMetadataEncryption, kErrorTimeoutWaitingForFirstSyncMetadataResponse, kErrorTimeoutWaitingForSecondSyncMetadataResponse, @@ -69,7 +71,18 @@ kMaxValue = kErrorTimeoutWaitingForShareGroupPrivateKeyResponse }; - enum class ResultType { kSuccess, kNonFatalError, kFatalError }; + // Enum class to denote the result type of a CryptAuth v2 DeviceSync attempt. + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. If entries are added, kMaxValue + // should be updated. + // TODO(nohle): Add numeric values. + enum class ResultType { + kSuccess, + kNonFatalError, + kFatalError, + // Used for UMA logs. + kMaxValue = kFatalError + }; static ResultType GetResultType(ResultCode result_code);
diff --git a/chromeos/services/device_sync/cryptauth_device_syncer.h b/chromeos/services/device_sync/cryptauth_device_syncer.h index 5a8d8e9..bd876a5 100644 --- a/chromeos/services/device_sync/cryptauth_device_syncer.h +++ b/chromeos/services/device_sync/cryptauth_device_syncer.h
@@ -7,6 +7,7 @@ #include "base/callback.h" #include "base/macros.h" +#include "chromeos/services/device_sync/cryptauth_device_sync_result.h" namespace cryptauthv2 { class ClientMetadata; @@ -17,8 +18,6 @@ namespace device_sync { -class CryptAuthDeviceSyncResult; - // Implements the client end of the CryptAuth v2 DeviceSync protocol, which // consists of three to four request/response interactions with the CryptAuth // servers: @@ -68,8 +67,10 @@ public: virtual ~CryptAuthDeviceSyncer(); + // The DeviceSync result is passed by value so that the device syner can be + // deleted before the result is processed. using DeviceSyncAttemptFinishedCallback = - base::OnceCallback<void(const CryptAuthDeviceSyncResult&)>; + base::OnceCallback<void(CryptAuthDeviceSyncResult)>; // Starts the CryptAuth v2 DeviceSync flow. // |client_metadata|: Information about the DeviceSync attempt--such as
diff --git a/chromeos/services/device_sync/cryptauth_device_syncer_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_device_syncer_impl_unittest.cc index 59811d9..636d273 100644 --- a/chromeos/services/device_sync/cryptauth_device_syncer_impl_unittest.cc +++ b/chromeos/services/device_sync/cryptauth_device_syncer_impl_unittest.cc
@@ -390,8 +390,7 @@ return fake_cryptauth_group_private_key_sharer_factory_->instances().back(); } - void OnDeviceSyncComplete( - const CryptAuthDeviceSyncResult& device_sync_result) { + void OnDeviceSyncComplete(CryptAuthDeviceSyncResult device_sync_result) { device_sync_result_ = device_sync_result; }
diff --git a/chromeos/services/device_sync/cryptauth_scheduler_impl.cc b/chromeos/services/device_sync/cryptauth_scheduler_impl.cc index 3ec6d19..0c8df64 100644 --- a/chromeos/services/device_sync/cryptauth_scheduler_impl.cc +++ b/chromeos/services/device_sync/cryptauth_scheduler_impl.cc
@@ -241,6 +241,7 @@ void CryptAuthSchedulerImpl::HandleDeviceSyncResult( const CryptAuthDeviceSyncResult& device_sync_result) { + // Note: "Success" for DeviceSync means no errors, not even non-fatal errors. HandleResult(RequestType::kDeviceSync, device_sync_result.IsSuccess(), device_sync_result.client_directive()); }
diff --git a/chromeos/services/device_sync/cryptauth_v2_device_manager_impl.cc b/chromeos/services/device_sync/cryptauth_v2_device_manager_impl.cc index 2e65f19..723472f 100644 --- a/chromeos/services/device_sync/cryptauth_v2_device_manager_impl.cc +++ b/chromeos/services/device_sync/cryptauth_v2_device_manager_impl.cc
@@ -4,16 +4,30 @@ #include "chromeos/services/device_sync/cryptauth_v2_device_manager_impl.h" +#include <sstream> +#include <utility> + #include "base/memory/ptr_util.h" #include "base/no_destructor.h" #include "chromeos/components/multidevice/logging/logging.h" #include "chromeos/services/device_sync/cryptauth_client.h" +#include "chromeos/services/device_sync/cryptauth_device_syncer_impl.h" #include "chromeos/services/device_sync/cryptauth_key_registry.h" +#include "chromeos/services/device_sync/public/cpp/client_app_metadata_provider.h" namespace chromeos { namespace device_sync { +namespace { + +// Timeout value for asynchronous operation. +// TODO(https://crbug.com/933656): Tune these values. +constexpr base::TimeDelta kWaitingForClientAppMetadataTimeout = + base::TimeDelta::FromSeconds(10); + +} // namespace + // static CryptAuthV2DeviceManagerImpl::Factory* CryptAuthV2DeviceManagerImpl::Factory::test_factory_ = nullptr; @@ -38,24 +52,33 @@ std::unique_ptr<CryptAuthV2DeviceManager> CryptAuthV2DeviceManagerImpl::Factory::BuildInstance( + ClientAppMetadataProvider* client_app_metadata_provider, CryptAuthDeviceRegistry* device_registry, CryptAuthKeyRegistry* key_registry, CryptAuthClientFactory* client_factory, CryptAuthGCMManager* gcm_manager, - CryptAuthScheduler* scheduler) { + CryptAuthScheduler* scheduler, + std::unique_ptr<base::OneShotTimer> timer) { return base::WrapUnique(new CryptAuthV2DeviceManagerImpl( - device_registry, key_registry, client_factory, gcm_manager, scheduler)); + client_app_metadata_provider, device_registry, key_registry, + client_factory, gcm_manager, scheduler, std::move(timer))); } CryptAuthV2DeviceManagerImpl::CryptAuthV2DeviceManagerImpl( + ClientAppMetadataProvider* client_app_metadata_provider, CryptAuthDeviceRegistry* device_registry, CryptAuthKeyRegistry* key_registry, CryptAuthClientFactory* client_factory, CryptAuthGCMManager* gcm_manager, - CryptAuthScheduler* scheduler) - : device_registry_(device_registry), + CryptAuthScheduler* scheduler, + std::unique_ptr<base::OneShotTimer> timer) + : client_app_metadata_provider_(client_app_metadata_provider), + device_registry_(device_registry), + key_registry_(key_registry), + client_factory_(client_factory), gcm_manager_(gcm_manager), - scheduler_(scheduler) { + scheduler_(scheduler), + timer_(std::move(timer)) { gcm_manager_->AddObserver(this); } @@ -105,58 +128,170 @@ // TODO(nohle): Log invocation reason metric. - // TODO(nohle): Start DeviceSync flow here. + if (!client_app_metadata_) { + // GCM registration is expected to be completed before the first enrollment. + DCHECK(!gcm_manager_->GetRegistrationId().empty()) + << "DeviceSync requested before GCM registration complete."; + + SetState(State::kWaitingForClientAppMetadata); + client_app_metadata_provider_->GetClientAppMetadata( + gcm_manager_->GetRegistrationId(), + base::BindOnce( + &CryptAuthV2DeviceManagerImpl::OnClientAppMetadataFetched, + callback_weak_ptr_factory_.GetWeakPtr())); + return; + } + + AttemptDeviceSync(); } void CryptAuthV2DeviceManagerImpl::OnResyncMessage( const base::Optional<std::string>& session_id, const base::Optional<CryptAuthFeatureType>& feature_type) { PA_LOG(VERBOSE) << "Received GCM message to re-sync devices (session ID: " - << session_id.value_or("[No session ID]") << ")"; + << session_id.value_or("[No session ID]") << ")."; ForceDeviceSyncNow(cryptauthv2::ClientMetadata::SERVER_INITIATED, session_id); } -void CryptAuthV2DeviceManagerImpl::OnDeviceSyncFinished( - const CryptAuthDeviceSyncResult& device_sync_result) { - // TODO(nohle): Invalidate callback weak pointers, if applicable, and reset - // the DeviceSyncer instance. +void CryptAuthV2DeviceManagerImpl::SetState(State state) { + timer_->Stop(); - if (device_sync_result.IsSuccess()) { - PA_LOG(INFO) << "DeviceSync attempt with invocation reason " - << current_client_metadata_->invocation_reason() - << " succeeded with result code " - << device_sync_result.result_code(); + PA_LOG(INFO) << "Transitioning from " << state_ << " to " << state << "."; + state_ = state; - // TODO(nohle): Log if the devices changed. - } else { - PA_LOG(WARNING) << "DeviceSync attempt with invocation reason " - << current_client_metadata_->invocation_reason() - << " failed with result code " - << device_sync_result.result_code(); + // Note: CryptAuthDeviceSyncerImpl guarantees that the callback passed to its + // public method is always invoked; in other words, the class handles is + // relevant timeouts internally. + if (state_ != State::kWaitingForClientAppMetadata) + return; + + // TODO(https://crbug.com/936273): Add metrics to track failure rates due + // to async timeouts. + timer_->Start(FROM_HERE, kWaitingForClientAppMetadataTimeout, + base::BindOnce(&CryptAuthV2DeviceManagerImpl::OnTimeout, + callback_weak_ptr_factory_.GetWeakPtr())); +} + +void CryptAuthV2DeviceManagerImpl::OnTimeout() { + DCHECK_EQ(State::kWaitingForClientAppMetadata, state_); + + OnDeviceSyncFinished( + CryptAuthDeviceSyncResult(CryptAuthDeviceSyncResult::ResultCode:: + kErrorTimeoutWaitingForClientAppMetadata, + false /* did_device_registry_change */, + base::nullopt /* client_directive */)); +} + +void CryptAuthV2DeviceManagerImpl::OnClientAppMetadataFetched( + const base::Optional<cryptauthv2::ClientAppMetadata>& client_app_metadata) { + DCHECK(state_ == State::kWaitingForClientAppMetadata); + + bool success = client_app_metadata.has_value(); + + if (!success) { + OnDeviceSyncFinished( + CryptAuthDeviceSyncResult(CryptAuthDeviceSyncResult::ResultCode:: + kErrorClientAppMetadataFetchFailed, + false /* did_device_registry_change */, + base::nullopt /* client_directive */)); + return; } + client_app_metadata_ = client_app_metadata; + + AttemptDeviceSync(); +} + +void CryptAuthV2DeviceManagerImpl::AttemptDeviceSync() { + DCHECK(current_client_metadata_); + DCHECK(client_app_metadata_); + + device_syncer_ = CryptAuthDeviceSyncerImpl::Factory::Get()->BuildInstance( + device_registry_, key_registry_, client_factory_); + + SetState(State::kWaitingForDeviceSync); + + device_syncer_->Sync( + *current_client_metadata_, *client_app_metadata_, + base::BindOnce(&CryptAuthV2DeviceManagerImpl::OnDeviceSyncFinished, + callback_weak_ptr_factory_.GetWeakPtr())); +} + +void CryptAuthV2DeviceManagerImpl::OnDeviceSyncFinished( + CryptAuthDeviceSyncResult device_sync_result) { + // Once a DeviceSync attempt finishes, no other callbacks should be invoked. + // This is particularly relevant for timeout failures. + callback_weak_ptr_factory_.InvalidateWeakPtrs(); + + // The DeviceSync result might be owned by the device syncer, so we copy the + // result here before destroying the device syncer. + CryptAuthDeviceSyncResult device_sync_result_copy = device_sync_result; + device_syncer_.reset(); + + std::stringstream prefix; + prefix << "DeviceSync attempt with invocation reason " + << current_client_metadata_->invocation_reason(); + std::stringstream suffix; + suffix << "with result code " << device_sync_result_copy.result_code() << "."; + switch (device_sync_result_copy.GetResultType()) { + case CryptAuthDeviceSyncResult::ResultType::kSuccess: + PA_LOG(INFO) << prefix.str() << " succeeded " << suffix.str(); + break; + case CryptAuthDeviceSyncResult::ResultType::kNonFatalError: + PA_LOG(WARNING) << prefix.str() << " finished with non-fatal errors " + << suffix.str(); + break; + case CryptAuthDeviceSyncResult::ResultType::kFatalError: + PA_LOG(ERROR) << prefix.str() << " failed " << suffix.str(); + break; + } + + PA_LOG(INFO) << "The device registry " + << (device_sync_result_copy.did_device_registry_change() + ? "changed." + : "did not change."); + current_client_metadata_.reset(); // TODO(nohle): Log DeviceSync result metrics: success, result code, and if // devices changed. - scheduler_->HandleDeviceSyncResult(device_sync_result); + scheduler_->HandleDeviceSyncResult(device_sync_result_copy); base::Optional<base::TimeDelta> time_to_next_attempt = GetTimeToNextAttempt(); if (time_to_next_attempt) { PA_LOG(INFO) << "Time until next DeviceSync attempt: " - << *time_to_next_attempt; + << *time_to_next_attempt << "."; } else { - PA_LOG(INFO) << "No future DeviceSync requests currently scheduled"; + PA_LOG(INFO) << "No future DeviceSync requests currently scheduled."; } - if (!device_sync_result.IsSuccess()) { - PA_LOG(INFO) << "Number of consecutive Enrollment failures: " - << scheduler_->GetNumConsecutiveEnrollmentFailures(); + if (!device_sync_result_copy.IsSuccess()) { + PA_LOG(INFO) << "Number of consecutive DeviceSync failures: " + << scheduler_->GetNumConsecutiveDeviceSyncFailures() << "."; } - NotifyDeviceSyncFinished(device_sync_result); + SetState(State::kIdle); + + NotifyDeviceSyncFinished(device_sync_result_copy); +} + +std::ostream& operator<<(std::ostream& stream, + const CryptAuthV2DeviceManagerImpl::State& state) { + switch (state) { + case CryptAuthV2DeviceManagerImpl::State::kIdle: + stream << "[DeviceManager state: Idle]"; + break; + case CryptAuthV2DeviceManagerImpl::State::kWaitingForClientAppMetadata: + stream << "[DeviceManager state: Waiting for ClientAppMetadata]"; + break; + case CryptAuthV2DeviceManagerImpl::State::kWaitingForDeviceSync: + stream << "[DeviceManager state: Waiting for DeviceSync to finish]"; + break; + } + + return stream; } } // namespace device_sync
diff --git a/chromeos/services/device_sync/cryptauth_v2_device_manager_impl.h b/chromeos/services/device_sync/cryptauth_v2_device_manager_impl.h index c93cbf6..f42654b 100644 --- a/chromeos/services/device_sync/cryptauth_v2_device_manager_impl.h +++ b/chromeos/services/device_sync/cryptauth_v2_device_manager_impl.h
@@ -6,24 +6,29 @@ #define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_V2_DEVICE_MANAGER_IMPL_H_ #include <memory> +#include <ostream> #include <string> #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "base/time/time.h" +#include "base/timer/timer.h" #include "chromeos/services/device_sync/cryptauth_device_registry.h" #include "chromeos/services/device_sync/cryptauth_device_sync_result.h" #include "chromeos/services/device_sync/cryptauth_gcm_manager.h" #include "chromeos/services/device_sync/cryptauth_scheduler.h" #include "chromeos/services/device_sync/cryptauth_v2_device_manager.h" +#include "chromeos/services/device_sync/proto/cryptauth_client_app_metadata.pb.h" #include "chromeos/services/device_sync/proto/cryptauth_common.pb.h" namespace chromeos { namespace device_sync { +class ClientAppMetadataProvider; class CryptAuthClientFactory; +class CryptAuthDeviceSyncer; class CryptAuthKeyRegistry; // Implementation of CryptAuthV2DeviceManager that considers three sources of @@ -44,11 +49,14 @@ static void SetFactoryForTesting(Factory* test_factory); virtual ~Factory(); virtual std::unique_ptr<CryptAuthV2DeviceManager> BuildInstance( + ClientAppMetadataProvider* client_app_metadata_provider, CryptAuthDeviceRegistry* device_registry, CryptAuthKeyRegistry* key_registry, CryptAuthClientFactory* client_factory, CryptAuthGCMManager* gcm_manager, - CryptAuthScheduler* scheduler); + CryptAuthScheduler* scheduler, + std::unique_ptr<base::OneShotTimer> timer = + std::make_unique<base::OneShotTimer>()); private: static Factory* test_factory_; @@ -57,13 +65,24 @@ ~CryptAuthV2DeviceManagerImpl() override; protected: - CryptAuthV2DeviceManagerImpl(CryptAuthDeviceRegistry* device_registry, - CryptAuthKeyRegistry* key_registry, - CryptAuthClientFactory* client_factory, - CryptAuthGCMManager* gcm_manager, - CryptAuthScheduler* scheduler); + CryptAuthV2DeviceManagerImpl( + ClientAppMetadataProvider* client_app_metadata_provider, + CryptAuthDeviceRegistry* device_registry, + CryptAuthKeyRegistry* key_registry, + CryptAuthClientFactory* client_factory, + CryptAuthGCMManager* gcm_manager, + CryptAuthScheduler* scheduler, + std::unique_ptr<base::OneShotTimer> timer); private: + enum class State { + kIdle, + kWaitingForClientAppMetadata, + kWaitingForDeviceSync + }; + + friend std::ostream& operator<<(std::ostream& stream, const State& state); + // CryptAuthV2DeviceManager: void Start() override; const CryptAuthDeviceRegistry::InstanceIdToDeviceMap& GetSyncedDevices() @@ -85,14 +104,34 @@ const base::Optional<std::string>& session_id, const base::Optional<CryptAuthFeatureType>& feature_type) override; - void OnDeviceSyncFinished( - const CryptAuthDeviceSyncResult& device_sync_result); + void SetState(State state); + void OnTimeout(); - CryptAuthDeviceRegistry* device_registry_ = nullptr; - CryptAuthGCMManager* gcm_manager_ = nullptr; - CryptAuthScheduler* scheduler_ = nullptr; + void OnClientAppMetadataFetched( + const base::Optional<cryptauthv2::ClientAppMetadata>& + client_app_metadata); + void AttemptDeviceSync(); + void OnDeviceSyncFinished(CryptAuthDeviceSyncResult device_sync_result); + + State state_ = State::kIdle; base::Optional<cryptauthv2::ClientMetadata> current_client_metadata_; + base::Optional<cryptauthv2::ClientAppMetadata> client_app_metadata_; + std::unique_ptr<CryptAuthDeviceSyncer> device_syncer_; + + ClientAppMetadataProvider* client_app_metadata_provider_ = nullptr; + CryptAuthDeviceRegistry* device_registry_ = nullptr; + CryptAuthKeyRegistry* key_registry_ = nullptr; + CryptAuthClientFactory* client_factory_ = nullptr; + CryptAuthGCMManager* gcm_manager_ = nullptr; + CryptAuthScheduler* scheduler_ = nullptr; + std::unique_ptr<base::OneShotTimer> timer_; + + // For weak pointers used in callbacks. These weak pointers are invalidated + // when the current DeviceSync attempt finishes in order to cancel outstanding + // callbacks. + base::WeakPtrFactory<CryptAuthV2DeviceManagerImpl> callback_weak_ptr_factory_{ + this}; // For sending a weak pointer to the scheduler, whose lifetime exceeds that of // CryptAuthV2DeviceManagerImpl.
diff --git a/chromeos/services/device_sync/cryptauth_v2_device_manager_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_v2_device_manager_impl_unittest.cc new file mode 100644 index 0000000..b3cb1f15 --- /dev/null +++ b/chromeos/services/device_sync/cryptauth_v2_device_manager_impl_unittest.cc
@@ -0,0 +1,394 @@ +// 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 "chromeos/services/device_sync/cryptauth_v2_device_manager_impl.h" + +#include "base/optional.h" +#include "base/timer/mock_timer.h" +#include "chromeos/services/device_sync/cryptauth_device_registry_impl.h" +#include "chromeos/services/device_sync/cryptauth_device_syncer_impl.h" +#include "chromeos/services/device_sync/cryptauth_key_registry_impl.h" +#include "chromeos/services/device_sync/fake_cryptauth_device_syncer.h" +#include "chromeos/services/device_sync/fake_cryptauth_gcm_manager.h" +#include "chromeos/services/device_sync/fake_cryptauth_scheduler.h" +#include "chromeos/services/device_sync/mock_cryptauth_client.h" +#include "chromeos/services/device_sync/proto/cryptauth_common.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_v2_test_util.h" +#include "chromeos/services/device_sync/public/cpp/fake_client_app_metadata_provider.h" +#include "components/prefs/testing_pref_service.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromeos { + +namespace device_sync { + +namespace { + +const char kFakeSessionId[] = "session_id"; +const double kFakeLastSuccessTimeSeconds = 1600600000; +constexpr base::TimeDelta kFakeFailureRetryTime = + base::TimeDelta::FromMinutes(15); + +// A FakeCryptAuthScheduler that updates its DeviceSync parameters based on the +// result of the DeviceSync attempt. This makes for reasonable logs. +class FakeCryptAuthSchedulerUpdatedByDeviceSyncResults + : public FakeCryptAuthScheduler { + void HandleDeviceSyncResult( + const CryptAuthDeviceSyncResult& device_sync_result) override { + FakeCryptAuthScheduler::HandleDeviceSyncResult(device_sync_result); + + if (device_sync_result.IsSuccess()) { + set_num_consecutive_device_sync_failures(0); + set_time_to_next_device_sync_request(base::nullopt); + set_last_successful_device_sync_time( + base::Time::FromDoubleT(kFakeLastSuccessTimeSeconds)); + } else { + set_num_consecutive_device_sync_failures( + GetNumConsecutiveDeviceSyncFailures() + 1); + set_time_to_next_device_sync_request(kFakeFailureRetryTime); + } + } +}; + +} // namespace + +class DeviceSyncCryptAuthV2DeviceManagerImplTest + : public testing::Test, + public CryptAuthV2DeviceManager::Observer { + protected: + DeviceSyncCryptAuthV2DeviceManagerImplTest() + : fake_gcm_manager_(cryptauthv2::kTestGcmRegistrationId), + mock_client_factory_( + MockCryptAuthClientFactory::MockType::MAKE_NICE_MOCKS) {} + + // testing::Test: + void SetUp() override { + CryptAuthDeviceRegistryImpl::RegisterPrefs(test_pref_service_.registry()); + CryptAuthKeyRegistryImpl::RegisterPrefs(test_pref_service_.registry()); + + device_registry_ = + CryptAuthDeviceRegistryImpl::Factory::Get()->BuildInstance( + &test_pref_service_); + key_registry_ = CryptAuthKeyRegistryImpl::Factory::Get()->BuildInstance( + &test_pref_service_); + + fake_device_syncer_factory_ = + std::make_unique<FakeCryptAuthDeviceSyncerFactory>(); + CryptAuthDeviceSyncerImpl::Factory::SetFactoryForTesting( + fake_device_syncer_factory_.get()); + } + + // testing::Test: + void TearDown() override { + if (device_manager_) + device_manager_->RemoveObserver(this); + + CryptAuthDeviceSyncerImpl::Factory::SetFactoryForTesting(nullptr); + } + + // CryptAuthV2DeviceManager::Observer: + void OnDeviceSyncStarted( + const cryptauthv2::ClientMetadata& client_metadata) override { + client_metadata_sent_to_observer_.push_back(client_metadata); + } + void OnDeviceSyncFinished( + const CryptAuthDeviceSyncResult& device_sync_result) override { + device_sync_results_sent_to_observer_.push_back(device_sync_result); + } + + void CreateAndStartDeviceManager() { + auto mock_timer = std::make_unique<base::MockOneShotTimer>(); + mock_timer_ = mock_timer.get(); + + device_manager_ = + CryptAuthV2DeviceManagerImpl::Factory::Get()->BuildInstance( + &fake_client_app_metadata_provider_, device_registry_.get(), + key_registry_.get(), &mock_client_factory_, &fake_gcm_manager_, + &fake_scheduler_, std::move(mock_timer)); + + device_manager_->AddObserver(this); + + EXPECT_FALSE(fake_scheduler_.HasDeviceSyncSchedulingStarted()); + device_manager_->Start(); + EXPECT_TRUE(fake_scheduler_.HasDeviceSyncSchedulingStarted()); + } + + void RequestDeviceSyncThroughSchedulerAndVerify( + const cryptauthv2::ClientMetadata::InvocationReason& invocation_reason, + const base::Optional<std::string>& session_id) { + fake_scheduler_.RequestDeviceSync(invocation_reason, session_id); + + ProcessAndVerifyNewDeviceSyncRequest(cryptauthv2::BuildClientMetadata( + fake_scheduler_.GetNumConsecutiveDeviceSyncFailures(), + invocation_reason, session_id)); + } + + void ForceDeviceSyncRequestAndVerify( + const cryptauthv2::ClientMetadata::InvocationReason& invocation_reason, + const base::Optional<std::string>& session_id) { + device_manager_->ForceDeviceSyncNow(invocation_reason, session_id); + + ProcessAndVerifyNewDeviceSyncRequest(cryptauthv2::BuildClientMetadata( + fake_scheduler_.GetNumConsecutiveDeviceSyncFailures(), + invocation_reason, session_id)); + } + + void RequestDeviceSyncThroughGcmAndVerify( + const base::Optional<std::string>& session_id) { + fake_gcm_manager_.PushResyncMessage(session_id, + base::nullopt /* feature_type */); + + ProcessAndVerifyNewDeviceSyncRequest(cryptauthv2::BuildClientMetadata( + fake_scheduler_.GetNumConsecutiveDeviceSyncFailures(), + cryptauthv2::ClientMetadata::SERVER_INITIATED, session_id)); + } + + void SucceedGetClientAppMetadataRequest() { + ASSERT_FALSE( + fake_client_app_metadata_provider_.metadata_requests().empty()); + EXPECT_EQ(cryptauthv2::kTestGcmRegistrationId, + fake_client_app_metadata_provider_.metadata_requests() + .back() + .gcm_registration_id); + std::move( + fake_client_app_metadata_provider_.metadata_requests().back().callback) + .Run(cryptauthv2::GetClientAppMetadataForTest()); + } + + void FailHandleGetClientAppMetadataRequestAndVerifyResult() { + ASSERT_FALSE( + fake_client_app_metadata_provider_.metadata_requests().empty()); + EXPECT_EQ(cryptauthv2::kTestGcmRegistrationId, + fake_client_app_metadata_provider_.metadata_requests() + .back() + .gcm_registration_id); + std::move( + fake_client_app_metadata_provider_.metadata_requests().back().callback) + .Run(base::nullopt /* client_app_metadata */); + ProcessAndVerifyNewDeviceSyncResult( + CryptAuthDeviceSyncResult(CryptAuthDeviceSyncResult::ResultCode:: + kErrorClientAppMetadataFetchFailed, + false /* did_device_registry_change */, + base::nullopt /* client_directive */)); + } + void TimeoutWaitingForClientAppMetadataAndVerifyResult() { + mock_timer_->Fire(); + ProcessAndVerifyNewDeviceSyncResult( + CryptAuthDeviceSyncResult(CryptAuthDeviceSyncResult::ResultCode:: + kErrorTimeoutWaitingForClientAppMetadata, + false /* did_device_registry_change */, + base::nullopt /* client_directive */)); + } + + void FinishDeviceSyncAttemptAndVerifyResult( + size_t expected_device_syncer_instance_index, + const CryptAuthDeviceSyncResult& device_sync_result) { + EXPECT_TRUE(device_manager_->IsDeviceSyncInProgress()); + + // A valid GCM registration ID and valid ClientAppMetadata must exist before + // the device syncer can be invoked. + EXPECT_EQ(cryptauthv2::kTestGcmRegistrationId, + fake_gcm_manager_.GetRegistrationId()); + ASSERT_FALSE( + fake_client_app_metadata_provider_.metadata_requests().empty()); + + // Only the most recently created device syncer is valid. + EXPECT_EQ(fake_device_syncer_factory_->instances().size() - 1, + expected_device_syncer_instance_index); + FakeCryptAuthDeviceSyncer* device_syncer = + fake_device_syncer_factory_ + ->instances()[expected_device_syncer_instance_index]; + + VerifyDeviceSyncerData(device_syncer, + expected_client_metadata_list_.back()); + + device_syncer->FinishAttempt(device_sync_result); + EXPECT_FALSE(device_manager_->IsDeviceSyncInProgress()); + + ProcessAndVerifyNewDeviceSyncResult(device_sync_result); + } + + CryptAuthV2DeviceManager* device_manager() { return device_manager_.get(); } + + private: + // Adds the ClientMetadata from the latest DeviceSync request to a list of + // expected ClientMetadata from all DeviceSync requests. Verifies that this + // ClientMetadata is communicated to the device manager's observers. + void ProcessAndVerifyNewDeviceSyncRequest( + const cryptauthv2::ClientMetadata& expected_client_metadata) { + expected_client_metadata_list_.push_back(expected_client_metadata); + + VerifyDeviceManagerObserversNotifiedOfStart(expected_client_metadata_list_); + } + + void VerifyDeviceManagerObserversNotifiedOfStart( + const std::vector<cryptauthv2::ClientMetadata>& + expected_client_metadata_list) { + ASSERT_EQ(expected_client_metadata_list.size(), + client_metadata_sent_to_observer_.size()); + for (size_t i = 0; i < expected_client_metadata_list.size(); ++i) { + EXPECT_EQ(expected_client_metadata_list[i].SerializeAsString(), + client_metadata_sent_to_observer_[i].SerializeAsString()); + } + } + + // Verifies the input to the device syncer. + void VerifyDeviceSyncerData( + FakeCryptAuthDeviceSyncer* device_syncer, + const cryptauthv2::ClientMetadata& expected_client_metadata) { + ASSERT_TRUE(device_syncer->client_metadata()); + ASSERT_TRUE(device_syncer->client_app_metadata()); + EXPECT_EQ(expected_client_metadata.SerializeAsString(), + device_syncer->client_metadata()->SerializeAsString()); + EXPECT_EQ(cryptauthv2::GetClientAppMetadataForTest().SerializeAsString(), + device_syncer->client_app_metadata()->SerializeAsString()); + } + + // Adds the result of the latest DeviceSync attempt to a list of all expected + // DeviceSync results. Verifies that the results are communicated to the + // device manager's observers and the scheduler. + void ProcessAndVerifyNewDeviceSyncResult( + const CryptAuthDeviceSyncResult& device_sync_result) { + expected_device_sync_results_.push_back(device_sync_result); + + EXPECT_EQ(expected_device_sync_results_, + device_sync_results_sent_to_observer_); + EXPECT_EQ(expected_device_sync_results_, + fake_scheduler_.handled_device_sync_results()); + } + + std::vector<cryptauthv2::ClientMetadata> expected_client_metadata_list_; + std::vector<CryptAuthDeviceSyncResult> expected_device_sync_results_; + + std::vector<cryptauthv2::ClientMetadata> client_metadata_sent_to_observer_; + std::vector<CryptAuthDeviceSyncResult> device_sync_results_sent_to_observer_; + + TestingPrefServiceSimple test_pref_service_; + FakeClientAppMetadataProvider fake_client_app_metadata_provider_; + FakeCryptAuthGCMManager fake_gcm_manager_; + FakeCryptAuthSchedulerUpdatedByDeviceSyncResults fake_scheduler_; + base::MockOneShotTimer* mock_timer_ = nullptr; + MockCryptAuthClientFactory mock_client_factory_; + std::unique_ptr<CryptAuthDeviceRegistry> device_registry_; + std::unique_ptr<CryptAuthKeyRegistry> key_registry_; + std::unique_ptr<FakeCryptAuthDeviceSyncerFactory> fake_device_syncer_factory_; + + std::unique_ptr<CryptAuthV2DeviceManager> device_manager_; +}; + +TEST_F(DeviceSyncCryptAuthV2DeviceManagerImplTest, + RequestDeviceSyncThroughScheduler) { + CreateAndStartDeviceManager(); + RequestDeviceSyncThroughSchedulerAndVerify( + cryptauthv2::ClientMetadata::INITIALIZATION, + base::nullopt /* session_id */); + SucceedGetClientAppMetadataRequest(); + FinishDeviceSyncAttemptAndVerifyResult( + 0u /* expected_device_sync_instance_index */, + CryptAuthDeviceSyncResult(CryptAuthDeviceSyncResult::ResultCode::kSuccess, + true /* did_device_registry_change */, + cryptauthv2::GetClientDirectiveForTest())); +} + +TEST_F(DeviceSyncCryptAuthV2DeviceManagerImplTest, ForceDeviceSync_Success) { + CreateAndStartDeviceManager(); + ForceDeviceSyncRequestAndVerify(cryptauthv2::ClientMetadata::MANUAL, + kFakeSessionId); + SucceedGetClientAppMetadataRequest(); + FinishDeviceSyncAttemptAndVerifyResult( + 0u /* expected_device_sync_instance_index */, + CryptAuthDeviceSyncResult(CryptAuthDeviceSyncResult::ResultCode::kSuccess, + true /* did_device_registry_change */, + cryptauthv2::GetClientDirectiveForTest())); +} + +TEST_F(DeviceSyncCryptAuthV2DeviceManagerImplTest, + RequestDeviceSyncThroughGcm) { + CreateAndStartDeviceManager(); + RequestDeviceSyncThroughGcmAndVerify(kFakeSessionId); + SucceedGetClientAppMetadataRequest(); + FinishDeviceSyncAttemptAndVerifyResult( + 0u /* expected_device_sync_instance_index */, + CryptAuthDeviceSyncResult(CryptAuthDeviceSyncResult::ResultCode::kSuccess, + true /* did_device_registry_change */, + cryptauthv2::GetClientDirectiveForTest())); +} + +TEST_F(DeviceSyncCryptAuthV2DeviceManagerImplTest, FailureRetry) { + CreateAndStartDeviceManager(); + RequestDeviceSyncThroughSchedulerAndVerify( + cryptauthv2::ClientMetadata::PERIODIC, base::nullopt /* session_id */); + SucceedGetClientAppMetadataRequest(); + + // Fail first attempt with fatal error. + FinishDeviceSyncAttemptAndVerifyResult( + 0u /* expected_device_sync_instance_index */, + CryptAuthDeviceSyncResult( + CryptAuthDeviceSyncResult::ResultCode:: + kErrorSyncMetadataApiCallInternalServerError, + false /* did_device_registry_change */, + base::nullopt /* client_directive */)); + EXPECT_EQ(kFakeFailureRetryTime, device_manager()->GetTimeToNextAttempt()); + EXPECT_EQ(base::nullopt, device_manager()->GetLastDeviceSyncTime()); + EXPECT_TRUE(device_manager()->IsRecoveringFromFailure()); + + // Fail second attempt with non-fatal error. + RequestDeviceSyncThroughSchedulerAndVerify( + cryptauthv2::ClientMetadata::PERIODIC, kFakeSessionId); + FinishDeviceSyncAttemptAndVerifyResult( + 1u /* expected_device_sync_instance_index */, + CryptAuthDeviceSyncResult( + CryptAuthDeviceSyncResult::ResultCode::kFinishedWithNonFatalErrors, + false /* did_device_registry_change */, + base::nullopt /* client_directive */)); + EXPECT_EQ(kFakeFailureRetryTime, device_manager()->GetTimeToNextAttempt()); + EXPECT_EQ(base::nullopt, device_manager()->GetLastDeviceSyncTime()); + EXPECT_TRUE(device_manager()->IsRecoveringFromFailure()); + + // Succeed third attempt. + RequestDeviceSyncThroughSchedulerAndVerify( + cryptauthv2::ClientMetadata::PERIODIC, kFakeSessionId); + FinishDeviceSyncAttemptAndVerifyResult( + 2u /* expected_device_sync_instance_index */, + CryptAuthDeviceSyncResult( + CryptAuthDeviceSyncResult::ResultCode::kSuccess, + true /* did_device_registry_change */, + cryptauthv2::GetClientDirectiveForTest() /* client_directive */)); + EXPECT_EQ(base::nullopt, device_manager()->GetTimeToNextAttempt()); + EXPECT_EQ(base::Time::FromDoubleT(kFakeLastSuccessTimeSeconds), + device_manager()->GetLastDeviceSyncTime()); + EXPECT_FALSE(device_manager()->IsRecoveringFromFailure()); +} + +TEST_F(DeviceSyncCryptAuthV2DeviceManagerImplTest, + ClientAppMetadataFetch_Failure) { + CreateAndStartDeviceManager(); + + // Fail to fetch ClientAppMetadata first attempt. + RequestDeviceSyncThroughSchedulerAndVerify( + cryptauthv2::ClientMetadata::PERIODIC, base::nullopt /* session_id */); + FailHandleGetClientAppMetadataRequestAndVerifyResult(); + + // Succeed ClientAppMetadata fetch second attempt. + RequestDeviceSyncThroughSchedulerAndVerify( + cryptauthv2::ClientMetadata::PERIODIC, base::nullopt /* session_id */); + SucceedGetClientAppMetadataRequest(); + FinishDeviceSyncAttemptAndVerifyResult( + 0u /* expected_device_sync_instance_index */, + CryptAuthDeviceSyncResult(CryptAuthDeviceSyncResult::ResultCode::kSuccess, + true /* did_device_registry_change */, + cryptauthv2::GetClientDirectiveForTest())); +} + +TEST_F(DeviceSyncCryptAuthV2DeviceManagerImplTest, + ClientAppMetadataFetch_Timeout) { + CreateAndStartDeviceManager(); + RequestDeviceSyncThroughSchedulerAndVerify( + cryptauthv2::ClientMetadata::PERIODIC, base::nullopt /* session_id */); + TimeoutWaitingForClientAppMetadataAndVerifyResult(); +} + +} // namespace device_sync + +} // namespace chromeos
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc index 37acb881..63628034 100644 --- a/components/autofill/core/browser/autofill_manager_unittest.cc +++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -66,7 +66,6 @@ #include "components/strings/grit/components_strings.h" #include "components/sync/driver/test_sync_service.h" #include "components/variations/variations_associated_data.h" -#include "components/variations/variations_params_manager.h" #include "components/version_info/channel.h" #include "net/base/url_util.h" #include "services/metrics/public/cpp/ukm_builders.h" @@ -367,8 +366,6 @@ /*call_parent_methods=*/false); autofill_manager_->SetExternalDelegate(external_delegate_.get()); - variation_params_.ClearAllVariationParams(); - // Initialize the TestPersonalDataManager with some default data. CreateTestAutofillProfiles(); CreateTestCreditCards(); @@ -621,7 +618,6 @@ MockAutofillDownloadManager* download_manager_; TestPersonalDataManager personal_data_; std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_; - variations::testing::VariationParamsManager variation_params_; base::test::ScopedFeatureList scoped_feature_list_; private:
diff --git a/components/browser_sync/browser_sync_client.h b/components/browser_sync/browser_sync_client.h index eedb660..9e2829a 100644 --- a/components/browser_sync/browser_sync_client.h +++ b/components/browser_sync/browser_sync_client.h
@@ -14,10 +14,6 @@ class BookmarkUndoService; -namespace autofill { -class PersonalDataManager; -} // namespace autofill - namespace bookmarks { class BookmarkModel; } // namespace bookmarks @@ -70,7 +66,6 @@ virtual sync_sessions::SessionSyncService* GetSessionSyncService() = 0; virtual send_tab_to_self::SendTabToSelfSyncService* GetSendTabToSelfSyncService() = 0; - virtual autofill::PersonalDataManager* GetPersonalDataManager() = 0; virtual BookmarkUndoService* GetBookmarkUndoService() = 0; virtual base::RepeatingClosure GetPasswordStateChangedCallback() = 0;
diff --git a/components/network_time/network_time_test_utils.cc b/components/network_time/network_time_test_utils.cc index 7261189..6ba8a358 100644 --- a/components/network_time/network_time_test_utils.cc +++ b/components/network_time/network_time_test_utils.cc
@@ -6,12 +6,7 @@ #include <memory> -#include "base/feature_list.h" -#include "base/metrics/field_trial.h" #include "base/strings/string_number_conversions.h" -#include "base/test/mock_entropy_provider.h" -#include "base/test/scoped_feature_list.h" -#include "components/variations/variations_associated_data.h" #include "net/http/http_response_headers.h" #include "net/test/embedded_test_server/http_response.h" #include "testing/gtest/include/gtest/gtest.h" @@ -60,15 +55,13 @@ bool enable, float query_probability, NetworkTimeTracker::FetchBehavior fetch_behavior) { - const std::string kTrialName = "Trial"; - const std::string kGroupName = "group"; - const base::Feature kFeature{"NetworkTimeServiceQuerying", - base::FEATURE_DISABLED_BY_DEFAULT}; + scoped_feature_list_.Reset(); + if (!enable) { + scoped_feature_list_.InitAndDisableFeature(kNetworkTimeServiceQuerying); + return; + } - // Clear all the things. - variations::testing::ClearAllVariationParams(); - - std::map<std::string, std::string> params; + base::FieldTrialParams params; params["RandomQueryProbability"] = base::NumberToString(query_probability); params["CheckTimeIntervalSeconds"] = base::NumberToString(360); std::string fetch_behavior_param; @@ -88,46 +81,8 @@ break; } params["FetchBehavior"] = fetch_behavior_param; - - // There are 3 things here: a FieldTrial, a FieldTrialList, and a - // FeatureList. Don't get confused! The FieldTrial is reference-counted, - // and a reference is held by the FieldTrialList. The FieldTrialList and - // FeatureList are both singletons. The authorized way to reset the former - // for testing is to destruct it (above). The latter, by contrast, should - // should already start in a clean state and can be manipulated via the - // ScopedFeatureList helper class. If this comment was useful to you - // please send me a postcard. - - // SetNetworkQueriesWithVariationsService() is usually called during test - // fixture setup (to establish a default state) and then again in certain - // tests that want to set special params. FieldTrialList is meant to be a - // singleton with only one instance existing at once, and the constructor - // fails a CHECK if this is violated. To allow these duplicate calls to this - // method, any existing FieldTrialList must be destroyed before creating a new - // one. (See https://crbug.com/684216#c5 for more discussion.) - field_trial_list_.reset(); - field_trial_list_.reset( - new base::FieldTrialList(std::make_unique<base::MockEntropyProvider>())); - - // refcounted, and reference held by the singleton FieldTrialList. - base::FieldTrial* trial = base::FieldTrialList::FactoryGetFieldTrial( - kTrialName, 100, kGroupName, base::FieldTrial::SESSION_RANDOMIZED, - nullptr /* default_group_number */); - // Disabling the field trial selects the default group, with which we - // associate the provided params. Disabling the field trial does not disable - // the feature itself, but just provides a default group to use to set the - // feature enabled/disabled state below. - trial->Disable(); - ASSERT_TRUE( - variations::AssociateVariationParams(kTrialName, kGroupName, params)); - - std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); - feature_list->RegisterFieldTrialOverride( - kFeature.name, enable ? base::FeatureList::OVERRIDE_ENABLE_FEATURE - : base::FeatureList::OVERRIDE_DISABLE_FEATURE, - trial); - scoped_feature_list_.reset(new base::test::ScopedFeatureList); - scoped_feature_list_->InitWithFeatureList(std::move(feature_list)); + scoped_feature_list_.InitAndEnableFeatureWithParameters( + kNetworkTimeServiceQuerying, params); } } // namespace network_time
diff --git a/components/network_time/network_time_test_utils.h b/components/network_time/network_time_test_utils.h index b99cf7a..7c797ec 100644 --- a/components/network_time/network_time_test_utils.h +++ b/components/network_time/network_time_test_utils.h
@@ -9,16 +9,9 @@ #include <memory> #include "base/macros.h" +#include "base/test/scoped_feature_list.h" #include "components/network_time/network_time_tracker.h" -namespace base { -namespace test { -class ScopedFeatureList; -} // namespace test - -class FieldTrialList; -} // namespace base - namespace net { namespace test_server { struct HttpRequest; @@ -62,8 +55,7 @@ NetworkTimeTracker::FetchBehavior fetch_behavior); private: - std::unique_ptr<base::FieldTrialList> field_trial_list_; - std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_; + base::test::ScopedFeatureList scoped_feature_list_; DISALLOW_COPY_AND_ASSIGN(FieldTrialTest); };
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc index a700e83..ce2b652 100644 --- a/components/password_manager/core/browser/login_database.cc +++ b/components/password_manager/core/browser/login_database.cc
@@ -651,8 +651,9 @@ } // namespace -LoginDatabase::LoginDatabase(const base::FilePath& db_path) - : db_path_(db_path) {} +LoginDatabase::LoginDatabase(const base::FilePath& db_path, + bool is_account_store) + : db_path_(db_path), is_account_store_(is_account_store) {} LoginDatabase::~LoginDatabase() { }
diff --git a/components/password_manager/core/browser/login_database.h b/components/password_manager/core/browser/login_database.h index bb2f85d5..89a21946 100644 --- a/components/password_manager/core/browser/login_database.h +++ b/components/password_manager/core/browser/login_database.h
@@ -45,9 +45,16 @@ // the login information. class LoginDatabase : public PasswordStoreSync::MetadataStore { public: - explicit LoginDatabase(const base::FilePath& db_path); + LoginDatabase(const base::FilePath& db_path, bool is_account_store); ~LoginDatabase() override; + // Returns whether this is the profile-scoped or the account-scoped storage: + // true: Gaia-account-scoped store, which is used for signed-in but not + // syncing users. + // false: Profile-scoped store, which is used for local storage and for + // syncing users. + bool is_account_store() const { return is_account_store_; } + // Actually creates/opens the database. If false is returned, no other method // should be called. virtual bool Init(); @@ -302,7 +309,9 @@ // enabled, or false otherwise. On all other platforms it returns false. bool IsUsingCleanupMechanism() const; - base::FilePath db_path_; + const base::FilePath db_path_; + const bool is_account_store_; + mutable sql::Database db_; sql::MetaTable meta_table_; StatisticsTable stats_table_;
diff --git a/components/password_manager/core/browser/login_database_ios_unittest.cc b/components/password_manager/core/browser/login_database_ios_unittest.cc index 52cb570..9478112 100644 --- a/components/password_manager/core/browser/login_database_ios_unittest.cc +++ b/components/password_manager/core/browser/login_database_ios_unittest.cc
@@ -29,7 +29,8 @@ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); base::FilePath login_db_path = temp_dir_.GetPath().AppendASCII("temp_login.db"); - login_db_.reset(new password_manager::LoginDatabase(login_db_path)); + login_db_.reset(new password_manager::LoginDatabase( + login_db_path, /*is_account_store=*/false)); login_db_->Init(); }
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc index 07f6bc0..a18a10e 100644 --- a/components/password_manager/core/browser/login_database_unittest.cc +++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -187,7 +187,7 @@ file_ = temp_dir_.GetPath().AppendASCII("TestMetadataStoreMacDatabase"); OSCryptMocker::SetUp(); - db_.reset(new LoginDatabase(file_)); + db_.reset(new LoginDatabase(file_, /*is_account_store=*/false)); ASSERT_TRUE(db_->Init()); } @@ -1797,7 +1797,7 @@ GenerateExamplePasswordForm(&password_form); base::FilePath file = temp_dir_.GetPath().AppendASCII("TestUnencryptedDB"); { - LoginDatabase db(file); + LoginDatabase db(file, /*is_account_store=*/false); ASSERT_TRUE(db.Init()); EXPECT_EQ(AddChangeForForm(password_form), db.AddLogin(password_form)); } @@ -1818,7 +1818,7 @@ GenerateExamplePasswordForm(&password_form); base::FilePath file = temp_dir_.GetPath().AppendASCII("TestUnencryptedDB"); { - LoginDatabase db(file); + LoginDatabase db(file, /*is_account_store=*/false); db.disable_encryption(); ASSERT_TRUE(db.Init()); EXPECT_EQ(AddChangeForForm(password_form), db.AddLogin(password_form)); @@ -1841,7 +1841,7 @@ base::FilePath file = temp_dir_.GetPath().AppendASCII("TestUnencryptedDB"); { - LoginDatabase db(file); + LoginDatabase db(file, /*is_account_store=*/false); ASSERT_TRUE(db.Init()); // Add obfuscated (new) entries. PasswordForm password_form; @@ -1862,7 +1862,7 @@ std::vector<std::unique_ptr<autofill::PasswordForm>> forms; { - LoginDatabase db(file); + LoginDatabase db(file, /*is_account_store=*/false); ASSERT_TRUE(db.Init()); ASSERT_TRUE(db.GetAutofillableLogins(&forms)); } @@ -1900,7 +1900,7 @@ // Now try to init the database with the file. The test succeeds if it does // not crash. - LoginDatabase db(database_path); + LoginDatabase db(database_path, /*is_account_store=*/false); EXPECT_FALSE(db.Init()); } @@ -1975,7 +1975,7 @@ { // Assert that the database was successfully opened and updated // to current version. - LoginDatabase db(database_path_); + LoginDatabase db(database_path_, /*is_account_store=*/false); ASSERT_TRUE(db.Init()); // Check that the contents was preserved. @@ -2125,7 +2125,7 @@ form.signon_realm = origin.GetOrigin().spec(); { - LoginDatabase db(database_path()); + LoginDatabase db(database_path(), /*is_account_store=*/false); EXPECT_TRUE(db.Init()); EXPECT_EQ(db.AddLogin(form), AddChangeForForm(form)); } @@ -2162,7 +2162,7 @@ auto form2 = AddDummyLogin("foo2", GURL("https://foo2.com/"), true); auto form3 = AddDummyLogin("foo3", GURL("https://foo3.com/"), false); - LoginDatabase db(database_path()); + LoginDatabase db(database_path(), /*is_account_store=*/false); base::HistogramTester histogram_tester; ASSERT_TRUE(db.Init()); @@ -2215,7 +2215,7 @@ auto form2 = AddDummyLogin("foo2", GURL("https://foo2.com/"), true); auto form3 = AddDummyLogin("foo3", GURL("https://foo3.com/"), false); - LoginDatabase db(database_path()); + LoginDatabase db(database_path(), /*is_account_store=*/false); ASSERT_TRUE(db.Init()); testing_local_state().registry()->RegisterTimePref(prefs::kPasswordRecovery, @@ -2248,7 +2248,7 @@ AddDummyLogin("foo1", GURL("https://foo1.com/"), false); AddDummyLogin("foo2", GURL("https://foo2.com/"), true); - LoginDatabase db(database_path()); + LoginDatabase db(database_path(), /*is_account_store=*/false); ASSERT_TRUE(db.Init()); testing_local_state().registry()->RegisterTimePref(prefs::kPasswordRecovery, @@ -2283,7 +2283,7 @@ OSCryptMocker::SetBackendLocked(true); - LoginDatabase db(database_path()); + LoginDatabase db(database_path(), /*is_account_store=*/false); ASSERT_TRUE(db.Init()); testing_local_state().registry()->RegisterTimePref(prefs::kPasswordRecovery, @@ -2319,7 +2319,7 @@ AddDummyLogin("foo2", GURL("https://foo2.com/"), true); OSCryptMocker::SetBackendLocked(true); - LoginDatabase db(database_path()); + LoginDatabase db(database_path(), /*is_account_store=*/false); base::HistogramTester histogram_tester; ASSERT_TRUE(db.Init()); EXPECT_EQ(DatabaseCleanupResult::kEncryptionUnavailable,
diff --git a/components/password_manager/core/browser/mock_password_store.h b/components/password_manager/core/browser/mock_password_store.h index 88928f5..e7d690cc 100644 --- a/components/password_manager/core/browser/mock_password_store.h +++ b/components/password_manager/core/browser/mock_password_store.h
@@ -94,6 +94,8 @@ MOCK_METHOD1(ReadAllLogins, FormRetrievalResult(PrimaryKeyToFormMap*)); MOCK_METHOD1(RemoveLoginByPrimaryKeySync, PasswordStoreChangeList(int)); MOCK_METHOD0(GetMetadataStore, PasswordStoreSync::MetadataStore*()); + MOCK_CONST_METHOD0(IsAccountStore, bool()); + MOCK_METHOD0(DeleteAndRecreateDatabaseFile, bool()); PasswordStoreSync* GetSyncInterface() { return this; }
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc index ef4adb5..22cb2ff 100644 --- a/components/password_manager/core/browser/password_manager.cc +++ b/components/password_manager/core/browser/password_manager.cc
@@ -873,7 +873,10 @@ if (logger) logger->LogMessage(Logger::STRING_DECISION_ASK); bool update_password = submitted_manager->IsPasswordUpdate(); - if (ShouldShowOnboarding(client_->GetPrefs(), update_password)) { + bool is_blacklisted = submitted_manager->IsBlacklisted(); + if (ShouldShowOnboarding(client_->GetPrefs(), + PasswordUpdateBool(update_password), + BlacklistedBool(is_blacklisted))) { if (client_->ShowOnboarding(MoveOwnedSubmittedManager())) { if (logger) logger->LogMessage(Logger::STRING_SHOW_ONBOARDING);
diff --git a/components/password_manager/core/browser/password_manager_onboarding.cc b/components/password_manager/core/browser/password_manager_onboarding.cc index 17ca35020..cd61b52 100644 --- a/components/password_manager/core/browser/password_manager_onboarding.cc +++ b/components/password_manager/core/browser/password_manager_onboarding.cc
@@ -60,10 +60,6 @@ void UpdateOnboardingState(scoped_refptr<password_manager::PasswordStore> store, PrefService* prefs, base::TimeDelta delay) { - if (!base::FeatureList::IsEnabled( - password_manager::features::kPasswordManagerOnboardingAndroid)) { - return; - } if (prefs->GetInteger(prefs::kPasswordManagerOnboardingState) == static_cast<int>(OnboardingState::kShown)) { return; @@ -73,17 +69,25 @@ delay); } -bool ShouldShowOnboarding(PrefService* prefs, bool is_password_update) { - if (!base::FeatureList::IsEnabled( - password_manager::features::kPasswordManagerOnboardingAndroid)) { +bool ShouldShowOnboarding(PrefService* prefs, + PasswordUpdateBool is_password_update, + BlacklistedBool is_blacklisted) { + if (is_blacklisted) { return false; } if (is_password_update) { return false; } - return prefs->GetInteger( - password_manager::prefs::kPasswordManagerOnboardingState) == - static_cast<int>(OnboardingState::kShouldShow); + if (prefs->GetInteger( + password_manager::prefs::kPasswordManagerOnboardingState) == + static_cast<int>(OnboardingState::kShouldShow)) { + // It is very important that the feature is checked last when we are certain + // that the onboarding needs to be shown. Otherwise, experiment data will be + // polluted. + return base::FeatureList::IsEnabled( + password_manager::features::kPasswordManagerOnboardingAndroid); + } + return false; } } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_manager_onboarding.h b/components/password_manager/core/browser/password_manager_onboarding.h index c81e512..1db73c3 100644 --- a/components/password_manager/core/browser/password_manager_onboarding.h +++ b/components/password_manager/core/browser/password_manager_onboarding.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_ONBOARDING_H_ #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_ONBOARDING_H_ +#include "base/util/type_safety/strong_alias.h" #include "components/password_manager/core/browser/password_store.h" #include "components/password_manager/core/browser/password_store_consumer.h" @@ -12,6 +13,9 @@ namespace password_manager { +using PasswordUpdateBool = util::StrongAlias<class IsPasswordUpdateTag, bool>; +using BlacklistedBool = util::StrongAlias<class IsBlacklistedTag, bool>; + // The onboarding won't be shown if there are this many // saved credentials or more. constexpr int kOnboardingCredentialsThreshold = 3; @@ -57,19 +61,20 @@ // This function updates the |kPasswordManagerOnboardingState| pref on // a separate thread after a given time delay. -// Runs if: -// 1. The PasswordManagerOnboardingAndroid feature is enabled. -// 2. The state is not |kShown|. +// Runs if the state is not |kShown|. void UpdateOnboardingState(scoped_refptr<password_manager::PasswordStore> store, PrefService* prefs, base::TimeDelta delay); // Return true if the password manager onboarding experience should be shown to // the user. Conditions (all must apply): -// 1. The PasswordManagerOnboardingAndroid feature is enabled. +// 1. The set of credentials is not blacklisted. // 2. We are dealing with a new set of credentials. // 3. |kPasswordManagerOnboardingState| is |kShouldShow|. -bool ShouldShowOnboarding(PrefService* prefs, bool is_password_update); +// 4. The PasswordManagerOnboardingAndroid feature is enabled. +bool ShouldShowOnboarding(PrefService* prefs, + PasswordUpdateBool is_password_update, + BlacklistedBool is_blacklisted); } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_manager_onboarding_unittest.cc b/components/password_manager/core/browser/password_manager_onboarding_unittest.cc index 21831ebf..1c6a543 100644 --- a/components/password_manager/core/browser/password_manager_onboarding_unittest.cc +++ b/components/password_manager/core/browser/password_manager_onboarding_unittest.cc
@@ -170,16 +170,6 @@ static_cast<int>(OnboardingState::kShown)); } -TEST_F(PasswordManagerOnboardingTest, FeatureDisabledNotShown) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - features::kPasswordManagerOnboardingAndroid); - UpdateOnboardingState(store_, GetPrefs(), base::TimeDelta::FromSeconds(0)); - RunAllPendingTasks(); - EXPECT_EQ(prefs_->GetInteger(prefs::kPasswordManagerOnboardingState), - static_cast<int>(OnboardingState::kDoNotShow)); -} - TEST_F(PasswordManagerOnboardingTest, FeatureDisabledAfterShowing) { prefs_->SetInteger(prefs::kPasswordManagerOnboardingState, static_cast<int>(OnboardingState::kShown)); @@ -197,22 +187,33 @@ base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( password_manager::features::kPasswordManagerOnboardingAndroid); - EXPECT_FALSE( - ShouldShowOnboarding(GetPrefs(), /* is_password_update */ false)); + EXPECT_FALSE(ShouldShowOnboarding(GetPrefs(), PasswordUpdateBool(false), + BlacklistedBool(false))); prefs_->SetInteger(password_manager::prefs::kPasswordManagerOnboardingState, static_cast<int>(OnboardingState::kShouldShow)); - EXPECT_TRUE(ShouldShowOnboarding(GetPrefs(), /* is_password_update */ false)); + EXPECT_TRUE(ShouldShowOnboarding(GetPrefs(), PasswordUpdateBool(false), + BlacklistedBool(false))); prefs_->SetInteger(password_manager::prefs::kPasswordManagerOnboardingState, static_cast<int>(OnboardingState::kDoNotShow)); - EXPECT_FALSE( - ShouldShowOnboarding(GetPrefs(), /* is_password_update */ false)); + EXPECT_FALSE(ShouldShowOnboarding(GetPrefs(), PasswordUpdateBool(false), + BlacklistedBool(false))); prefs_->SetInteger(password_manager::prefs::kPasswordManagerOnboardingState, static_cast<int>(OnboardingState::kShown)); - EXPECT_FALSE( - ShouldShowOnboarding(GetPrefs(), /* is_password_update */ false)); + EXPECT_FALSE(ShouldShowOnboarding(GetPrefs(), PasswordUpdateBool(false), + BlacklistedBool(false))); +} + +TEST_F(PasswordManagerOnboardingTest, ShouldShowOnboardingFeatureDisabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + features::kPasswordManagerOnboardingAndroid); + prefs_->SetInteger(password_manager::prefs::kPasswordManagerOnboardingState, + static_cast<int>(OnboardingState::kShouldShow)); + EXPECT_FALSE(ShouldShowOnboarding(GetPrefs(), PasswordUpdateBool(false), + BlacklistedBool(false))); } TEST_F(PasswordManagerOnboardingTest, ShouldShowOnboardingPasswordUpdate) { @@ -220,7 +221,18 @@ base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( password_manager::features::kPasswordManagerOnboardingAndroid); - EXPECT_FALSE(ShouldShowOnboarding(GetPrefs(), /* is_password_update */ true)); + EXPECT_FALSE(ShouldShowOnboarding(GetPrefs(), PasswordUpdateBool(true), + BlacklistedBool(false))); +} + +TEST_F(PasswordManagerOnboardingTest, + ShouldShowOnboardingBlacklistedCredentials) { + // Blacklisted credentials ==> don't show. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + password_manager::features::kPasswordManagerOnboardingAndroid); + EXPECT_FALSE(ShouldShowOnboarding(GetPrefs(), PasswordUpdateBool(false), + BlacklistedBool(true))); } } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_default.cc b/components/password_manager/core/browser/password_store_default.cc index 8930f4e..8189a1e8 100644 --- a/components/password_manager/core/browser/password_store_default.cc +++ b/components/password_manager/core/browser/password_store_default.cc
@@ -261,6 +261,14 @@ return login_db_.get(); } +bool PasswordStoreDefault::IsAccountStore() const { + return login_db_->is_account_store(); +} + +bool PasswordStoreDefault::DeleteAndRecreateDatabaseFile() { + return login_db_->DeleteAndRecreateDatabaseFile(); +} + void PasswordStoreDefault::ResetLoginDB() { DCHECK(background_task_runner()->RunsTasksInCurrentSequence()); login_db_.reset();
diff --git a/components/password_manager/core/browser/password_store_default.h b/components/password_manager/core/browser/password_store_default.h index 0de8f56..7d9a020 100644 --- a/components/password_manager/core/browser/password_store_default.h +++ b/components/password_manager/core/browser/password_store_default.h
@@ -90,10 +90,8 @@ PrimaryKeyToFormMap* key_to_form_map) override; PasswordStoreChangeList RemoveLoginByPrimaryKeySync(int primary_key) override; PasswordStoreSync::MetadataStore* GetMetadataStore() override; - - inline bool DeleteAndRecreateDatabaseFile() { - return login_db_->DeleteAndRecreateDatabaseFile(); - } + bool IsAccountStore() const override; + bool DeleteAndRecreateDatabaseFile() override; private: // Resets |login_db_| on the background sequence.
diff --git a/components/password_manager/core/browser/password_store_default_unittest.cc b/components/password_manager/core/browser/password_store_default_unittest.cc index 363bf792..9e986f4 100644 --- a/components/password_manager/core/browser/password_store_default_unittest.cc +++ b/components/password_manager/core/browser/password_store_default_unittest.cc
@@ -51,7 +51,8 @@ // A mock LoginDatabase that simulates a failing Init() method. class BadLoginDatabase : public LoginDatabase { public: - BadLoginDatabase() : LoginDatabase(base::FilePath()) {} + BadLoginDatabase() + : LoginDatabase(base::FilePath(), /*is_account_store=*/false) {} ~BadLoginDatabase() override {} // LoginDatabase: @@ -108,8 +109,8 @@ : task_environment_(base::test::TaskEnvironment::MainThreadType::UI) { OSCryptMocker::SetUp(); SetupTempDir(); - store_ = CreateInitializedStore( - std::make_unique<LoginDatabase>(test_login_db_file_path())); + store_ = CreateInitializedStore(std::make_unique<LoginDatabase>( + test_login_db_file_path(), /*is_account_store=*/false)); } PasswordStoreDefaultTestDelegate::PasswordStoreDefaultTestDelegate(
diff --git a/components/password_manager/core/browser/password_store_factory_util.cc b/components/password_manager/core/browser/password_store_factory_util.cc index d2a29d4..77d637ef 100644 --- a/components/password_manager/core/browser/password_store_factory_util.cc +++ b/components/password_manager/core/browser/password_store_factory_util.cc
@@ -89,14 +89,16 @@ const base::FilePath& profile_path) { base::FilePath login_db_file_path = profile_path.Append(kLoginDataForProfileFileName); - return std::make_unique<LoginDatabase>(login_db_file_path); + return std::make_unique<LoginDatabase>(login_db_file_path, + /*is_account_store=*/false); } std::unique_ptr<LoginDatabase> CreateLoginDatabaseForAccountStorage( const base::FilePath& profile_path) { base::FilePath login_db_file_path = profile_path.Append(kLoginDataForAccountFileName); - return std::make_unique<LoginDatabase>(login_db_file_path); + return std::make_unique<LoginDatabase>(login_db_file_path, + /*is_account_store=*/true); } } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_sync.h b/components/password_manager/core/browser/password_store_sync.h index 0640c1c3..b03d1062 100644 --- a/components/password_manager/core/browser/password_store_sync.h +++ b/components/password_manager/core/browser/password_store_sync.h
@@ -163,6 +163,15 @@ // sync metadata. virtual MetadataStore* GetMetadataStore() = 0; + // Returns whether this is the profile-scoped or the account-scoped storage: + // true: Gaia-account-scoped store, which is used for signed-in but not + // syncing users. + // false: Profile-scoped store, which is used for local storage and for + // syncing users. + virtual bool IsAccountStore() const = 0; + + virtual bool DeleteAndRecreateDatabaseFile() = 0; + protected: virtual ~PasswordStoreSync();
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc index 08381d9..79535e8 100644 --- a/components/password_manager/core/browser/password_store_unittest.cc +++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -128,6 +128,11 @@ return temp_dir_.GetPath().Append(FILE_PATH_LITERAL("login_test")); } + scoped_refptr<PasswordStoreDefault> CreatePasswordStore() { + return new PasswordStoreDefault(std::make_unique<LoginDatabase>( + test_login_db_file_path(), /*is_account_store=*/false)); + } + private: base::ScopedTempDir temp_dir_; base::test::TaskEnvironment task_environment_; @@ -146,8 +151,7 @@ } TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) { - scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault( - std::make_unique<LoginDatabase>(test_login_db_file_path()))); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); const time_t cutoff = 1325376000; // 00:00 Jan 1 2012 UTC @@ -241,8 +245,7 @@ // This test isn't relevant for USS code path. if (base::FeatureList::IsEnabled(switches::kSyncUSSPasswords)) return; - scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault( - std::make_unique<LoginDatabase>(test_login_db_file_path()))); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); StartSyncFlareMock mock; store->Init( base::Bind(&StartSyncFlareMock::StartSyncFlare, base::Unretained(&mock)), @@ -277,8 +280,7 @@ L"", true, 1}}; /* clang-format on */ - scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault( - std::make_unique<LoginDatabase>(test_login_db_file_path()))); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); std::unique_ptr<PasswordForm> old_form( @@ -329,8 +331,7 @@ L"", true, 1}; /* clang-format on */ - scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault( - std::make_unique<LoginDatabase>(test_login_db_file_path()))); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); std::unique_ptr<PasswordForm> test_form( @@ -381,8 +382,7 @@ L"", true, 1}}; /* clang-format on */ - scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault( - std::make_unique<LoginDatabase>(test_login_db_file_path()))); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); std::vector<std::unique_ptr<PasswordForm>> all_credentials; @@ -481,8 +481,7 @@ false, }}; - scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault( - std::make_unique<LoginDatabase>(test_login_db_file_path()))); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); std::vector<std::unique_ptr<PasswordForm>> all_credentials; @@ -649,8 +648,7 @@ SCOPED_TRACE(testing::Message("test_remove_and_add_login: ") << test_remove_and_add_login); - scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault( - std::make_unique<LoginDatabase>(test_login_db_file_path()))); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); store->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(), base::Closure()); @@ -747,8 +745,7 @@ {PasswordForm::Scheme::kHtml, kTestWebRealm3, kTestWebOrigin3, "", L"", L"", L"", nullptr, L"", true, 1}}; - auto store = base::MakeRefCounted<PasswordStoreDefault>( - std::make_unique<LoginDatabase>(test_login_db_file_path())); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); std::vector<std::unique_ptr<PasswordForm>> all_credentials; @@ -798,8 +795,7 @@ {PasswordForm::Scheme::kHtml, kTestWebRealm3, kTestWebOrigin3, "", L"", L"", L"", nullptr, tested_password, true, 1}}; - auto store = base::MakeRefCounted<PasswordStoreDefault>( - std::make_unique<LoginDatabase>(test_login_db_file_path())); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); std::vector<std::unique_ptr<PasswordForm>> all_credentials; @@ -854,8 +850,7 @@ {PasswordForm::Scheme::kHtml, kTestWebRealm3, kTestWebOrigin3, "", L"", L"", L"", nullptr, L"", true, 1}}; - auto store = base::MakeRefCounted<PasswordStoreDefault>( - std::make_unique<LoginDatabase>(test_login_db_file_path())); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); std::vector<std::unique_ptr<PasswordForm>> all_credentials; @@ -911,8 +906,7 @@ {PasswordForm::Scheme::kHtml, "https://facebook.com", "https://facebook.com", "", L"", L"", L"", L"", L"topsecret", true, 1}}; - scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault( - std::make_unique<LoginDatabase>(test_login_db_file_path()))); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); for (const auto& test_credentials : kTestCredentials) { @@ -951,8 +945,7 @@ } TEST_F(PasswordStoreTest, SavingClearingProtectedPassword) { - scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault( - std::make_unique<LoginDatabase>(test_login_db_file_path()))); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); TestingPrefServiceSimple prefs; prefs.registry()->RegisterListPref(prefs::kPasswordHashDataList, @@ -1091,8 +1084,7 @@ } TEST_F(PasswordStoreTest, SubscriptionAndUnsubscriptionFromSignInEvents) { - scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault( - std::make_unique<LoginDatabase>(test_login_db_file_path()))); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); std::unique_ptr<MockPasswordStoreSigninNotifier> notifier = std::make_unique<MockPasswordStoreSigninNotifier>(); @@ -1109,8 +1101,7 @@ } TEST_F(PasswordStoreTest, ReportMetricsForAdvancedProtection) { - scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault( - std::make_unique<LoginDatabase>(test_login_db_file_path()))); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); TestingPrefServiceSimple prefs; prefs.registry()->RegisterListPref(prefs::kPasswordHashDataList, @@ -1144,8 +1135,7 @@ } TEST_F(PasswordStoreTest, ReportMetricsForNonSyncPassword) { - scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault( - std::make_unique<LoginDatabase>(test_login_db_file_path()))); + scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore(); TestingPrefServiceSimple prefs; prefs.registry()->RegisterListPref(prefs::kPasswordHashDataList,
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge.cc b/components/password_manager/core/browser/sync/password_sync_bridge.cc index 567cb1b..3740209a 100644 --- a/components/password_manager/core/browser/sync/password_sync_bridge.cc +++ b/components/password_manager/core/browser/sync/password_sync_bridge.cc
@@ -749,6 +749,25 @@ std::unique_ptr<syncer::MetadataChangeList> delete_metadata_change_list) { if (delete_metadata_change_list) { password_store_sync_->GetMetadataStore()->DeleteAllSyncMetadata(); + + // If this is the account store, also delete the actual data. + if (password_store_sync_->IsAccountStore()) { + base::AutoReset<bool> processing_changes( + &is_processing_remote_sync_changes_, true); + + PasswordStoreChangeList password_store_changes; + PrimaryKeyToFormMap logins; + FormRetrievalResult result = password_store_sync_->ReadAllLogins(&logins); + if (result == FormRetrievalResult::kSuccess) { + for (const auto& primary_key_and_form : logins) { + password_store_changes.emplace_back(PasswordStoreChange::REMOVE, + *primary_key_and_form.second, + primary_key_and_form.first); + } + } + password_store_sync_->DeleteAndRecreateDatabaseFile(); + password_store_sync_->NotifyLoginsChanged(password_store_changes); + } } }
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc index fb2b72b..4d60261 100644 --- a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc +++ b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
@@ -212,6 +212,8 @@ MOCK_METHOD0(CommitTransaction, bool()); MOCK_METHOD0(RollbackTransaction, void()); MOCK_METHOD0(GetMetadataStore, PasswordStoreSync::MetadataStore*()); + MOCK_CONST_METHOD0(IsAccountStore, bool()); + MOCK_METHOD0(DeleteAndRecreateDatabaseFile, bool()); }; } // namespace
diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc index 1812f582..a9fae60 100644 --- a/components/password_manager/core/browser/test_password_store.cc +++ b/components/password_manager/core/browser/test_password_store.cc
@@ -252,4 +252,13 @@ return nullptr; } +bool TestPasswordStore::IsAccountStore() const { + return false; +} + +bool TestPasswordStore::DeleteAndRecreateDatabaseFile() { + NOTIMPLEMENTED(); + return false; +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/test_password_store.h b/components/password_manager/core/browser/test_password_store.h index cf8cced8..541f70c 100644 --- a/components/password_manager/core/browser/test_password_store.h +++ b/components/password_manager/core/browser/test_password_store.h
@@ -94,6 +94,8 @@ PrimaryKeyToFormMap* key_to_form_map) override; PasswordStoreChangeList RemoveLoginByPrimaryKeySync(int primary_key) override; PasswordStoreSync::MetadataStore* GetMetadataStore() override; + bool IsAccountStore() const override; + bool DeleteAndRecreateDatabaseFile() override; private: PasswordMap stored_passwords_;
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto index a544d667..103b71bc 100644 --- a/components/policy/proto/device_management_backend.proto +++ b/components/policy/proto/device_management_backend.proto
@@ -2602,7 +2602,10 @@ // Request from device to upload RSU lookup key. optional RsuLookupKeyUploadRequest rsu_lookup_key_upload_request = 31; - // Next id: 32. + // Request from device for SAML IdP URL address. + optional PublicSamlUserRequest public_saml_user_request = 32; + + // Next id: 33. } // Response from server to device. @@ -2721,5 +2724,8 @@ // Response to RSU lookup key upload request. optional RsuLookupKeyUploadResponse rsu_lookup_key_upload_response = 30; - // Next id: 31. + // Response to public SAML session user request. + optional PublicSamlUserResponse public_saml_user_response = 31; + + // Next id: 32. }
diff --git a/components/safe_browsing/triggers/trigger_throttler_unittest.cc b/components/safe_browsing/triggers/trigger_throttler_unittest.cc index 1ef5be96..3998665 100644 --- a/components/safe_browsing/triggers/trigger_throttler_unittest.cc +++ b/components/safe_browsing/triggers/trigger_throttler_unittest.cc
@@ -4,7 +4,6 @@ #include "components/safe_browsing/triggers/trigger_throttler.h" -#include "base/metrics/field_trial_params.h" #include "base/strings/stringprintf.h" #include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" @@ -206,25 +205,19 @@ class TriggerThrottlerTestFinch : public ::testing::Test { public: - std::unique_ptr<base::FeatureList> SetupQuotaInFinch( - const TriggerType trigger_type, - const std::string& group_name, - int quota) { - std::string feature_name = ""; + void SetupQuotaParams(const TriggerType trigger_type, + const std::string& group_name, + int quota, + base::test::ScopedFeatureList* scoped_feature_list) { + const base::Feature* feature = nullptr; std::string param_name = ""; - GetFeatureAndParamForTrigger(trigger_type, &feature_name, ¶m_name); + GetFeatureAndParamForTrigger(trigger_type, &feature, ¶m_name); - base::FieldTrial* trial = - base::FieldTrialList::CreateFieldTrial(feature_name, group_name); - std::map<std::string, std::string> feature_params; + base::FieldTrialParams feature_params; feature_params[param_name] = GetQuotaParamValueForTrigger(trigger_type, quota); - base::AssociateFieldTrialParams(feature_name, group_name, feature_params); - std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); - feature_list->InitializeFromCommandLine(feature_name, std::string()); - feature_list->AssociateReportingFieldTrial( - feature_name, base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial); - return feature_list; + scoped_feature_list->InitAndEnableFeatureWithParameters(*feature, + feature_params); } size_t GetDailyQuotaForTrigger(const TriggerThrottler& throttler, @@ -234,16 +227,16 @@ private: void GetFeatureAndParamForTrigger(const TriggerType trigger_type, - std::string* out_feature, + const base::Feature** out_feature, std::string* out_param) { switch (trigger_type) { case TriggerType::AD_SAMPLE: - *out_feature = safe_browsing::kTriggerThrottlerDailyQuotaFeature.name; + *out_feature = &safe_browsing::kTriggerThrottlerDailyQuotaFeature; *out_param = safe_browsing::kTriggerTypeAndQuotaParam; break; case TriggerType::SUSPICIOUS_SITE: - *out_feature = safe_browsing::kSuspiciousSiteTriggerQuotaFeature.name; + *out_feature = &safe_browsing::kSuspiciousSiteTriggerQuotaFeature; *out_param = safe_browsing::kSuspiciousSiteTriggerQuotaParam; break; @@ -263,10 +256,9 @@ }; TEST_F(TriggerThrottlerTestFinch, ConfigureQuotaViaFinch) { - base::FieldTrialList field_trial_list(nullptr); base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatureList(SetupQuotaInFinch( - TriggerType::AD_SAMPLE, "Group_ConfigureQuotaViaFinch", 3)); + SetupQuotaParams(TriggerType::AD_SAMPLE, "Group_ConfigureQuotaViaFinch", 3, + &scoped_feature_list); // Make sure that setting the quota param via Finch params works as expected. // The throttler has been configured (above) to allow ad samples to fire three @@ -293,10 +285,9 @@ GetDailyQuotaForTrigger(throttler_default, TriggerType::AD_SAMPLE)); EXPECT_TRUE(throttler_default.TriggerCanFire(TriggerType::AD_SAMPLE)); - base::FieldTrialList field_trial_list(nullptr); base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatureList(SetupQuotaInFinch( - TriggerType::AD_SAMPLE, "Group_AdSamplerDefaultQuota", 4)); + SetupQuotaParams(TriggerType::AD_SAMPLE, "Group_AdSamplerDefaultQuota", 4, + &scoped_feature_list); TriggerThrottler throttler_finch(nullptr); EXPECT_EQ(4u, GetDailyQuotaForTrigger(throttler_finch, TriggerType::AD_SAMPLE)); @@ -310,11 +301,10 @@ GetDailyQuotaForTrigger(throttler_default, TriggerType::SUSPICIOUS_SITE)); EXPECT_TRUE(throttler_default.TriggerCanFire(TriggerType::SUSPICIOUS_SITE)); - base::FieldTrialList field_trial_list(nullptr); base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatureList( - SetupQuotaInFinch(TriggerType::SUSPICIOUS_SITE, - "Group_SuspiciousSiteTriggerDefaultQuota", 7)); + SetupQuotaParams(TriggerType::SUSPICIOUS_SITE, + "Group_SuspiciousSiteTriggerDefaultQuota", 7, + &scoped_feature_list); TriggerThrottler throttler_finch(nullptr); EXPECT_EQ(7u, GetDailyQuotaForTrigger(throttler_finch, TriggerType::SUSPICIOUS_SITE));
diff --git a/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc b/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc index 653b73b0..c5245ca 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc +++ b/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
@@ -10,17 +10,13 @@ #include <utility> #include <vector> -#include "base/feature_list.h" #include "base/macros.h" -#include "base/metrics/field_trial.h" -#include "base/metrics/field_trial_params.h" #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h" #include "components/subresource_filter/core/common/common_features.h" -#include "components/variations/variations_associated_data.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -28,35 +24,47 @@ namespace { -constexpr const char kTestFieldTrialName[] = "FieldTrialNameShouldNotMatter"; -constexpr const char kTestExperimentGroupName[] = "GroupNameShouldNotMatter"; - class ScopedExperimentalStateToggle { public: - ScopedExperimentalStateToggle( - base::FeatureList::OverrideState feature_state, - std::map<std::string, std::string> variation_params) - : field_trial_list_(nullptr /* entropy_provider */), - scoped_configurator_(nullptr) { - EXPECT_TRUE(base::AssociateFieldTrialParams( - kTestFieldTrialName, kTestExperimentGroupName, variation_params)); - base::FieldTrial* field_trial = base::FieldTrialList::CreateFieldTrial( - kTestFieldTrialName, kTestExperimentGroupName); + ScopedExperimentalStateToggle(base::FeatureList::OverrideState feature_state, + base::FieldTrialParams variation_params) + : scoped_configurator_(nullptr) { + const base::Feature& kFeature = kSafeBrowsingSubresourceFilter; - std::unique_ptr<base::FeatureList> feature_list = - std::make_unique<base::FeatureList>(); - feature_list->RegisterFieldTrialOverride( - kSafeBrowsingSubresourceFilter.name, feature_state, field_trial); - scoped_feature_list_.InitWithFeatureList(std::move(feature_list)); + // Handle OVERRIDE_USE_DEFAULT which ScopedFeatureList does not support. + if (feature_state == base::FeatureList::OVERRIDE_USE_DEFAULT) { + // Init a temp ScopedFeatureList to query the current default state. + // Note that this will take account any overrides coming from the + // command-line, unlike testing the feature's |default_state|. + base::test::ScopedFeatureList temp_scoped_feature_list; + temp_scoped_feature_list.Init(); + if (base::FeatureList::IsEnabled(kFeature)) { + feature_state = base::FeatureList::OVERRIDE_ENABLE_FEATURE; + } else { + feature_state = base::FeatureList::OVERRIDE_DISABLE_FEATURE; + } + } + + switch (feature_state) { + case base::FeatureList::OVERRIDE_ENABLE_FEATURE: + scoped_feature_list_.InitAndEnableFeatureWithParameters( + kFeature, variation_params); + break; + + case base::FeatureList::OVERRIDE_DISABLE_FEATURE: + scoped_feature_list_.InitAndDisableFeature(kFeature); + break; + + case base::FeatureList::OVERRIDE_USE_DEFAULT: + NOTREACHED(); + break; + } } ~ScopedExperimentalStateToggle() { - variations::testing::ClearAllVariationParams(); } private: - base::FieldTrialList field_trial_list_; - testing::ScopedSubresourceFilterConfigurator scoped_configurator_; base::test::ScopedFeatureList scoped_feature_list_;
diff --git a/components/sync/driver/glue/sync_engine_backend.cc b/components/sync/driver/glue/sync_engine_backend.cc index c56cd42..c6f3cdf 100644 --- a/components/sync/driver/glue/sync_engine_backend.cc +++ b/components/sync/driver/glue/sync_engine_backend.cc
@@ -33,6 +33,7 @@ #include "components/sync/engine_impl/sync_encryption_handler_impl.h" #include "components/sync/model_impl/forwarding_model_type_controller_delegate.h" #include "components/sync/nigori/nigori_model_type_processor.h" +#include "components/sync/nigori/nigori_storage_impl.h" #include "components/sync/nigori/nigori_sync_bridge_impl.h" #include "components/sync/syncable/directory.h" #include "components/sync/syncable/nigori_handler_proxy.h" @@ -57,6 +58,9 @@ namespace { +const base::FilePath::CharType kNigoriStorageFilename[] = + FILE_PATH_LITERAL("Nigori.bin"); + void RecordPerModelTypeInvalidation(int model_type, bool is_grouped) { UMA_HISTOGRAM_ENUMERATION("Sync.InvalidationPerModelType", model_type, static_cast<int>(syncer::ModelType::NUM_ENTRIES)); @@ -342,8 +346,10 @@ NIGORI, std::make_unique<ForwardingModelTypeControllerDelegate>( nigori_processor->GetControllerDelegate().get())); sync_encryption_handler_ = std::make_unique<NigoriSyncBridgeImpl>( - std::move(nigori_processor), &encryptor_, - params.restored_key_for_bootstrapping); + std::move(nigori_processor), + std::make_unique<NigoriStorageImpl>( + sync_data_folder_.Append(kNigoriStorageFilename), &encryptor_), + &encryptor_, params.restored_key_for_bootstrapping); nigori_handler_proxy_ = std::make_unique<syncable::NigoriHandlerProxy>(&user_share_); sync_encryption_handler_->AddObserver(nigori_handler_proxy_.get());
diff --git a/components/sync/nigori/cryptographer.cc b/components/sync/nigori/cryptographer.cc index 596f8ed4..15f6a32 100644 --- a/components/sync/nigori/cryptographer.cc +++ b/components/sync/nigori/cryptographer.cc
@@ -24,6 +24,25 @@ KeyParams::KeyParams(KeyParams&& other) = default; KeyParams::~KeyParams() = default; +CryptographerDataWithPendingKeys::CryptographerDataWithPendingKeys() = default; +CryptographerDataWithPendingKeys::CryptographerDataWithPendingKeys( + CryptographerDataWithPendingKeys&& other) = default; +CryptographerDataWithPendingKeys::~CryptographerDataWithPendingKeys() = default; + +// static +Cryptographer Cryptographer::CreateFromCryptographerDataWithPendingKeys( + const CryptographerDataWithPendingKeys& serialized_state) { + std::unique_ptr<sync_pb::EncryptedData> pending_keys; + if (serialized_state.pending_keys.has_value()) { + pending_keys = std::make_unique<sync_pb::EncryptedData>( + *serialized_state.pending_keys); + } + return Cryptographer(NigoriKeyBag::CreateFromProto( + serialized_state.cryptographer_data.key_bag()), + serialized_state.cryptographer_data.default_key_name(), + std::move(pending_keys)); +} + Cryptographer::Cryptographer() : key_bag_(NigoriKeyBag::CreateEmpty()) {} Cryptographer::Cryptographer(const Cryptographer& other) @@ -46,6 +65,17 @@ } } +CryptographerDataWithPendingKeys +Cryptographer::ToCryptographerDataWithPendingKeys() const { + CryptographerDataWithPendingKeys output; + *output.cryptographer_data.mutable_key_bag() = key_bag_.ToProto(); + output.cryptographer_data.set_default_key_name(default_nigori_name_); + if (pending_keys_) { + output.pending_keys = *pending_keys_; + } + return output; +} + void Cryptographer::Bootstrap(const Encryptor& encryptor, const std::string& restored_bootstrap_token) { if (is_initialized()) { @@ -326,4 +356,12 @@ return true; } +Cryptographer::Cryptographer( + NigoriKeyBag key_bag, + const std::string& default_nigori_name, + std::unique_ptr<sync_pb::EncryptedData> pending_keys) + : key_bag_(std::move(key_bag)), + default_nigori_name_(std::move(default_nigori_name)), + pending_keys_(std::move(pending_keys)) {} + } // namespace syncer
diff --git a/components/sync/nigori/cryptographer.h b/components/sync/nigori/cryptographer.h index 72c04517..42e3491 100644 --- a/components/sync/nigori/cryptographer.h +++ b/components/sync/nigori/cryptographer.h
@@ -10,10 +10,12 @@ #include <string> #include "base/macros.h" +#include "base/optional.h" #include "components/sync/base/passphrase_enums.h" #include "components/sync/nigori/nigori.h" #include "components/sync/nigori/nigori_key_bag.h" #include "components/sync/protocol/encryption.pb.h" +#include "components/sync/protocol/nigori_local_data.pb.h" namespace sync_pb { class NigoriKeyBag; @@ -36,6 +38,18 @@ std::string password; }; +struct CryptographerDataWithPendingKeys { + CryptographerDataWithPendingKeys(); + CryptographerDataWithPendingKeys(CryptographerDataWithPendingKeys&& other); + ~CryptographerDataWithPendingKeys(); + + sync_pb::CryptographerData cryptographer_data; + base::Optional<sync_pb::EncryptedData> pending_keys; + + private: + DISALLOW_COPY_AND_ASSIGN(CryptographerDataWithPendingKeys); +}; + // This class manages the Nigori objects used to encrypt and decrypt sensitive // sync data (eg. passwords). Each Nigori object knows how to handle data // protected with a particular passphrase. @@ -52,12 +66,19 @@ // delayed until after it can be decrypted. class Cryptographer { public: + // Deserialization. + static Cryptographer CreateFromCryptographerDataWithPendingKeys( + const CryptographerDataWithPendingKeys& serialized_state); + Cryptographer(); Cryptographer(const Cryptographer& other); ~Cryptographer(); void CopyFrom(const Cryptographer& other); + // Serialization. + CryptographerDataWithPendingKeys ToCryptographerDataWithPendingKeys() const; + // |restored_bootstrap_token| can be provided via this method to bootstrap // Cryptographer instance into the ready state (is_ready will be true). // It must be a string that was previously built by the @@ -191,6 +212,11 @@ bool ImportNigoriKey(const std::string& serialized_nigori_key); private: + // Initializes cryptographer with completely provided state. + Cryptographer(NigoriKeyBag key_bag, + const std::string& default_nigori_name, + std::unique_ptr<sync_pb::EncryptedData> pending_keys); + // Helper method to instantiate Nigori instances for each set of key // parameters in |bag|. // Does not update the default nigori.
diff --git a/components/sync/nigori/cryptographer_unittest.cc b/components/sync/nigori/cryptographer_unittest.cc index 8996b43..9e0224ac 100644 --- a/components/sync/nigori/cryptographer_unittest.cc +++ b/components/sync/nigori/cryptographer_unittest.cc
@@ -6,6 +6,7 @@ #include "base/strings/string_util.h" #include "components/sync/base/fake_encryptor.h" +#include "components/sync/protocol/nigori_local_data.pb.h" #include "components/sync/protocol/password_specifics.pb.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -14,7 +15,10 @@ namespace { -using ::testing::_; +using testing::_; +using testing::Eq; +using testing::Ne; +using testing::SizeIs; } // namespace @@ -301,4 +305,27 @@ EXPECT_TRUE(another_cryptographer.CanDecrypt(encrypted_k2)); } +TEST_F(CryptographerTest, ShouldConvertToCryptographerDataWithPendingKeys) { + const KeyParams kKeyParams = {KeyDerivationParams::CreateForPbkdf2(), + "password1"}; + ASSERT_TRUE(cryptographer_.AddKey(kKeyParams)); + + CryptographerDataWithPendingKeys serialized = + cryptographer_.ToCryptographerDataWithPendingKeys(); + EXPECT_THAT(serialized.cryptographer_data.key_bag().key(), SizeIs(1)); + + std::string expected_key_name; + Nigori::CreateByDerivation(kKeyParams.derivation_params, kKeyParams.password) + ->Permute(Nigori::Password, kNigoriKeyName, &expected_key_name); + EXPECT_THAT(serialized.cryptographer_data.default_key_name(), + Eq(expected_key_name)); + EXPECT_THAT(serialized.cryptographer_data.key_bag().key(0).name(), + Eq(expected_key_name)); + EXPECT_THAT(serialized.cryptographer_data.key_bag().key(0).user_key(), + Ne("")); + EXPECT_THAT(serialized.cryptographer_data.key_bag().key(0).encryption_key(), + Ne("")); + EXPECT_THAT(serialized.cryptographer_data.key_bag().key(0).mac_key(), Ne("")); +} + } // namespace syncer
diff --git a/components/sync/nigori/nigori_storage_impl.h b/components/sync/nigori/nigori_storage_impl.h index 2efe071..eff96dc 100644 --- a/components/sync/nigori/nigori_storage_impl.h +++ b/components/sync/nigori/nigori_storage_impl.h
@@ -13,7 +13,7 @@ class Encryptor; -class NigoriStorageImpl : NigoriStorage { +class NigoriStorageImpl : public NigoriStorage { public: // |encryptor| must be not null and must outlive this object. NigoriStorageImpl(const base::FilePath& path, const Encryptor* encryptor);
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.cc b/components/sync/nigori/nigori_sync_bridge_impl.cc index 2cf1b06d..8fce609 100644 --- a/components/sync/nigori/nigori_sync_bridge_impl.cc +++ b/components/sync/nigori/nigori_sync_bridge_impl.cc
@@ -14,7 +14,9 @@ #include "components/sync/base/time.h" #include "components/sync/model/entity_data.h" #include "components/sync/nigori/nigori.h" +#include "components/sync/nigori/nigori_storage.h" #include "components/sync/protocol/encryption.pb.h" +#include "components/sync/protocol/nigori_local_data.pb.h" #include "components/sync/protocol/nigori_specifics.pb.h" namespace syncer { @@ -396,21 +398,113 @@ return cryptographer.CanDecrypt(encrypted_data); } +std::string ComputePbkdf2KeyName(const std::string& password) { + std::string key_name; + Nigori::CreateByDerivation(KeyDerivationParams::CreateForPbkdf2(), password) + ->Permute(Nigori::Password, kNigoriKeyName, &key_name); + return key_name; +} + +sync_pb::CustomPassphraseKeyDerivationParams +CustomPassphraseKeyDerivationParamsToProto(const KeyDerivationParams& params) { + sync_pb::CustomPassphraseKeyDerivationParams output; + output.set_custom_passphrase_key_derivation_method( + EnumKeyDerivationMethodToProto(params.method())); + if (params.method() == KeyDerivationMethod::SCRYPT_8192_8_11) { + output.set_custom_passphrase_key_derivation_salt(params.scrypt_salt()); + } + return output; +} + +KeyDerivationParams CustomPassphraseKeyDerivationParamsFromProto( + const sync_pb::CustomPassphraseKeyDerivationParams& proto) { + switch (ProtoKeyDerivationMethodToEnum( + proto.custom_passphrase_key_derivation_method())) { + case KeyDerivationMethod::PBKDF2_HMAC_SHA1_1003: + return KeyDerivationParams::CreateForPbkdf2(); + case KeyDerivationMethod::SCRYPT_8192_8_11: + return KeyDerivationParams::CreateForScrypt( + proto.custom_passphrase_key_derivation_salt()); + case KeyDerivationMethod::UNSUPPORTED: + NOTREACHED(); + return KeyDerivationParams::CreateWithUnsupportedMethod(); + } +} + +ModelTypeSet GetEncryptedTypes(bool encrypt_everything) { + if (encrypt_everything) { + return EncryptableUserTypes(); + } + return SyncEncryptionHandler::SensitiveTypes(); +} + } // namespace NigoriSyncBridgeImpl::NigoriSyncBridgeImpl( std::unique_ptr<NigoriLocalChangeProcessor> processor, + std::unique_ptr<NigoriStorage> storage, const Encryptor* encryptor, const std::string& packed_explicit_passphrase_key) : encryptor_(encryptor), processor_(std::move(processor)), + storage_(std::move(storage)), serialized_explicit_passphrase_key_( UnpackExplicitPassphraseKey(*encryptor, packed_explicit_passphrase_key)), passphrase_type_(NigoriSpecifics::UNKNOWN), encrypt_everything_(false) { DCHECK(encryptor); - processor_->ModelReadyToSync(this, NigoriMetadataBatch()); + + // TODO(crbug.com/922900): we currently don't verify |deserialized_data|. + // It's quite unlikely we get a corrupted data, since it was successfully + // deserialized and decrypted. But we may want to consider some + // verifications, taking into account sensitivity of this data. + base::Optional<sync_pb::NigoriLocalData> deserialized_data = + storage_->RestoreData(); + if (!deserialized_data) { + // We either have no Nigori node stored locally or it was corrupted. + processor_->ModelReadyToSync(this, NigoriMetadataBatch()); + return; + } + + // TODO(crbug.com/922900): consider factoring-out model state to a struct and + // introducing helper function for deserialization instead of having it in + // ctor. + // Restore state of the bridge. + const sync_pb::NigoriModel& nigori_model = deserialized_data->nigori_model(); + + // Restore |cryptographer_|. + CryptographerDataWithPendingKeys serialized_cryptographer; + serialized_cryptographer.cryptographer_data = + nigori_model.cryptographer_data(); + if (nigori_model.has_pending_keys()) { + serialized_cryptographer.pending_keys = nigori_model.pending_keys(); + } + cryptographer_.CopyFrom( + Cryptographer::CreateFromCryptographerDataWithPendingKeys( + serialized_cryptographer)); + + // Restore rest of the state. + passphrase_type_ = nigori_model.passphrase_type(); + keystore_migration_time_ = + ProtoTimeToTime(nigori_model.keystore_migration_time()); + custom_passphrase_time_ = + ProtoTimeToTime(nigori_model.custom_passphrase_time()); + if (nigori_model.has_custom_passphrase_key_derivation_params()) { + custom_passphrase_key_derivation_params_ = + CustomPassphraseKeyDerivationParamsFromProto( + nigori_model.custom_passphrase_key_derivation_params()); + } + encrypt_everything_ = nigori_model.encrypt_everything(); + for (int i = 0; i < nigori_model.keystore_key_size(); ++i) { + keystore_keys_.push_back(nigori_model.keystore_key(i)); + } + + // Restore metadata. + NigoriMetadataBatch metadata_batch; + metadata_batch.model_type_state = deserialized_data->model_type_state(); + metadata_batch.entity_metadata = deserialized_data->entity_metadata(); + processor_->ModelReadyToSync(this, std::move(metadata_batch)); } NigoriSyncBridgeImpl::~NigoriSyncBridgeImpl() { @@ -429,24 +523,35 @@ bool NigoriSyncBridgeImpl::Init() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // Init() is called after the first sync cycle, so we can have - // |encrypt_everything_| enabled even if we don't persist the local state. - // TODO(crbug.com/922900): try to avoid double notification. Currently it - // happens iff we received explicit passphrase Nigori during the first - // sync cycle, and more complicated once we persist the local state. - ModelTypeSet encrypted_types; - if (encrypt_everything_) { - encrypted_types = EncryptableUserTypes(); - } else { - encrypted_types = SensitiveTypes(); + // We need to expose whole bridge state through notifications, because it + // can be different from default due to restoring from the file or + // completeness of first sync cycle (which happens before Init() call). + // TODO(crbug.com/922900): try to avoid double notification (second one can + // happen during UpdateLocalState() call). + if (cryptographer_.has_pending_keys()) { + for (auto& observer : observers_) { + observer.OnPassphraseRequired(REASON_DECRYPTION, + GetKeyDerivationParamsForPendingKeys(), + cryptographer_.GetPendingKeys()); + } } for (auto& observer : observers_) { - observer.OnEncryptedTypesChanged(encrypted_types, encrypt_everything_); + observer.OnEncryptedTypesChanged(GetEncryptedTypes(encrypt_everything_), + encrypt_everything_); } - NOTIMPLEMENTED(); - // TODO(crbug.com/922900): notify observers about cryptographer change in - // case UpdateLocalState() is not called in this function (i.e. - // initialization implemented in constructor). + for (auto& observer : observers_) { + observer.OnCryptographerStateChanged(&cryptographer_); + } + if (passphrase_type_ != NigoriSpecifics::UNKNOWN) { + // if |passphrase_type_| is unknown, it is not yet initialized and we + // shouldn't expose it. + for (auto& observer : observers_) { + observer.OnPassphraseTypeChanged( + *ProtoPassphraseInt32ToEnum(passphrase_type_), + GetExplicitPassphraseTime()); + } + } + return true; } @@ -479,6 +584,7 @@ encrypt_everything_ = true; custom_passphrase_time_ = base::Time::Now(); processor_->Put(GetData()); + storage_->StoreData(SerializeAsNigoriLocalData()); for (auto& observer : observers_) { observer.OnPassphraseAccepted(); } @@ -526,6 +632,7 @@ "Failed to decrypt pending keys with provided explicit passphrase.")); return; } + storage_->StoreData(SerializeAsNigoriLocalData()); for (auto& observer : observers_) { observer.OnCryptographerStateChanged(&cryptographer_); } @@ -587,7 +694,9 @@ base::Base64Encode(keys[i], &keystore_keys_[i]); } - // TODO(crbug.com/922900): persist keystore keys. + // Note: we don't need to persist keystore keys here, because we will receive + // Nigori node right after this method and persist all the data during + // UpdateLocalState(). // TODO(crbug.com/922900): support key rotation. // TODO(crbug.com/922900): verify that this method is always called before // update or init of Nigori node. If this is the case we don't need to touch @@ -644,8 +753,9 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_NE(passphrase_type_, NigoriSpecifics::UNKNOWN); if (!data) { - // TODO(crbug.com/922900): persist SyncMetadata and ModelTypeState. - NOTIMPLEMENTED(); + // Receiving empty |data| means metadata-only change, we need to persist + // its state. + storage_->StoreData(SerializeAsNigoriLocalData()); return base::nullopt; } DCHECK(data->specifics.has_nigori()); @@ -713,6 +823,7 @@ UpdateCryptographerFromExplicitPassphraseNigori(encryption_keybag); } + storage_->StoreData(SerializeAsNigoriLocalData()); if (passphrase_type_changed) { for (auto& observer : observers_) { observer.OnPassphraseTypeChanged( @@ -923,4 +1034,59 @@ } } +sync_pb::NigoriLocalData NigoriSyncBridgeImpl::SerializeAsNigoriLocalData() + const { + sync_pb::NigoriLocalData output; + + // Serialize the metadata. + const NigoriMetadataBatch metadata_batch = processor_->GetMetadata(); + *output.mutable_model_type_state() = metadata_batch.model_type_state; + if (metadata_batch.entity_metadata) { + *output.mutable_entity_metadata() = *metadata_batch.entity_metadata; + } + + // Serialize the data. + sync_pb::NigoriModel* nigori_model = output.mutable_nigori_model(); + CryptographerDataWithPendingKeys serialized_cryptographer = + cryptographer_.ToCryptographerDataWithPendingKeys(); + *nigori_model->mutable_cryptographer_data() = + serialized_cryptographer.cryptographer_data; + if (serialized_cryptographer.pending_keys.has_value()) { + *nigori_model->mutable_pending_keys() = + *serialized_cryptographer.pending_keys; + } + if (!keystore_keys_.empty()) { + nigori_model->set_current_keystore_key_name( + ComputePbkdf2KeyName(keystore_keys_.back())); + } + nigori_model->set_passphrase_type(passphrase_type_); + if (!keystore_migration_time_.is_null()) { + nigori_model->set_keystore_migration_time( + TimeToProtoTime(keystore_migration_time_)); + } + if (!custom_passphrase_time_.is_null()) { + nigori_model->set_custom_passphrase_time( + TimeToProtoTime(custom_passphrase_time_)); + } + if (custom_passphrase_key_derivation_params_) { + *nigori_model->mutable_custom_passphrase_key_derivation_params() = + CustomPassphraseKeyDerivationParamsToProto( + *custom_passphrase_key_derivation_params_); + } + nigori_model->set_encrypt_everything(encrypt_everything_); + for (ModelType model_type : GetEncryptedTypes(encrypt_everything_)) { + nigori_model->add_encrypted_types_specifics_field_number( + GetSpecificsFieldNumberFromModelType(model_type)); + } + // TODO(crbug.com/970213): we currently store keystore keys in proto only to + // allow rollback of USS Nigori. Having keybag with all keystore keys and + // |current_keystore_key_name| is enough to support all bridge logic. We + // should remove them few milestones after USS migration completed. + for (const std::string& keystore_key : keystore_keys_) { + nigori_model->add_keystore_key(keystore_key); + } + + return output; +} + } // namespace syncer
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.h b/components/sync/nigori/nigori_sync_bridge_impl.h index aee1824..d80cd10 100644 --- a/components/sync/nigori/nigori_sync_bridge_impl.h +++ b/components/sync/nigori/nigori_sync_bridge_impl.h
@@ -22,9 +22,14 @@ #include "components/sync/nigori/nigori_local_change_processor.h" #include "components/sync/nigori/nigori_sync_bridge.h" +namespace sync_pb { +class NigoriLocalData; +} // namespace sync_pb + namespace syncer { class Encryptor; +class NigoriStorage; // USS implementation of SyncEncryptionHandler. // This class holds the current Nigori state and processes incoming changes and @@ -40,6 +45,7 @@ public: // |encryptor| must be not null and must outlive this object. NigoriSyncBridgeImpl(std::unique_ptr<NigoriLocalChangeProcessor> processor, + std::unique_ptr<NigoriStorage> storage, const Encryptor* encryptor, const std::string& packed_explicit_passphrase_key); ~NigoriSyncBridgeImpl() override; @@ -100,9 +106,13 @@ // just won't be updated. void MaybeNotifyBootstrapTokenUpdated() const; + // Serializes state of the bridge and sync metadata into the proto. + sync_pb::NigoriLocalData SerializeAsNigoriLocalData() const; + const Encryptor* const encryptor_; const std::unique_ptr<NigoriLocalChangeProcessor> processor_; + const std::unique_ptr<NigoriStorage> storage_; // Stores serialized sync_pb::NigoriKey derived from explicit passphrase and // loaded from the prefs. Empty if prefs doesn't contain this key or in case
diff --git a/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc index fbd03e03..273d526 100644 --- a/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc +++ b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
@@ -10,6 +10,7 @@ #include "components/sync/base/fake_encryptor.h" #include "components/sync/base/time.h" #include "components/sync/model/entity_data.h" +#include "components/sync/nigori/nigori_storage.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -22,9 +23,14 @@ using testing::Ne; using testing::Not; using testing::NotNull; +using testing::Return; const char kNigoriKeyName[] = "nigori-key"; +NigoriMetadataBatch CreateDummyNigoriMetadataBatch( + const std::string& progress_marker_token, + int64_t entity_metadata_sequence_number); + MATCHER(NotNullTime, "") { return !arg.is_null(); } @@ -98,6 +104,24 @@ given.blob() == expected.blob(); } +MATCHER_P2(IsDummyNigoriMetadataBatchWithTokenAndSequenceNumber, + expected_token, + expected_sequence_number, + "") { + const NigoriMetadataBatch& given = arg; + NigoriMetadataBatch expected = + CreateDummyNigoriMetadataBatch(expected_token, expected_sequence_number); + if (given.model_type_state.SerializeAsString() != + expected.model_type_state.SerializeAsString()) { + return false; + } + if (!given.entity_metadata.has_value()) { + return !expected.entity_metadata.has_value(); + } + return given.entity_metadata->SerializeAsString() == + expected.entity_metadata->SerializeAsString(); +} + KeyParams Pbkdf2KeyParams(std::string key) { return {KeyDerivationParams::CreateForPbkdf2(), std::move(key)}; } @@ -196,6 +220,18 @@ return specifics; } +NigoriMetadataBatch CreateDummyNigoriMetadataBatch( + const std::string& progress_marker_token, + int64_t entity_metadata_sequence_number) { + NigoriMetadataBatch metadata_batch; + metadata_batch.model_type_state.mutable_progress_marker()->set_token( + progress_marker_token); + metadata_batch.entity_metadata = sync_pb::EntityMetadata::default_instance(); + metadata_batch.entity_metadata->set_sequence_number( + entity_metadata_sequence_number); + return metadata_batch; +} + class MockNigoriLocalChangeProcessor : public NigoriLocalChangeProcessor { public: MockNigoriLocalChangeProcessor() = default; @@ -229,6 +265,15 @@ void(const SyncEncryptionHandler::NigoriState&)); }; +class MockNigoriStorage : public NigoriStorage { + public: + MockNigoriStorage() = default; + ~MockNigoriStorage() override = default; + + MOCK_METHOD1(StoreData, void(const sync_pb::NigoriLocalData&)); + MOCK_METHOD0(RestoreData, base::Optional<sync_pb::NigoriLocalData>()); +}; + class NigoriSyncBridgeImplTest : public testing::Test { protected: NigoriSyncBridgeImplTest() { @@ -236,7 +281,8 @@ std::make_unique<testing::NiceMock<MockNigoriLocalChangeProcessor>>(); processor_ = processor.get(); bridge_ = std::make_unique<NigoriSyncBridgeImpl>( - std::move(processor), &encryptor_, + std::move(processor), + std::make_unique<testing::NiceMock<MockNigoriStorage>>(), &encryptor_, /*packed_explicit_passphrase_key=*/std::string()); bridge_->AddObserver(&observer_); } @@ -585,7 +631,8 @@ auto processor = std::make_unique<testing::NiceMock<MockNigoriLocalChangeProcessor>>(); auto bridge = std::make_unique<NigoriSyncBridgeImpl>( - std::move(processor), &encryptor, + std::move(processor), + std::make_unique<testing::NiceMock<MockNigoriStorage>>(), &encryptor, PackKeyAsExplicitPassphrase(kKeyParams, encryptor)); testing::NiceMock<MockObserver> observer; bridge->AddObserver(&observer); @@ -605,6 +652,71 @@ bridge->RemoveObserver(&observer); } +TEST(NigoriSyncBridgeImplPersistenceTest, ShouldRestoreKeystoreNigori) { + // Emulate storing on disc. + auto storage1 = std::make_unique<testing::NiceMock<MockNigoriStorage>>(); + sync_pb::NigoriLocalData nigori_local_data; + ON_CALL(*storage1, StoreData(_)) + .WillByDefault([&](const sync_pb::NigoriLocalData& data) { + nigori_local_data = data; + }); + + // Provide some metadata to verify that we store it. + auto processor1 = + std::make_unique<testing::NiceMock<MockNigoriLocalChangeProcessor>>(); + const std::string kDummyProgressMarkerToken = "dummy_token"; + const int64_t kDummySequenceNumber = 100; + ON_CALL(*processor1, GetMetadata()).WillByDefault([&] { + return CreateDummyNigoriMetadataBatch(kDummyProgressMarkerToken, + kDummySequenceNumber); + }); + + const FakeEncryptor kEncryptor; + auto bridge1 = std::make_unique<NigoriSyncBridgeImpl>( + std::move(processor1), std::move(storage1), &kEncryptor, + /*packed_explicit_passphrase_key=*/std::string()); + + // Perform initial sync with simple keystore Nigori. + const std::string kRawKeystoreKey = "raw_keystore_key"; + const KeyParams kKeystoreKeyParams = KeystoreKeyParams(kRawKeystoreKey); + EntityData entity_data; + *entity_data.specifics.mutable_nigori() = BuildKeystoreNigoriSpecifics( + /*keybag_keys_params=*/{kKeystoreKeyParams}, + /*keystore_decryptor_params=*/kKeystoreKeyParams, + /*keystore_key_params=*/kKeystoreKeyParams); + + ASSERT_TRUE(bridge1->SetKeystoreKeys({kRawKeystoreKey})); + ASSERT_THAT(bridge1->MergeSyncData(std::move(entity_data)), + Eq(base::nullopt)); + // At this point |nigori_local_data| must be initialized with metadata + // provided by CreateDummyNigoriMetadataBatch() and data should represent + // the simple keystore Nigori. + + // Create secondary storage which will return |nigori_local_data| on + // RestoreData() call. + auto storage2 = std::make_unique<testing::NiceMock<MockNigoriStorage>>(); + ON_CALL(*storage2, RestoreData()).WillByDefault(Return(nigori_local_data)); + + // Create secondary processor, which should expect ModelReadyToSync() call + // with previously stored metadata. + auto processor2 = + std::make_unique<testing::NiceMock<MockNigoriLocalChangeProcessor>>(); + EXPECT_CALL( + *processor2, + ModelReadyToSync(NotNull(), + IsDummyNigoriMetadataBatchWithTokenAndSequenceNumber( + kDummyProgressMarkerToken, kDummySequenceNumber))); + + auto bridge2 = std::make_unique<NigoriSyncBridgeImpl>( + std::move(processor2), std::move(storage2), &kEncryptor, + /*packed_explicit_passphrase_key=*/std::string()); + + // Verify that we restored Cryptographer state. + const Cryptographer& cryptographer = bridge2->GetCryptographerForTesting(); + EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams)); + EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeystoreKeyParams)); +} + } // namespace } // namespace syncer
diff --git a/components/sync/protocol/nigori_local_data.proto b/components/sync/protocol/nigori_local_data.proto index 3a4b3cbf..d9d343b 100644 --- a/components/sync/protocol/nigori_local_data.proto +++ b/components/sync/protocol/nigori_local_data.proto
@@ -79,13 +79,13 @@ // The list of encrypted UserEncryptableTypes, represented by their specifics // field number. - repeated int32 encrypted_types_specifics_field_numbers = 9; + repeated int32 encrypted_types_specifics_field_number = 9; // Keystore keys are used to decrypt keystore-based Nigori. Should be // persisted in order to not ask the keystore server for them during every // browser startup. Due to backward compatibility requirements keys are // always Base64 encoded. - repeated string keystore_keys = 10; + repeated string keystore_key = 10; } // Sync proto to store Nigori data in storage. Proto should be encrypted with
diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h index 489cc4d..ada817fa 100644 --- a/components/sync/protocol/proto_visitors.h +++ b/components/sync/protocol/proto_visitors.h
@@ -640,8 +640,8 @@ VISIT(custom_passphrase_time); VISIT(custom_passphrase_key_derivation_params); VISIT(encrypt_everything); - VISIT_REP(encrypted_types_specifics_field_numbers); - VISIT_REP(keystore_keys); + VISIT_REP(encrypted_types_specifics_field_number); + VISIT_REP(keystore_key); } VISIT_PROTO_FIELDS(const sync_pb::NigoriLocalData& proto) {
diff --git a/components/variations/proto/study.proto b/components/variations/proto/study.proto index 69e4e4a..5dfdcab9 100644 --- a/components/variations/proto/study.proto +++ b/components/variations/proto/study.proto
@@ -299,7 +299,8 @@ // Takes the same range of values as form_factor, e.g. [PHONE, TABLET]. repeated FormFactor exclude_form_factor = 14; - // List of Chrome OS hardware classes that will receive this study. + // List of hardware classes that will receive this study. + // This supports Chrome OS and as of M77, Android. // // Starting with Chrome M67, this does a case insensitive match on the same // hardware class field that is reported to UMA in the SystemProfileProto's @@ -315,7 +316,8 @@ // Ex: ["veyron_minnie", "daisy"] repeated string hardware_class = 8; - // List of Chrome OS hardware classes that will be excluded in this study. + // List of hardware classes that will be excluded in this study. + // This supports Chrome OS and as of M77, Android. // // Starting with Chrome M67, this does a case insensitive match on the same // hardware class field that is reported to UMA in the SystemProfileProto's
diff --git a/components/variations/variations_associated_data.h b/components/variations/variations_associated_data.h index 006ecfd..55b9021c 100644 --- a/components/variations/variations_associated_data.h +++ b/components/variations/variations_associated_data.h
@@ -146,14 +146,12 @@ // Expose some functions for testing. namespace testing { -// Clears all of the mapped associations. Deprecated, try to use -// VariationParamsManager instead as it does a lot of work for you -// automatically. +// Clears all of the mapped associations. Deprecated, use ScopedFeatureList +// instead as it does a lot of work for you automatically. void ClearAllVariationIDs(); -// Clears all of the associated params. Deprecated, try to use -// VariationParamsManager instead as it does a lot of work for you -// automatically. +// Clears all of the associated params. Deprecated, use ScopedFeatureList +// instead as it does a lot of work for you automatically. void ClearAllVariationParams(); } // namespace testing
diff --git a/components/viz/demo/demo_main.cc b/components/viz/demo/demo_main.cc index c12b97b..f5785dc 100644 --- a/components/viz/demo/demo_main.cc +++ b/components/viz/demo/demo_main.cc
@@ -31,7 +31,7 @@ #endif #if defined(USE_X11) -#include "ui/platform_window/x11/x11_window.h" +#include "ui/platform_window/x11/x11_window.h" // nogncheck #endif namespace { @@ -119,7 +119,9 @@ #elif defined(OS_WIN) return std::make_unique<ui::WinWindow>(this, props.bounds); #elif defined(USE_X11) - return std::make_unique<ui::X11Window>(this, props.bounds); + auto x11_window = std::make_unique<ui::X11Window>(this, nullptr); + x11_window->Initialize(std::move(props)); + return x11_window; #else NOTIMPLEMENTED(); return nullptr;
diff --git a/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc b/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc index 6c9e745b..be0cb34 100644 --- a/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc +++ b/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc
@@ -106,9 +106,6 @@ params->external_begin_frame_controller = MakeRequestAssociatedWithDedicatedPipe( &external_begin_frame_controller_ptr_); - params->external_begin_frame_controller_client = - external_begin_frame_controller_client_.BindInterfacePtr() - .PassInterface(); return params; }
diff --git a/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.h b/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.h index 4b91feaf..f27762f 100644 --- a/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.h +++ b/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.h
@@ -15,7 +15,6 @@ #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/test/fake_compositor_frame_sink_client.h" #include "components/viz/test/fake_display_client.h" -#include "components/viz/test/fake_external_begin_frame_controller_client.h" namespace viz { @@ -56,8 +55,6 @@ FakeDisplayClient display_client_; mojom::ExternalBeginFrameControllerAssociatedPtr external_begin_frame_controller_ptr_; - FakeExternalBeginFrameControllerClient - external_begin_frame_controller_client_; ParentLocalSurfaceIdAllocator lsi_allocator_;
diff --git a/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc b/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc index 00d7015..b64ce75 100644 --- a/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc +++ b/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc
@@ -8,35 +8,35 @@ ExternalBeginFrameSourceMojo::ExternalBeginFrameSourceMojo( mojom::ExternalBeginFrameControllerAssociatedRequest controller_request, - mojom::ExternalBeginFrameControllerClientPtr client, uint32_t restart_id) : ExternalBeginFrameSource(this, restart_id), - binding_(this, std::move(controller_request)), - client_(std::move(client)) {} + binding_(this, std::move(controller_request)) {} ExternalBeginFrameSourceMojo::~ExternalBeginFrameSourceMojo() { DCHECK(!display_); } void ExternalBeginFrameSourceMojo::IssueExternalBeginFrame( - const BeginFrameArgs& args) { + const BeginFrameArgs& args, + bool force, + base::OnceCallback<void(const BeginFrameAck&)> callback) { OnBeginFrame(args); + DCHECK(!pending_frame_callback_) << "Got overlapping IssueExternalBeginFrame"; + pending_frame_callback_ = std::move(callback); + // Ensure that Display will receive the BeginFrame (as a missed one), even // if it doesn't currently need it. This way, we ensure that // OnDisplayDidFinishFrame will be called for this BeginFrame. - DCHECK(display_); - display_->SetNeedsOneBeginFrame(); -} - -void ExternalBeginFrameSourceMojo::OnNeedsBeginFrames(bool needs_begin_frames) { - needs_begin_frames_ = needs_begin_frames; - client_->OnNeedsBeginFrames(needs_begin_frames_); + if (force) + display_->SetNeedsOneBeginFrame(); } void ExternalBeginFrameSourceMojo::OnDisplayDidFinishFrame( const BeginFrameAck& ack) { - client_->OnDisplayDidFinishFrame(ack); + if (!pending_frame_callback_) + return; + std::move(pending_frame_callback_).Run(ack); } void ExternalBeginFrameSourceMojo::OnDisplayDestroyed() {
diff --git a/components/viz/service/frame_sinks/external_begin_frame_source_mojo.h b/components/viz/service/frame_sinks/external_begin_frame_source_mojo.h index ca394c1..34f65713 100644 --- a/components/viz/service/frame_sinks/external_begin_frame_source_mojo.h +++ b/components/viz/service/frame_sinks/external_begin_frame_source_mojo.h
@@ -21,33 +21,34 @@ // completion. class VIZ_SERVICE_EXPORT ExternalBeginFrameSourceMojo : public mojom::ExternalBeginFrameController, - public ExternalBeginFrameSourceClient, public DisplayObserver, - public ExternalBeginFrameSource { + public ExternalBeginFrameSource, + public ExternalBeginFrameSourceClient { public: ExternalBeginFrameSourceMojo( mojom::ExternalBeginFrameControllerAssociatedRequest controller_request, - mojom::ExternalBeginFrameControllerClientPtr client, uint32_t restart_id); ~ExternalBeginFrameSourceMojo() override; // mojom::ExternalBeginFrameController implementation. - void IssueExternalBeginFrame(const BeginFrameArgs& args) override; + void IssueExternalBeginFrame( + const BeginFrameArgs& args, + bool force, + base::OnceCallback<void(const BeginFrameAck&)> callback) override; void SetDisplay(Display* display); private: // ExternalBeginFrameSourceClient implementation. - void OnNeedsBeginFrames(bool needs_begin_frames) override; + void OnNeedsBeginFrames(bool needs_begin_frames) override {} - // DisplayObserver implementation. + // DisplayObserver overrides. void OnDisplayDidFinishFrame(const BeginFrameAck& ack) override; void OnDisplayDestroyed() override; + base::OnceCallback<void(const BeginFrameAck& ack)> pending_frame_callback_; mojo::AssociatedBinding<mojom::ExternalBeginFrameController> binding_; - mojom::ExternalBeginFrameControllerClientPtr client_; - bool needs_begin_frames_ = false; Display* display_ = nullptr; };
diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc index 7af0101..6d9c0f7 100644 --- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc +++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -61,14 +61,10 @@ std::unique_ptr<SyntheticBeginFrameSource> synthetic_begin_frame_source; ExternalBeginFrameSourceMojo* external_begin_frame_source_mojo = nullptr; - if (params->external_begin_frame_controller.is_pending() && - params->external_begin_frame_controller_client) { + if (params->external_begin_frame_controller.is_pending()) { auto owned_external_begin_frame_source_mojo = std::make_unique<ExternalBeginFrameSourceMojo>( - std::move(params->external_begin_frame_controller), - mojom::ExternalBeginFrameControllerClientPtr( - std::move(params->external_begin_frame_controller_client)), - restart_id); + std::move(params->external_begin_frame_controller), restart_id); external_begin_frame_source_mojo = owned_external_begin_frame_source_mojo.get(); external_begin_frame_source =
diff --git a/components/viz/test/BUILD.gn b/components/viz/test/BUILD.gn index ec7227f1..a4407d0 100644 --- a/components/viz/test/BUILD.gn +++ b/components/viz/test/BUILD.gn
@@ -20,8 +20,6 @@ "fake_delay_based_time_source.h", "fake_display_client.cc", "fake_display_client.h", - "fake_external_begin_frame_controller_client.cc", - "fake_external_begin_frame_controller_client.h", "fake_external_begin_frame_source.cc", "fake_external_begin_frame_source.h", "fake_host_frame_sink_client.cc",
diff --git a/components/viz/test/fake_external_begin_frame_controller_client.cc b/components/viz/test/fake_external_begin_frame_controller_client.cc deleted file mode 100644 index 9240709..0000000 --- a/components/viz/test/fake_external_begin_frame_controller_client.cc +++ /dev/null
@@ -1,28 +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. - -#include "components/viz/test/fake_external_begin_frame_controller_client.h" - -namespace viz { - -FakeExternalBeginFrameControllerClient::FakeExternalBeginFrameControllerClient() - : binding_(this) {} - -FakeExternalBeginFrameControllerClient:: - ~FakeExternalBeginFrameControllerClient() = default; - -mojom::ExternalBeginFrameControllerClientPtr -FakeExternalBeginFrameControllerClient::BindInterfacePtr() { - mojom::ExternalBeginFrameControllerClientPtr ptr; - binding_.Bind(mojo::MakeRequest(&ptr)); - return ptr; -} - -void FakeExternalBeginFrameControllerClient::OnNeedsBeginFrames( - bool needs_begin_frames) {} - -void FakeExternalBeginFrameControllerClient::OnDisplayDidFinishFrame( - const BeginFrameAck& ack) {} - -} // namespace viz
diff --git a/components/viz/test/fake_external_begin_frame_controller_client.h b/components/viz/test/fake_external_begin_frame_controller_client.h deleted file mode 100644 index 408c2b5b..0000000 --- a/components/viz/test/fake_external_begin_frame_controller_client.h +++ /dev/null
@@ -1,33 +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. - -#ifndef COMPONENTS_VIZ_TEST_FAKE_EXTERNAL_BEGIN_FRAME_CONTROLLER_CLIENT_H_ -#define COMPONENTS_VIZ_TEST_FAKE_EXTERNAL_BEGIN_FRAME_CONTROLLER_CLIENT_H_ - -#include "mojo/public/cpp/bindings/binding.h" -#include "services/viz/privileged/mojom/compositing/external_begin_frame_controller.mojom.h" - -namespace viz { - -class FakeExternalBeginFrameControllerClient - : public mojom::ExternalBeginFrameControllerClient { - public: - FakeExternalBeginFrameControllerClient(); - ~FakeExternalBeginFrameControllerClient() override; - - mojom::ExternalBeginFrameControllerClientPtr BindInterfacePtr(); - - private: - // ExternalBeginFrameControllerClient implementation. - void OnNeedsBeginFrames(bool needs_begin_frames) override; - void OnDisplayDidFinishFrame(const BeginFrameAck& ack) override; - - mojo::Binding<mojom::ExternalBeginFrameControllerClient> binding_; - - DISALLOW_COPY_AND_ASSIGN(FakeExternalBeginFrameControllerClient); -}; - -} // namespace viz - -#endif // COMPONENTS_VIZ_TEST_FAKE_EXTERNAL_BEGIN_FRAME_CONTROLLER_CLIENT_H_
diff --git a/components/wifi/wifi_test.cc b/components/wifi/wifi_test.cc index e4c57793..378498b 100644 --- a/components/wifi/wifi_test.cc +++ b/components/wifi/wifi_test.cc
@@ -14,14 +14,15 @@ #include "base/command_line.h" #include "base/files/file_util.h" #include "base/logging.h" -#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_current.h" +#include "base/message_loop/message_pump_type.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/task/single_thread_task_executor.h" #include "base/time/time.h" #include "build/build_config.h" #include "components/wifi/wifi_service.h" @@ -103,7 +104,6 @@ return RESULT_WRONG_USAGE; } - base::MessageLoopForIO loop; result_ = RESULT_PENDING; return result_; @@ -135,10 +135,10 @@ MessageBoxA(nullptr, __FUNCTION__, "Debug Me!", MB_OK); #endif - base::MessageLoopForIO loop; + base::SingleThreadTaskExecutor executor(base::MessagePumpType::IO); wifi_service_.reset(WiFiService::Create()); - wifi_service_->Initialize(loop.task_runner()); + wifi_service_->Initialize(executor.task_runner()); if (parsed_command_line.HasSwitch("list")) { base::ListValue network_list; @@ -198,7 +198,7 @@ } wifi_service_->SetEventObservers( - loop.task_runner(), + executor.task_runner(), base::Bind(&WiFiTest::OnNetworksChanged, base::Unretained(this)), base::Bind(&WiFiTest::OnNetworkListChanged, base::Unretained(this))); @@ -231,7 +231,7 @@ if (parsed_command_line.HasSwitch("scan")) { wifi_service_->SetEventObservers( - loop.task_runner(), + executor.task_runner(), base::Bind(&WiFiTest::OnNetworksChanged, base::Unretained(this)), base::Bind(&WiFiTest::OnNetworkListChanged, base::Unretained(this))); wifi_service_->RequestNetworkScan();
diff --git a/content/app/android/content_child_process_service_delegate.cc b/content/app/android/content_child_process_service_delegate.cc index 70724fc..ac1c9661 100644 --- a/content/app/android/content_child_process_service_delegate.cc +++ b/content/app/android/content_child_process_service_delegate.cc
@@ -19,6 +19,7 @@ #include "content/public/common/content_descriptors.h" #include "content/public/common/content_switches.h" #include "gpu/ipc/common/android/scoped_surface_request_conduit.h" +#include "gpu/ipc/common/android/texture_owner.h" #include "gpu/ipc/common/gpu_surface_lookup.h" #include "services/service_manager/embedder/shared_file_util.h" #include "services/service_manager/embedder/switches.h"
diff --git a/content/browser/android/scoped_surface_request_manager.cc b/content/browser/android/scoped_surface_request_manager.cc index befd0a7..8faf9be 100644 --- a/content/browser/android/scoped_surface_request_manager.cc +++ b/content/browser/android/scoped_surface_request_manager.cc
@@ -8,6 +8,7 @@ #include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "gpu/ipc/common/android/texture_owner.h" namespace content {
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc index 95ec004..217fa10 100644 --- a/content/browser/back_forward_cache_browsertest.cc +++ b/content/browser/back_forward_cache_browsertest.cc
@@ -1786,4 +1786,35 @@ EXPECT_EQ(rfh_a, current_frame_host()); } +IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CachePagesWithBeacon) { + constexpr char kKeepalivePath[] = "/keepalive"; + + net::test_server::ControllableHttpResponse keepalive(embedded_test_server(), + kKeepalivePath); + ASSERT_TRUE(embedded_test_server()->Start()); + + GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); + GURL url_ping(embedded_test_server()->GetURL("a.com", kKeepalivePath)); + + // 1) Navigate to A. + EXPECT_TRUE(NavigateToURL(shell(), url_a)); + RenderFrameHostImpl* rfh_a = current_frame_host(); + RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); + + EXPECT_TRUE( + ExecJs(shell(), JsReplace(R"(navigator.sendBeacon($1, "");)", url_ping))); + + // 2) Navigate to B. + GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); + EXPECT_TRUE(NavigateToURL(shell(), url_b)); + + // Ensure that the keepalive request is sent. + keepalive.WaitForRequest(); + // Don't actually send the response. + + // Page A should be in the cache. + EXPECT_FALSE(delete_observer_rfh_a.deleted()); + EXPECT_TRUE(rfh_a->is_in_back_forward_cache()); +} + } // namespace content
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc index 0e86a4b9..a8bb9cfd 100644 --- a/content/browser/background_sync/background_sync_manager.cc +++ b/content/browser/background_sync/background_sync_manager.cc
@@ -1867,7 +1867,6 @@ proxy_.ScheduleBrowserWakeUp(sync_type); } -// TODO(crbug.com/996166): Remove reschedule from method signatures. void BackgroundSyncManager::FireReadyEvents( blink::mojom::BackgroundSyncType sync_type, bool reschedule, @@ -1932,22 +1931,20 @@ } } - if (to_fire.empty()) { - ScheduleOrCancelDelayedProcessing(sync_type); - if (!reschedule) { - // This method has been called from a Chrome wakeup task. - BackgroundSyncMetrics::RecordEventsFiredFromWakeupTask( - sync_type, /* events_fired= */ false); - } - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - std::move(callback)); - return; - } - if (!reschedule) { // This method has been called from a Chrome wakeup task. BackgroundSyncMetrics::RecordEventsFiredFromWakeupTask( - sync_type, /* events_fired= */ true); + sync_type, /* events_fired= */ !to_fire.empty()); + } + + if (to_fire.empty()) { + // TODO(crbug.com/996166): Reschedule wakeup after a non-zero delay if + // called from a wakeup task. + if (reschedule) + ScheduleOrCancelDelayedProcessing(sync_type); + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + std::move(callback)); + return; } base::TimeTicks start_time = base::TimeTicks::Now(); @@ -2061,7 +2058,8 @@ base::OnceClosure callback) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - ScheduleOrCancelDelayedProcessing(sync_type); + if (reschedule) + ScheduleOrCancelDelayedProcessing(sync_type); base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback)); }
diff --git a/content/browser/blob_storage/blob_registry_wrapper.cc b/content/browser/blob_storage/blob_registry_wrapper.cc index 409d10e..336e46c5 100644 --- a/content/browser/blob_storage/blob_registry_wrapper.cc +++ b/content/browser/blob_storage/blob_registry_wrapper.cc
@@ -73,14 +73,6 @@ std::make_unique<BindingDelegate>(process_id)); } -void BlobRegistryWrapper::BindForRequest( - int process_id, - blink::mojom::BlobRegistryRequest request) { - // Implicit conversion |request| to - // mojo::PendingReceiver<blink::mojom::BlobRegistry>. - Bind(process_id, std::move(request)); -} - BlobRegistryWrapper::~BlobRegistryWrapper() {} void BlobRegistryWrapper::InitializeOnIOThread(
diff --git a/content/browser/blob_storage/blob_registry_wrapper.h b/content/browser/blob_storage/blob_registry_wrapper.h index 05d5524..e3dd822c 100644 --- a/content/browser/blob_storage/blob_registry_wrapper.h +++ b/content/browser/blob_storage/blob_registry_wrapper.h
@@ -34,12 +34,6 @@ void Bind(int process_id, mojo::PendingReceiver<blink::mojom::BlobRegistry> receiver); - // TODO(https://crbug.com/955171): Remove this method and use Bind once - // RenderProcessHostImpl uses service_manager::BinderMap instead of - // service_manager::BinderRegistry. - void BindForRequest(int process_id, - blink::mojom::BlobRegistryRequest request); - private: BlobRegistryWrapper(); friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
diff --git a/content/browser/browser_thread_unittest.cc b/content/browser/browser_thread_unittest.cc index 4ec26451..2cd0a69 100644 --- a/content/browser/browser_thread_unittest.cc +++ b/content/browser/browser_thread_unittest.cc
@@ -57,7 +57,8 @@ BrowserTaskExecutor::CreateForTesting( std::move(browser_ui_thread_scheduler), - std::make_unique<BrowserIOThreadDelegate>()); + std::make_unique<BrowserIOThreadDelegate>( + BrowserIOThreadDelegate::BrowserTaskExecutorPresent::kYes)); BrowserTaskExecutor::EnableAllQueues(); } @@ -116,6 +117,7 @@ BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::UI); BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::IO); + BrowserTaskExecutor::ResetForTesting(); } // Prepares this BrowserThreadTest for Release() to be invoked. |on_release| @@ -284,7 +286,7 @@ run_loop.Run(); } -TEST_F(BrowserThreadTest, RunsTasksInCurrentSequencedDuringShutdown) { +TEST_F(BrowserThreadTest, RunsTasksInCurrentSequenceDuringShutdown) { bool did_shutdown = false; base::RunLoop loop; UIThreadDestructionObserver observer(&did_shutdown, loop.QuitClosure()); @@ -311,7 +313,8 @@ QueueType::kDefault)); BrowserTaskExecutor::CreateForTesting( std::move(browser_ui_thread_scheduler), - std::make_unique<BrowserIOThreadDelegate>()); + std::make_unique<BrowserIOThreadDelegate>( + BrowserIOThreadDelegate::BrowserTaskExecutorPresent::kYes)); ui_thread_ = BrowserTaskExecutor::CreateIOThread(); BrowserTaskExecutor::InitializeIOThread();
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc index cc5bbfb..66d95df 100644 --- a/content/browser/compositor/gpu_process_transport_factory.cc +++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -67,7 +67,6 @@ #include "third_party/khronos/GLES2/gl2.h" #include "ui/base/ui_base_switches_util.h" #include "ui/compositor/compositor.h" -#include "ui/compositor/host/external_begin_frame_controller_client_impl.h" #include "ui/compositor/layer.h" #include "ui/display/display_switches.h" #include "ui/display/types/display_snapshot.h" @@ -156,8 +155,6 @@ std::unique_ptr<viz::SyntheticBeginFrameSource> synthetic_begin_frame_source; std::unique_ptr<viz::ExternalBeginFrameSourceMojo> external_begin_frame_source_mojo; - std::unique_ptr<ui::ExternalBeginFrameControllerClientImpl> - external_begin_frame_controller_client; ReflectorImpl* reflector = nullptr; std::unique_ptr<viz::Display> display; std::unique_ptr<viz::mojom::DisplayClient> display_client; @@ -422,14 +419,8 @@ std::unique_ptr<viz::SyntheticBeginFrameSource> synthetic_begin_frame_source; std::unique_ptr<viz::ExternalBeginFrameSourceMojo> external_begin_frame_source_mojo; - std::unique_ptr<ui::ExternalBeginFrameControllerClientImpl> - external_begin_frame_controller_client; - viz::BeginFrameSource* begin_frame_source = nullptr; - if (compositor->external_begin_frame_client()) { - external_begin_frame_controller_client = - std::make_unique<ui::ExternalBeginFrameControllerClientImpl>( - compositor->external_begin_frame_client()); + if (compositor->use_external_begin_frame_control()) { // We don't bind the controller mojo interface, since we only use the // ExternalBeginFrameSourceMojo directly and not via mojo (plus, as it // is an associated interface, binding it would require a separate pipe). @@ -437,7 +428,6 @@ external_begin_frame_source_mojo = std::make_unique<viz::ExternalBeginFrameSourceMojo>( std::move(request), - external_begin_frame_controller_client->GetBoundPtr(), viz::BeginFrameSource::kNotRestartableId); begin_frame_source = external_begin_frame_source_mojo.get(); } else if (disable_frame_rate_limit_) { @@ -482,8 +472,6 @@ data->synthetic_begin_frame_source = std::move(synthetic_begin_frame_source); data->external_begin_frame_source_mojo = std::move(external_begin_frame_source_mojo); - data->external_begin_frame_controller_client = - std::move(external_begin_frame_controller_client); if (data->external_begin_frame_source_mojo) data->external_begin_frame_source_mojo->SetDisplay(data->display.get()); @@ -718,14 +706,17 @@ void GpuProcessTransportFactory::IssueExternalBeginFrame( ui::Compositor* compositor, - const viz::BeginFrameArgs& args) { + const viz::BeginFrameArgs& args, + bool force, + base::OnceCallback<void(const viz::BeginFrameAck&)> callback) { auto it = per_compositor_data_.find(compositor); if (it == per_compositor_data_.end()) return; PerCompositorData* data = it->second.get(); DCHECK(data); DCHECK(data->external_begin_frame_source_mojo); - data->external_begin_frame_source_mojo->IssueExternalBeginFrame(args); + data->external_begin_frame_source_mojo->IssueExternalBeginFrame( + args, force, std::move(callback)); } void GpuProcessTransportFactory::SetOutputIsSecure(ui::Compositor* compositor,
diff --git a/content/browser/compositor/gpu_process_transport_factory.h b/content/browser/compositor/gpu_process_transport_factory.h index 9d32cbc..09aca908 100644 --- a/content/browser/compositor/gpu_process_transport_factory.h +++ b/content/browser/compositor/gpu_process_transport_factory.h
@@ -97,8 +97,11 @@ void SetDisplayVSyncParameters(ui::Compositor* compositor, base::TimeTicks timebase, base::TimeDelta interval) override; - void IssueExternalBeginFrame(ui::Compositor* compositor, - const viz::BeginFrameArgs& args) override; + void IssueExternalBeginFrame( + ui::Compositor* compositor, + const viz::BeginFrameArgs& args, + bool force, + base::OnceCallback<void(const viz::BeginFrameAck&)> callback) override; void SetOutputIsSecure(ui::Compositor* compositor, bool secure) override; void AddVSyncParameterObserver( ui::Compositor* compositor,
diff --git a/content/browser/compositor/test/test_image_transport_factory.h b/content/browser/compositor/test/test_image_transport_factory.h index cf67e37..68ed98ce 100644 --- a/content/browser/compositor/test/test_image_transport_factory.h +++ b/content/browser/compositor/test/test_image_transport_factory.h
@@ -76,8 +76,11 @@ void SetDisplayVSyncParameters(ui::Compositor* compositor, base::TimeTicks timebase, base::TimeDelta interval) override {} - void IssueExternalBeginFrame(ui::Compositor* compositor, - const viz::BeginFrameArgs& args) override {} + void IssueExternalBeginFrame( + ui::Compositor* compositor, + const viz::BeginFrameArgs& args, + bool force, + base::OnceCallback<void(const viz::BeginFrameAck&)> callback) override {} void SetOutputIsSecure(ui::Compositor* compositor, bool secure) override {} void AddVSyncParameterObserver( ui::Compositor* compositor,
diff --git a/content/browser/compositor/viz_process_transport_factory.cc b/content/browser/compositor/viz_process_transport_factory.cc index 2b112a3..5f0a7b8 100644 --- a/content/browser/compositor/viz_process_transport_factory.cc +++ b/content/browser/compositor/viz_process_transport_factory.cc
@@ -409,24 +409,24 @@ IsWorkerContextLost(worker_context_provider_.get())) worker_context_provider_.reset(); + bool enable_oop_rasterization = + gpu_feature_info.status_values[gpu::GPU_FEATURE_TYPE_OOP_RASTERIZATION] == + gpu::kGpuFeatureStatusEnabled; + if (!worker_context_provider_) { - bool enable_oop_rasterization = - gpu_feature_info - .status_values[gpu::GPU_FEATURE_TYPE_OOP_RASTERIZATION] == - gpu::kGpuFeatureStatusEnabled && - features::IsUiOopRasterizationEnabled(); - - bool enable_gpu_rasterization = - !enable_oop_rasterization && features::IsUiGpuRasterizationEnabled(); - - const bool supports_gles2 = enable_gpu_rasterization; - const bool supports_gr_context = enable_gpu_rasterization; - const bool supports_oopr = enable_oop_rasterization; + constexpr bool kSharedWorkerContextSupportsLocking = true; + constexpr bool kSharedWorkerContextSupportsRaster = true; + const bool kSharedWorkerContextSupportsGLES2 = + features::IsUiGpuRasterizationEnabled() && !enable_oop_rasterization; + const bool kSharedWorkerContextSupportsGrContext = + features::IsUiGpuRasterizationEnabled() && !enable_oop_rasterization; + const bool kSharedWorkerContextSupportsOOPR = enable_oop_rasterization; worker_context_provider_ = CreateContextProviderImpl( gpu_channel_host, GetGpuMemoryBufferManager(), - /*supports_locking=*/true, supports_gles2, - /*supports_raster=*/true, supports_gr_context, supports_oopr, + kSharedWorkerContextSupportsLocking, kSharedWorkerContextSupportsGLES2, + kSharedWorkerContextSupportsRaster, + kSharedWorkerContextSupportsGrContext, kSharedWorkerContextSupportsOOPR, viz::command_buffer_metrics::ContextType::BROWSER_WORKER); // Don't observer context loss on |worker_context_provider_| here, that is
diff --git a/content/browser/devtools/protocol/memory_handler.cc b/content/browser/devtools/protocol/memory_handler.cc index 6fb7a8c7..dea2d14 100644 --- a/content/browser/devtools/protocol/memory_handler.cc +++ b/content/browser/devtools/protocol/memory_handler.cc
@@ -111,8 +111,8 @@ } leak_detection_callback_ = std::move(callback); - BindInterface(process, &leak_detector_); - leak_detector_.set_connection_error_handler(base::BindOnce( + BindInterface(process, leak_detector_.BindNewPipeAndPassReceiver()); + leak_detector_.set_disconnect_handler(base::BindOnce( &MemoryHandler::OnLeakDetectorIsGone, base::Unretained(this))); leak_detector_->PerformLeakDetection(base::BindOnce( &MemoryHandler::OnLeakDetectionComplete, weak_factory_.GetWeakPtr()));
diff --git a/content/browser/devtools/protocol/memory_handler.h b/content/browser/devtools/protocol/memory_handler.h index 0c933e5b..fd456c6 100644 --- a/content/browser/devtools/protocol/memory_handler.h +++ b/content/browser/devtools/protocol/memory_handler.h
@@ -9,6 +9,7 @@ #include "base/memory/weak_ptr.h" #include "content/browser/devtools/protocol/devtools_domain_handler.h" #include "content/browser/devtools/protocol/memory.h" +#include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/public/mojom/leak_detector/leak_detector.mojom.h" namespace content { @@ -36,7 +37,7 @@ void OnLeakDetectorIsGone(); int process_host_id_; - blink::mojom::LeakDetectorPtr leak_detector_; + mojo::Remote<blink::mojom::LeakDetector> leak_detector_; std::unique_ptr<PrepareForLeakDetectionCallback> leak_detection_callback_; base::WeakPtrFactory<MemoryHandler> weak_factory_{this};
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc index 2e45b7d..3f207fcf 100644 --- a/content/browser/frame_host/navigation_controller_impl.cc +++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -2378,11 +2378,20 @@ } void NavigationControllerImpl::RemoveEntryAtIndexInternal(int index) { - DCHECK(index < GetEntryCount()); - DCHECK(index != last_committed_entry_index_); + DCHECK_LT(index, GetEntryCount()); + DCHECK_NE(index, last_committed_entry_index_); + + const bool was_transient = index == transient_entry_index_; DiscardNonCommittedEntries(); + if (was_transient) { + // There's nothing left to do if the index referred to a transient entry + // that we just discarded. + DCHECK(!GetTransientEntry()); + return; + } + entries_.erase(entries_.begin() + index); if (last_committed_entry_index_ > index) last_committed_entry_index_--;
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc index 648b1cda..3216e72a 100644 --- a/content/browser/frame_host/navigation_controller_impl_unittest.cc +++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -2832,6 +2832,33 @@ EXPECT_EQ(controller.GetEntryAtIndex(4)->GetURL(), url4); } +// Test that RemoveEntryAtIndex can handle an index that refers to a transient +// entry. +TEST_F(NavigationControllerTest, RemoveTransientByIndex) { + NavigationControllerImpl& controller = controller_impl(); + const GURL url0("http://foo/0"); + const GURL transient_url("http://foo/transient"); + + NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url0); + + std::unique_ptr<NavigationEntry> transient_entry = + std::make_unique<NavigationEntryImpl>(); + transient_entry->SetURL(transient_url); + controller.SetTransientEntry(std::move(transient_entry)); + + EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); + EXPECT_EQ(controller.GetEntryCount(), 2); + EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); + EXPECT_TRUE(controller.GetTransientEntry()); + EXPECT_EQ(controller.GetTransientEntry(), controller.GetEntryAtIndex(1)); + + EXPECT_TRUE(controller.RemoveEntryAtIndex(1)); + + EXPECT_EQ(controller.GetEntryCount(), 1); + EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); + EXPECT_FALSE(controller.GetTransientEntry()); +} + // Test that Reload initiates a new navigation to a transient entry's URL. TEST_F(NavigationControllerTest, ReloadTransient) { NavigationControllerImpl& controller = controller_impl();
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 6b428692..62756de 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -4287,11 +4287,11 @@ registry_->AddInterface(base::BindRepeating( [](RenderFrameHostImpl* frame, - blink::mojom::PresentationServiceRequest request) { + mojo::PendingReceiver<blink::mojom::PresentationService> receiver) { if (!frame->presentation_service_) frame->presentation_service_ = PresentationServiceImpl::Create(frame); - frame->presentation_service_->Bind(std::move(request)); + frame->presentation_service_->Bind(std::move(receiver)); }, base::Unretained(this))); @@ -4458,14 +4458,15 @@ if (base::FeatureList::IsEnabled(blink::features::kNativeFileSystemAPI)) { registry_->AddInterface(base::BindRepeating( [](RenderFrameHostImpl* frame, - blink::mojom::NativeFileSystemManagerRequest request) { - NativeFileSystemManagerImpl::BindRequestFromUIThread( + mojo::PendingReceiver<blink::mojom::NativeFileSystemManager> + receiver) { + NativeFileSystemManagerImpl::BindReceiverFromUIThread( static_cast<StoragePartitionImpl*>( frame->GetProcess()->GetStoragePartition()), NativeFileSystemManagerImpl::BindingContext( frame->GetLastCommittedOrigin(), frame->GetLastCommittedURL(), frame->GetProcess()->GetID(), frame->GetRoutingID()), - std::move(request)); + std::move(receiver)); }, base::Unretained(this))); } @@ -6246,11 +6247,11 @@ } void RenderFrameHostImpl::CreateDedicatedWorkerHostFactory( - blink::mojom::DedicatedWorkerHostFactoryRequest request) { + mojo::PendingReceiver<blink::mojom::DedicatedWorkerHostFactory> receiver) { content::CreateDedicatedWorkerHostFactory( process_->GetID(), /*ancestor_render_frame_id=*/routing_id_, /*creator_render_frame_id=*/routing_id_, last_committed_origin_, - std::move(request)); + std::move(receiver)); } void RenderFrameHostImpl::OnMediaInterfaceFactoryConnectionError() {
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index 7e48cb24..c21321f 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -1506,17 +1506,11 @@ void BindMediaInterfaceFactoryRequest( media::mojom::InterfaceFactoryRequest request); - // TODO(https://crbug.com/955171): Remove this method and use - // CreateWebSocketConnector directly once |this| uses - // service_manager::BinderMap instead of |registry_|. - void CreateWebSocketConnectorForRequest( - blink::mojom::WebSocketConnectorRequest request); - void CreateWebSocketConnector( mojo::PendingReceiver<blink::mojom::WebSocketConnector> receiver); void CreateDedicatedWorkerHostFactory( - blink::mojom::DedicatedWorkerHostFactoryRequest request); + mojo::PendingReceiver<blink::mojom::DedicatedWorkerHostFactory> receiver); // Callback for connection error on the media::mojom::InterfaceFactory client. void OnMediaInterfaceFactoryConnectionError();
diff --git a/content/browser/mime_registry_impl.cc b/content/browser/mime_registry_impl.cc index 19a50c1..9343bfc 100644 --- a/content/browser/mime_registry_impl.cc +++ b/content/browser/mime_registry_impl.cc
@@ -6,7 +6,7 @@ #include "base/files/file_path.h" #include "content/public/browser/browser_thread.h" -#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/base/mime_util.h" namespace content { @@ -17,9 +17,9 @@ // static void MimeRegistryImpl::Create( - blink::mojom::MimeRegistryRequest request) { - mojo::MakeStrongBinding(std::make_unique<MimeRegistryImpl>(), - std::move(request)); + mojo::PendingReceiver<blink::mojom::MimeRegistry> receiver) { + mojo::MakeSelfOwnedReceiver(std::make_unique<MimeRegistryImpl>(), + std::move(receiver)); } void MimeRegistryImpl::GetMimeTypeFromExtension(
diff --git a/content/browser/mime_registry_impl.h b/content/browser/mime_registry_impl.h index 0964330..84399cf 100644 --- a/content/browser/mime_registry_impl.h +++ b/content/browser/mime_registry_impl.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "base/sequence_checker.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" #include "third_party/blink/public/mojom/mime/mime_registry.mojom.h" namespace content { @@ -16,7 +17,8 @@ MimeRegistryImpl(); ~MimeRegistryImpl() override; - static void Create(blink::mojom::MimeRegistryRequest request); + static void Create( + mojo::PendingReceiver<blink::mojom::MimeRegistry> receiver); private: void GetMimeTypeFromExtension(
diff --git a/content/browser/native_file_system/native_file_system_manager_impl.cc b/content/browser/native_file_system/native_file_system_manager_impl.cc index 8aa23c1..aa027b1 100644 --- a/content/browser/native_file_system/native_file_system_manager_impl.cc +++ b/content/browser/native_file_system/native_file_system_manager_impl.cc
@@ -170,17 +170,6 @@ std::move(receiver))); } -// static -void NativeFileSystemManagerImpl::BindRequestFromUIThread( - StoragePartitionImpl* storage_partition, - const BindingContext& binding_context, - blink::mojom::NativeFileSystemManagerRequest request) { - // Implicit conversion |request| to - // mojo::PendingReceiver<blink::mojom::NativeFileSystemManager>. - BindReceiverFromUIThread(storage_partition, binding_context, - std::move(request)); -} - void NativeFileSystemManagerImpl::GetSandboxedFileSystem( GetSandboxedFileSystemCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::IO);
diff --git a/content/browser/native_file_system/native_file_system_manager_impl.h b/content/browser/native_file_system/native_file_system_manager_impl.h index 8cf9077..9925a312 100644 --- a/content/browser/native_file_system/native_file_system_manager_impl.h +++ b/content/browser/native_file_system/native_file_system_manager_impl.h
@@ -88,15 +88,6 @@ const BindingContext& binding_context, mojo::PendingReceiver<blink::mojom::NativeFileSystemManager> receiver); - // TODO(https://crbug.com/955171): Remove this method and use - // BindReceiverFromUIThread once RendererInterfaceBinders and - // RenderFrameHostImpl use service_manager::BinderMap instead of - // service_manager::BinderRegistry. - static void BindRequestFromUIThread( - StoragePartitionImpl* storage_partition, - const BindingContext& binding_context, - blink::mojom::NativeFileSystemManagerRequest request); - // blink::mojom::NativeFileSystemManager: void GetSandboxedFileSystem(GetSandboxedFileSystemCallback callback) override; void ChooseEntries(
diff --git a/content/browser/network_context_client_base_impl.cc b/content/browser/network_context_client_base_impl.cc index e77169d..414ea85 100644 --- a/content/browser/network_context_client_base_impl.cc +++ b/content/browser/network_context_client_base_impl.cc
@@ -103,7 +103,10 @@ uint32_t routing_id, uint32_t request_id, const scoped_refptr<net::SSLCertRequestInfo>& cert_info, - network::mojom::ClientCertificateResponderPtr cert_responder) { + mojo::PendingRemote<network::mojom::ClientCertificateResponder> + cert_responder_remote) { + mojo::Remote<network::mojom::ClientCertificateResponder> cert_responder( + std::move(cert_responder_remote)); cert_responder->CancelRequest(); }
diff --git a/content/browser/quota_dispatcher_host.cc b/content/browser/quota_dispatcher_host.cc index faf2e15..f66ad1c 100644 --- a/content/browser/quota_dispatcher_host.cc +++ b/content/browser/quota_dispatcher_host.cc
@@ -18,7 +18,7 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/storage_partition.h" #include "content/public/common/content_client.h" -#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/base/url_util.h" #include "storage/browser/quota/quota_manager.h" #include "url/origin.h" @@ -31,22 +31,23 @@ namespace { -void BindConnectorOnIOThread(int render_process_id, - int render_frame_id, - storage::QuotaManager* quota_manager, - blink::mojom::QuotaDispatcherHostRequest request) { - mojo::MakeStrongBinding( +void BindConnectorOnIOThread( + int render_process_id, + int render_frame_id, + storage::QuotaManager* quota_manager, + mojo::PendingReceiver<blink::mojom::QuotaDispatcherHost> receiver) { + mojo::MakeSelfOwnedReceiver( std::make_unique<QuotaDispatcherHost>( render_process_id, render_frame_id, quota_manager, GetContentClient()->browser()->CreateQuotaPermissionContext()), - std::move(request)); + std::move(receiver)); } } // namespace // static void QuotaDispatcherHost::CreateForWorker( - blink::mojom::QuotaDispatcherHostRequest request, + mojo::PendingReceiver<blink::mojom::QuotaDispatcherHost> receiver, RenderProcessHost* host, const url::Origin& origin) { // TODO(crbug.com/779444): Save the |origin| here and use it rather than the @@ -58,21 +59,21 @@ base::BindOnce( &BindConnectorOnIOThread, host->GetID(), MSG_ROUTING_NONE, base::RetainedRef(host->GetStoragePartition()->GetQuotaManager()), - std::move(request))); + std::move(receiver))); } // static void QuotaDispatcherHost::CreateForFrame( RenderProcessHost* host, int render_frame_id, - blink::mojom::QuotaDispatcherHostRequest request) { + mojo::PendingReceiver<blink::mojom::QuotaDispatcherHost> receiver) { // Bind on the IO thread. base::PostTask( FROM_HERE, {BrowserThread::IO}, base::BindOnce( &BindConnectorOnIOThread, host->GetID(), render_frame_id, base::RetainedRef(host->GetStoragePartition()->GetQuotaManager()), - std::move(request))); + std::move(receiver))); } QuotaDispatcherHost::QuotaDispatcherHost(
diff --git a/content/browser/quota_dispatcher_host.h b/content/browser/quota_dispatcher_host.h index 680f491f..efef5a6 100644 --- a/content/browser/quota_dispatcher_host.h +++ b/content/browser/quota_dispatcher_host.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "content/public/browser/quota_permission_context.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" #include "storage/browser/quota/quota_manager.h" #include "third_party/blink/public/mojom/quota/quota_dispatcher_host.mojom.h" @@ -24,13 +25,15 @@ class QuotaDispatcherHost : public blink::mojom::QuotaDispatcherHost { public: - static void CreateForWorker(blink::mojom::QuotaDispatcherHostRequest request, - RenderProcessHost* host, - const url::Origin& origin); + static void CreateForWorker( + mojo::PendingReceiver<blink::mojom::QuotaDispatcherHost> receiver, + RenderProcessHost* host, + const url::Origin& origin); - static void CreateForFrame(RenderProcessHost* host, - int render_frame_id, - blink::mojom::QuotaDispatcherHostRequest request); + static void CreateForFrame( + RenderProcessHost* host, + int render_frame_id, + mojo::PendingReceiver<blink::mojom::QuotaDispatcherHost> receiver); QuotaDispatcherHost(int process_id, int render_frame_id,
diff --git a/content/browser/renderer_host/code_cache_host_impl.cc b/content/browser/renderer_host/code_cache_host_impl.cc index f118ecd..ef6d89d 100644 --- a/content/browser/renderer_host/code_cache_host_impl.cc +++ b/content/browser/renderer_host/code_cache_host_impl.cc
@@ -23,7 +23,7 @@ #include "content/public/browser/storage_partition.h" #include "content/public/common/content_features.h" #include "content/public/common/url_constants.h" -#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/base/io_buffer.h" #include "third_party/blink/public/common/cache_storage/cache_storage_utils.h" #include "url/gurl.h" @@ -112,13 +112,13 @@ int render_process_id, scoped_refptr<CacheStorageContextImpl> cache_storage_context, scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context, - blink::mojom::CodeCacheHostRequest request) { + mojo::PendingReceiver<blink::mojom::CodeCacheHost> receiver) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - mojo::MakeStrongBinding( + mojo::MakeSelfOwnedReceiver( std::make_unique<CodeCacheHostImpl>( render_process_id, std::move(cache_storage_context), std::move(generated_code_cache_context)), - std::move(request)); + std::move(receiver)); } void CodeCacheHostImpl::DidGenerateCacheableMetadata(
diff --git a/content/browser/renderer_host/code_cache_host_impl.h b/content/browser/renderer_host/code_cache_host_impl.h index e2670509..37eeb00 100644 --- a/content/browser/renderer_host/code_cache_host_impl.h +++ b/content/browser/renderer_host/code_cache_host_impl.h
@@ -14,7 +14,7 @@ #include "content/browser/cache_storage/cache_storage_cache_handle.h" #include "content/common/content_export.h" #include "mojo/public/cpp/base/big_buffer.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom.h" #include "third_party/blink/public/mojom/loader/code_cache.mojom.h" @@ -51,7 +51,7 @@ int render_process_id, scoped_refptr<CacheStorageContextImpl> cache_storage_context, scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context, - blink::mojom::CodeCacheHostRequest request); + mojo::PendingReceiver<blink::mojom::CodeCacheHost> receiver); private: // blink::mojom::CodeCacheHost implementation.
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index 4512ee4..d37e3cf 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -75,7 +75,6 @@ #include "third_party/khronos/GLES2/gl2ext.h" #include "third_party/skia/include/core/SkMallocPixelRef.h" #include "ui/android/window_android.h" -#include "ui/compositor/host/external_begin_frame_controller_client_impl.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/gfx/ca_layer_params.h"
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index 78adbe8..8cc4b80 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -37,7 +37,6 @@ #include "ui/android/window_android.h" #include "ui/android/window_android_compositor.h" #include "ui/compositor/compositor_lock.h" -#include "ui/compositor/external_begin_frame_client.h" #include "ui/display/display_observer.h" struct ANativeWindow; @@ -48,10 +47,6 @@ class LayerTreeHost; } -namespace ui { -class ExternalBeginFrameControllerClientImpl; -} - namespace viz { class FrameSinkId; class HostDisplayClient;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 38f1afe5..39166c8f 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2156,7 +2156,7 @@ base::Unretained(this))); registry->AddInterface( - base::BindRepeating(&BlobRegistryWrapper::BindForRequest, + base::BindRepeating(&BlobRegistryWrapper::Bind, storage_partition_impl_->GetBlobRegistry(), GetID())); #if BUILDFLAG(ENABLE_PLUGINS)
diff --git a/content/browser/renderer_interface_binders.cc b/content/browser/renderer_interface_binders.cc index 086f55a..c413b93 100644 --- a/content/browser/renderer_interface_binders.cc +++ b/content/browser/renderer_interface_binders.cc
@@ -89,14 +89,6 @@ private: void InitializeParameterizedBinderRegistry(); - // TODO(https://crbug.com/955171): Remove this method and use - // CreateWebSocketConnector directly once |this| uses - // service_manager::BinderMap instead of |parameterized_binder_registry_|. - static void CreateWebSocketConnectorForRequest( - blink::mojom::WebSocketConnectorRequest request, - RenderProcessHost* host, - const url::Origin& origin); - static void CreateWebSocketConnector( mojo::PendingReceiver<blink::mojom::WebSocketConnector> receiver, RenderProcessHost* host, @@ -186,7 +178,7 @@ // TODO(nhiroki): Consider moving this into SharedWorkerHost and // ServiceWorkerProviderHost. parameterized_binder_registry_.AddInterface( - base::BindRepeating(CreateWebSocketConnectorForRequest)); + base::BindRepeating(CreateWebSocketConnector)); parameterized_binder_registry_.AddInterface( base::Bind([](payments::mojom::PaymentManagerRequest request, @@ -216,12 +208,13 @@ })); if (base::FeatureList::IsEnabled(blink::features::kNativeFileSystemAPI)) { parameterized_binder_registry_.AddInterface(base::BindRepeating( - [](blink::mojom::NativeFileSystemManagerRequest request, + [](mojo::PendingReceiver<blink::mojom::NativeFileSystemManager> + receiver, RenderProcessHost* host, const url::Origin& origin) { // This code path is only for workers, hence always pass in // MSG_ROUTING_NONE as frame ID. Frames themselves go through // RenderFrameHostImpl instead. - NativeFileSystemManagerImpl::BindRequestFromUIThread( + NativeFileSystemManagerImpl::BindReceiverFromUIThread( static_cast<StoragePartitionImpl*>(host->GetStoragePartition()), NativeFileSystemManagerImpl::BindingContext( origin, @@ -230,7 +223,7 @@ // will be used for SafeBrowsing checks and for the Quarantine // Service. origin.GetURL(), host->GetID(), MSG_ROUTING_NONE), - std::move(request)); + std::move(receiver)); })); } parameterized_binder_registry_.AddInterface(base::Bind( @@ -279,15 +272,6 @@ return *binders; } -void RendererInterfaceBinders::CreateWebSocketConnectorForRequest( - blink::mojom::WebSocketConnectorRequest request, - RenderProcessHost* host, - const url::Origin& origin) { - // Implicit conversion from WebSocketConnectorRequest to - // mojo::PendingReceiver<blink::mojom::WebSocketConnector>. - CreateWebSocketConnector(std::move(request), host, origin); -} - void RendererInterfaceBinders::CreateWebSocketConnector( mojo::PendingReceiver<blink::mojom::WebSocketConnector> receiver, RenderProcessHost* host,
diff --git a/content/browser/scheduler/browser_io_thread_delegate.cc b/content/browser/scheduler/browser_io_thread_delegate.cc index ec65f10a..adf0fb9 100644 --- a/content/browser/scheduler/browser_io_thread_delegate.cc +++ b/content/browser/scheduler/browser_io_thread_delegate.cc
@@ -7,6 +7,8 @@ #include "base/message_loop/message_pump_type.h" #include "base/task/sequence_manager/sequence_manager.h" #include "base/task/sequence_manager/task_queue.h" +#include "base/task/task_executor.h" +#include "content/browser/scheduler/browser_task_executor.h" #include "content/public/browser/browser_thread.h" namespace content { @@ -15,17 +17,20 @@ using ::base::sequence_manager::SequenceManager; using ::base::sequence_manager::TaskQueue; -BrowserIOThreadDelegate::BrowserIOThreadDelegate() +BrowserIOThreadDelegate::BrowserIOThreadDelegate( + BrowserTaskExecutorPresent browser_task_executor_present) : sequence_manager_(CreateUnboundSequenceManager( SequenceManager::Settings::Builder() .SetMessagePumpType(base::MessagePumpType::IO) - .Build())) { + .Build())), + browser_task_executor_present_(browser_task_executor_present) { Init(sequence_manager_.get()); } BrowserIOThreadDelegate::BrowserIOThreadDelegate( SequenceManager* sequence_manager) - : sequence_manager_(nullptr) { + : sequence_manager_(nullptr), + browser_task_executor_present_(BrowserTaskExecutorPresent::kYes) { Init(sequence_manager); } @@ -42,7 +47,11 @@ return default_task_runner_; } -BrowserIOThreadDelegate::~BrowserIOThreadDelegate() = default; +BrowserIOThreadDelegate::~BrowserIOThreadDelegate() { + if (browser_task_executor_present_ == BrowserTaskExecutorPresent::kYes) { + base::SetTaskExecutorForCurrentThread(nullptr); + } +} void BrowserIOThreadDelegate::BindToCurrentThread( base::TimerSlack timer_slack) { @@ -51,6 +60,10 @@ base::MessagePump::Create(base::MessagePumpType::IO)); sequence_manager_->SetTimerSlack(timer_slack); sequence_manager_->SetDefaultTaskRunner(GetDefaultTaskRunner()); + + if (browser_task_executor_present_ == BrowserTaskExecutorPresent::kYes) { + base::SetTaskExecutorForCurrentThread(BrowserTaskExecutor::Get()); + } } } // namespace content
diff --git a/content/browser/scheduler/browser_io_thread_delegate.h b/content/browser/scheduler/browser_io_thread_delegate.h index 49c337d..857290d 100644 --- a/content/browser/scheduler/browser_io_thread_delegate.h +++ b/content/browser/scheduler/browser_io_thread_delegate.h
@@ -28,12 +28,19 @@ public: using Handle = BrowserTaskQueues::Handle; + // Normally, creating a BrowserIOThreadDelegate relies on a + // BrowserTaskExecutor already existing to register it as the executor for the + // current (IO) thread. However, BrowserIOThreadDelegateTest tests it in + // isolation, so we need to disable registering the executor to pass checks. + enum class BrowserTaskExecutorPresent { kYes, kNoForTesting }; + static std::unique_ptr<BrowserIOThreadDelegate> CreateForTesting( base::sequence_manager::SequenceManager* sequence_manager) { return base::WrapUnique(new BrowserIOThreadDelegate(sequence_manager)); } - BrowserIOThreadDelegate(); + BrowserIOThreadDelegate( + BrowserTaskExecutorPresent browser_task_executor_present); ~BrowserIOThreadDelegate() override; scoped_refptr<base::SingleThreadTaskRunner> GetDefaultTaskRunner() override; @@ -64,6 +71,8 @@ std::unique_ptr<BrowserTaskQueues> task_queues_; scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; + + const BrowserTaskExecutorPresent browser_task_executor_present_; }; } // namespace content
diff --git a/content/browser/scheduler/browser_io_thread_delegate_unittest.cc b/content/browser/scheduler/browser_io_thread_delegate_unittest.cc index 2be9c02..f7378f0 100644 --- a/content/browser/scheduler/browser_io_thread_delegate_unittest.cc +++ b/content/browser/scheduler/browser_io_thread_delegate_unittest.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" +#include "content/browser/scheduler/browser_task_executor.h" #include "content/browser/scheduler/browser_task_queues.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -19,7 +20,8 @@ TEST(BrowserIOThreadDelegateTest, CanPostTasksToThread) { base::Thread thread("my_thread"); - auto delegate = std::make_unique<BrowserIOThreadDelegate>(); + auto delegate = std::make_unique<BrowserIOThreadDelegate>( + BrowserIOThreadDelegate::BrowserTaskExecutorPresent::kNoForTesting); auto handle = delegate->CreateHandle(); handle->EnableAllQueues(); @@ -36,10 +38,11 @@ event.Wait(); } -TEST(BrowserIOThreadDelegateTest, DefaultTaskRunnerIsAllwaysActive) { +TEST(BrowserIOThreadDelegateTest, DefaultTaskRunnerIsAlwaysActive) { base::Thread thread("my_thread"); - auto delegate = std::make_unique<BrowserIOThreadDelegate>(); + auto delegate = std::make_unique<BrowserIOThreadDelegate>( + BrowserIOThreadDelegate::BrowserTaskExecutorPresent::kNoForTesting); auto task_runner = delegate->GetDefaultTaskRunner(); base::Thread::Options options;
diff --git a/content/browser/scheduler/browser_task_executor.cc b/content/browser/scheduler/browser_task_executor.cc index f2ddb987..dfd65de4 100644 --- a/content/browser/scheduler/browser_task_executor.cc +++ b/content/browser/scheduler/browser_task_executor.cc
@@ -11,6 +11,7 @@ #include "base/message_loop/message_pump_type.h" #include "base/no_destructor.h" #include "base/task/post_task.h" +#include "base/third_party/dynamic_annotations/dynamic_annotations.h" #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" @@ -74,13 +75,17 @@ browser_io_thread_delegate_(std::move(browser_io_thread_delegate)), browser_io_thread_handle_(browser_io_thread_delegate_->CreateHandle()) {} -BrowserTaskExecutor::~BrowserTaskExecutor() = default; +BrowserTaskExecutor::~BrowserTaskExecutor() { + base::SetTaskExecutorForCurrentThread(nullptr); +} // static void BrowserTaskExecutor::Create() { DCHECK(!base::ThreadTaskRunnerHandle::IsSet()); - CreateInternal(std::make_unique<BrowserUIThreadScheduler>(), - std::make_unique<BrowserIOThreadDelegate>()); + CreateInternal( + std::make_unique<BrowserUIThreadScheduler>(), + std::make_unique<BrowserIOThreadDelegate>( + BrowserIOThreadDelegate::BrowserTaskExecutorPresent::kYes)); } // static @@ -104,21 +109,32 @@ g_browser_task_executor->browser_ui_thread_handle_ ->EnableAllExceptBestEffortQueues(); + base::SetTaskExecutorForCurrentThread(g_browser_task_executor); + #if defined(OS_ANDROID) base::PostTaskAndroid::SignalNativeSchedulerReady(); #endif } // static +BrowserTaskExecutor* BrowserTaskExecutor::Get() { + DCHECK(g_browser_task_executor); + return g_browser_task_executor; +} + +// static void BrowserTaskExecutor::ResetForTesting() { #if defined(OS_ANDROID) base::PostTaskAndroid::SignalNativeSchedulerShutdown(); #endif - + base::SetTaskExecutorForCurrentThread(nullptr); if (g_browser_task_executor) { base::UnregisterTaskExecutorForTesting( BrowserTaskTraitsExtension::kExtensionId); delete g_browser_task_executor; + ANNOTATE_BENIGN_RACE( + &g_browser_task_executor, + "Test-only data race in content/browser/browser_thread_unittest"); g_browser_task_executor = nullptr; } }
diff --git a/content/browser/scheduler/browser_task_executor.h b/content/browser/scheduler/browser_task_executor.h index c873e97..b3f6bc2 100644 --- a/content/browser/scheduler/browser_task_executor.h +++ b/content/browser/scheduler/browser_task_executor.h
@@ -162,6 +162,10 @@ FRIEND_TEST_ALL_PREFIXES(BrowserTaskExecutorTest, BestEffortTasksRunAfterStartup); + // For Get*(); + FRIEND_TEST_ALL_PREFIXES(BrowserTaskExecutorTest, + RegisterExecutorForBothThreads); + explicit BrowserTaskExecutor( std::unique_ptr<BrowserUIThreadScheduler> browser_ui_thread_scheduler, std::unique_ptr<BrowserIOThreadDelegate> browser_io_thread_delegate); @@ -170,6 +174,9 @@ scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner( const base::TaskTraits& traits) const; + friend class BrowserIOThreadDelegate; + static BrowserTaskExecutor* Get(); + std::unique_ptr<BrowserUIThreadScheduler> browser_ui_thread_scheduler_; scoped_refptr<BrowserUIThreadScheduler::Handle> browser_ui_thread_handle_;
diff --git a/content/browser/scheduler/browser_task_executor_unittest.cc b/content/browser/scheduler/browser_task_executor_unittest.cc index 3bae309..12adb00 100644 --- a/content/browser/scheduler/browser_task_executor_unittest.cc +++ b/content/browser/scheduler/browser_task_executor_unittest.cc
@@ -47,6 +47,23 @@ using StrictMockTask = testing::StrictMock<base::MockCallback<base::RepeatingCallback<void()>>>; +TEST_F(BrowserTaskExecutorTest, RegisterExecutorForBothThreads) { + base::PostTask(FROM_HERE, {BrowserThread::UI}, + base::BindLambdaForTesting([&]() { + EXPECT_EQ(BrowserTaskExecutor::Get(), + base::GetTaskExecutorForCurrentThread()); + })); + + base::PostTask(FROM_HERE, {BrowserThread::IO}, + base::BindLambdaForTesting([&]() { + EXPECT_EQ(BrowserTaskExecutor::Get(), + base::GetTaskExecutorForCurrentThread()); + })); + + BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::UI); + BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::IO); +} + TEST_F(BrowserTaskExecutorTest, RunAllPendingTasksForTestingOnUI) { StrictMockTask task_1; StrictMockTask task_2; @@ -179,7 +196,8 @@ QueueType::kDefault)); BrowserTaskExecutor::CreateForTesting( std::move(browser_ui_thread_scheduler), - std::make_unique<BrowserIOThreadDelegate>()); + std::make_unique<BrowserIOThreadDelegate>( + BrowserIOThreadDelegate::BrowserTaskExecutorPresent::kYes)); } };
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc index e87204fc..ad49c24 100644 --- a/content/browser/service_worker/service_worker_context_core.cc +++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -502,6 +502,45 @@ return next_embedded_worker_id_++; } +scoped_refptr<blink::URLLoaderFactoryBundle> +ServiceWorkerContextCore::GetLoaderFactoryBundleForUpdateCheck() { + DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); + DCHECK(blink::ServiceWorkerUtils::IsImportedScriptUpdateCheckEnabled()); + + // Update the default factory in the bundle with a newly cloned network + // factory before update check because the old default factory may be invalid + // due to crash of network service. + // TODO(crbug.com/995763): This should call WillCreateURLLoaderFactory(). + + if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) { + StoragePartitionImpl* storage_partition = wrapper()->storage_partition(); + if (storage_partition) { + mojo::PendingRemote<network::mojom::URLLoaderFactory> remote; + scoped_refptr<network::SharedURLLoaderFactory> network_factory = + storage_partition->GetURLLoaderFactoryForBrowserProcess(); + network_factory->Clone(remote.InitWithNewPipeAndPassReceiver()); + + auto pending_factory_bundle = + std::make_unique<blink::URLLoaderFactoryBundleInfo>(); + pending_factory_bundle->pending_default_factory() = std::move(remote); + loader_factory_bundle_for_update_check_->Update( + std::move(pending_factory_bundle)); + } + } else { + network::mojom::URLLoaderFactoryPtr network_factory_ptr; + loader_factory_getter_->CloneNetworkFactory( + mojo::MakeRequest(&network_factory_ptr)); + auto pending_factory_bundle = + std::make_unique<blink::URLLoaderFactoryBundleInfo>(); + pending_factory_bundle->pending_default_factory() = + network_factory_ptr.PassInterface(); + loader_factory_bundle_for_update_check_->Update( + std::move(pending_factory_bundle)); + } + + return loader_factory_bundle_for_update_check_; +} + void ServiceWorkerContextCore::RegistrationComplete( const GURL& scope, ServiceWorkerContextCore::RegistrationCallback callback,
diff --git a/content/browser/service_worker/service_worker_context_core.h b/content/browser/service_worker/service_worker_context_core.h index c3fbdcfa..164c4ef8 100644 --- a/content/browser/service_worker/service_worker_context_core.h +++ b/content/browser/service_worker/service_worker_context_core.h
@@ -280,17 +280,21 @@ return loader_factory_getter_.get(); } - const scoped_refptr<blink::URLLoaderFactoryBundle>& - loader_factory_bundle_for_update_check() { - return loader_factory_bundle_for_update_check_; - } - base::WeakPtr<ServiceWorkerContextCore> AsWeakPtr() { return weak_factory_.GetWeakPtr(); } int GetNextEmbeddedWorkerId(); + // Called when ServiceWorkerImportedScriptUpdateCheck is enabled. + // Returns a factory bundle suitable for the browser process to use to fetch + // a non-installed service worker main script or imported script during an + // update check. It must not be sent to a renderer process. The bundle does + // not support reconnection to the network service, so it should be used for + // only a single service worker update check. + scoped_refptr<blink::URLLoaderFactoryBundle> + GetLoaderFactoryBundleForUpdateCheck(); + private: friend class ServiceWorkerContextCoreTest; FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextCoreTest, FailureInfo);
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc index d9082e6..5ab1912 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.cc +++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -1920,91 +1920,6 @@ return factory_bundle; } -void ServiceWorkerContextWrapper::GetLoaderFactoryForUpdateCheck( - const GURL& scope, - base::OnceCallback<void(scoped_refptr<network::SharedURLLoaderFactory>)> - callback) { - DCHECK_CURRENTLY_ON(GetCoreThreadId()); - - RunOrPostTaskOnThread( - FROM_HERE, BrowserThread::UI, - base::BindOnce( - &ServiceWorkerContextWrapper::SetUpLoaderFactoryForUpdateCheckOnUI, - this, scope, - base::BindOnce( - &ServiceWorkerContextWrapper::DidSetUpLoaderFactoryForUpdateCheck, - this, std::move(callback)))); -} - -void ServiceWorkerContextWrapper::SetUpLoaderFactoryForUpdateCheckOnUI( - const GURL& scope, - base::OnceCallback< - void(mojo::PendingRemote<network::mojom::URLLoaderFactory>, - mojo::PendingReceiver<network::mojom::URLLoaderFactory>, - bool)> setup_complete_callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - mojo::PendingRemote<network::mojom::URLLoaderFactory> remote; - mojo::PendingReceiver<network::mojom::URLLoaderFactory> pending_receiver = - remote.InitWithNewPipeAndPassReceiver(); - mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient> - default_header_client; - bool bypass_redirect_checks = false; - - if (storage_partition_) { - GetContentClient()->browser()->WillCreateURLLoaderFactory( - storage_partition_->browser_context(), /*frame=*/nullptr, - ChildProcessHost::kInvalidUniqueID, - ContentBrowserClient::URLLoaderFactoryType::kServiceWorkerScript, - url::Origin::Create(scope), &pending_receiver, &default_header_client, - &bypass_redirect_checks); - } - - RunOrPostTaskOnThread( - FROM_HERE, GetCoreThreadId(), - base::BindOnce(std::move(setup_complete_callback), std::move(remote), - std::move(pending_receiver), bypass_redirect_checks)); -} - -void ServiceWorkerContextWrapper::DidSetUpLoaderFactoryForUpdateCheck( - base::OnceCallback<void(scoped_refptr<network::SharedURLLoaderFactory>)> - callback, - mojo::PendingRemote<network::mojom::URLLoaderFactory> remote, - mojo::PendingReceiver<network::mojom::URLLoaderFactory> pending_receiver, - bool bypass_redirect_checks) { - DCHECK_CURRENTLY_ON(GetCoreThreadId()); - - // Set up a Mojo connection to the network loader factory. - if (IsServiceWorkerOnUIEnabled()) { - if (!storage_partition_) { - std::move(callback).Run(nullptr); - return; - } - scoped_refptr<network::SharedURLLoaderFactory> network_factory = - storage_partition_->GetURLLoaderFactoryForBrowserProcess(); - network_factory->Clone(std::move(pending_receiver)); - } else { - context()->loader_factory_getter()->CloneNetworkFactory( - std::move(pending_receiver)); - } - - // Clone context()->loader_factory_bundle_for_update_check() and set up the - // default factory. - std::unique_ptr<network::SharedURLLoaderFactoryInfo> - loader_factory_bundle_info = - context()->loader_factory_bundle_for_update_check()->Clone(); - static_cast<blink::URLLoaderFactoryBundleInfo*>( - loader_factory_bundle_info.get()) - ->pending_default_factory() = std::move(remote); - static_cast<blink::URLLoaderFactoryBundleInfo*>( - loader_factory_bundle_info.get()) - ->set_bypass_redirect_checks(bypass_redirect_checks); - scoped_refptr<network::SharedURLLoaderFactory> loader_factory = - network::SharedURLLoaderFactory::Create( - std::move(loader_factory_bundle_info)); - std::move(callback).Run(std::move(loader_factory)); -} - bool ServiceWorkerContextWrapper::HasRegistrationForOrigin( const GURL& origin) const { DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/content/browser/service_worker/service_worker_context_wrapper.h b/content/browser/service_worker/service_worker_context_wrapper.h index 17166fd..65a3f16 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.h +++ b/content/browser/service_worker/service_worker_context_wrapper.h
@@ -318,13 +318,6 @@ bool HasRegistrationForOrigin(const GURL& origin) const; void WaitForRegistrationsInitializedForTest(); - // This must be called on the core thread, and the |callback| also runs on - // the core thread which can be called with nullptr on failure. - void GetLoaderFactoryForUpdateCheck( - const GURL& scope, - base::OnceCallback<void(scoped_refptr<network::SharedURLLoaderFactory>)> - callback); - private: friend class BackgroundSyncManagerTest; friend class base::RefCountedThreadSafe<ServiceWorkerContextWrapper>; @@ -443,24 +436,6 @@ CreateNonNetworkURLLoaderFactoryBundleInfoForUpdateCheck( BrowserContext* browser_context); - void SetUpLoaderFactoryForUpdateCheckOnUI( - const GURL& scope, - base::OnceCallback< - void(mojo::PendingRemote<network::mojom::URLLoaderFactory>, - mojo::PendingReceiver<network::mojom::URLLoaderFactory>, - bool)> setup_complete_callback); - - // This method completes the remaining work of - // SetUpLoaderFactoryForUpdateCheckOnUI() on Core thread: Binds the pending - // network factory receiver and creates the loader factory bundle for update - // check. - void DidSetUpLoaderFactoryForUpdateCheck( - base::OnceCallback<void(scoped_refptr<network::SharedURLLoaderFactory>)> - callback, - mojo::PendingRemote<network::mojom::URLLoaderFactory> remote, - mojo::PendingReceiver<network::mojom::URLLoaderFactory> pending_receiver, - bool bypass_redirect_checks); - // Called when the stored registrations are loaded, and each time a new // service worker is registered. void OnRegistrationUpdated(
diff --git a/content/browser/service_worker/service_worker_register_job.cc b/content/browser/service_worker/service_worker_register_job.cc index b2fcab14..1bd93e6 100644 --- a/content/browser/service_worker/service_worker_register_job.cc +++ b/content/browser/service_worker/service_worker_register_job.cc
@@ -312,21 +312,9 @@ } void ServiceWorkerRegisterJob::TriggerUpdateCheckInBrowser( - scoped_refptr<network::SharedURLLoaderFactory> loader_factory) { - DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); + ServiceWorkerUpdateChecker::UpdateStatusCallback callback) { DCHECK_EQ(GetUpdateCheckType(), UpdateCheckType::kAllScriptsBeforeStartWorker); - - if (!loader_factory) { - // We can't continue with update checking appropriately without - // |loader_factory|. Null |loader_factory| means that the storage partition - // was not available probably because it's shutting down. - // This terminates the current job (|this|). - Complete(blink::ServiceWorkerStatusCode::kErrorAbort, - ServiceWorkerConsts::kShutdownErrorMessage); - return; - } - ServiceWorkerVersion* version_to_update = registration()->GetNewestVersion(); base::TimeDelta time_since_last_check = base::Time::Now() - registration()->last_update_check(); @@ -339,12 +327,10 @@ update_checker_ = std::make_unique<ServiceWorkerUpdateChecker>( std::move(resources), script_url_, script_resource_id, version_to_update, - std::move(loader_factory), force_bypass_cache_, + context_->GetLoaderFactoryBundleForUpdateCheck(), force_bypass_cache_, registration()->update_via_cache(), time_since_last_check, context_.get()); - update_checker_->Start( - base::BindOnce(&ServiceWorkerRegisterJob::OnUpdateCheckFinished, - weak_factory_.GetWeakPtr())); + update_checker_->Start(std::move(callback)); } ServiceWorkerRegisterJob::UpdateCheckType @@ -506,11 +492,8 @@ StartWorkerForUpdate(); return; } - - // This will start the update check after loader factory is retrieved. - context_->wrapper()->GetLoaderFactoryForUpdateCheck( - scope_, - base::BindOnce(&ServiceWorkerRegisterJob::TriggerUpdateCheckInBrowser, + TriggerUpdateCheckInBrowser( + base::BindOnce(&ServiceWorkerRegisterJob::OnUpdateCheckFinished, weak_factory_.GetWeakPtr())); return; case UpdateCheckType::kMainScriptDuringStartWorker:
diff --git a/content/browser/service_worker/service_worker_register_job.h b/content/browser/service_worker/service_worker_register_job.h index e7c84f8..f688e5d 100644 --- a/content/browser/service_worker/service_worker_register_job.h +++ b/content/browser/service_worker/service_worker_register_job.h
@@ -117,7 +117,7 @@ // Trigger the UpdateCheckType::kAllScriptsBeforeStartWorker type check if // ServiceWorkerImportedScriptUpdateCheck is enabled. void TriggerUpdateCheckInBrowser( - scoped_refptr<network::SharedURLLoaderFactory> loader_factory); + ServiceWorkerUpdateChecker::UpdateStatusCallback callback); // When ServiceWorkerImportedScriptUpdateCheck is enabled, returns // UpdateCheckType::kAllScriptsBeforeStartWorker, otherwise, returns
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 e51d6cc..4c11e41 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
@@ -8,10 +8,9 @@ #include "base/bind.h" #include "base/containers/queue.h" #include "base/run_loop.h" -#include "base/test/bind_test_util.h" #include "base/test/scoped_feature_list.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" -#include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_storage.h" #include "content/browser/service_worker/service_worker_test_utils.h" #include "content/public/test/browser_task_environment.h" @@ -118,15 +117,14 @@ network::TestURLLoaderFactory* loader_factory, base::Optional<CheckResult>* out_check_result) { helper_->SetNetworkFactory(loader_factory); - GetLoaderFactoryForUpdateCheck(scope); return std::make_unique<ServiceWorkerSingleScriptUpdateChecker>( GURL(url), url == main_script_url, GURL(main_script_url), scope, force_bypass_cache, update_via_cache, time_since_last_check, net::HttpRequestHeaders(), base::BindRepeating([](BrowserContext* context) { return context; }, browser_context_.get()), - loader_factory_for_update_check_, std::move(compare_reader), - std::move(copy_reader), std::move(writer), + helper_->context()->GetLoaderFactoryBundleForUpdateCheck(), + std::move(compare_reader), std::move(copy_reader), std::move(writer), base::BindOnce( [](base::Optional<CheckResult>* out_check_result_param, const GURL& script_url, @@ -161,25 +159,10 @@ } protected: - void GetLoaderFactoryForUpdateCheck(const GURL& scope) { - base::RunLoop loop; - helper_->context_wrapper()->GetLoaderFactoryForUpdateCheck( - scope, - base::BindLambdaForTesting( - [&](scoped_refptr<network::SharedURLLoaderFactory> loader_factory) { - DCHECK(loader_factory); - loader_factory_for_update_check_ = std::move(loader_factory); - loop.Quit(); - })); - loop.Run(); - } - BrowserTaskEnvironment task_environment_; std::unique_ptr<EmbeddedWorkerTestHelper> helper_; base::test::ScopedFeatureList feature_list_; std::unique_ptr<TestBrowserContext> browser_context_; - scoped_refptr<network::SharedURLLoaderFactory> - loader_factory_for_update_check_; private: DISALLOW_COPY_AND_ASSIGN(ServiceWorkerSingleScriptUpdateCheckerTest);
diff --git a/content/browser/service_worker/service_worker_update_checker.cc b/content/browser/service_worker/service_worker_update_checker.cc index 38f4f616..752297b0 100644 --- a/content/browser/service_worker/service_worker_update_checker.cc +++ b/content/browser/service_worker/service_worker_update_checker.cc
@@ -38,10 +38,9 @@ trace_id, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (!process_manager) { - // If no process manager is found, maybe it's being shut down. - // ServiceWorkerUpdateChecker is going to be destroyed after this task, so - // just do nothing here. + if (!process_manager || process_manager->IsShutdown()) { + // If it's being shut down, ServiceWorkerUpdateChecker is going to be + // destroyed after this task. We do nothing here. return; }
diff --git a/content/browser/site_per_process_unload_browsertest.cc b/content/browser/site_per_process_unload_browsertest.cc index 68ea471..dfe8ce2 100644 --- a/content/browser/site_per_process_unload_browsertest.cc +++ b/content/browser/site_per_process_unload_browsertest.cc
@@ -570,6 +570,9 @@ EXPECT_EQ(RenderFrameHostImpl::UnloadState::NotRun, rfh_b->unload_state_); EXPECT_EQ(RenderFrameHostImpl::UnloadState::InProgress, rfh_c->unload_state_); RenderFrameHostImpl* rfh_d = rfh_b->child_at(0)->current_frame_host(); + // Set an arbitrarily long timeout to ensure the subframe unload timer doesn't + // fire before we call OnDetach(). + rfh_d->SetSubframeUnloadTimeoutForTesting(base::TimeDelta::FromSeconds(30)); RenderFrameDeletedObserver delete_d(rfh_d); @@ -632,6 +635,9 @@ b1->GetProcess()->AddFilter(detach_filter_b.get()); a1->DisableSwapOutTimerForTesting(); + // Set an arbitrarily long timeout to ensure the subframe unload timer doesn't + // fire before we call OnDetach(). + b1->SetSubframeUnloadTimeoutForTesting(base::TimeDelta::FromSeconds(30)); // Add unload handler on A2, but not on the other frames. UnloadPrint(a2->frame_tree_node(), "A2");
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index c3deabb2..37cfd36 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc
@@ -68,6 +68,7 @@ #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "mojo/public/cpp/bindings/callback_helpers.h" +#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/base/net_errors.h" #include "net/cookies/canonical_cookie.h" @@ -723,12 +724,13 @@ // a mojo connection error occurs). class SSLClientAuthDelegate : public SSLClientAuthHandler::Delegate { public: - SSLClientAuthDelegate(network::mojom::ClientCertificateResponderPtrInfo - client_cert_responder_info, - content::ResourceContext* resource_context, - WebContents::Getter web_contents_getter, - const scoped_refptr<net::SSLCertRequestInfo>& cert_info) - : client_cert_responder_(std::move(client_cert_responder_info)), + SSLClientAuthDelegate( + mojo::PendingRemote<network::mojom::ClientCertificateResponder> + client_cert_responder_remote, + content::ResourceContext* resource_context, + WebContents::Getter web_contents_getter, + const scoped_refptr<net::SSLCertRequestInfo>& cert_info) + : client_cert_responder_(std::move(client_cert_responder_remote)), ssl_client_auth_handler_(std::make_unique<SSLClientAuthHandler>( GetContentClient()->browser()->CreateClientCertStore( resource_context), @@ -738,7 +740,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK(client_cert_responder_); ssl_client_auth_handler_->SelectCertificate(); - client_cert_responder_.set_connection_error_handler(base::BindOnce( + client_cert_responder_.set_disconnect_handler(base::BindOnce( &SSLClientAuthDelegate::DeleteSelf, base::Unretained(this))); } @@ -777,18 +779,19 @@ } private: - network::mojom::ClientCertificateResponderPtr client_cert_responder_; + mojo::Remote<network::mojom::ClientCertificateResponder> + client_cert_responder_; std::unique_ptr<SSLClientAuthHandler> ssl_client_auth_handler_; }; void CreateSSLClientAuthDelegateOnIO( - network::mojom::ClientCertificateResponderPtrInfo - client_cert_responder_info, + mojo::PendingRemote<network::mojom::ClientCertificateResponder> + client_cert_responder_remote, content::ResourceContext* resource_context, WebContents::Getter web_contents_getter, scoped_refptr<net::SSLCertRequestInfo> cert_info) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - new SSLClientAuthDelegate(std::move(client_cert_responder_info), + new SSLClientAuthDelegate(std::move(client_cert_responder_remote), resource_context, std::move(web_contents_getter), cert_info); // deletes self } @@ -798,8 +801,8 @@ uint32_t routing_id, uint32_t request_id, const scoped_refptr<net::SSLCertRequestInfo>& cert_info, - network::mojom::ClientCertificateResponderPtrInfo - client_cert_responder_info, + mojo::PendingRemote<network::mojom::ClientCertificateResponder> + client_cert_responder_remote, base::RepeatingCallback<WebContents*(void)> web_contents_getter) { if (!web_contents_getter) { web_contents_getter = @@ -807,9 +810,9 @@ } WebContents* web_contents = web_contents_getter.Run(); if (!web_contents) { - DCHECK(client_cert_responder_info); - network::mojom::ClientCertificateResponderPtr client_cert_responder( - std::move(client_cert_responder_info)); + DCHECK(client_cert_responder_remote); + mojo::Remote<network::mojom::ClientCertificateResponder> + client_cert_responder(std::move(client_cert_responder_remote)); client_cert_responder->CancelRequest(); return; } @@ -817,7 +820,7 @@ base::PostTask( FROM_HERE, {BrowserThread::IO}, base::BindOnce(&CreateSSLClientAuthDelegateOnIO, - std::move(client_cert_responder_info), + std::move(client_cert_responder_remote), web_contents->GetBrowserContext()->GetResourceContext(), std::move(web_contents_getter), cert_info)); } @@ -1636,28 +1639,27 @@ uint32_t routing_id, uint32_t request_id, const scoped_refptr<net::SSLCertRequestInfo>& cert_info, - network::mojom::ClientCertificateResponderPtr cert_responder) { + mojo::PendingRemote<network::mojom::ClientCertificateResponder> + cert_responder) { // Use |window_id| if it's provided. if (window_id) { if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) { OnCertificateRequestedContinuation( process_id, routing_id, request_id, cert_info, - cert_responder.PassInterface(), - GetWebContentsFromRegistry(*window_id)); + std::move(cert_responder), GetWebContentsFromRegistry(*window_id)); } else { base::PostTaskAndReplyWithResult( FROM_HERE, {BrowserThread::IO}, base::BindOnce(&GetWebContentsFromRegistry, *window_id), base::BindOnce(&OnCertificateRequestedContinuation, process_id, routing_id, request_id, cert_info, - cert_responder.PassInterface())); + std::move(cert_responder))); } return; } OnCertificateRequestedContinuation(process_id, routing_id, request_id, - cert_info, cert_responder.PassInterface(), - {}); + cert_info, std::move(cert_responder), {}); } void StoragePartitionImpl::OnSSLCertificateError(
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h index f8d097ac..b716567 100644 --- a/content/browser/storage_partition_impl.h +++ b/content/browser/storage_partition_impl.h
@@ -207,7 +207,8 @@ uint32_t routing_id, uint32_t request_id, const scoped_refptr<net::SSLCertRequestInfo>& cert_info, - network::mojom::ClientCertificateResponderPtr cert_responder) override; + mojo::PendingRemote<network::mojom::ClientCertificateResponder> + cert_responder) override; void OnSSLCertificateError(uint32_t process_id, uint32_t routing_id, const GURL& url,
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc index 2ddd2bd..7ba29e5 100644 --- a/content/browser/web_contents/web_contents_impl_browsertest.cc +++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -1498,8 +1498,14 @@ GenURL("d.com", "/title1.html"), true); } +// TODO(http://crbug.com/997808): Flaky on Linux ASAN. +#if defined(OS_LINUX) && defined(ADDRESS_SANITIZER) +#define MAYBE_SplitCacheDedicatedWorkers DISABLED_SplitCacheDedicatedWorkers +#else +#define MAYBE_SplitCacheDedicatedWorkers SplitCacheDedicatedWorkers +#endif IN_PROC_BROWSER_TEST_P(WebContentsSplitCacheBrowserTestEnabled, - SplitCacheDedicatedWorkers) { + MAYBE_SplitCacheDedicatedWorkers) { // Load 3p.com/script from a.com's worker. The first time it's loaded from the // network and the second it's cached. EXPECT_FALSE(TestResourceLoadFromDedicatedWorker( @@ -1590,12 +1596,6 @@ GenURL("e.com", "/worker.js"))); } -// TODO(http://crbug.com/997808): Flaky on Linux. -#if defined(OS_LINUX) -#define MAYBE_SplitCacheDedicatedWorkers DISABLED_SplitCacheDedicatedWorkers -#else -#define MAYBE_SplitCacheDedicatedWorkers SplitCacheDedicatedWorkers -#endif IN_PROC_BROWSER_TEST_F(WebContentsSplitCacheBrowserTestDisabled, MAYBE_SplitCacheDedicatedWorkers) { // Load 3p.com/script from a.com's worker. The first time it's loaded from the
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc index 5f9cbeb..08d45d6 100644 --- a/content/browser/worker_host/dedicated_worker_host.cc +++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -368,12 +368,12 @@ } void DedicatedWorkerHost::CreateNestedDedicatedWorker( - blink::mojom::DedicatedWorkerHostFactoryRequest request) { + mojo::PendingReceiver<blink::mojom::DedicatedWorkerHostFactory> receiver) { DCHECK_CURRENTLY_ON(BrowserThread::UI); CreateDedicatedWorkerHostFactory(worker_process_id_, ancestor_render_frame_id_, /*creator_render_frame_id=*/MSG_ROUTING_NONE, - origin_, std::move(request)); + origin_, std::move(receiver)); } void DedicatedWorkerHost::BindFileSystemManager(
diff --git a/content/browser/worker_host/dedicated_worker_host.h b/content/browser/worker_host/dedicated_worker_host.h index 316cade..4e56abf 100644 --- a/content/browser/worker_host/dedicated_worker_host.h +++ b/content/browser/worker_host/dedicated_worker_host.h
@@ -125,17 +125,11 @@ void CreateWebUsbService( mojo::PendingReceiver<blink::mojom::WebUsbService> receiver); - // TODO(https://crbug.com/955171): Remove these methods and use - // CreateWebSocketConnector directly once |this| uses - // service_manager::BinderMap instead of |registry_|. - void CreateWebSocketConnectorForRequest( - blink::mojom::WebSocketConnectorRequest request); - void CreateWebSocketConnector( mojo::PendingReceiver<blink::mojom::WebSocketConnector> receiver); void CreateNestedDedicatedWorker( - blink::mojom::DedicatedWorkerHostFactoryRequest request); + mojo::PendingReceiver<blink::mojom::DedicatedWorkerHostFactory> receiver); // May return a nullptr. RenderFrameHostImpl* GetAncestorRenderFrameHost();
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 0951c26..108f5ba 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -577,6 +577,9 @@ WebRuntimeFeatures::EnablePointerLockOptions( base::FeatureList::IsEnabled(features::kPointerLockOptions)); + + WebRuntimeFeatures::EnableDocumentPolicy( + base::FeatureList::IsEnabled(features::kDocumentPolicy)); } } // namespace
diff --git a/content/gpu/gpu_sandbox_hook_linux.cc b/content/gpu/gpu_sandbox_hook_linux.cc index 39bb09d..078b93b 100644 --- a/content/gpu/gpu_sandbox_hook_linux.cc +++ b/content/gpu/gpu_sandbox_hook_linux.cc
@@ -8,6 +8,7 @@ #include <errno.h> #include <memory> +#include <sstream> #include <utility> #include <vector> @@ -102,26 +103,32 @@ const service_manager::SandboxSeccompBPF::Options& options) { if (options.accelerated_video_decode_enabled) { // Device nodes for V4L2 video decode accelerator drivers. + // We do not use a FileEnumerator because the device files may not exist + // yet when the sandbox is created. But since we are restricting access + // to the video-dec* and media-dec* prefixes we know that we cannot + // authorize a non-decoder device by accident. + static constexpr size_t MAX_V4L2_DECODERS = 5; static const base::FilePath::CharType kDevicePath[] = FILE_PATH_LITERAL("/dev/"); - static const base::FilePath::CharType kVideoDecPattern[] = "video-dec[0-9]"; - base::FileEnumerator video_enumerator( - base::FilePath(kDevicePath), false, base::FileEnumerator::FILES, - base::FilePath(kVideoDecPattern).value()); - for (base::FilePath name = video_enumerator.Next(); !name.empty(); - name = video_enumerator.Next()) - permissions->push_back(BrokerFilePermission::ReadWrite(name.value())); + static const base::FilePath::CharType kVideoDecBase[] = "video-dec"; + static const base::FilePath::CharType kMediaDecBase[] = "media-dec"; + for (size_t i = 0; i < MAX_V4L2_DECODERS; i++) { + std::ostringstream decoderPath; + decoderPath << kDevicePath << kVideoDecBase << i; + permissions->push_back( + BrokerFilePermission::ReadWrite(decoderPath.str())); - // Device nodes for V4L2 media devices (for request API and camera) - static const base::FilePath::CharType kMediaDecPattern[] = "media-dec[0-9]"; - base::FileEnumerator media_enumerator( - base::FilePath(kDevicePath), false, base::FileEnumerator::FILES, - base::FilePath(kMediaDecPattern).value()); - for (base::FilePath name = media_enumerator.Next(); !name.empty(); - name = media_enumerator.Next()) - permissions->push_back(BrokerFilePermission::ReadWrite(name.value())); + std::ostringstream mediaDevicePath; + mediaDevicePath << kDevicePath << kMediaDecBase << i; + permissions->push_back( + BrokerFilePermission::ReadWrite(mediaDevicePath.str())); + } } + // Image processor used on ARM platforms. + static const char kDevImageProc0Path[] = "/dev/image-proc0"; + permissions->push_back(BrokerFilePermission::ReadWrite(kDevImageProc0Path)); + if (options.accelerated_video_encode_enabled) { // Device node for V4L2 video encode accelerator drivers. static const char kDevVideoEncPath[] = "/dev/video-enc"; @@ -141,11 +148,7 @@ // Device file needed by the ARM GPU userspace. static const char kMali0Path[] = "/dev/mali0"; - // Image processor used on ARM platforms. - static const char kDevImageProc0Path[] = "/dev/image-proc0"; - permissions->push_back(BrokerFilePermission::ReadWrite(kMali0Path)); - permissions->push_back(BrokerFilePermission::ReadWrite(kDevImageProc0Path)); // Non-privileged render nodes for format enumeration. // https://dri.freedesktop.org/docs/drm/gpu/drm-uapi.html#render-nodes
diff --git a/content/public/browser/network_context_client_base.h b/content/public/browser/network_context_client_base.h index c5e0badd..b9ab9b1 100644 --- a/content/public/browser/network_context_client_base.h +++ b/content/public/browser/network_context_client_base.h
@@ -7,6 +7,7 @@ #include "build/build_config.h" #include "content/common/content_export.h" +#include "mojo/public/cpp/bindings/pending_remote.h" #include "services/network/public/mojom/network_context.mojom.h" namespace content { @@ -38,7 +39,8 @@ uint32_t routing_id, uint32_t request_id, const scoped_refptr<net::SSLCertRequestInfo>& cert_info, - network::mojom::ClientCertificateResponderPtr cert_responder) override; + mojo::PendingRemote<network::mojom::ClientCertificateResponder> + cert_responder) override; void OnSSLCertificateError(uint32_t process_id, uint32_t routing_id, const GURL& url,
diff --git a/content/public/common/bind_interface_helpers.h b/content/public/common/bind_interface_helpers.h index 5fbd015..f4362d4 100644 --- a/content/public/common/bind_interface_helpers.h +++ b/content/public/common/bind_interface_helpers.h
@@ -27,6 +27,10 @@ auto receiver = remote->InitWithNewPipeAndPassReceiver(); host->BindInterface(Interface::Name_, receiver.PassPipe()); } +template <typename Host, typename Interface> +void BindInterface(Host* host, mojo::PendingReceiver<Interface> receiver) { + host->BindInterface(Interface::Name_, receiver.PassPipe()); +} } // namespace
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 2b09e01..2f7e0b6d 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -130,6 +130,10 @@ const base::Feature kDesktopCaptureChangeSource{ "DesktopCaptureChangeSource", base::FEATURE_ENABLED_BY_DEFAULT}; +// Enable document policy for configuring and restricting feature behavior. +const base::Feature kDocumentPolicy{"DocumentPolicy", + base::FEATURE_DISABLED_BY_DEFAULT}; + // When a screen reader is detected, allow users the option of letting // Google provide descriptions for unlabeled images. const base::Feature kExperimentalAccessibilityLabels{
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 703c2152..1d57428 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -38,6 +38,7 @@ CONTENT_EXPORT extern const base::Feature kCrashReporting; CONTENT_EXPORT extern const base::Feature kDataSaverHoldback; CONTENT_EXPORT extern const base::Feature kDesktopCaptureChangeSource; +CONTENT_EXPORT extern const base::Feature kDocumentPolicy; CONTENT_EXPORT extern const base::Feature kExperimentalAccessibilityLabels; CONTENT_EXPORT extern const base::Feature kExperimentalProductivityFeatures; CONTENT_EXPORT extern const base::Feature kExpensiveBackgroundTimerThrottling;
diff --git a/content/public/test/DEPS b/content/public/test/DEPS index 75250ec5..ad1434c 100644 --- a/content/public/test/DEPS +++ b/content/public/test/DEPS
@@ -16,6 +16,7 @@ "+ui/ozone/public", "+ui/views/test", "+v8/include/v8.h", + "+ui/platform_window/common/platform_window_defaults.h", ] # Ensure we don't leak internal content headers through public headers.
diff --git a/content/public/test/browser_task_environment.cc b/content/public/test/browser_task_environment.cc index a7aee30a..1116975 100644 --- a/content/public/test/browser_task_environment.cc +++ b/content/public/test/browser_task_environment.cc
@@ -93,7 +93,8 @@ browser_ui_thread_scheduler->GetHandle()->GetDefaultTaskRunner(); auto browser_io_thread_delegate = real_io_thread_ - ? std::make_unique<BrowserIOThreadDelegate>() + ? std::make_unique<BrowserIOThreadDelegate>( + BrowserIOThreadDelegate::BrowserTaskExecutorPresent::kYes) : BrowserIOThreadDelegate::CreateForTesting(sequence_manager()); browser_io_thread_delegate->SetAllowBlockingForTesting();
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc index ba65b011..3546123 100644 --- a/content/public/test/browser_test_base.cc +++ b/content/public/test/browser_test_base.cc
@@ -64,12 +64,15 @@ #include "services/service_manager/embedder/switches.h" #include "services/service_manager/public/cpp/connector.h" #include "services/tracing/public/cpp/trace_startup.h" -#include "ui/base/platform_window_defaults.h" #include "ui/compositor/compositor_switches.h" #include "ui/display/display_switches.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_switches.h" +#if defined(OS_LINUX) +#include "ui/platform_window/common/platform_window_defaults.h" // nogncheck +#endif + #if defined(OS_ANDROID) #include "base/android/task_scheduler/post_task_android.h" #include "components/discardable_memory/service/discardable_shared_memory_manager.h" // nogncheck @@ -173,7 +176,9 @@ enable_pixel_output_(false), use_software_compositing_(false), set_up_called_(false) { +#if defined(OS_LINUX) ui::test::EnableTestConfigForPlatformWindows(); +#endif #if defined(OS_POSIX) handle_sigterm_ = true;
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc index 6a93806..0137955 100644 --- a/content/public/test/render_view_test.cc +++ b/content/public/test/render_view_test.cc
@@ -39,6 +39,7 @@ #include "content/test/mock_render_process.h" #include "content/test/test_content_client.h" #include "content/test/test_render_frame.h" +#include "mojo/public/cpp/bindings/remote.h" #include "net/base/escape.h" #include "services/service_manager/public/cpp/connector.h" #include "third_party/blink/public/common/dom_storage/session_storage_namespace_id.h" @@ -463,8 +464,8 @@ // Run the loop so the release task from the renderwidget executes. base::RunLoop().RunUntilIdle(); - blink::mojom::LeakDetectorPtr leak_detector; - BindInterface(&binder_registry_, &leak_detector); + mojo::Remote<blink::mojom::LeakDetector> leak_detector; + BindInterface(&binder_registry_, leak_detector.BindNewPipeAndPassReceiver()); // Close the main |view_| as well as any other windows that might have been // opened by the test.
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 88a1726..a0003b12 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -760,9 +760,8 @@ audio_output_ipc_factory_.emplace(GetIOTaskRunner()); - registry->AddInterface( - base::BindRepeating(&SharedWorkerFactoryImpl::CreateForRequest), - base::ThreadTaskRunnerHandle::Get()); + registry->AddInterface(base::BindRepeating(&SharedWorkerFactoryImpl::Create), + base::ThreadTaskRunnerHandle::Get()); registry->AddInterface(base::BindRepeating(CreateResourceUsageReporter, weak_factory_.GetWeakPtr()), base::ThreadTaskRunnerHandle::Get());
diff --git a/content/renderer/render_thread_impl_discardable_memory_browsertest.cc b/content/renderer/render_thread_impl_discardable_memory_browsertest.cc index 1c6aa4ec..179c98fd 100644 --- a/content/renderer/render_thread_impl_discardable_memory_browsertest.cc +++ b/content/renderer/render_thread_impl_discardable_memory_browsertest.cc
@@ -135,8 +135,9 @@ EXPECT_LT(base::TimeTicks::Now(), end); } +// TODO(crbug.com/974850): Flaky on all platforms. IN_PROC_BROWSER_TEST_F(RenderThreadImplDiscardableMemoryBrowserTest, - ReleaseFreeMemory) { + DISABLED_ReleaseFreeMemory) { const size_t kSize = 1024 * 1024; // 1MiB. std::unique_ptr<base::DiscardableMemory> memory =
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc index 539ced1..6a81c4a 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -67,8 +67,6 @@ #include "media/video/gpu_video_accelerator_factories.h" #include "media/webrtc/webrtc_switches.h" #include "mojo/public/cpp/base/big_buffer.h" -#include "mojo/public/cpp/bindings/strong_associated_binding.h" -#include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/cpp/system/platform_handle.h" #include "ppapi/buildflags/buildflags.h" #include "services/network/public/cpp/features.h" @@ -218,7 +216,7 @@ main_thread_scheduler_->SetTopLevelBlameContext(&top_level_blame_context_); GetBrowserInterfaceBrokerProxy()->GetInterface( - mojo::MakeRequest(&code_cache_host_info_)); + code_cache_host_remote_.InitWithNewPipeAndPassReceiver()); } RendererBlinkPlatformImpl::~RendererBlinkPlatformImpl() { @@ -963,12 +961,12 @@ blink::mojom::CodeCacheHost& RendererBlinkPlatformImpl::GetCodeCacheHost() { if (!code_cache_host_) { - code_cache_host_ = blink::mojom::ThreadSafeCodeCacheHostPtr::Create( - std::move(code_cache_host_info_), + code_cache_host_ = mojo::SharedRemote<blink::mojom::CodeCacheHost>( + std::move(code_cache_host_remote_), base::CreateSequencedTaskRunner( {base::ThreadPool(), base::WithBaseSyncPrimitives()})); } - return **code_cache_host_; + return *code_cache_host_; } } // namespace content
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h index 282174c..0db3cf9 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h
@@ -21,6 +21,8 @@ #include "content/child/blink_platform_impl.h" #include "content/common/content_export.h" #include "content/renderer/top_level_blame_context.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/shared_remote.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/blink/public/common/screen_orientation/web_screen_orientation_type.h" @@ -244,8 +246,8 @@ TopLevelBlameContext top_level_blame_context_; - blink::mojom::CodeCacheHostPtrInfo code_cache_host_info_; - scoped_refptr<blink::mojom::ThreadSafeCodeCacheHostPtr> code_cache_host_; + mojo::PendingRemote<blink::mojom::CodeCacheHost> code_cache_host_remote_; + mojo::SharedRemote<blink::mojom::CodeCacheHost> code_cache_host_; std::unique_ptr<blink::WebTransmissionEncodingInfoHandler> web_transmission_encoding_info_handler_;
diff --git a/content/renderer/worker/shared_worker_factory_impl.cc b/content/renderer/worker/shared_worker_factory_impl.cc index 4d9a0ae..f499dd9 100644 --- a/content/renderer/worker/shared_worker_factory_impl.cc +++ b/content/renderer/worker/shared_worker_factory_impl.cc
@@ -11,13 +11,6 @@ #include "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom.h" namespace content { -// static -void SharedWorkerFactoryImpl::CreateForRequest( - blink::mojom::SharedWorkerFactoryRequest request) { - // Implicit conversion to - // mojo::PendingReceiver<blink::mojom::SharedWorkerFactory>. - Create(std::move(request)); -} // static void SharedWorkerFactoryImpl::Create(
diff --git a/content/renderer/worker/shared_worker_factory_impl.h b/content/renderer/worker/shared_worker_factory_impl.h index cb70d83..3215a17 100644 --- a/content/renderer/worker/shared_worker_factory_impl.h +++ b/content/renderer/worker/shared_worker_factory_impl.h
@@ -19,12 +19,6 @@ class SharedWorkerFactoryImpl : public blink::mojom::SharedWorkerFactory { public: - // TODO(https://crbug.com/955171): Remove this method and use Create once - // RendererInterfaceBinders uses service_manager::BinderMap instead of - // service_manager::BinderRegistry. - static void CreateForRequest( - blink::mojom::SharedWorkerFactoryRequest request); - static void Create( mojo::PendingReceiver<blink::mojom::SharedWorkerFactory> receiver);
diff --git a/content/shell/browser/web_test/leak_detector.cc b/content/shell/browser/web_test/leak_detector.cc index 3bfeec8a..085f931 100644 --- a/content/shell/browser/web_test/leak_detector.cc +++ b/content/shell/browser/web_test/leak_detector.cc
@@ -67,8 +67,8 @@ ReportCallback callback) { callback_ = std::move(callback); - BindInterface(process, &leak_detector_); - leak_detector_.set_connection_error_handler(base::BindOnce( + BindInterface(process, leak_detector_.BindNewPipeAndPassReceiver()); + leak_detector_.set_disconnect_handler(base::BindOnce( &LeakDetector::OnLeakDetectorIsGone, base::Unretained(this))); leak_detector_->PerformLeakDetection(base::BindOnce( &LeakDetector::OnLeakDetectionComplete, weak_factory_.GetWeakPtr()));
diff --git a/content/shell/browser/web_test/leak_detector.h b/content/shell/browser/web_test/leak_detector.h index ad7901ff..dc6b02a 100644 --- a/content/shell/browser/web_test/leak_detector.h +++ b/content/shell/browser/web_test/leak_detector.h
@@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/public/mojom/leak_detector/leak_detector.mojom.h" namespace content { @@ -38,7 +39,7 @@ void OnLeakDetectionComplete(blink::mojom::LeakDetectionResultPtr result); void OnLeakDetectorIsGone(); - blink::mojom::LeakDetectorPtr leak_detector_; + mojo::Remote<blink::mojom::LeakDetector> leak_detector_; blink::mojom::LeakDetectionResultPtr previous_result_; ReportCallback callback_; base::WeakPtrFactory<LeakDetector> weak_factory_{this};
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index fb449d8..2b8672f6 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -583,6 +583,10 @@ "//ui/accelerated_widget_mac", ] } + + if (is_linux) { + deps += [ "//ui/platform_window/common" ] + } } # browsertest_support can be used by targets that run content_shell based
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt index b585a332..4a97e98 100644 --- a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -24,6 +24,10 @@ crbug.com/497411 [ mountainlion debug ] ContextLost_WebGLContextLostFromSelectElement [ Skip ] crbug.com/498149 [ lion debug ] ContextLost_WebGLContextLostFromSelectElement [ Skip ] +# Flaky on Mac +crbug.com/999327 [ mac ] ContextLost_WebGLBlockedAfterJSNavigation [ Skip ] +crbug.com/999327 [ mac ] ContextLost_WebGLContextLostFromGPUProcessExit [ Skip ] + # Too difficult to make this test work on Mac and Android for now. Disabling # GLES3 support at the GL bindings level doesn't work there yet. crbug.com/923134 [ mac ] ContextLost_WebGL2Blocked [ Skip ]
diff --git a/device/vr/public/mojom/vr_service.mojom b/device/vr/public/mojom/vr_service.mojom index a8bbb47..f12fd04 100644 --- a/device/vr/public/mojom/vr_service.mojom +++ b/device/vr/public/mojom/vr_service.mojom
@@ -426,7 +426,7 @@ // WebVR 1.1 functionality compatibility method. To stop listening pass a null // client. - SetListeningForActivate(VRDisplayClient? client); + SetListeningForActivate(pending_remote<VRDisplayClient>? client); // Request to initialize a session in the browser process. If successful, the // XRSession struct with the requisite interfaces will be returned.
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc index b692888..f9e1b62 100644 --- a/extensions/browser/api/web_request/web_request_api.cc +++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -712,9 +712,10 @@ browser_context_)); WebRequestProxyingURLLoaderFactory::StartProxying( browser_context, is_navigation ? -1 : render_process_id, - request_id_generator_, std::move(navigation_ui_data), - std::move(proxied_receiver), std::move(target_factory_info), - std::move(header_client_receiver), proxies_.get(), type); + type == URLLoaderFactoryType::kDownload, request_id_generator_, + std::move(navigation_ui_data), std::move(proxied_receiver), + std::move(target_factory_info), std::move(header_client_receiver), + proxies_.get()); return true; }
diff --git a/extensions/browser/api/web_request/web_request_info.cc b/extensions/browser/api/web_request/web_request_info.cc index 3e84b22..a330972 100644 --- a/extensions/browser/api/web_request/web_request_info.cc +++ b/extensions/browser/api/web_request/web_request_info.cc
@@ -161,8 +161,7 @@ int32_t routing_id, const network::ResourceRequest& request, bool is_download, - bool is_async, - bool is_service_worker_script) + bool is_async) : id(request_id), url(request.url), site_for_cookies(request.site_for_cookies), @@ -174,8 +173,7 @@ initiator(request.request_initiator), type(static_cast<content::ResourceType>(request.resource_type)), is_async(is_async), - extra_request_headers(request.headers), - is_service_worker_script(is_service_worker_script) { + extra_request_headers(request.headers) { if (url.SchemeIsWSOrWSS()) web_request_type = WebRequestResourceType::WEB_SOCKET; else if (is_download) @@ -238,8 +236,7 @@ is_web_view(params.is_web_view), web_view_instance_id(params.web_view_instance_id), web_view_rules_registry_id(params.web_view_rules_registry_id), - web_view_embedder_process_id(params.web_view_embedder_process_id), - is_service_worker_script(params.is_service_worker_script) {} + web_view_embedder_process_id(params.web_view_embedder_process_id) {} WebRequestInfo::~WebRequestInfo() = default;
diff --git a/extensions/browser/api/web_request/web_request_info.h b/extensions/browser/api/web_request/web_request_info.h index ac265b0..bbe9337 100644 --- a/extensions/browser/api/web_request/web_request_info.h +++ b/extensions/browser/api/web_request/web_request_info.h
@@ -49,8 +49,7 @@ int32_t routing_id, const network::ResourceRequest& request, bool is_download, - bool is_async, - bool is_service_worker_script); + bool is_async); ~WebRequestInfoInitParams(); @@ -73,7 +72,6 @@ int web_view_rules_registry_id = -1; int web_view_embedder_process_id = -1; ExtensionApiFrameIdMap::FrameData frame_data; - bool is_service_worker_script = false; private: void InitializeWebViewAndFrameData( @@ -171,8 +169,6 @@ mutable base::Optional<declarative_net_request::RulesetManager::Action> dnr_action; - const bool is_service_worker_script; - private: DISALLOW_COPY_AND_ASSIGN(WebRequestInfo); };
diff --git a/extensions/browser/api/web_request/web_request_info_unittest.cc b/extensions/browser/api/web_request/web_request_info_unittest.cc index 1cafa25..74640e6 100644 --- a/extensions/browser/api/web_request/web_request_info_unittest.cc +++ b/extensions/browser/api/web_request/web_request_info_unittest.cc
@@ -28,8 +28,8 @@ request.request_body->AppendFileRange(base::FilePath(kFilePath), 0, std::numeric_limits<uint64_t>::max(), base::Time()); - WebRequestInfo info(WebRequestInfoInitParams(0, 0, 0, nullptr, 0, request, - false, false, false)); + WebRequestInfo info( + WebRequestInfoInitParams(0, 0, 0, nullptr, 0, request, false, false)); ASSERT_TRUE(info.request_body_data); auto* value = info.request_body_data->FindKey( extension_web_request_api_constants::kRequestBodyRawKey);
diff --git a/extensions/browser/api/web_request/web_request_permissions.cc b/extensions/browser/api/web_request/web_request_permissions.cc index e6754765..8eb46c35 100644 --- a/extensions/browser/api/web_request/web_request_permissions.cc +++ b/extensions/browser/api/web_request/web_request_permissions.cc
@@ -246,14 +246,6 @@ bool is_request_from_browser = request.render_process_id == -1; if (is_request_from_browser) { - // Browser initiated service worker script requests (e.g., for update check) - // are not hidden. - if (request.is_service_worker_script) { - DCHECK(request.type == content::ResourceType::kServiceWorker || - request.type == content::ResourceType::kScript); - return false; - } - // Hide all non-navigation requests made by the browser. crbug.com/884932. if (!request.is_navigation_request) return true;
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 6290a9b..77e8042 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
@@ -68,12 +68,14 @@ int32_t routing_id, uint32_t options, const network::ResourceRequest& request, + bool is_download, const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, network::mojom::URLLoaderRequest loader_request, network::mojom::URLLoaderClientPtr client) : factory_(factory), request_(request), original_initiator_(request.request_initiator), + is_download_(is_download), request_id_(request_id), network_service_request_id_(network_service_request_id), routing_id_(routing_id), @@ -128,9 +130,8 @@ request_id_, factory_->render_process_id_, request_.render_frame_id, factory_->navigation_ui_data_ ? factory_->navigation_ui_data_->DeepCopy() : nullptr, - routing_id_, request_for_info, factory_->IsForDownload(), - !(options_ & network::mojom::kURLLoadOptionSynchronous), - factory_->IsForServiceWorkerScript())); + routing_id_, request_for_info, is_download_, + !(options_ & network::mojom::kURLLoadOptionSynchronous))); current_request_uses_header_client_ = factory_->url_loader_header_client_receiver_.is_bound() && @@ -355,16 +356,6 @@ auth_info, std::move(callback))); } -bool WebRequestProxyingURLLoaderFactory::IsForServiceWorkerScript() const { - return loader_factory_type_ == content::ContentBrowserClient:: - URLLoaderFactoryType::kServiceWorkerScript; -} - -bool WebRequestProxyingURLLoaderFactory::IsForDownload() const { - return loader_factory_type_ == - content::ContentBrowserClient::URLLoaderFactoryType::kDownload; -} - void WebRequestProxyingURLLoaderFactory::InProgressRequest::OnLoaderCreated( mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) { header_client_receiver_.Bind(std::move(receiver)); @@ -848,20 +839,20 @@ WebRequestProxyingURLLoaderFactory::WebRequestProxyingURLLoaderFactory( content::BrowserContext* browser_context, int render_process_id, + bool is_download, scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator, std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data, network::mojom::URLLoaderFactoryRequest loader_request, network::mojom::URLLoaderFactoryPtrInfo target_factory_info, mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient> header_client_receiver, - WebRequestAPI::ProxySet* proxies, - content::ContentBrowserClient::URLLoaderFactoryType loader_factory_type) + WebRequestAPI::ProxySet* proxies) : browser_context_(browser_context), render_process_id_(render_process_id), + is_download_(is_download), request_id_generator_(std::move(request_id_generator)), navigation_ui_data_(std::move(navigation_ui_data)), - proxies_(proxies), - loader_factory_type_(loader_factory_type) { + proxies_(proxies) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); // base::Unretained is safe here because the callback will be canceled when // |shutdown_notifier_| is destroyed, and |proxies_| owns this. @@ -887,21 +878,21 @@ void WebRequestProxyingURLLoaderFactory::StartProxying( content::BrowserContext* browser_context, int render_process_id, + bool is_download, scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator, std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data, network::mojom::URLLoaderFactoryRequest loader_request, network::mojom::URLLoaderFactoryPtrInfo target_factory_info, mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient> header_client_receiver, - WebRequestAPI::ProxySet* proxies, - content::ContentBrowserClient::URLLoaderFactoryType loader_factory_type) { + WebRequestAPI::ProxySet* proxies) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); auto proxy = std::make_unique<WebRequestProxyingURLLoaderFactory>( - browser_context, render_process_id, std::move(request_id_generator), - std::move(navigation_ui_data), std::move(loader_request), - std::move(target_factory_info), std::move(header_client_receiver), - proxies, loader_factory_type); + browser_context, render_process_id, is_download, + std::move(request_id_generator), std::move(navigation_ui_data), + std::move(loader_request), std::move(target_factory_info), + std::move(header_client_receiver), proxies); proxies->AddProxy(std::move(proxy)); } @@ -916,10 +907,8 @@ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - // Make sure we are not proxying a browser initiated non-navigation request - // except for loading service worker scripts. - DCHECK(render_process_id_ != -1 || navigation_ui_data_ || - IsForServiceWorkerScript()); + // Make sure we are not proxying a browser initiated non-navigation request. + DCHECK(render_process_id_ != -1 || navigation_ui_data_); // The request ID doesn't really matter. It just needs to be unique // per-BrowserContext so extensions can make sense of it. Note that @@ -938,10 +927,10 @@ } auto result = requests_.emplace( - web_request_id, - std::make_unique<InProgressRequest>( - this, web_request_id, request_id, routing_id, options, request, - traffic_annotation, std::move(loader_request), std::move(client))); + web_request_id, std::make_unique<InProgressRequest>( + this, web_request_id, request_id, routing_id, options, + request, is_download_, traffic_annotation, + std::move(loader_request), std::move(client))); result.first->second->Restart(); }
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h index c4f34864..7452fc01 100644 --- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h +++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -15,7 +15,6 @@ #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "components/keyed_service/core/keyed_service_shutdown_notifier.h" -#include "content/public/browser/content_browser_client.h" #include "extensions/browser/api/web_request/web_request_api.h" #include "extensions/browser/api/web_request/web_request_info.h" #include "mojo/public/cpp/bindings/binding_set.h" @@ -50,6 +49,7 @@ int32_t network_service_request_id, uint32_t options, const network::ResourceRequest& request, + bool is_download, const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, network::mojom::URLLoaderRequest loader_request, network::mojom::URLLoaderClientPtr client); @@ -122,6 +122,7 @@ WebRequestProxyingURLLoaderFactory* const factory_; network::ResourceRequest request_; const base::Optional<url::Origin> original_initiator_; + const bool is_download_; const uint64_t request_id_; const int32_t network_service_request_id_; const int32_t routing_id_; @@ -186,28 +187,28 @@ WebRequestProxyingURLLoaderFactory( content::BrowserContext* browser_context, int render_process_id, + bool is_download, scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator, std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data, network::mojom::URLLoaderFactoryRequest loader_request, network::mojom::URLLoaderFactoryPtrInfo target_factory_info, mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient> header_client_receiver, - WebRequestAPI::ProxySet* proxies, - content::ContentBrowserClient::URLLoaderFactoryType loader_factory_type); + WebRequestAPI::ProxySet* proxies); ~WebRequestProxyingURLLoaderFactory() override; static void StartProxying( content::BrowserContext* browser_context, int render_process_id, + bool is_download, scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator, std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data, network::mojom::URLLoaderFactoryRequest loader_request, network::mojom::URLLoaderFactoryPtrInfo target_factory_info, mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient> header_client_receiver, - WebRequestAPI::ProxySet* proxies, - content::ContentBrowserClient::URLLoaderFactoryType loader_factory_type); + WebRequestAPI::ProxySet* proxies); // network::mojom::URLLoaderFactory: void CreateLoaderAndStart(network::mojom::URLLoaderRequest loader_request, @@ -233,14 +234,6 @@ int32_t request_id, WebRequestAPI::AuthRequestCallback callback) override; - content::ContentBrowserClient::URLLoaderFactoryType loader_factory_type() - const { - return loader_factory_type_; - } - - bool IsForServiceWorkerScript() const; - bool IsForDownload() const; - private: void OnTargetFactoryError(); void OnProxyBindingError(); @@ -249,6 +242,7 @@ content::BrowserContext* const browser_context_; const int render_process_id_; + const bool is_download_; scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator_; std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data_; mojo::BindingSet<network::mojom::URLLoaderFactory> proxy_bindings_; @@ -258,9 +252,6 @@ // Owns |this|. WebRequestAPI::ProxySet* const proxies_; - const content::ContentBrowserClient::URLLoaderFactoryType - loader_factory_type_; - // Mapping from our own internally generated request ID to an // InProgressRequest instance. std::map<uint64_t, std::unique_ptr<InProgressRequest>> requests_;
diff --git a/extensions/browser/api/web_request/web_request_proxying_websocket.cc b/extensions/browser/api/web_request/web_request_proxying_websocket.cc index 7df1fa30..585fa267 100644 --- a/extensions/browser/api/web_request/web_request_proxying_websocket.cc +++ b/extensions/browser/api/web_request/web_request_proxying_websocket.cc
@@ -65,9 +65,8 @@ nullptr, MSG_ROUTING_NONE, request, - /*is_download=*/false, - /*is_async=*/true, - /*is_service_worker_script=*/false)), + false /* is_download */, + true /* is_async */)), proxies_(proxies) { // base::Unretained is safe here because the callback will be canceled when // |shutdown_notifier_| is destroyed, and |proxies_| owns this.
diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h index 0403f0a..359ebe6 100644 --- a/extensions/browser/extension_event_histogram_value.h +++ b/extensions/browser/extension_event_histogram_value.h
@@ -460,6 +460,7 @@ ACTION_ON_CLICKED = 438, ACCESSIBILITY_PRIVATE_ON_SWITCH_ACCESS_COMMAND = 439, ACCESSIBILITY_PRIVATE_FIND_SCROLLABLE_BOUNDS_FOR_POINT = 440, + LOGIN_STATE_ON_SESSION_STATE_CHANGED = 441, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index 411decaf6..77c76fc 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1439,6 +1439,8 @@ AUTOTESTPRIVATE_GETALLINSTALLEDAPPS = 1376, AUTOTESTPRIVATE_SWAPWINDOWSINSPLITVIEW = 1377, AUTOTESTPRIVATE_SETARCAPPWINDOWFOCUS = 1378, + LOGINSTATE_GETPROFILETYPE = 1379, + LOGINSTATE_GETSESSIONSTATE = 1380, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json index 52a07ef..db11de1 100644 --- a/extensions/common/api/_api_features.json +++ b/extensions/common/api/_api_features.json
@@ -217,7 +217,8 @@ }, "fileSystem": { "dependencies": ["permission:fileSystem"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "guestViewInternal": [ { @@ -271,7 +272,6 @@ "management": [{ "dependencies": ["permission:management"], "contexts": ["blessed_extension"], - "disallow_for_service_workers": false, "default_parent": true }, { "channel": "stable", @@ -425,12 +425,14 @@ }, "printerProvider": { "dependencies": ["permission:printerProvider"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "printerProviderInternal": { "internal": true, "dependencies": ["permission:printerProvider"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, "runtime": { "channel": "stable", @@ -443,8 +445,10 @@ "contexts": [ "blessed_extension", "lock_screen_extension" - ], - "disallow_for_service_workers": false + ] + }, + "runtime.getBackgroundPage": { + "disallow_for_service_workers": true }, "runtime.getManifest": { "contexts": [ @@ -464,13 +468,11 @@ "unblessed_extension", "web_page" ], - "disallow_for_service_workers": false, "matches": ["<all_urls>"] }, "runtime.connectNative": { "dependencies": ["permission:nativeMessaging"], - "contexts": ["blessed_extension"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension"] }, "runtime.getURL": { "contexts": [ @@ -478,8 +480,7 @@ "lock_screen_extension", "unblessed_extension", "content_script" - ], - "disallow_for_service_workers": false + ] }, "runtime.id": { "contexts": [ @@ -487,8 +488,7 @@ "lock_screen_extension", "unblessed_extension", "content_script" - ], - "disallow_for_service_workers": false + ] }, "runtime.lastError": { "contexts": "all", @@ -501,8 +501,7 @@ "lock_screen_extension", "unblessed_extension", "content_script" - ], - "disallow_for_service_workers": false + ] }, "runtime.onConnectNative": { "dependencies": ["permission:nativeMessaging"], @@ -514,8 +513,7 @@ "lock_screen_extension", "unblessed_extension", "content_script" - ], - "disallow_for_service_workers": false + ] }, "runtime.sendMessage": { // Everything except WebUI. @@ -527,13 +525,11 @@ "unblessed_extension", "web_page" ], - "disallow_for_service_workers": false, "matches": ["<all_urls>"] }, "runtime.sendNativeMessage": { "dependencies": ["permission:nativeMessaging"], - "contexts": ["blessed_extension"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension"] }, "serial": { "dependencies": ["permission:serial"], @@ -557,8 +553,7 @@ }, "storage": { "dependencies": ["permission:storage"], - "contexts": ["blessed_extension", "unblessed_extension", "content_script"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension", "unblessed_extension", "content_script"] }, "system.cpu": { "dependencies": ["permission:system.cpu"], @@ -566,7 +561,8 @@ }, "system.display": [{ "dependencies": ["permission:system.display"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "disallow_for_service_workers": true }, { "channel": "stable", "contexts": ["webui"], @@ -607,8 +603,7 @@ "content_script", "lock_screen_extension", "unblessed_extension" - ], - "disallow_for_service_workers": false + ] }, { "channel": "stable", "contexts": ["webui"], @@ -637,14 +632,12 @@ }, "webRequest": { "dependencies": ["permission:webRequest"], - "contexts": ["blessed_extension"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension"] }, "webRequestInternal": [{ "internal": true, "channel": "stable", - "contexts": ["blessed_extension"], - "disallow_for_service_workers": false + "contexts": ["blessed_extension"] }, { // webview uses webRequestInternal API. "channel": "stable",
diff --git a/extensions/common/features/manifest_feature.cc b/extensions/common/features/manifest_feature.cc index f5127d6..4d36d52 100644 --- a/extensions/common/features/manifest_feature.cc +++ b/extensions/common/features/manifest_feature.cc
@@ -9,9 +9,6 @@ namespace extensions { ManifestFeature::ManifestFeature() { - // TODO(crbug.com/979790): This will default to false once the transition - // to blocklisting unsupported APIs is complete. - set_disallow_for_service_workers(false); } ManifestFeature::~ManifestFeature() {
diff --git a/extensions/common/features/permission_feature.cc b/extensions/common/features/permission_feature.cc index 5480830c..fe63041 100644 --- a/extensions/common/features/permission_feature.cc +++ b/extensions/common/features/permission_feature.cc
@@ -10,9 +10,6 @@ namespace extensions { PermissionFeature::PermissionFeature() { - // TODO(crbug.com/979790): This will default to false once the transition - // to blocklisting unsupported APIs is complete. - set_disallow_for_service_workers(false); } PermissionFeature::~PermissionFeature() {
diff --git a/extensions/common/features/simple_feature.cc b/extensions/common/features/simple_feature.cc index e911f5b..7698e2b 100644 --- a/extensions/common/features/simple_feature.cc +++ b/extensions/common/features/simple_feature.cc
@@ -207,9 +207,7 @@ SimpleFeature::SimpleFeature() : component_extensions_auto_granted_(true), is_internal_(false), - // TODO(crbug.com/979790): This will default to false once the transition - // to blocklisting unsupported APIs is complete. - disallow_for_service_workers_(true) {} + disallow_for_service_workers_(false) {} SimpleFeature::~SimpleFeature() {}
diff --git a/extensions/common/features/simple_feature_unittest.cc b/extensions/common/features/simple_feature_unittest.cc index ece7b0db..148dcd5 100644 --- a/extensions/common/features/simple_feature_unittest.cc +++ b/extensions/common/features/simple_feature_unittest.cc
@@ -1006,11 +1006,8 @@ ASSERT_TRUE(extension.get()); EXPECT_TRUE(BackgroundInfo::IsServiceWorkerBased(extension.get())); - // Expect the feature is not allowed, since the initial state is disallowed. - // TODO(crbug.com/979790): This will default to allowed once the transition - // to blocklisting unsupported APIs is complete. This will require swapping - // these two EXPECTs. - EXPECT_EQ(Feature::INVALID_CONTEXT, + // Expect the feature is allowed, since the default is to allow. + EXPECT_EQ(Feature::IS_AVAILABLE, feature .IsAvailableToContext( extension.get(), Feature::BLESSED_EXTENSION_CONTEXT, @@ -1029,9 +1026,9 @@ Feature::CHROMEOS_PLATFORM) .result()); - // Enable the feature for service workers. - feature.set_disallow_for_service_workers(false); - EXPECT_EQ(Feature::IS_AVAILABLE, + // Disable the feature for service workers. The feature should be disallowed. + feature.set_disallow_for_service_workers(true); + EXPECT_EQ(Feature::INVALID_CONTEXT, feature .IsAvailableToContext( extension.get(), Feature::BLESSED_EXTENSION_CONTEXT,
diff --git a/extensions/common/permissions/api_permission.h b/extensions/common/permissions/api_permission.h index 08be0b1..f3ddb903 100644 --- a/extensions/common/permissions/api_permission.h +++ b/extensions/common/permissions/api_permission.h
@@ -263,6 +263,7 @@ kTransientBackground = 219, kLogin = 220, kLoginScreenStorage = 221, + kLoginState = 222, // Last entry: Add new entries above and ensure to update the // "ExtensionPermission3" enum in tools/metrics/histograms/enums.xml // (by running update_extension_permission.py).
diff --git a/extensions/common/permissions/extensions_api_permissions.cc b/extensions/common/permissions/extensions_api_permissions.cc index fbcb281b..000d8653 100644 --- a/extensions/common/permissions/extensions_api_permissions.cc +++ b/extensions/common/permissions/extensions_api_permissions.cc
@@ -79,6 +79,7 @@ {APIPermission::kLogin, "login"}, {APIPermission::kLoginScreenStorage, "loginScreenStorage"}, {APIPermission::kLoginScreenUi, "loginScreenUi"}, + {APIPermission::kLoginState, "loginState"}, {APIPermission::kMediaPerceptionPrivate, "mediaPerceptionPrivate"}, {APIPermission::kMetricsPrivate, "metricsPrivate", APIPermissionInfo::kFlagCannotBeOptional},
diff --git a/gpu/ipc/common/android/scoped_surface_request_conduit.h b/gpu/ipc/common/android/scoped_surface_request_conduit.h index 994cd55..3cdea88d 100644 --- a/gpu/ipc/common/android/scoped_surface_request_conduit.h +++ b/gpu/ipc/common/android/scoped_surface_request_conduit.h
@@ -6,13 +6,13 @@ #define GPU_IPC_COMMON_ANDROID_SCOPED_SURFACE_REQUEST_CONDUIT_H_ #include "gpu/gpu_export.h" -#include "gpu/ipc/common/android/texture_owner.h" namespace base { class UnguessableToken; } namespace gpu { +class TextureOwner; // Allows the forwarding of TextureOwners from the GPU or the browser process // to fulfill requests registered by the ScopedSurfaceRequestManager.
diff --git a/gpu/vulkan/demo/vulkan_demo.cc b/gpu/vulkan/demo/vulkan_demo.cc index 12bd91e..2e2bc6b 100644 --- a/gpu/vulkan/demo/vulkan_demo.cc +++ b/gpu/vulkan/demo/vulkan_demo.cc
@@ -19,6 +19,7 @@ #include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/GrContext.h" #include "ui/events/platform/platform_event_source.h" +#include "ui/platform_window/platform_window_init_properties.h" #include "ui/platform_window/x11/x11_window.h" namespace gpu { @@ -41,13 +42,17 @@ event_source_ = ui::PlatformEventSource::CreateDefault(); - gfx::Size size(800, 600); - window_ = std::make_unique<ui::X11Window>( - this, gfx::Rect(gfx::Point(100, 100), size)); + ui::PlatformWindowInitProperties properties; + properties.bounds = gfx::Rect(100, 100, 800, 600); + auto x11_window = std::make_unique<ui::X11Window>(this, nullptr); + x11_window->Initialize(std::move(properties)); + + window_ = std::move(x11_window); window_->Show(); // Sync up size between |window_| and |vulkan_surface_| - vulkan_surface_->Reshape(size, gfx::OVERLAY_TRANSFORM_NONE); + vulkan_surface_->Reshape(window_->GetBounds().size(), + gfx::OVERLAY_TRANSFORM_NONE); sk_surfaces_.resize(vulkan_surface_->swap_chain()->num_images()); }
diff --git a/headless/lib/browser/headless_browser_impl_aura.cc b/headless/lib/browser/headless_browser_impl_aura.cc index 8425f90..4cee8645 100644 --- a/headless/lib/browser/headless_browser_impl_aura.cc +++ b/headless/lib/browser/headless_browser_impl_aura.cc
@@ -39,8 +39,7 @@ void HeadlessBrowserImpl::PlatformInitializeWebContents( HeadlessWebContentsImpl* web_contents) { auto window_tree_host = std::make_unique<HeadlessWindowTreeHost>( - gfx::Rect(), - web_contents->begin_frame_control_enabled() ? web_contents : nullptr); + web_contents->begin_frame_control_enabled()); window_tree_host->InitHost(); gfx::NativeWindow parent_window = window_tree_host->window(); parent_window->Show();
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc index 998cf6ce..5a69748 100644 --- a/headless/lib/browser/headless_web_contents_impl.cc +++ b/headless/lib/browser/headless_web_contents_impl.cc
@@ -202,26 +202,45 @@ DISALLOW_COPY_AND_ASSIGN(Delegate); }; -struct HeadlessWebContentsImpl::PendingFrame { - public: - PendingFrame() = default; - ~PendingFrame() = default; +namespace { +constexpr uint64_t kBeginFrameSourceId = viz::BeginFrameArgs::kManualSourceId; +} - bool MaybeRunCallback() { - if (wait_for_copy_result || !display_did_finish_frame) - return false; - std::move(callback).Run(has_damage, std::move(bitmap)); - return true; +class HeadlessWebContentsImpl::PendingFrame + : public base::RefCounted<HeadlessWebContentsImpl::PendingFrame>, + public base::SupportsWeakPtr<HeadlessWebContentsImpl::PendingFrame> { + public: + PendingFrame(uint64_t sequence_number, FrameFinishedCallback callback) + : sequence_number_(sequence_number), callback_(std::move(callback)) {} + + void OnFrameComplete(const viz::BeginFrameAck& ack) { + DCHECK_EQ(kBeginFrameSourceId, ack.source_id); + DCHECK_EQ(sequence_number_, ack.sequence_number); + has_damage_ = ack.has_damage; } - uint64_t sequence_number = 0; - bool wait_for_copy_result = false; - bool display_did_finish_frame = false; - bool has_damage = false; - std::unique_ptr<SkBitmap> bitmap; - FrameFinishedCallback callback; + void OnReadbackComplete(const SkBitmap& bitmap) { + TRACE_EVENT2( + "headless", "HeadlessWebContentsImpl::PendingFrame::OnReadbackComplete", + "sequence_number", sequence_number_, "success", !bitmap.drawsNothing()); + if (bitmap.drawsNothing()) { + LOG(WARNING) << "Readback from surface failed."; + return; + } + bitmap_ = std::make_unique<SkBitmap>(bitmap); + } private: + friend class base::RefCounted<PendingFrame>; + + ~PendingFrame() { std::move(callback_).Run(has_damage_, std::move(bitmap_)); } + + const uint64_t sequence_number_; + + FrameFinishedCallback callback_; + bool has_damage_ = false; + std::unique_ptr<SkBitmap> bitmap_; + DISALLOW_COPY_AND_ASSIGN(PendingFrame); }; @@ -261,8 +280,9 @@ // There may already be frames, so make sure they also have our services. for (content::RenderFrameHost* frame_host : - child->web_contents_->GetAllFrames()) + child->web_contents_->GetAllFrames()) { child->RenderFrameCreated(frame_host); + } return child; } @@ -450,63 +470,7 @@ return browser_context_; } -void HeadlessWebContentsImpl::OnDisplayDidFinishFrame( - const viz::BeginFrameAck& ack) { - TRACE_EVENT2("headless", "HeadlessWebContentsImpl::OnDisplayDidFinishFrame", - "source_id", ack.source_id, "sequence_number", - ack.sequence_number); - - auto it = pending_frames_.begin(); - while (it != pending_frames_.end()) { - if (begin_frame_source_id_ == ack.source_id && - (*it)->sequence_number <= ack.sequence_number) { - (*it)->has_damage = ack.has_damage; - (*it)->display_did_finish_frame = true; - if ((*it)->MaybeRunCallback()) { - it = pending_frames_.erase(it); - } else { - ++it; - } - } else { - ++it; - } - } -} - -void HeadlessWebContentsImpl::OnNeedsExternalBeginFrames( - bool needs_begin_frames) { - protocol::HeadlessHandler::OnNeedsBeginFrames(this, needs_begin_frames); - TRACE_EVENT1("headless", - "HeadlessWebContentsImpl::OnNeedsExternalBeginFrames", - "needs_begin_frames", needs_begin_frames); - needs_external_begin_frames_ = needs_begin_frames; -} - -void HeadlessWebContentsImpl::PendingFrameReadbackComplete( - HeadlessWebContentsImpl::PendingFrame* pending_frame, - const SkBitmap& bitmap) { - TRACE_EVENT2("headless", - "HeadlessWebContentsImpl::PendingFrameReadbackComplete", - "sequence_number", pending_frame->sequence_number, "success", - !bitmap.drawsNothing()); - if (bitmap.drawsNothing()) { - LOG(WARNING) << "Readback from surface failed."; - } else { - pending_frame->bitmap = std::make_unique<SkBitmap>(bitmap); - } - - pending_frame->wait_for_copy_result = false; - - // Run callback if the frame was already finished by the display. - if (pending_frame->MaybeRunCallback()) { - base::EraseIf(pending_frames_, - [pending_frame](const std::unique_ptr<PendingFrame>& frame) { - return frame.get() == pending_frame; - }); - } -} - -void HeadlessWebContentsImpl::BeginFrame( +bool HeadlessWebContentsImpl::BeginFrame( const base::TimeTicks& frame_timeticks, const base::TimeTicks& deadline, const base::TimeDelta& interval, @@ -514,45 +478,38 @@ bool capture_screenshot, FrameFinishedCallback frame_finished_callback) { DCHECK(begin_frame_control_enabled_); + if (pending_frame_) + return false; TRACE_EVENT2("headless", "HeadlessWebContentsImpl::BeginFrame", "frame_time", frame_timeticks, "capture_screenshot", capture_screenshot); - uint64_t sequence_number = begin_frame_sequence_number_++; - - auto pending_frame = std::make_unique<PendingFrame>(); - pending_frame->sequence_number = sequence_number; - pending_frame->callback = std::move(frame_finished_callback); - // Note: It's important to move |pending_frame| into |pending_frames_| now - // since the CopyFromSurface() call below can run its result callback - // synchronously on certain platforms/environments. - auto* const pending_frame_raw_ptr = pending_frame.get(); - pending_frames_.emplace_back(std::move(pending_frame)); - + int64_t sequence_number = begin_frame_sequence_number_++; + auto pending_frame = base::MakeRefCounted<PendingFrame>( + sequence_number, std::move(frame_finished_callback)); + pending_frame_ = pending_frame->AsWeakPtr(); if (capture_screenshot) { content::RenderWidgetHostView* view = web_contents()->GetRenderWidgetHostView(); if (view && view->IsSurfaceAvailableForCopy()) { - pending_frame_raw_ptr->wait_for_copy_result = true; view->CopyFromSurface( gfx::Rect(), gfx::Size(), - base::BindOnce(&HeadlessWebContentsImpl::PendingFrameReadbackComplete, - weak_ptr_factory_.GetWeakPtr(), - pending_frame_raw_ptr)); + base::BindOnce(&PendingFrame::OnReadbackComplete, pending_frame)); } else { LOG(WARNING) << "Surface not ready for screenshot."; } } - ui::Compositor* compositor = browser()->PlatformGetCompositor(this); - DCHECK(compositor); - auto args = viz::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, begin_frame_source_id_, sequence_number, + BEGINFRAME_FROM_HERE, kBeginFrameSourceId, sequence_number, frame_timeticks, deadline, interval, viz::BeginFrameArgs::NORMAL); args.animate_only = animate_only; - compositor->context_factory_private()->IssueExternalBeginFrame(compositor, - args); + ui::Compositor* compositor = browser()->PlatformGetCompositor(this); + DCHECK(compositor); + compositor->context_factory_private()->IssueExternalBeginFrame( + compositor, args, /* force= */ true, + base::BindOnce(&PendingFrame::OnFrameComplete, pending_frame)); + return true; } HeadlessWebContents::Builder::Builder(
diff --git a/headless/lib/browser/headless_web_contents_impl.h b/headless/lib/browser/headless_web_contents_impl.h index 96b6bd3..f05a8fe 100644 --- a/headless/lib/browser/headless_web_contents_impl.h +++ b/headless/lib/browser/headless_web_contents_impl.h
@@ -5,11 +5,11 @@ #ifndef HEADLESS_LIB_BROWSER_HEADLESS_WEB_CONTENTS_IMPL_H_ #define HEADLESS_LIB_BROWSER_HEADLESS_WEB_CONTENTS_IMPL_H_ -#include <list> #include <memory> +#include <set> #include <string> -#include <unordered_map> +#include "base/memory/scoped_refptr.h" #include "base/observer_list.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "content/public/browser/devtools_agent_host_observer.h" @@ -19,7 +19,6 @@ #include "headless/public/headless_devtools_target.h" #include "headless/public/headless_export.h" #include "headless/public/headless_web_contents.h" -#include "ui/compositor/external_begin_frame_client.h" class SkBitmap; @@ -42,8 +41,7 @@ public HeadlessDevToolsTarget, public content::DevToolsAgentHostObserver, public content::RenderProcessHostObserver, - public content::WebContentsObserver, - public ui::ExternalBeginFrameClient { + public content::WebContentsObserver { public: ~HeadlessWebContentsImpl() override; @@ -90,10 +88,6 @@ void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override; void RenderViewReady() override; - // ui::ExternalBeginFrameClient implementation: - void OnDisplayDidFinishFrame(const viz::BeginFrameAck& ack) override; - void OnNeedsExternalBeginFrames(bool needs_begin_frames) override; - content::WebContents* web_contents() const; bool OpenURL(const GURL& url); @@ -125,39 +119,29 @@ return begin_frame_control_enabled_; } - bool needs_external_begin_frames() const { - return needs_external_begin_frames_; - } - using FrameFinishedCallback = base::OnceCallback<void(bool /* has_damage */, std::unique_ptr<SkBitmap>)>; - void BeginFrame(const base::TimeTicks& frame_timeticks, + // If the frame was started, the function returns true and will + // invoke callback eventually. If an immediate error occurs, the + // function return false and will not invoke the callback. + bool BeginFrame(const base::TimeTicks& frame_timeticks, const base::TimeTicks& deadline, const base::TimeDelta& interval, bool animate_only, bool capture_screenshot, FrameFinishedCallback frame_finished_callback); - bool HasPendingFrame() const { return !pending_frames_.empty(); } private: - struct PendingFrame; - // Takes ownership of |web_contents|. HeadlessWebContentsImpl(std::unique_ptr<content::WebContents> web_contents, HeadlessBrowserContextImpl* browser_context); void InitializeWindow(const gfx::Rect& initial_bounds); - void PendingFrameReadbackComplete(PendingFrame* pending_frame, - const SkBitmap& bitmap); - - uint64_t begin_frame_source_id_ = viz::BeginFrameArgs::kManualSourceId; uint64_t begin_frame_sequence_number_ = viz::BeginFrameArgs::kStartingFrameNumber; bool begin_frame_control_enabled_ = false; - bool needs_external_begin_frames_ = false; - std::list<std::unique_ptr<PendingFrame>> pending_frames_; class Delegate; std::unique_ptr<Delegate> web_contents_delegate_; @@ -176,7 +160,8 @@ base::ObserverList<HeadlessWebContents::Observer>::Unchecked observers_; - base::WeakPtrFactory<HeadlessWebContentsImpl> weak_ptr_factory_{this}; + class PendingFrame; + base::WeakPtr<PendingFrame> pending_frame_; DISALLOW_COPY_AND_ASSIGN(HeadlessWebContentsImpl); };
diff --git a/headless/lib/browser/headless_window_tree_host.cc b/headless/lib/browser/headless_window_tree_host.cc index ed63d0e..9c0bb79 100644 --- a/headless/lib/browser/headless_window_tree_host.cc +++ b/headless/lib/browser/headless_window_tree_host.cc
@@ -15,10 +15,8 @@ namespace headless { HeadlessWindowTreeHost::HeadlessWindowTreeHost( - const gfx::Rect& bounds, - ui::ExternalBeginFrameClient* external_begin_frame_client) - : bounds_(bounds) { - CreateCompositor(viz::FrameSinkId(), false, external_begin_frame_client); + bool use_external_begin_frame_control) { + CreateCompositor(viz::FrameSinkId(), false, use_external_begin_frame_control); OnAcceleratedWidgetAvailable(); focus_client_.reset(new HeadlessFocusClient());
diff --git a/headless/lib/browser/headless_window_tree_host.h b/headless/lib/browser/headless_window_tree_host.h index 09fe9042..cdeb361 100644 --- a/headless/lib/browser/headless_window_tree_host.h +++ b/headless/lib/browser/headless_window_tree_host.h
@@ -30,9 +30,7 @@ class HeadlessWindowTreeHost : public aura::WindowTreeHost, public ui::PlatformEventDispatcher { public: - HeadlessWindowTreeHost( - const gfx::Rect& bounds, - ui::ExternalBeginFrameClient* external_begin_frame_client); + explicit HeadlessWindowTreeHost(bool use_external_begin_frame_control); ~HeadlessWindowTreeHost() override; void SetParentWindow(gfx::NativeWindow window);
diff --git a/headless/lib/browser/protocol/headless_handler.cc b/headless/lib/browser/protocol/headless_handler.cc index fef9538..f0f137a 100644 --- a/headless/lib/browser/protocol/headless_handler.cc +++ b/headless/lib/browser/protocol/headless_handler.cc
@@ -7,7 +7,6 @@ #include "base/base_switches.h" #include "base/bind.h" #include "base/command_line.h" -#include "base/lazy_instance.h" #include "cc/base/switches.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/common/switches.h" @@ -28,8 +27,6 @@ namespace { -base::LazyInstance<std::set<HeadlessHandler*>>::Leaky g_instances = - LAZY_INSTANCE_INITIALIZER; enum class ImageEncoding { kPng, kJpeg }; constexpr int kDefaultScreenshotQuality = 80; @@ -68,25 +65,12 @@ } // namespace -// static -void HeadlessHandler::OnNeedsBeginFrames( - HeadlessWebContentsImpl* headless_contents, - bool needs_begin_frames) { - if (!g_instances.IsCreated()) - return; - for (const HeadlessHandler* handler : g_instances.Get()) { - if (handler->enabled_ && handler->frontend_) - handler->frontend_->NeedsBeginFramesChanged(needs_begin_frames); - } -} - HeadlessHandler::HeadlessHandler(base::WeakPtr<HeadlessBrowserImpl> browser, content::WebContents* web_contents) : DomainHandler(HeadlessExperimental::Metainfo::domainName, browser), web_contents_(web_contents) {} HeadlessHandler::~HeadlessHandler() { - DCHECK(g_instances.Get().find(this) == g_instances.Get().end()); } void HeadlessHandler::Wire(UberDispatcher* dispatcher) { @@ -95,18 +79,12 @@ } Response HeadlessHandler::Enable() { - g_instances.Get().insert(this); - HeadlessWebContentsImpl* headless_contents = - HeadlessWebContentsImpl::From(browser().get(), web_contents_); - enabled_ = true; - if (headless_contents->needs_external_begin_frames() && frontend_) + if (frontend_) frontend_->NeedsBeginFramesChanged(true); return Response::OK(); } Response HeadlessHandler::Disable() { - enabled_ = false; - g_instances.Get().erase(this); return Response::OK(); } @@ -125,9 +103,11 @@ if (!base::CommandLine::ForCurrentProcess()->HasSwitch( ::switches::kRunAllCompositorStagesBeforeDraw)) { - LOG(WARNING) << "BeginFrameControl commands are designed to be used with " - "--run-all-compositor-stages-before-draw, see " - "https://goo.gl/3zHXhB for more info."; + callback->sendFailure( + Response::Error("Command is only supported with " + "--run-all-compositor-stages-before-draw, see " + "https://goo.gl/3zHXhB for more info.")); + return; } base::TimeTicks frame_time_ticks; @@ -180,19 +160,15 @@ } } - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - ::switches::kRunAllCompositorStagesBeforeDraw) && - headless_contents->HasPendingFrame()) { - LOG(WARNING) << "A BeginFrame is already in flight. In " - "--run-all-compositor-stages-before-draw mode, only a " - "single BeginFrame should be active at the same time."; + if (!headless_contents->BeginFrame( + frame_time_ticks, deadline, interval, no_display_updates, + capture_screenshot, + base::BindOnce(&OnBeginFrameFinished, std::move(callback), encoding, + quality))) { + callback->sendFailure(Response::Error( + "Failed to request a frame, is another frame pending?")); + return; } - - headless_contents->BeginFrame( - frame_time_ticks, deadline, interval, no_display_updates, - capture_screenshot, - base::BindOnce(&OnBeginFrameFinished, std::move(callback), encoding, - quality)); } } // namespace protocol
diff --git a/headless/lib/browser/protocol/headless_handler.h b/headless/lib/browser/protocol/headless_handler.h index a24e523..034e1655 100644 --- a/headless/lib/browser/protocol/headless_handler.h +++ b/headless/lib/browser/protocol/headless_handler.h
@@ -14,8 +14,6 @@ namespace headless { -class HeadlessWebContentsImpl; - namespace protocol { class HeadlessHandler : public DomainHandler, @@ -27,9 +25,6 @@ void Wire(UberDispatcher* dispatcher) override; - static void OnNeedsBeginFrames(HeadlessWebContentsImpl* headless_contents, - bool needs_begin_frames); - // Headless::Backend implementation Response Enable() override; Response Disable() override; @@ -41,7 +36,6 @@ private: content::WebContents* web_contents_; - bool enabled_ = false; std::unique_ptr<HeadlessExperimental::Frontend> frontend_; DISALLOW_COPY_AND_ASSIGN(HeadlessHandler); };
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.h b/ios/chrome/browser/sync/ios_chrome_sync_client.h index 5564ae1..1033746 100644 --- a/ios/chrome/browser/sync/ios_chrome_sync_client.h +++ b/ios/chrome/browser/sync/ios_chrome_sync_client.h
@@ -48,7 +48,6 @@ base::Closure GetPasswordStateChangedCallback() override; syncer::DataTypeController::TypeVector CreateDataTypeControllers( syncer::SyncService* sync_service) override; - autofill::PersonalDataManager* GetPersonalDataManager() override; invalidation::InvalidationService* GetInvalidationService() override; BookmarkUndoService* GetBookmarkUndoService() override; scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override;
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm index de279ba..93cde8a9 100644 --- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm +++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -42,7 +42,6 @@ #include "components/sync_sessions/favicon_cache.h" #include "components/sync_sessions/session_sync_service.h" #include "components/sync_user_events/user_event_service.h" -#include "ios/chrome/browser/autofill/personal_data_manager_factory.h" #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" #include "ios/chrome/browser/bookmarks/bookmark_sync_service_factory.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" @@ -163,12 +162,6 @@ return SessionSyncServiceFactory::GetForBrowserState(browser_state_); } -autofill::PersonalDataManager* IOSChromeSyncClient::GetPersonalDataManager() { - DCHECK_CURRENTLY_ON(web::WebThread::UI); - return autofill::PersonalDataManagerFactory::GetForBrowserState( - browser_state_); -} - base::Closure IOSChromeSyncClient::GetPasswordStateChangedCallback() { return base::Bind( &IOSChromePasswordStoreFactory::OnPasswordsSyncedStatePotentiallyChanged,
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm index c3f9bd4..1edbd43 100644 --- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm
@@ -24,6 +24,7 @@ #include "ios/chrome/browser/signin/identity_manager_factory.h" #include "ios/chrome/browser/sync/consent_auditor_factory.h" #include "ios/chrome/browser/sync/ios_user_event_service_factory.h" +#import "ios/chrome/browser/ui/util/transparent_link_button.h" #include "ios/chrome/browser/unified_consent/unified_consent_service_factory.h" #include "ios/chrome/grit/ios_chromium_strings.h" #include "ios/chrome/grit/ios_strings.h" @@ -39,6 +40,9 @@ #error "This file requires ARC support." #endif +using base::test::ios::kWaitForUIElementTimeout; +using base::test::ios::WaitUntilConditionOrTimeout; + @interface FakeChromeSigninViewControllerDelegate : NSObject<ChromeSigninViewControllerDelegate> @@ -79,6 +83,21 @@ namespace { +// Returns the first TransparentLinkButton view in |mainView|. +TransparentLinkButton* FindLinkButton(UIView* mainView) { + NSMutableArray* views = [NSMutableArray array]; + [views addObject:mainView]; + while (views.count > 0) { + UIView* view = [views objectAtIndex:0]; + [views removeObjectAtIndex:0]; + [views addObjectsFromArray:view.subviews]; + if ([view isKindOfClass:[TransparentLinkButton class]]) { + return base::mac::ObjCCastStrict<TransparentLinkButton>(view); + } + } + return nil; +} + const bool kUnifiedConsentParam[] = { false, true, }; @@ -316,7 +335,7 @@ // Scrolls to the bottom if needed and returns once the primary button is // found with the confirmation title (based on ConfirmationStringId()). // The scroll is done without animation. Otherwise, the scroll view doesn't - // scroll correctly inside base::test::ios::WaitUntilConditionOrTimeout(). + // scroll correctly inside WaitUntilConditionOrTimeout(). void ScrollConsentViewToBottom() { ConditionBlock condition = ^bool() { if (IsPrimaryButtonVisibleWithTitle( @@ -331,7 +350,7 @@ return IsPrimaryButtonVisibleWithTitle(ConfirmationStringId()); }; bool condition_met = - base::test::ios::WaitUntilConditionOrTimeout(10, condition); + WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, condition); EXPECT_TRUE(condition_met); } @@ -356,7 +375,7 @@ return [found_strings isEqual:expected_strings]; }; bool condition_met = - base::test::ios::WaitUntilConditionOrTimeout(10, condition); + WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, condition); NSString* failureExplaination = [NSString stringWithFormat:@"Strings not found: %@, Strings not expected: %@", not_found_strings, not_expected_strings]; @@ -396,7 +415,7 @@ ConditionBlock condition = ^bool() { return this->vc_delegate_.didSigninCalled; }; - EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(10, condition)); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, condition)); const std::vector<int>& recorded_ids = fake_consent_auditor_->recorded_id_vectors().at(0); EXPECT_EQ(ExpectedConsentStringIds(), recorded_ids); @@ -424,7 +443,18 @@ // ids, and settings confirmation string id. TEST_P(ChromeSigninViewControllerTest, TestConsentWithSettings) { WaitAndExpectAllStringsOnScreen(); - [vc_ signinConfirmationControllerDidTapSettingsLink:vc_.confirmationVC]; + if (unified_consent_enabled_) { + UIButton* linkButton = FindLinkButton([vc_ view]); + EXPECT_NE(nil, linkButton); + [linkButton sendActionsForControlEvents:UIControlEventTouchUpInside]; + ConditionBlock condition = ^bool() { + return this->vc_delegate_.didSigninCalled; + }; + EXPECT_TRUE( + WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, condition)); + } else { + [vc_ signinConfirmationControllerDidTapSettingsLink:vc_.confirmationVC]; + } const std::vector<int>& recorded_ids = fake_consent_auditor_->recorded_id_vectors().at(0); EXPECT_EQ(ExpectedConsentStringIds(), recorded_ids);
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.mm b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.mm index c2ee19e4..46bd95f 100644 --- a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.mm +++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.mm
@@ -104,7 +104,8 @@ - (void)creditCardMediatorShowScanner:(AutofillAddCreditCardMediator*)mediator API_AVAILABLE(ios(13.0)) { self.creditCardScannerCoordinator = [[CreditCardScannerCoordinator alloc] - initWithBaseViewController:self.addCreditCardViewController]; + initWithBaseViewController:self.addCreditCardViewController + creditCardConsumer:self.addCreditCardViewController]; [self.creditCardScannerCoordinator start]; }
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.mm b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.mm index c63cf80b6..9929c83 100644 --- a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.mm +++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.mm
@@ -98,6 +98,8 @@ style:UIBarButtonItemStyleDone target:self action:@selector(didTapAddButton:)]; + self.navigationItem.rightBarButtonItem.enabled = NO; + [self loadModel]; } @@ -218,14 +220,19 @@ base::mac::ObjCCast<TableViewTextEditCell>(cell); editCell.textField.delegate = self; editCell.selectionStyle = UITableViewCellSelectionStyleNone; + // The cell could be reused by TableView. + [editCell.textField removeTarget:self + action:@selector(textFieldDidChange:) + forControlEvents:UIControlEventEditingChanged]; + [editCell.textField addTarget:self + action:@selector(textFieldDidChange:) + forControlEvents:UIControlEventEditingChanged]; return cell; } #pragma mark - CreditCardConsumer -// TODO(crbug.com/984545): This method will be called from -// CreditCardScannerMediator after it is implemented. - (void)setCreditCardNumber:(NSString*)cardNumber expirationMonth:(NSString*)expirationMonth expirationYear:(NSString*)expirationYear { @@ -306,6 +313,12 @@ [self reconfigureCellsForItems:@[ item ]]; } +// Updates the status of the "Add" button based on the content of the +// textfields. +- (void)textFieldDidChange:(id)sender { + self.navigationItem.rightBarButtonItem.enabled = [self tableViewHasUserInput]; +} + // Dimisses this view controller when Cancel button is tapped. - (void)handleCancelButton:(id)sender { [self.delegate addCreditCardViewControllerDidCancel:self];
diff --git a/ios/chrome/browser/ui/settings/credit_card_scanner/BUILD.gn b/ios/chrome/browser/ui/settings/credit_card_scanner/BUILD.gn index b5c0c28..007d49f 100644 --- a/ios/chrome/browser/ui/settings/credit_card_scanner/BUILD.gn +++ b/ios/chrome/browser/ui/settings/credit_card_scanner/BUILD.gn
@@ -14,6 +14,7 @@ "credit_card_scanner_coordinator.mm", "credit_card_scanner_mediator.h", "credit_card_scanner_mediator.mm", + "credit_card_scanner_mediator_delegate.h", "credit_card_scanner_mediator_util.h", "credit_card_scanner_mediator_util.mm", "credit_card_scanner_view.h",
diff --git a/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_coordinator.h b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_coordinator.h index 74668c0..1a28dec 100644 --- a/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_coordinator.h +++ b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_coordinator.h
@@ -7,10 +7,29 @@ #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" +@protocol CreditCardConsumer; + // The coordinator for the Credit Card Scanner screen. API_AVAILABLE(ios(13.0)) @interface CreditCardScannerCoordinator : ChromeCoordinator +// Initializes with the Credit Card consumer. +- (instancetype)initWithBaseViewController:(UIViewController*)baseViewController + creditCardConsumer: + (id<CreditCardConsumer>)creditCardConsumer + NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + NS_UNAVAILABLE; + +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + browserState: + (ios::ChromeBrowserState*)browserState + NS_UNAVAILABLE; + +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + browser:(Browser*)browser NS_UNAVAILABLE; + @end #endif // IOS_CHROME_BROWSER_UI_SETTINGS_CREDIT_CARD_SCANNER_CREDIT_CARD_SCANNER_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_coordinator.mm b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_coordinator.mm index c6af3f6..1b9d1b2 100644 --- a/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_coordinator.mm +++ b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_coordinator.mm
@@ -4,15 +4,19 @@ #import "ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_coordinator.h" +#include "base/logging.h" #import "ios/chrome/browser/ui/scanner/scanner_presenting.h" +#import "ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_consumer.h" #import "ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator.h" +#import "ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator_delegate.h" #import "ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_view_controller.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -@interface CreditCardScannerCoordinator () <ScannerPresenting> +@interface CreditCardScannerCoordinator () <CreditCardScannerMediatorDelegate, + ScannerPresenting> // The view controller attached to this coordinator. @property(nonatomic, strong) @@ -22,16 +26,35 @@ @property(nonatomic, strong) CreditCardScannerMediator* creditCardScannerMediator; +// The consumer for credit card scanner. +@property(nonatomic, weak) id<CreditCardConsumer> creditCardConsumer; + @end @implementation CreditCardScannerCoordinator +#pragma mark - Lifecycle + +- (instancetype)initWithBaseViewController:(UIViewController*)baseViewController + creditCardConsumer: + (id<CreditCardConsumer>)creditCardConsumer { + self = [super initWithBaseViewController:baseViewController browserState:nil]; + if (self) { + DCHECK(self); + _creditCardConsumer = creditCardConsumer; + } + return self; +} + #pragma mark - ChromeCoordinator - (void)start { [super start]; - self.creditCardScannerMediator = [[CreditCardScannerMediator alloc] init]; + self.creditCardScannerMediator = [[CreditCardScannerMediator alloc] + initWithDelegate:self + creditCardConsumer:self.creditCardConsumer]; + self.creditCardScannerViewController = [[CreditCardScannerViewController alloc] initWithPresentationProvider:self @@ -47,7 +70,6 @@ - (void)stop { [super stop]; - self.creditCardScannerViewController.cameraController = nil; [self.creditCardScannerViewController dismissViewControllerAnimated:YES completion:nil]; @@ -62,4 +84,11 @@ [self stop]; } +#pragma mark - CreditCardScannerMediatorDelegate + +- (void)creditCardScannerMediatorDidFinishScan: + (CreditCardScannerMediator*)mediator { + [self stop]; +} + @end
diff --git a/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator.h b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator.h index 48e025d6..39c613e 100644 --- a/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator.h +++ b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator.h
@@ -9,10 +9,21 @@ #import "ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanned_image_delegate.h" +@protocol CreditCardConsumer; +@protocol CreditCardScannerMediatorDelegate; + // A mediator for CreditCardScanner which manages processing images. API_AVAILABLE(ios(13.0)) @interface CreditCardScannerMediator : NSObject <CreditCardScannedImageDelegate> +// Initializes with Credit Card mediator delegate and Credit Card consumer. +- (instancetype)initWithDelegate:(id<CreditCardScannerMediatorDelegate>) + creditCardScannerMediatorDelegate + creditCardConsumer:(id<CreditCardConsumer>)creditCardConsumer + NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + @end #endif // IOS_CHROME_BROWSER_UI_SETTINGS_CREDIT_CARD_SCANNER_CREDIT_CARD_SCANNER_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator.mm b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator.mm index 5285da98..0131a52 100644 --- a/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator.mm +++ b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator.mm
@@ -8,17 +8,30 @@ #import <Vision/Vision.h> #include "base/logging.h" +#include "base/metrics/user_metrics.h" +#include "base/metrics/user_metrics_action.h" +#import "ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_consumer.h" +#import "ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator_delegate.h" #import "ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif +using base::UserMetricsAction; + @interface CreditCardScannerMediator () // An image analysis request that finds and recognizes text in an image. @property(nonatomic, strong) VNRecognizeTextRequest* textRecognitionRequest; +// Delegate notified when a card has been scanned. +@property(nonatomic, weak) id<CreditCardScannerMediatorDelegate> + creditCardScannerMediatorDelegate; + +// This property is for an interface which notfies the credit card consumer. +@property(nonatomic, weak) id<CreditCardConsumer> creditCardConsumer; + // The card number set after |textRecognitionRequest| from recognised text on // the card. @property(nonatomic, strong) NSString* cardNumber; @@ -35,6 +48,19 @@ @implementation CreditCardScannerMediator +#pragma mark - Lifecycle + +- (instancetype)initWithDelegate:(id<CreditCardScannerMediatorDelegate>) + creditCardScannerMediatorDelegate + creditCardConsumer:(id<CreditCardConsumer>)creditCardConsumer { + self = [super init]; + if (self) { + _creditCardScannerMediatorDelegate = creditCardScannerMediatorDelegate; + _creditCardConsumer = creditCardConsumer; + } + return self; +} + #pragma mark - CreditCardScannerImageDelegate - (void)processOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer @@ -45,6 +71,9 @@ auto completionHandler = ^(VNRequest* request, NSError* error) { if (request.results.count != 0) { [weakSelf searchInRecognizedText:request.results]; + if (self.cardNumber) { + [self dismissScannerOnCardScanned]; + } } }; @@ -80,6 +109,13 @@ #pragma mark - Helper Methods +// Dismisses the scanner when credit card number is found. +- (void)dismissScannerOnCardScanned { + base::RecordAction(UserMetricsAction("MobileCreditCardScannerScannedCard")); + [self.creditCardScannerMediatorDelegate + creditCardScannerMediatorDidFinishScan:self]; +} + // Searches in |recognizedText| for credit card number and expiration date. - (void)searchInRecognizedText: (NSArray<VNRecognizedTextObservation*>*)recognizedText { @@ -93,6 +129,14 @@ } [self extractDataFromText:candidate.string]; } + + if (self.cardNumber) { + [self.creditCardConsumer setCreditCardNumber:self.cardNumber + expirationMonth:self.expirationMonth + expirationYear:self.expirationYear]; + [self.creditCardScannerMediatorDelegate + creditCardScannerMediatorDidFinishScan:self]; + } } // Checks the type of |text| to assign it to appropriate property. @@ -108,7 +152,6 @@ } } - // Extracts credit card number from |string|. - (NSString*)extractCreditCardNumber:(NSString*)string { NSString* text = [[NSString alloc] initWithString:string]; @@ -118,9 +161,9 @@ text = [text stringByReplacingOccurrencesOfString:symbol withString:@""]; } - // Matches strings which have 13-19 numbers between the start(^) and the + // Matches strings which have 13-19 characters between the start(^) and the // end($) of the line. - NSString* pattern = @"^([0-9]{13,19})$"; + NSString* pattern = @"^(\\w{13,19})$"; NSError* error; NSRegularExpression* regex = [[NSRegularExpression alloc] @@ -135,8 +178,49 @@ if (!match) { return nil; } - NSString* creditCardNumber = [text substringWithRange:match.range]; - return creditCardNumber; + + NSString* stringMatchingPattern = [text substringWithRange:match.range]; + + NSString* creditCardNumber = + [self substituteSimilarCharactersInRecognizedText:stringMatchingPattern]; + NSCharacterSet* allowedCharacterSet = + [NSCharacterSet decimalDigitCharacterSet]; + NSCharacterSet* creditCardNumberSet = + [NSCharacterSet characterSetWithCharactersInString:creditCardNumber]; + if ([allowedCharacterSet isSupersetOfSet:creditCardNumberSet]) { + return creditCardNumber; + } + return nil; +} + +// Substitutes commonly misrecognized characters, for example: 'S' -> '5' or +// 'l' -> '1' +- (NSString*)substituteSimilarCharactersInRecognizedText: + (NSString*)recognizedText { + NSDictionary* misrecognisedAlphabets = @{ + @"B" : @"8", + @"C" : @"0", + @"D" : @"0", + @"G" : @"9", + @"I" : @"1", + @"L" : @"1", + @"O" : @"0", + @"Q" : @"0", + @"S" : @"5", + @"T" : @"7", + @"U" : @"0", + @"Z" : @"7" + }; + + NSString* substitutedText = + [[NSString alloc] initWithString:recognizedText].uppercaseString; + for (NSString* alphabet in misrecognisedAlphabets) { + NSString* digit = misrecognisedAlphabets[alphabet]; + substitutedText = + [substitutedText stringByReplacingOccurrencesOfString:alphabet + withString:digit]; + } + return substitutedText; } @end
diff --git a/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator_delegate.h b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator_delegate.h new file mode 100644 index 0000000..7286864 --- /dev/null +++ b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_mediator_delegate.h
@@ -0,0 +1,19 @@ +// 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 IOS_CHROME_BROWSER_UI_SETTINGS_CREDIT_CARD_SCANNER_CREDIT_CARD_SCANNER_MEDIATOR_DELEGATE_H_ +#define IOS_CHROME_BROWSER_UI_SETTINGS_CREDIT_CARD_SCANNER_CREDIT_CARD_SCANNER_MEDIATOR_DELEGATE_H_ + +@class CreditCardScannerMediator; + +// This delegate is notified when a credit card is scanned. +@protocol CreditCardScannerMediatorDelegate + +// Notifies that the scanner has finished scanning a credit card. +- (void)creditCardScannerMediatorDidFinishScan: + (CreditCardScannerMediator*)mediator API_AVAILABLE(ios(13.0)); + +@end + +#endif // IOS_CHROME_BROWSER_UI_SETTINGS_CREDIT_CARD_SCANNER_CREDIT_CARD_SCANNER_MEDIATOR_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_view_controller.mm b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_view_controller.mm index 5ae052e..20aa6d20 100644 --- a/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_view_controller.mm +++ b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_scanner_view_controller.mm
@@ -38,6 +38,29 @@ return self; } +#pragma mark - UIViewController + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + // Crop the scanner subviews to the size of the |scannerView| to avoid the + // preview overlay being visible outside the screen bounds while presenting. + self.scannerView.clipsToBounds = YES; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + // Allow the constraints to modify the preview overlay size to cover the + // entire screen during rotation. + self.scannerView.clipsToBounds = NO; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + // Crop the scanner subviews to the size of the |scannerView| to avoid the + // preview overlay being visible outside the screen bounds while dismissing. + self.scannerView.clipsToBounds = YES; +} + #pragma mark - ScannerViewController - (ScannerView*)buildScannerView { @@ -60,9 +83,7 @@ base::RecordAction(UserMetricsAction("MobileCreditCardScannerError")); break; case scannerViewController::SCAN_COMPLETE: - base::RecordAction( - UserMetricsAction("MobileCreditCardScannerScannedCard")); - break; + // Fall through. case scannerViewController::IMPOSSIBLY_UNLIKELY_AUTHORIZATION_CHANGE: break; }
diff --git a/ios/web_view/internal/sync/web_view_sync_client.h b/ios/web_view/internal/sync/web_view_sync_client.h index 9a4fc2a..f6a9b11 100644 --- a/ios/web_view/internal/sync/web_view_sync_client.h +++ b/ios/web_view/internal/sync/web_view_sync_client.h
@@ -51,7 +51,6 @@ base::RepeatingClosure GetPasswordStateChangedCallback() override; syncer::DataTypeController::TypeVector CreateDataTypeControllers( syncer::SyncService* sync_service) override; - autofill::PersonalDataManager* GetPersonalDataManager() override; invalidation::InvalidationService* GetInvalidationService() override; BookmarkUndoService* GetBookmarkUndoService() override; scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override;
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm index 73baee4..aa9af38d 100644 --- a/ios/web_view/internal/sync/web_view_sync_client.mm +++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -30,7 +30,6 @@ #include "components/version_info/version_string.h" #include "ios/web/public/thread/web_task_traits.h" #include "ios/web/public/thread/web_thread.h" -#include "ios/web_view/internal/autofill/web_view_personal_data_manager_factory.h" #include "ios/web_view/internal/passwords/web_view_password_store_factory.h" #include "ios/web_view/internal/pref_names.h" #import "ios/web_view/internal/sync/web_view_device_info_sync_service_factory.h" @@ -128,11 +127,6 @@ return nullptr; } -autofill::PersonalDataManager* WebViewSyncClient::GetPersonalDataManager() { - DCHECK_CURRENTLY_ON(web::WebThread::UI); - return WebViewPersonalDataManagerFactory::GetForBrowserState(browser_state_); -} - base::RepeatingClosure WebViewSyncClient::GetPasswordStateChangedCallback() { return base::BindRepeating( &WebViewPasswordStoreFactory::OnPasswordsSyncedStatePotentiallyChanged,
diff --git a/media/capture/video/chromeos/camera_app_device_impl.cc b/media/capture/video/chromeos/camera_app_device_impl.cc index 41973c5..c0c3312 100644 --- a/media/capture/video/chromeos/camera_app_device_impl.cc +++ b/media/capture/video/chromeos/camera_app_device_impl.cc
@@ -110,6 +110,11 @@ std::move(callback).Run(it->second); } +cros::mojom::CaptureIntent CameraAppDeviceImpl::GetCaptureIntent() { + base::AutoLock lock(capture_intent_lock_); + return capture_intent_; +} + void CameraAppDeviceImpl::SetReprocessResult( SetReprocessOptionCallback callback, const int32_t status, @@ -195,4 +200,12 @@ std::move(callback).Run(true); } +void CameraAppDeviceImpl::SetCaptureIntent( + cros::mojom::CaptureIntent capture_intent, + SetCaptureIntentCallback callback) { + base::AutoLock lock(capture_intent_lock_); + capture_intent_ = capture_intent; + std::move(callback).Run(); +} + } // namespace media
diff --git a/media/capture/video/chromeos/camera_app_device_impl.h b/media/capture/video/chromeos/camera_app_device_impl.h index 6c6bf7b..50579472 100644 --- a/media/capture/video/chromeos/camera_app_device_impl.h +++ b/media/capture/video/chromeos/camera_app_device_impl.h
@@ -73,6 +73,8 @@ void GetFpsRange(const gfx::Size& resolution, GetFpsRangeCallback callback); + cros::mojom::CaptureIntent GetCaptureIntent(); + void SetReprocessResult(SetReprocessOptionCallback callback, const int32_t status, media::mojom::BlobPtr blob); @@ -87,6 +89,9 @@ const gfx::Range& fps_range, SetFpsRangeCallback callback) override; + void SetCaptureIntent(cros::mojom::CaptureIntent capture_intent, + SetCaptureIntentCallback callback) override; + private: std::string device_id_; @@ -104,6 +109,10 @@ ResolutionFpsRangeMap resolution_fps_range_map_; + base::Lock capture_intent_lock_; + + cros::mojom::CaptureIntent capture_intent_; + std::unique_ptr<base::WeakPtrFactory<CameraAppDeviceImpl>> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(CameraAppDeviceImpl);
diff --git a/media/capture/video/chromeos/camera_device_delegate.cc b/media/capture/video/chromeos/camera_device_delegate.cc index efcbf10..4590b04 100644 --- a/media/capture/video/chromeos/camera_device_delegate.cc +++ b/media/capture/video/chromeos/camera_device_delegate.cc
@@ -512,7 +512,24 @@ return; } device_context_->SetState(CameraDeviceContext::State::kInitialized); - ConfigureStreams(false, base::nullopt); + bool require_photo = [&] { + if (camera_app_device_ == nullptr) { + return false; + } + auto capture_intent = camera_app_device_->GetCaptureIntent(); + switch (capture_intent) { + case cros::mojom::CaptureIntent::DEFAULT: + return false; + case cros::mojom::CaptureIntent::STILL_CAPTURE: + return true; + case cros::mojom::CaptureIntent::VIDEO_RECORD: + return false; + default: + NOTREACHED() << "Unknown capture intent: " << capture_intent; + return false; + } + }(); + ConfigureStreams(require_photo, base::nullopt); } void CameraDeviceDelegate::ConfigureStreams(
diff --git a/media/capture/video/chromeos/mojom/camera_app.mojom b/media/capture/video/chromeos/mojom/camera_app.mojom index 7c69dc88..08fcebe 100644 --- a/media/capture/video/chromeos/mojom/camera_app.mojom +++ b/media/capture/video/chromeos/mojom/camera_app.mojom
@@ -22,6 +22,14 @@ ERROR_INVALID_ID = 2, }; +// The purpose of this capture is to help the camera device decide optimal +// configurations. +enum CaptureIntent { + DEFAULT = 0, + VIDEO_RECORD = 1, + STILL_CAPTURE = 2, +}; + // Interface to let Chrome Camera App (Remote) get specific CameraAppDevice from // Chrome (Receiver). interface CameraAppDeviceProvider { @@ -83,4 +91,10 @@ // previously will be cleared and |is_success| will return false. SetFpsRange(gfx.mojom.Size resolution, gfx.mojom.Range fps_range) => (bool is_success); + + // Sets the intent for the upcoming capture session. The underlying video + // capture device should configure the streams accordingly. Returns an empty + // response after the intent is set, which could be used to sequence the + // other calls such as getUserMedia(). + SetCaptureIntent(CaptureIntent intent) => (); };
diff --git a/net/cookies/cookie_monster_perftest.cc b/net/cookies/cookie_monster_perftest.cc index 2829477..6880c75 100644 --- a/net/cookies/cookie_monster_perftest.cc +++ b/net/cookies/cookie_monster_perftest.cc
@@ -7,12 +7,12 @@ #include "base/bind.h" #include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" #include "base/optional.h" #include "base/run_loop.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/test/perf_time_logger.h" +#include "base/test/task_environment.h" #include "base/time/time.h" #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_monster.h" @@ -32,10 +32,11 @@ class CookieMonsterTest : public testing::Test { public: - CookieMonsterTest() : message_loop_(new base::MessageLoopForIO()) {} + CookieMonsterTest() {} private: - std::unique_ptr<base::MessageLoop> message_loop_; + base::test::SingleThreadTaskEnvironment task_environment_{ + base::test::SingleThreadTaskEnvironment::MainThreadType::IO}; }; class CookieTestCallback {
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc index baa8ec7..e7f04f42 100644 --- a/net/http/transport_security_state.cc +++ b/net/http/transport_security_state.cc
@@ -42,6 +42,9 @@ namespace net { +const base::Feature kEnforceCTForNewCerts{"EnforceCTForNewCerts", + base::FEATURE_DISABLED_BY_DEFAULT}; + namespace { #include "net/http/transport_security_state_ct_policies.inc" @@ -67,10 +70,6 @@ // 1: Unless a delegate says otherwise, require CT. int g_ct_required_for_testing = 0; -// Controls whether or not Certificate Transparency should be enforced for -// newly-issued certificates. -const base::Feature kEnforceCTForNewCerts{"EnforceCTForNewCerts", - base::FEATURE_DISABLED_BY_DEFAULT}; // The date (as the number of seconds since the Unix Epoch) to enforce CT for // new certificates. constexpr base::FeatureParam<int> kEnforceCTForNewCertsDate{
diff --git a/net/http/transport_security_state.h b/net/http/transport_security_state.h index 48ccb74..3488fb6 100644 --- a/net/http/transport_security_state.h +++ b/net/http/transport_security_state.h
@@ -34,6 +34,10 @@ class SSLInfo; class X509Certificate; +// Controls whether or not Certificate Transparency should be enforced for +// newly-issued certificates. +extern const NET_EXPORT_PRIVATE base::Feature kEnforceCTForNewCerts; + void NET_EXPORT_PRIVATE SetTransportSecurityStateSourceForTesting( const TransportSecurityStateSource* source);
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc index dc4e86d..d8504f24 100644 --- a/net/http/transport_security_state_unittest.cc +++ b/net/http/transport_security_state_unittest.cc
@@ -1711,26 +1711,14 @@ // However, simulating a Field Trial in which CT is required for certificates // after 2017-12-01 should cause CT to be required for this certificate, as // it was issued 2017-12-20. - const char kTrialName[] = "EnforceCTForNewCertsTrial"; - const char kGroupName[] = "Unused"; // Value not used. - const char kFeatureName[] = "EnforceCTForNewCerts"; - base::test::ScopedFeatureList scoped_feature_list; - base::FieldTrialList field_trial_list( - std::make_unique<base::MockEntropyProvider>()); - scoped_refptr<base::FieldTrial> trial = - base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName); - std::map<std::string, std::string> params; + base::FieldTrialParams params; // Set the enforcement date to 2017-12-01 00:00:00; params["date"] = "1512086400"; - base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams( - kTrialName, kGroupName, params); - std::unique_ptr<base::FeatureList> feature_list( - std::make_unique<base::FeatureList>()); - feature_list->RegisterFieldTrialOverride( - kFeatureName, base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get()); - scoped_feature_list.InitWithFeatureList(std::move(feature_list)); + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters(kEnforceCTForNewCerts, + params); // It should fail if it doesn't comply with policy. EXPECT_EQ(TransportSecurityState::CT_REQUIREMENTS_NOT_MET,
diff --git a/net/socket/websocket_transport_connect_job.cc b/net/socket/websocket_transport_connect_job.cc index 5510ec1..36b5b72 100644 --- a/net/socket/websocket_transport_connect_job.cc +++ b/net/socket/websocket_transport_connect_job.cc
@@ -199,8 +199,8 @@ FROM_HERE, base::TimeDelta::FromMilliseconds( TransportConnectJob::kIPv6FallbackTimerInMs), - base::Bind(&WebSocketTransportConnectJob::StartIPv4JobAsync, - base::Unretained(this))); + base::BindOnce(&WebSocketTransportConnectJob::StartIPv4JobAsync, + base::Unretained(this))); } return result;
diff --git a/net/websockets/websocket_channel.cc b/net/websockets/websocket_channel.cc index 8e401d3..2119f3c 100644 --- a/net/websockets/websocket_channel.cc +++ b/net/websockets/websocket_channel.cc
@@ -370,9 +370,8 @@ // This use of base::Unretained() is safe because we stop the timer in the // destructor. close_timer_.Start( - FROM_HERE, - closing_handshake_timeout_, - base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this))); + FROM_HERE, closing_handshake_timeout_, + base::BindOnce(&WebSocketChannel::CloseTimeout, base::Unretained(this))); // Javascript actually only permits 1000 and 3000-4999, but the implementation // itself may produce different codes. The length of |reason| is also checked @@ -522,9 +521,8 @@ // WebSocketStream and destroying it cancels all callbacks. result = stream_->WriteFrames( data_being_sent_->frames(), - base::Bind(base::IgnoreResult(&WebSocketChannel::OnWriteDone), - base::Unretained(this), - false)); + base::BindOnce(base::IgnoreResult(&WebSocketChannel::OnWriteDone), + base::Unretained(this), false)); if (result != ERR_IO_PENDING) { if (OnWriteDone(true, result) == CHANNEL_DELETED) return CHANNEL_DELETED; @@ -602,8 +600,8 @@ // destroyed. const int result = stream_->ReadFrames( &read_frames_, - base::Bind(base::IgnoreResult(&WebSocketChannel::OnReadDone), - base::Unretained(this), false)); + base::BindOnce(base::IgnoreResult(&WebSocketChannel::OnReadDone), + base::Unretained(this), false)); if (result == ERR_IO_PENDING) { is_reading_ = true; return CHANNEL_ALIVE; @@ -846,9 +844,9 @@ close_timer_.Stop(); // This use of base::Unretained() is safe because we stop the timer // in the destructor. - close_timer_.Start( - FROM_HERE, underlying_connection_close_timeout_, - base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this))); + close_timer_.Start(FROM_HERE, underlying_connection_close_timeout_, + base::BindOnce(&WebSocketChannel::CloseTimeout, + base::Unretained(this))); // From RFC6455 section 7.1.5: "Each endpoint // will see the status code sent by the other end as _The WebSocket @@ -880,7 +878,7 @@ // in the destructor. close_timer_.Start( FROM_HERE, underlying_connection_close_timeout_, - base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this))); + base::BindOnce(&WebSocketChannel::CloseTimeout, base::Unretained(this))); event_interface_->OnClosingHandshake(); return CHANNEL_ALIVE;
diff --git a/net/websockets/websocket_stream.cc b/net/websockets/websocket_stream.cc index fb78883..607c2f9 100644 --- a/net/websockets/websocket_stream.cc +++ b/net/websockets/websocket_stream.cc
@@ -181,8 +181,8 @@ kHandshakeTimeoutIntervalInSeconds)); timer_ = std::move(timer); timer_->Start(FROM_HERE, timeout, - base::Bind(&WebSocketStreamRequestImpl::OnTimeout, - base::Unretained(this))); + base::BindOnce(&WebSocketStreamRequestImpl::OnTimeout, + base::Unretained(this))); url_request_->Start(); }
diff --git a/net/websockets/websocket_stream_cookie_test.cc b/net/websockets/websocket_stream_cookie_test.cc index 37d5655e..4638839 100644 --- a/net/websockets/websocket_stream_cookie_test.cc +++ b/net/websockets/websocket_stream_cookie_test.cc
@@ -155,9 +155,9 @@ base::nullopt /* server_time */); store->SetCanonicalCookieAsync( std::move(cookie), cookie_url.scheme(), CookieOptions(), - base::Bind(&SetCookieHelperFunction, run_loop.QuitClosure(), - weak_is_called.GetWeakPtr(), - weak_set_cookie_result.GetWeakPtr())); + base::BindOnce(&SetCookieHelperFunction, run_loop.QuitClosure(), + weak_is_called.GetWeakPtr(), + weak_set_cookie_result.GetWeakPtr())); run_loop.Run(); ASSERT_TRUE(is_called); ASSERT_TRUE(set_cookie_result);
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom index 86d7cee2..953e518 100644 --- a/services/network/public/mojom/network_context.mojom +++ b/services/network/public/mojom/network_context.mojom
@@ -609,12 +609,13 @@ // // |window_id| or else |process_id| and |routing_id| indicates the frame // making the request, see network::ResourceRequest::fetch_window_id. - OnCertificateRequested(mojo_base.mojom.UnguessableToken? window_id, - uint32 process_id, - uint32 routing_id, - uint32 request_id, - network.mojom.SSLCertRequestInfo cert_info, - ClientCertificateResponder cert_responder); + OnCertificateRequested( + mojo_base.mojom.UnguessableToken? window_id, + uint32 process_id, + uint32 routing_id, + uint32 request_id, + network.mojom.SSLCertRequestInfo cert_info, + pending_remote<ClientCertificateResponder> cert_responder); // Called when an SSL certificate is encountered. // The callback argument is a net::ERROR value. If it's net::OK, then the
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc index af31dce3..b0f1b08 100644 --- a/services/network/restricted_cookie_manager.cc +++ b/services/network/restricted_cookie_manager.cc
@@ -13,6 +13,7 @@ #include "base/debug/crash_logging.h" #include "base/debug/dump_without_crashing.h" #include "base/memory/weak_ptr.h" +#include "base/metrics/histogram_macros.h" #include "base/sequenced_task_runner.h" #include "base/strings/string_util.h" #include "base/threading/sequenced_task_runner_handle.h" @@ -304,12 +305,29 @@ bool blocked = !cookie_settings_->IsCookieAccessAllowed(url, site_for_cookies, top_frame_origin); - if (blocked) { + CookieInclusionStatus status; + if (blocked) + status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_USER_PREFERENCES); + + // Don't allow URLs with leading dots like https://.some-weird-domain.com + // This probably never happens. + if (!net::cookie_util::DomainIsHostOnly(url.host())) + status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN); + + // Don't allow setting cookies on other domains. + // TODO(crbug.com/996786): This should never happen. This should eventually + // result in a renderer kill, but for now just log metrics. + bool domain_match = cookie.IsDomainMatch(url.host()); + if (!domain_match) + status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH); + UMA_HISTOGRAM_BOOLEAN( + "Net.RestrictedCookieManager.SetCanonicalCookieDomainMatch", + domain_match); + + if (!status.IsInclude()) { if (network_context_client_) { - std::vector<net::CookieWithStatus> result_with_status; - result_with_status.push_back( - {cookie, CookieInclusionStatus( - CookieInclusionStatus::EXCLUDE_USER_PREFERENCES)}); + std::vector<net::CookieWithStatus> result_with_status = { + {cookie, status}}; network_context_client_->OnCookiesChanged( is_service_worker_, process_id_, frame_id_, url, site_for_cookies, result_with_status); @@ -320,6 +338,7 @@ // TODO(pwnall): Validate the CanonicalCookie fields. + // Update the creation and last access times. base::Time now = base::Time::NowFromSystemTime(); auto sanitized_cookie = std::make_unique<net::CanonicalCookie>( cookie.Name(), cookie.Value(), cookie.Domain(), cookie.Path(), now,
diff --git a/services/network/restricted_cookie_manager_unittest.cc b/services/network/restricted_cookie_manager_unittest.cc index 5cc987d..9b9c8818 100644 --- a/services/network/restricted_cookie_manager_unittest.cc +++ b/services/network/restricted_cookie_manager_unittest.cc
@@ -556,6 +556,27 @@ } } +TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieValidateDomain) { + GURL other_site("https://not-example.com"); + auto cookie = net::CanonicalCookie::Create( + other_site, "cookie=foo;domain=not-example.com", base::Time::Now(), + base::nullopt); + ASSERT_EQ(".not-example.com", cookie->Domain()); + EXPECT_FALSE(sync_service_->SetCanonicalCookie( + *cookie, GURL("http://example.com/test"), GURL("http://example.com"))); + ASSERT_EQ(1u, recorded_activity().size()); + EXPECT_TRUE(recorded_activity()[0].status.HasExclusionReason( + net::CanonicalCookie::CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH)); + + auto options = mojom::CookieManagerGetOptions::New(); + options->name = "cookie"; + options->match_type = mojom::CookieMatchType::EQUALS; + std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl( + GURL("http://example.com/test/"), GURL("http://example.com"), + std::move(options)); + EXPECT_THAT(cookies, testing::SizeIs(0)); +} + TEST_P(RestrictedCookieManagerTest, SetCookieFromString) { EXPECT_TRUE(backend()->SetCookieFromString( GURL("http://example.com/test/"), GURL("http://example.com"),
diff --git a/services/network/test/test_network_context_client.h b/services/network/test/test_network_context_client.h index cb09ce5..716ad15 100644 --- a/services/network/test/test_network_context_client.h +++ b/services/network/test/test_network_context_client.h
@@ -43,7 +43,8 @@ uint32_t routing_id, uint32_t request_id, const scoped_refptr<net::SSLCertRequestInfo>& cert_info, - mojom::ClientCertificateResponderPtr client_cert_responder) override {} + mojo::PendingRemote<mojom::ClientCertificateResponder> + client_cert_responder) override {} void OnSSLCertificateError(uint32_t process_id, uint32_t routing_id, const GURL& url,
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc index 7801e34f..ba96f45 100644 --- a/services/network/url_loader.cc +++ b/services/network/url_loader.cc
@@ -351,7 +351,6 @@ keepalive_(request.keepalive), do_not_prompt_for_login_(request.do_not_prompt_for_login), binding_(this, std::move(url_loader_request)), - client_cert_responder_binding_(this), url_loader_client_(std::move(url_loader_client)), writable_handle_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL, @@ -845,7 +844,7 @@ void URLLoader::OnCertificateRequested(net::URLRequest* unused, net::SSLCertRequestInfo* cert_info) { - DCHECK(!client_cert_responder_binding_.is_bound()); + DCHECK(!client_cert_responder_receiver_.is_bound()); if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kIgnoreUrlFetcherCertRequests) && @@ -861,25 +860,20 @@ } // Set up mojo endpoints for ClientCertificateResponder and bind to the - // InterfaceRequest. This enables us to receive messages regarding the client + // Receiver. This enables us to receive messages regarding the client // certificate selection. - mojom::ClientCertificateResponderPtr client_cert_responder; - auto client_cert_responder_request = - mojo::MakeRequest(&client_cert_responder); - client_cert_responder_binding_.Bind(std::move(client_cert_responder_request)); - client_cert_responder_binding_.set_connection_error_handler( - base::BindOnce(&URLLoader::CancelRequest, base::Unretained(this))); - if (fetch_window_id_) { network_context_client_->OnCertificateRequested( fetch_window_id_, -1 /* process_id */, -1 /* routing_id */, request_id_, - cert_info, std::move(client_cert_responder)); + cert_info, client_cert_responder_receiver_.BindNewPipeAndPassRemote()); } else { network_context_client_->OnCertificateRequested( base::nullopt /* window_id */, factory_params_->process_id, render_frame_id_, request_id_, cert_info, - std::move(client_cert_responder)); + client_cert_responder_receiver_.BindNewPipeAndPassRemote()); } + client_cert_responder_receiver_.set_disconnect_handler( + base::BindOnce(&URLLoader::CancelRequest, base::Unretained(this))); } void URLLoader::OnSSLCertificateError(net::URLRequest* request, @@ -1278,7 +1272,7 @@ const std::string& provider_name, const std::vector<uint16_t>& algorithm_preferences, mojom::SSLPrivateKeyPtr ssl_private_key) { - client_cert_responder_binding_.Close(); + client_cert_responder_receiver_.reset(); auto key = base::MakeRefCounted<SSLPrivateKeyInternal>( provider_name, algorithm_preferences, std::move(ssl_private_key)); url_request_->ContinueWithCertificate(std::move(x509_certificate), @@ -1286,12 +1280,12 @@ } void URLLoader::ContinueWithoutCertificate() { - client_cert_responder_binding_.Close(); + client_cert_responder_receiver_.reset(); url_request_->ContinueWithCertificate(nullptr, nullptr); } void URLLoader::CancelRequest() { - client_cert_responder_binding_.Close(); + client_cert_responder_receiver_.reset(); url_request_->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); }
diff --git a/services/network/url_loader.h b/services/network/url_loader.h index 628c0b35..302e469ad 100644 --- a/services/network/url_loader.h +++ b/services/network/url_loader.h
@@ -268,8 +268,8 @@ mojo::Binding<mojom::URLLoader> binding_; mojo::Receiver<mojom::AuthChallengeResponder> auth_challenge_responder_receiver_{this}; - mojo::Binding<mojom::ClientCertificateResponder> - client_cert_responder_binding_; + mojo::Receiver<mojom::ClientCertificateResponder> + client_cert_responder_receiver_{this}; mojom::URLLoaderClientPtr url_loader_client_; int64_t total_written_bytes_ = 0;
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc index 65188d9..352c171f 100644 --- a/services/network/url_loader_unittest.cc +++ b/services/network/url_loader_unittest.cc
@@ -32,6 +32,7 @@ #include "base/time/time.h" #include "build/build_config.h" #include "mojo/public/c/system/data_pipe.h" +#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/cpp/system/data_pipe_utils.h" #include "mojo/public/cpp/system/wait.h" @@ -2628,7 +2629,10 @@ uint32_t routing_id, uint32_t request_id, const scoped_refptr<net::SSLCertRequestInfo>& cert_info, - mojom::ClientCertificateResponderPtr client_cert_responder) override { + mojo::PendingRemote<mojom::ClientCertificateResponder> + client_cert_responder_remote) override { + mojo::Remote<mojom::ClientCertificateResponder> client_cert_responder( + std::move(client_cert_responder_remote)); switch (certificate_response_) { case CertificateResponse::INVALID: NOTREACHED();
diff --git a/services/viz/privileged/mojom/compositing/external_begin_frame_controller.mojom b/services/viz/privileged/mojom/compositing/external_begin_frame_controller.mojom index 408fd57..aa95208 100644 --- a/services/viz/privileged/mojom/compositing/external_begin_frame_controller.mojom +++ b/services/viz/privileged/mojom/compositing/external_begin_frame_controller.mojom
@@ -6,13 +6,13 @@ import "services/viz/public/mojom/compositing/begin_frame_args.mojom"; -// Exposes a way to manually issue BeginFrames to a Display. The client is -// notified when BeginFrames are needed and completed. +// Exposes a way to manually issue BeginFrames to a Display. interface ExternalBeginFrameController { - IssueExternalBeginFrame(BeginFrameArgs args); -}; - -interface ExternalBeginFrameControllerClient { - OnNeedsBeginFrames(bool needs_begin_frames); - OnDisplayDidFinishFrame(BeginFrameAck ack); + // Request a frame. The callback is invoked when frame has either been + // produced or can not be produced at this time. + // If force is set to true, the frame will either begin or fail immediately, + // otherwise the frame will be deferred till one of the frame sinks indicates + // it's interested in a frame. + IssueExternalBeginFrame(BeginFrameArgs args, bool force) + => (BeginFrameAck ack); };
diff --git a/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom b/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom index e5662a6..6bb7afe 100644 --- a/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom +++ b/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom
@@ -40,7 +40,6 @@ DisplayClient display_client; associated ExternalBeginFrameController&? external_begin_frame_controller; - ExternalBeginFrameControllerClient? external_begin_frame_controller_client; }; // The FrameSinkManager interface is a privileged interface that allows the
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 5fe7cad..7697d5f1 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -6282,25 +6282,6 @@ ] } ], - "V8AsmJSToWasm": [ - { - "platforms": [ - "android", - "chromeos", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "AsmJsToWebAssembly", - "enable_features": [ - "AsmJsToWebAssembly" - ] - } - ] - } - ], "V8CacheInlineScriptCode": [ { "platforms": [ @@ -6319,25 +6300,6 @@ ] } ], - "V8Ignition": [ - { - "platforms": [ - "android", - "chromeos", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Future", - "enable_features": [ - "V8Future" - ] - } - ] - } - ], "V8LowMemoryModeForSubframes": [ { "platforms": [
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h index c0aeb41..2b5d114 100644 --- a/third_party/blink/public/platform/web_runtime_features.h +++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -95,6 +95,7 @@ BLINK_PLATFORM_EXPORT static void EnableDatabase(bool); BLINK_PLATFORM_EXPORT static void EnableDecodeLossyWebPImagesToYUV(bool); BLINK_PLATFORM_EXPORT static void EnableDisplayCutoutAPI(bool); + BLINK_PLATFORM_EXPORT static void EnableDocumentPolicy(bool); BLINK_PLATFORM_EXPORT static void EnableFallbackCursorMode(bool); BLINK_PLATFORM_EXPORT static void EnableFastMobileScrolling(bool); BLINK_PLATFORM_EXPORT static void EnableFeaturePolicyForSandbox(bool);
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/attribute.py b/third_party/blink/renderer/bindings/scripts/web_idl/attribute.py index a5d4add..e493966 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/attribute.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/attribute.py
@@ -6,19 +6,21 @@ from .composition_parts import WithCodeGeneratorInfo from .composition_parts import WithComponent from .composition_parts import WithDebugInfo +from .composition_parts import WithExposure from .composition_parts import WithExtendedAttributes from .composition_parts import WithIdentifier from .composition_parts import WithOwner +from .exposure import Exposure from .idl_type import IdlType from .make_copy import make_copy class Attribute(WithIdentifier, WithExtendedAttributes, WithCodeGeneratorInfo, - WithOwner, WithComponent, WithDebugInfo): + WithExposure, WithOwner, WithComponent, WithDebugInfo): """https://heycam.github.io/webidl/#idl-attributes""" class IR(WithIdentifier, WithExtendedAttributes, WithCodeGeneratorInfo, - WithComponent, WithDebugInfo): + WithExposure, WithComponent, WithDebugInfo): def __init__(self, identifier, idl_type, @@ -26,9 +28,7 @@ is_readonly=False, does_inherit_getter=False, extended_attributes=None, - code_generator_info=None, component=None, - components=None, debug_info=None): assert isinstance(idl_type, IdlType) assert isinstance(is_static, bool) @@ -37,9 +37,9 @@ WithIdentifier.__init__(self, identifier) WithExtendedAttributes.__init__(self, extended_attributes) - WithCodeGeneratorInfo.__init__(self, code_generator_info) - WithComponent.__init__( - self, component=component, components=components) + WithCodeGeneratorInfo.__init__(self) + WithExposure.__init__(self) + WithComponent.__init__(self, component=component) WithDebugInfo.__init__(self, debug_info) self.idl_type = idl_type @@ -55,6 +55,7 @@ WithExtendedAttributes.__init__(self, ir.extended_attributes) WithCodeGeneratorInfo.__init__( self, CodeGeneratorInfo(ir.code_generator_info)) + WithExposure.__init__(self, Exposure(ir.exposure)) WithOwner.__init__(self, owner) WithComponent.__init__(self, components=ir.components) WithDebugInfo.__init__(self, ir.debug_info)
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/composition_parts.py b/third_party/blink/renderer/bindings/scripts/web_idl/composition_parts.py index d8bb992f..edc9fc24 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/composition_parts.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/composition_parts.py
@@ -5,6 +5,7 @@ from .code_generator_info import CodeGeneratorInfo from .code_generator_info import CodeGeneratorInfoMutable from .exposure import Exposure +from .exposure import ExposureMutable from .extended_attribute import ExtendedAttributes @@ -52,11 +53,15 @@ class WithExposure(object): - """Implements |exposures| as a readonly attribute.""" + """Implements |exposure| as a readonly attribute.""" - def __init__(self, exposures=None): - # TODO(peria): Design Exposure and this class. - pass + def __init__(self, exposure=None): + assert exposure is None or isinstance(exposure, Exposure) + self._exposure = exposure or ExposureMutable() + + @property + def exposure(self): + return self._exposure class Component(str): @@ -65,8 +70,6 @@ 'core' and 'modules'. """ - pass - class WithComponent(object): """
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/constant.py b/third_party/blink/renderer/bindings/scripts/web_idl/constant.py index c8dd527..1b6c4176b 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/constant.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/constant.py
@@ -6,37 +6,37 @@ from .composition_parts import WithCodeGeneratorInfo from .composition_parts import WithComponent from .composition_parts import WithDebugInfo +from .composition_parts import WithExposure from .composition_parts import WithExtendedAttributes from .composition_parts import WithIdentifier from .composition_parts import WithOwner +from .exposure import Exposure from .idl_type import IdlType from .literal_constant import LiteralConstant from .make_copy import make_copy class Constant(WithIdentifier, WithExtendedAttributes, WithCodeGeneratorInfo, - WithOwner, WithComponent, WithDebugInfo): + WithExposure, WithOwner, WithComponent, WithDebugInfo): """https://heycam.github.io/webidl/#idl-constants""" class IR(WithIdentifier, WithExtendedAttributes, WithCodeGeneratorInfo, - WithComponent, WithDebugInfo): + WithExposure, WithComponent, WithDebugInfo): def __init__(self, identifier, idl_type, value, extended_attributes=None, - code_generator_info=None, component=None, - components=None, debug_info=None): assert isinstance(idl_type, IdlType) assert isinstance(value, LiteralConstant) WithIdentifier.__init__(self, identifier) WithExtendedAttributes.__init__(self, extended_attributes) - WithCodeGeneratorInfo.__init__(self, code_generator_info) - WithComponent.__init__( - self, component=component, components=components) + WithCodeGeneratorInfo.__init__(self) + WithExposure.__init__(self) + WithComponent.__init__(self, component=component) WithDebugInfo.__init__(self, debug_info) self.idl_type = idl_type @@ -50,6 +50,7 @@ WithExtendedAttributes.__init__(self, ir.extended_attributes) WithCodeGeneratorInfo.__init__( self, CodeGeneratorInfo(ir.code_generator_info)) + WithExposure.__init__(self, Exposure(ir.exposure)) WithOwner.__init__(self, owner) WithComponent.__init__(self, components=ir.components) WithDebugInfo.__init__(self, ir.debug_info)
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/dictionary.py b/third_party/blink/renderer/bindings/scripts/web_idl/dictionary.py index b9c2aca5..a2a9aae 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/dictionary.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/dictionary.py
@@ -6,11 +6,13 @@ from .composition_parts import WithCodeGeneratorInfo from .composition_parts import WithComponent from .composition_parts import WithDebugInfo +from .composition_parts import WithExposure from .composition_parts import WithExtendedAttributes from .composition_parts import WithIdentifier from .composition_parts import WithOwner -from .ir_map import IRMap +from .exposure import Exposure from .idl_type import IdlType +from .ir_map import IRMap from .literal_constant import LiteralConstant from .make_copy import make_copy from .reference import RefById @@ -18,20 +20,19 @@ class Dictionary(UserDefinedType, WithExtendedAttributes, - WithCodeGeneratorInfo, WithComponent, WithDebugInfo): + WithCodeGeneratorInfo, WithExposure, WithComponent, + WithDebugInfo): """https://heycam.github.io/webidl/#idl-dictionaries""" class IR(IRMap.IR, WithExtendedAttributes, WithCodeGeneratorInfo, - WithComponent, WithDebugInfo): + WithExposure, WithComponent, WithDebugInfo): def __init__(self, identifier, is_partial, inherited=None, own_members=None, extended_attributes=None, - code_generator_info=None, component=None, - components=None, debug_info=None): assert isinstance(is_partial, bool) assert inherited is None or isinstance(inherited, RefById) @@ -43,15 +44,18 @@ if is_partial else IRMap.IR.Kind.DICTIONARY) IRMap.IR.__init__(self, identifier=identifier, kind=kind) WithExtendedAttributes.__init__(self, extended_attributes) - WithCodeGeneratorInfo.__init__(self, code_generator_info) - WithComponent.__init__( - self, component=component, components=components) + WithCodeGeneratorInfo.__init__(self) + WithExposure.__init__(self) + WithComponent.__init__(self, component=component) WithDebugInfo.__init__(self, debug_info) self.is_partial = is_partial self.inherited = inherited self.own_members = own_members + def iter_all_members(self): + return iter(self.own_members) + def __init__(self, ir): assert isinstance(ir, Dictionary.IR) assert not ir.is_partial @@ -61,6 +65,7 @@ WithExtendedAttributes.__init__(self, ir.extended_attributes) WithCodeGeneratorInfo.__init__( self, CodeGeneratorInfo(ir.code_generator_info)) + WithExposure.__init__(self, Exposure(ir.exposure)) WithComponent.__init__(self, components=ir.components) WithDebugInfo.__init__(self, ir.debug_info) @@ -108,18 +113,16 @@ class DictionaryMember(WithIdentifier, WithExtendedAttributes, - WithCodeGeneratorInfo, WithOwner, WithComponent, - WithDebugInfo): + WithCodeGeneratorInfo, WithExposure, WithOwner, + WithComponent, WithDebugInfo): class IR(WithIdentifier, WithExtendedAttributes, WithCodeGeneratorInfo, - WithComponent, WithDebugInfo): + WithExposure, WithComponent, WithDebugInfo): def __init__(self, identifier, idl_type=None, default_value=None, extended_attributes=None, - code_generator_info=None, component=None, - components=None, debug_info=None): assert isinstance(idl_type, IdlType) assert default_value is None or isinstance(default_value, @@ -128,9 +131,9 @@ WithIdentifier.__init__(self, identifier) WithExtendedAttributes.__init__(self, extended_attributes) - WithCodeGeneratorInfo.__init__(self, code_generator_info) - WithComponent.__init__( - self, component=component, components=components) + WithCodeGeneratorInfo.__init__(self) + WithExposure.__init__(self) + WithComponent.__init__(self, component=component) WithDebugInfo.__init__(self, debug_info) self.idl_type = idl_type @@ -145,6 +148,7 @@ WithExtendedAttributes.__init__(self, ir.extended_attributes) WithCodeGeneratorInfo.__init__( self, CodeGeneratorInfo(ir.code_generator_info)) + WithExposure.__init__(self, Exposure(ir.exposure)) WithOwner.__init__(self, owner) WithComponent.__init__(self, components=ir.components) WithDebugInfo.__init__(self, ir.debug_info)
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/exposure.py b/third_party/blink/renderer/bindings/scripts/web_idl/exposure.py index 903da5f..9ea66a9 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/exposure.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/exposure.py
@@ -2,41 +2,106 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import exceptions -# Exposure is a part of ExtendedAttribute in a concept, but it should be -# accessible from other classes easily. +class _GlobalNameAndFeature(object): + def __init__(self, global_name, feature=None): + assert isinstance(global_name, str) + assert feature is None or isinstance(feature, str) + + self._global_name = global_name + self._feature = feature + + @property + def global_name(self): + return self._global_name + + @property + def feature(self): + return self._feature class Exposure(object): - @property - def global_interfaces(self): - """ - Returns the global interface to be visible in. - @return tuple(Interface) - """ - raise exceptions.NotImplementedError() + def __init__(self, other=None): + assert other is None or isinstance(other, Exposure) + + if other: + self._global_names_and_features = tuple( + other.global_names_and_features) + self._runtime_enabled_features = tuple( + other.runtime_enabled_features) + self._context_enabled_features = tuple( + other.context_enabled_features) + self._only_in_secure_contexts = other.only_in_secure_contexts + else: + self._global_names_and_features = tuple() + self._runtime_enabled_features = tuple() + self._context_enabled_features = tuple() + self._only_in_secure_contexts = False @property - def runtime_enabled_flags(self): + def global_names_and_features(self): """ - Returns a list of runtime enabled featuers. - @return tuple(str) + Returns a list of pairs of global name and runtime enabled feature, + which is None if not applicable. """ - raise exceptions.NotImplementedError() + return self._global_names_and_features @property - def origin_trials(self): + def runtime_enabled_features(self): """ - Returns a list of origin trial features. - @return tuple(str) + Returns a list of runtime enabled features. This construct is exposed + only when these features are enabled. """ - raise exceptions.NotImplementedError() + return self._runtime_enabled_features @property - def is_secure_context(self): + def context_enabled_features(self): """ - Return true if the exposure requires secure context. - @return bool + Returns a list of context enabled features. This construct is exposed + only when these features are enabled in the context. """ - raise exceptions.NotImplementedError() + return self._context_enabled_features + + @property + def only_in_secure_contexts(self): + """ + Returns whether this construct is available only in secure contexts or + not. The returned value will be either of a boolean (always true or + false) or a flag name (only when the flag is enabled). + + https://heycam.github.io/webidl/#dfn-available-only-in-secure-contexts + """ + return self._only_in_secure_contexts + + +class ExposureMutable(Exposure): + def __init__(self): + Exposure.__init__(self) + + self._global_names_and_features = [] + self._runtime_enabled_features = [] + self._context_enabled_features = [] + self._only_in_secure_contexts = False + + def __getstate__(self): + assert False, "ExposureMutable must not be pickled." + + def __setstate__(self, state): + assert False, "ExposureMutable must not be pickled." + + def add_global_name_and_feature(self, global_name, feature_name=None): + self._global_names_and_features.append( + _GlobalNameAndFeature(global_name, feature_name)) + + def add_runtime_enabled_feature(self, name): + assert isinstance(name, str) + self._runtime_enabled_features.append(name) + + def add_context_enabled_feature(self, name): + assert isinstance(name, str) + self._context_enabled_features.append(name) + + def set_only_in_secure_contexts(self, value): + assert isinstance(value, (bool, str)) + assert self._only_in_secure_contexts is False and value is not False + self._only_in_secure_contexts = value
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py b/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py index c940165..89a6971 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py
@@ -106,6 +106,11 @@ self.syntactic_form)) @property + def has_values(self): + return self._format in (self._FORM_NO_ARGS, self._FORM_IDENT, + self._FORM_IDENT_LIST) + + @property def values(self): """ Returns a list of values for format Ident and IdentList. Returns an @@ -121,6 +126,10 @@ self.syntactic_form)) @property + def has_arguments(self): + return self._format in (self._FORM_ARG_LIST, self._FORM_NAMED_ARG_LIST) + + @property def arguments(self): """ Returns a list of value pairs for format ArgList and NamedArgList.
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py index 1db6822..7e4f154 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import functools import itertools from .callback_function import CallbackFunction @@ -101,40 +102,85 @@ return Database(self._db) def _propagate_extattrs_per_idl_fragment(self): + def propagate_extattr(extattr_key_and_attr_name, + bag=None, + default_value=None, + only_to_members_of_partial_or_mixin=True, + ir=None): + """ + Given |extattr_key| and |attr_name|, this function works like below. + + extattr = ir.extended_attributes.get(extattr_key) + ir.exposure.attr_name(extattr's contents) # [1] + + |bag| selects either of code_generator_info or exposure. |apply_to| + defined below performs the second line above [1]. + """ + extattr_key, attr_name = extattr_key_and_attr_name + extattr = ir.extended_attributes.get(extattr_key) + if extattr is None: + return + + def apply_to(x): + set_func = getattr(getattr(x, bag), attr_name) + if extattr.has_values: + for value in extattr.values: + set_func(value) + if not extattr.values and default_value: + set_func(default_value) + elif extattr.has_arguments: + for left, right in extattr.arguments: + set_func(left, right) + else: + assert False + + apply_to(ir) + + if not hasattr(ir, 'iter_all_members'): + return + if (only_to_members_of_partial_or_mixin + and ((hasattr(ir, 'is_partial') and ir.is_partial) or + (hasattr(ir, 'is_mixin') and ir.is_mixin))): + return + for member in ir.iter_all_members(): + apply_to(member) + def process_interface_like(ir): ir = make_copy(ir) - implemented_as = ir.extended_attributes.get('ImplementedAs') - if implemented_as: - ir.code_generator_info.set_receiver_implemented_as( - implemented_as.value) - map(process_member_like, ir.attributes) - map(process_member_like, ir.constants) - map(process_member_like, ir.operations) + propagate = functools.partial(propagate_extattr, ir=ir) + propagate(('ImplementedAs', 'set_receiver_implemented_as'), + bag='code_generator_info', + only_to_members_of_partial_or_mixin=False) + propagate_to_exposure(propagate) + + map(process_member_like, ir.iter_all_members()) self._ir_map.add(ir) - def process_member_like(prop): - implemented_as = prop.extended_attributes.get('ImplementedAs') - if implemented_as: - prop.code_generator_info.set_property_implemented_as( - implemented_as.value) + def process_member_like(ir): + propagate = functools.partial(propagate_extattr, ir=ir) + propagate(('ImplementedAs', 'set_property_implemented_as'), + bag='code_generator_info') + propagate_to_exposure(propagate) - old_interfaces = self._ir_map.find_by_kind(IRMap.IR.Kind.INTERFACE) - old_mixins = self._ir_map.find_by_kind(IRMap.IR.Kind.INTERFACE_MIXIN) - old_partial_interfaces = self._ir_map.find_by_kind( - IRMap.IR.Kind.PARTIAL_INTERFACE) - old_partial_mixins = self._ir_map.find_by_kind( - IRMap.IR.Kind.PARTIAL_INTERFACE_MIXIN) + def propagate_to_exposure(propagate): + propagate = functools.partial(propagate, bag='exposure') + propagate(('Exposed', 'add_global_name_and_feature')) + propagate(('RuntimeEnabled', 'add_runtime_enabled_feature')) + propagate(('ContextEnabled', 'add_context_enabled_feature')) + propagate(('SecureContext', 'set_only_in_secure_contexts'), + default_value=True) + + old_irs = self._ir_map.irs_of_kinds( + IRMap.IR.Kind.INTERFACE, IRMap.IR.Kind.INTERFACE_MIXIN, + IRMap.IR.Kind.DICTIONARY, IRMap.IR.Kind.PARTIAL_INTERFACE, + IRMap.IR.Kind.PARTIAL_INTERFACE_MIXIN, + IRMap.IR.Kind.PARTIAL_DICTIONARY) self._ir_map.move_to_new_phase() - map(process_interface_like, old_interfaces.itervalues()) - map(process_interface_like, old_mixins.itervalues()) - for partials in old_partial_interfaces.itervalues(): - map(process_interface_like, partials) - for partials in old_partial_mixins.itervalues(): - map(process_interface_like, partials) + map(process_interface_like, old_irs) def _merge_partial_interfaces(self): old_interfaces = self._ir_map.find_by_kind(IRMap.IR.Kind.INTERFACE)
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/interface.py b/third_party/blink/renderer/bindings/scripts/web_idl/interface.py index 013c8ea0..5ef3c3c 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/interface.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/interface.py
@@ -7,9 +7,11 @@ from .composition_parts import WithCodeGeneratorInfo from .composition_parts import WithComponent from .composition_parts import WithDebugInfo +from .composition_parts import WithExposure from .composition_parts import WithExtendedAttributes from .composition_parts import WithOwner from .constant import Constant +from .exposure import Exposure from .idl_type import IdlType from .ir_map import IRMap from .make_copy import make_copy @@ -20,11 +22,11 @@ class Interface(UserDefinedType, WithExtendedAttributes, WithCodeGeneratorInfo, - WithComponent, WithDebugInfo): + WithExposure, WithComponent, WithDebugInfo): """https://heycam.github.io/webidl/#idl-interfaces""" class IR(IRMap.IR, WithExtendedAttributes, WithCodeGeneratorInfo, - WithComponent, WithDebugInfo): + WithExposure, WithComponent, WithDebugInfo): def __init__(self, identifier, is_partial, @@ -38,9 +40,7 @@ maplike=None, setlike=None, extended_attributes=None, - code_generator_info=None, component=None, - components=None, debug_info=None): assert isinstance(is_partial, bool) assert isinstance(is_mixin, bool) @@ -79,9 +79,9 @@ kind = IRMap.IR.Kind.INTERFACE IRMap.IR.__init__(self, identifier=identifier, kind=kind) WithExtendedAttributes.__init__(self, extended_attributes) - WithCodeGeneratorInfo.__init__(self, code_generator_info) - WithComponent.__init__( - self, component=component, components=components) + WithCodeGeneratorInfo.__init__(self) + WithExposure.__init__(self) + WithComponent.__init__(self, component=component) WithDebugInfo.__init__(self, debug_info) self.is_partial = is_partial @@ -96,6 +96,14 @@ self.maplike = maplike self.setlike = setlike + def iter_all_members(self): + for attribute in self.attributes: + yield attribute + for constant in self.constants: + yield constant + for operation in self.operations: + yield operation + def __init__(self, ir): assert isinstance(ir, Interface.IR) assert not ir.is_partial @@ -105,6 +113,7 @@ WithExtendedAttributes.__init__(self, ir.extended_attributes) WithCodeGeneratorInfo.__init__( self, CodeGeneratorInfo(ir.code_generator_info)) + WithExposure.__init__(self, Exposure(ir.exposure)) WithComponent.__init__(self, components=ir.components) WithDebugInfo.__init__(self, ir.debug_info)
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/operation.py b/third_party/blink/renderer/bindings/scripts/web_idl/operation.py index 2d6a332a..892cd118 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/operation.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/operation.py
@@ -7,8 +7,10 @@ from .composition_parts import WithCodeGeneratorInfo from .composition_parts import WithComponent from .composition_parts import WithDebugInfo +from .composition_parts import WithExposure from .composition_parts import WithExtendedAttributes from .composition_parts import WithOwner +from .exposure import Exposure from .function_like import FunctionLike from .idl_type import IdlType from .make_copy import make_copy @@ -16,20 +18,18 @@ class Operation(FunctionLike, WithExtendedAttributes, WithCodeGeneratorInfo, - WithOwner, WithComponent, WithDebugInfo): + WithExposure, WithOwner, WithComponent, WithDebugInfo): """https://heycam.github.io/webidl/#idl-operations""" class IR(FunctionLike.IR, WithExtendedAttributes, WithCodeGeneratorInfo, - WithComponent, WithDebugInfo): + WithExposure, WithComponent, WithDebugInfo): def __init__(self, identifier, arguments, return_type, is_static=False, extended_attributes=None, - code_generator_info=None, component=None, - components=None, debug_info=None): FunctionLike.IR.__init__( self, @@ -38,9 +38,9 @@ return_type=return_type, is_static=is_static) WithExtendedAttributes.__init__(self, extended_attributes) - WithCodeGeneratorInfo.__init__(self, code_generator_info) - WithComponent.__init__( - self, component=component, components=components) + WithCodeGeneratorInfo.__init__(self) + WithExposure.__init__(self) + WithComponent.__init__(self, component=component) WithDebugInfo.__init__(self, debug_info) self.is_stringifier = False @@ -52,6 +52,7 @@ WithExtendedAttributes.__init__(self, ir.extended_attributes) WithCodeGeneratorInfo.__init__( self, CodeGeneratorInfo(ir.code_generator_info)) + WithExposure.__init__(self, Exposure(ir.exposure)) WithOwner.__init__(self, owner) WithComponent.__init__(self, components=ir.components) WithDebugInfo.__init__(self, ir.debug_info) @@ -63,8 +64,8 @@ return self._is_stringifier -class OperationGroup(OverloadGroup, WithCodeGeneratorInfo, WithOwner, - WithDebugInfo): +class OperationGroup(OverloadGroup, WithCodeGeneratorInfo, WithExposure, + WithOwner, WithDebugInfo): """ Represents a group of operations with the same identifier. @@ -72,13 +73,15 @@ the operations are overloaded. """ - class IR(OverloadGroup.IR, WithCodeGeneratorInfo, WithDebugInfo): + class IR(OverloadGroup.IR, WithCodeGeneratorInfo, WithExposure, + WithDebugInfo): def __init__(self, operations, code_generator_info=None, debug_info=None): OverloadGroup.IR.__init__(self, operations) WithCodeGeneratorInfo.__init__(self, code_generator_info) + WithExposure.__init__(self) WithDebugInfo.__init__(self, debug_info) def __init__(self, ir, operations, owner): @@ -93,5 +96,6 @@ OverloadGroup.__init__(self, functions=operations) WithCodeGeneratorInfo.__init__( self, CodeGeneratorInfo(ir.code_generator_info)) + WithExposure.__init__(self, Exposure(ir.exposure)) WithOwner.__init__(self, owner) WithDebugInfo.__init__(self, ir.debug_info)
diff --git a/third_party/blink/renderer/controller/blink_leak_detector.cc b/third_party/blink/renderer/controller/blink_leak_detector.cc index 6a5b4fc..16d7fdf 100644 --- a/third_party/blink/renderer/controller/blink_leak_detector.cc +++ b/third_party/blink/renderer/controller/blink_leak_detector.cc
@@ -4,7 +4,7 @@ #include "third_party/blink/renderer/controller/blink_leak_detector.h" -#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h" @@ -33,9 +33,10 @@ BlinkLeakDetector::~BlinkLeakDetector() = default; // static -void BlinkLeakDetector::Create(mojom::blink::LeakDetectorRequest request) { - mojo::MakeStrongBinding(std::make_unique<BlinkLeakDetector>(), - std::move(request)); +void BlinkLeakDetector::Create( + mojo::PendingReceiver<mojom::blink::LeakDetector> receiver) { + mojo::MakeSelfOwnedReceiver(std::make_unique<BlinkLeakDetector>(), + std::move(receiver)); } void BlinkLeakDetector::PerformLeakDetection(
diff --git a/third_party/blink/renderer/controller/blink_leak_detector.h b/third_party/blink/renderer/controller/blink_leak_detector.h index 70756f2..c6d23514 100644 --- a/third_party/blink/renderer/controller/blink_leak_detector.h +++ b/third_party/blink/renderer/controller/blink_leak_detector.h
@@ -5,7 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CONTROLLER_BLINK_LEAK_DETECTOR_H_ #define THIRD_PARTY_BLINK_RENDERER_CONTROLLER_BLINK_LEAK_DETECTOR_H_ -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" #include "third_party/blink/public/mojom/leak_detector/leak_detector.mojom-blink.h" #include "third_party/blink/renderer/controller/controller_export.h" #include "third_party/blink/renderer/platform/heap/handle.h" @@ -16,7 +16,7 @@ // Implementation of Leak Detector. class CONTROLLER_EXPORT BlinkLeakDetector : public mojom::blink::LeakDetector { public: - static void Create(mojom::blink::LeakDetectorRequest); + static void Create(mojo::PendingReceiver<mojom::blink::LeakDetector>); BlinkLeakDetector(); ~BlinkLeakDetector() override;
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc index fea1d799..ce92a0c1 100644 --- a/third_party/blink/renderer/core/animation/animation.cc +++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -51,7 +51,6 @@ #include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/platform/animation/compositor_animation.h" -#include "third_party/blink/renderer/platform/bindings/microtask.h" #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h" #include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/persistent.h" @@ -68,14 +67,10 @@ return ++next; } -double SecondsToMilliseconds(double seconds) { +double ToMilliseconds(double seconds) { return seconds * 1000; } -double MillisecondsToSeconds(double milliseconds) { - return milliseconds / 1000; -} - bool AreEqualOrNull(double a, double b) { // Null values are represented as NaNs, which have the property NaN != NaN. if (IsNull(a) && IsNull(b)) @@ -90,18 +85,6 @@ return value; } -double Max(base::Optional<double> a, double b) { - if (a.has_value()) - return std::max(a.value(), b); - return b; -} - -double Min(base::Optional<double> a, double b) { - if (a.has_value()) - return std::min(a.value(), b); - return b; -} - void RecordCompositorAnimationFailureReasons( CompositorAnimations::FailureReasons failure_reasons) { // UMA_HISTOGRAM_ENUMERATION requires that the enum_max must be strictly @@ -169,6 +152,7 @@ AnimationTimeline* timeline, AnimationEffect* content) : ContextLifecycleObserver(execution_context), + internal_play_state_(kIdle), animation_play_state_(kIdle), playback_rate_(1), start_time_(), @@ -176,18 +160,17 @@ sequence_number_(NextSequenceNumber()), content_(content), timeline_(timeline), + paused_(false), is_paused_for_testing_(false), is_composited_animation_disabled_for_testing_(false), pending_pause_(false), pending_play_(false), - pending_effect_(false), - pending_finish_notification_(false), - has_queued_microtask_(false), outdated_(false), - finished_(false), + finished_(true), compositor_state_(nullptr), compositor_pending_(false), compositor_group_(0), + current_time_pending_(false), state_is_being_updated_(false), effect_suppressed_(false) { if (content_) { @@ -228,8 +211,8 @@ } bool Animation::Limited(double current_time) const { - return (EffectivePlaybackRate() < 0 && current_time <= 0) || - (EffectivePlaybackRate() > 0 && current_time >= EffectEnd()); + return (playback_rate_ < 0 && current_time <= 0) || + (playback_rate_ > 0 && current_time >= EffectEnd()); } Document* Animation::GetDocument() { @@ -249,7 +232,6 @@ return document_->Timeline(); } -// https://drafts.csswg.org/web-animations/#setting-the-current-time-of-an-animation. void Animation::setCurrentTime(double new_current_time, bool is_null, ExceptionState& exception_state) { @@ -263,6 +245,10 @@ return; } + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand); + + // Step 1. of the procedure to silently set the current time of an + // animation states that we abort if the new time is null. if (is_null) { // If the current time is resolved, then throw a TypeError. if (!IsNull(CurrentTimeInternal())) { @@ -272,40 +258,70 @@ return; } - SetCurrentTimeInternal(MillisecondsToSeconds(new_current_time)); + if (PlayStateInternal() == kIdle) + paused_ = true; - // Synchronously resolve pending pause task. - if (pending_pause_) { - hold_time_ = MillisecondsToSeconds(new_current_time); - ApplyPendingPlaybackRate(); - start_time_ = base::nullopt; - pending_pause_ = false; - if (ready_promise_) - ResolvePromiseMaybeAsync(ready_promise_.Get()); - } + current_time_pending_ = false; + internal_play_state_ = kUnset; + SetCurrentTimeInternal(new_current_time / 1000, kTimingUpdateOnDemand); - // Update the finished state. - UpdateFinishedState(UpdateType::kDiscontinuous, NotificationType::kAsync); + if (CalculatePlayState() == kFinished) + start_time_ = CalculateStartTime(new_current_time); } -void Animation::SetCurrentTimeInternal(double new_current_time) { - // Update either the hold time or the start time. - if (hold_time_ || !start_time_ || !timeline_ || !timeline_->IsActive() || - playback_rate_ == 0) +void Animation::SetCurrentTimeInternal(double new_current_time, + TimingUpdateReason reason) { + DCHECK(std::isfinite(new_current_time)); + + bool outdated = false; + bool is_limited = Limited(new_current_time); + bool is_held = paused_ || !playback_rate_ || is_limited || !start_time_; + if (is_held) { + // We only need to update the animation if the seek changes the hold time. + if (!hold_time_ || hold_time_ != new_current_time) + outdated = true; hold_time_ = new_current_time; - else + if (paused_ || !playback_rate_) { + start_time_ = base::nullopt; + } else if (is_limited && !start_time_ && + reason == kTimingUpdateForAnimationFrame) { + start_time_ = CalculateStartTime(new_current_time); + } + } else { + hold_time_ = base::nullopt; start_time_ = CalculateStartTime(new_current_time); + finished_ = false; + outdated = true; + } - // Preserve invariant that we can only set a start time or a hold time in the - // absence of an active timeline. - if (!timeline_ || !timeline_->IsActive()) - start_time_ = base::nullopt; + if (outdated) { + SetOutdated(); + } +} - // Reset the previous current time. - previous_current_time_ = base::nullopt; - - SetOutdated(); - SetCompositorPending(); +// Update timing to reflect updated animation clock due to tick +void Animation::UpdateCurrentTimingState(TimingUpdateReason reason) { + if (internal_play_state_ == kIdle || !timeline_ || !timeline_->IsActive()) + return; + if (hold_time_) { + double new_current_time = hold_time_.value(); + if (internal_play_state_ == kFinished && start_time_ && timeline_) { + // Add hystersis due to floating point error accumulation + if (!Limited(CalculateCurrentTime() + 0.001 * playback_rate_)) { + // The current time became unlimited, eg. due to a backwards + // seek of the timeline. + new_current_time = CalculateCurrentTime(); + } else if (!Limited(hold_time_.value())) { + // The hold time became unlimited, eg. due to the effect + // becoming longer. + new_current_time = + clampTo<double>(CalculateCurrentTime(), 0, EffectEnd()); + } + } + SetCurrentTimeInternal(new_current_time, reason); + } else if (Limited(CalculateCurrentTime())) { + hold_time_ = playback_rate_ < 0 ? 0 : EffectEnd(); + } } double Animation::startTime(bool& is_null) const { @@ -326,19 +342,23 @@ } // https://drafts.csswg.org/web-animations/#the-current-time-of-an-animation -double Animation::currentTime() const { +double Animation::currentTime() { + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand); + // 1. If the animation’s hold time is resolved, // The current time is the animation’s hold time. - if (hold_time_) - return SecondsToMilliseconds(hold_time_.value()); + if (hold_time_.has_value()) + return ToMilliseconds(hold_time_.value()); // 2. If any of the following are true: // * the animation has no associated timeline, or // * the associated timeline is inactive, or // * the animation’s start time is unresolved. // The current time is an unresolved time value. - if (!timeline_ || !timeline_->IsActive() || !start_time_) + if (!timeline_ || !timeline_->IsActive() || PlayStateInternal() == kIdle || + !start_time_) { return NullValue(); + } // 3. Otherwise, // current time = (timeline time - start time) × playback rate @@ -350,30 +370,42 @@ } double current_time = (timeline_time.value() - start_time_.value()) * playback_rate_; - return SecondsToMilliseconds(current_time); + return ToMilliseconds(current_time); } double Animation::CurrentTimeInternal() const { - return hold_time_.value_or(CalculateCurrentTime()); + double result = hold_time_.value_or(CalculateCurrentTime()); +#if DCHECK_IS_ON() + // We can't enforce this check during Unset due to other assertions. + if (internal_play_state_ != kUnset) { + const_cast<Animation*>(this)->UpdateCurrentTimingState( + kTimingUpdateOnDemand); + double hold_or_current_time = hold_time_.value_or(CalculateCurrentTime()); + DCHECK(AreEqualOrNull(result, hold_or_current_time)); + } +#endif + return result; } double Animation::UnlimitedCurrentTimeInternal() const { - AnimationPlayState play_state = CalculateAnimationPlayState(); - return play_state == kPaused || !start_time_ ? CurrentTimeInternal() - : CalculateCurrentTime(); +#if DCHECK_IS_ON() + CurrentTimeInternal(); +#endif + return PlayStateInternal() == kPaused || !start_time_ + ? CurrentTimeInternal() + : CalculateCurrentTime(); } bool Animation::PreCommit( int compositor_group, const PaintArtifactCompositor* paint_artifact_compositor, bool start_on_compositor) { - // Early exit to prevent canceling an animation that is paused for testing. - if (is_paused_for_testing_) - return true; + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand, + kDoNotSetCompositorPending); bool soft_change = compositor_state_ && - (Paused() || compositor_state_->playback_rate != EffectivePlaybackRate()); + (Paused() || compositor_state_->playback_rate != playback_rate_); bool hard_change = compositor_state_ && (compositor_state_->effect_changed || compositor_state_->start_time != start_time_ || @@ -399,10 +431,9 @@ DCHECK(!compositor_state_ || compositor_state_->start_time); - // Apply updates that do not requiring a sync up on a start time. Play-pending - // animations are updated only after receiving a start time notification. - if (!should_start && pending()) - ApplyUpdates(); + if (!should_start) { + current_time_pending_ = false; + } if (should_start) { compositor_group_ = compositor_group; @@ -425,6 +456,9 @@ } void Animation::PostCommit(double timeline_time) { + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand, + kDoNotSetCompositorPending); + compositor_pending_ = false; if (!compositor_state_ || compositor_state_->pending_action == kNone) @@ -438,6 +472,9 @@ } void Animation::NotifyCompositorStartTime(double timeline_time) { + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand, + kDoNotSetCompositorPending); + if (compositor_state_) { DCHECK_EQ(compositor_state_->pending_action, kStart); DCHECK(!compositor_state_->start_time); @@ -455,7 +492,7 @@ // Unlikely, but possible. // FIXME: Depending on what changed above this might still be pending. // Maybe... - ApplyUpdates(timeline_time); + current_time_pending_ = false; return; } @@ -466,7 +503,28 @@ return; } } - ApplyUpdates(timeline_time); + + NotifyStartTime(timeline_time); +} + +void Animation::NotifyStartTime(double timeline_time) { + if (Playing()) { + DCHECK(!start_time_); + DCHECK(hold_time_.has_value()); + + if (playback_rate_ == 0) { + SetStartTimeInternal(timeline_time); + } else { + SetStartTimeInternal(timeline_time + + CurrentTimeInternal() / -playback_rate_); + } + + // FIXME: This avoids marking this animation as outdated needlessly when a + // start time is notified, but we should refactor how outdating works to + // avoid this. + ClearOutdated(); + current_time_pending_ = false; + } } bool Animation::Affects(const Element& element, @@ -518,45 +576,63 @@ return; } + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand); + base::Optional<double> new_start_time; if (!is_null) - new_start_time = MillisecondsToSeconds(start_time); + new_start_time = start_time / 1000; + + // Setting the start time resolves the pending playback rate and cancels any + // pending tasks regardless of whether setting to the current value. + ResetPendingTasks(); + + // Reevaluate the play state, as setting the start time can affect the + // finished state. + current_time_pending_ = false; + internal_play_state_ = kUnset; SetStartTimeInternal(new_start_time); - NotifyProbe(); } void Animation::SetStartTimeInternal(base::Optional<double> new_start_time) { + bool had_start_time = start_time_.has_value(); + double previous_current_time = CurrentTimeInternal(); + // Scroll-linked animations are initialized with the start time of // zero (i.e., scroll origin). // Changing scroll-linked animation start_time initialization is under // consideration here: https://github.com/w3c/csswg-drafts/issues/2075. - if (timeline_ && !timeline_->IsDocumentTimeline()) - new_start_time = 0; + start_time_ = + (!timeline_ || timeline_->IsDocumentTimeline()) ? new_start_time : 0; - double previous_current_time = CurrentTimeInternal(); - bool had_start_time = start_time_.has_value(); + // When we don't have an active timeline it is only possible to set either the + // start time or the current time. Resetting the hold time clears current + // time. + if (!timeline_ && new_start_time.has_value()) + hold_time_ = base::nullopt; - // Update start and hold times. - ApplyPendingPlaybackRate(); - start_time_ = new_start_time; - if (start_time_) { - if (playback_rate_ != 0) - hold_time_ = base::nullopt; - } else { + if (!new_start_time.has_value()) { hold_time_ = ValueOrUnresolved(previous_current_time); + // Explicitly setting the start time to null pauses the animation. This + // prevents the start time from simply being overridden when reevaluating + // the play state. + paused_ = true; + } else if (hold_time_ && playback_rate_) { + // If held, the start time would still be derived from the hold time. + // Force a new, limited, current time. + hold_time_ = base::nullopt; + paused_ = false; + double current_time = CalculateCurrentTime(); + if (playback_rate_ > 0 && current_time > EffectEnd()) { + current_time = EffectEnd(); + } else if (playback_rate_ < 0 && current_time < 0) { + current_time = 0; + } + SetCurrentTimeInternal(current_time, kTimingUpdateOnDemand); } - - // Cancel pending tasks and resolve ready promise. - if (pending_pause_ || pending_play_) { - pending_pause_ = pending_play_ = false; - if (ready_promise_) - ResolvePromiseMaybeAsync(ready_promise_.Get()); - } - - UpdateFinishedState(UpdateType::kDiscontinuous, NotificationType::kAsync); - + UpdateCurrentTimingState(kTimingUpdateOnDemand); double new_current_time = CurrentTimeInternal(); + if (!AreEqualOrNull(previous_current_time, new_current_time)) { SetOutdated(); } else if (!had_start_time && timeline_) { @@ -566,37 +642,34 @@ } } -// https://drafts.csswg.org/web-animations/#setting-the-target-effect void Animation::setEffect(AnimationEffect* new_effect) { if (content_ == new_effect) return; + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand, + kSetCompositorPendingWithEffectChanged); - pending_effect_ = true; + double stored_current_time = CurrentTimeInternal(); if (content_) content_->Detach(); content_ = new_effect; if (new_effect) { // FIXME: This logic needs to be updated once groups are implemented - if (new_effect->GetAnimation()) + if (new_effect->GetAnimation()) { + new_effect->GetAnimation()->cancel(); new_effect->GetAnimation()->setEffect(nullptr); + } new_effect->Attach(this); SetOutdated(); } - - UpdateFinishedState(UpdateType::kContinuous, NotificationType::kAsync); - SetCompositorPending(true); - NotifyProbe(); + if (!IsNull(stored_current_time)) + SetCurrentTimeInternal(stored_current_time, kTimingUpdateOnDemand); } -// ---------------------------------------------- -// Play state methods. -// ---------------------------------------------- - const char* Animation::PlayStateString(AnimationPlayState play_state) { switch (play_state) { case kIdle: return "idle"; - case kPending: // TODO(crbug/958433): remove. + case kPending: return "pending"; case kRunning: return "running"; @@ -610,6 +683,28 @@ } } +Animation::AnimationPlayState Animation::PlayStateInternal() const { + DCHECK_NE(internal_play_state_, kUnset); + return internal_play_state_; +} + +Animation::AnimationPlayState Animation::CalculatePlayState() const { + if (paused_ && !current_time_pending_) + return kPaused; + if (internal_play_state_ == kIdle) + return kIdle; + if (current_time_pending_ || (!start_time_ && playback_rate_ != 0)) + return kPending; + if (Limited()) + return kFinished; + return kRunning; +} + +Animation::AnimationPlayState Animation::GetPlayState() const { + DCHECK_NE(animation_play_state_, kUnset); + return animation_play_state_; +} + // https://drafts.csswg.org/web-animations/#play-states Animation::AnimationPlayState Animation::CalculateAnimationPlayState() const { // 1. All of the following conditions are true: @@ -617,8 +712,7 @@ // * animation does not have either a pending play task or a pending pause // task, // then idle. - double current_time = CurrentTimeInternal(); - if (IsNull(current_time) && !pending_pause_ && !pending_play_) + if (IsNull(CurrentTimeInternal()) && !pending()) return kIdle; // 2. Either of the following conditions are true: @@ -626,11 +720,11 @@ // * both the start time of animation is unresolved and it does not have a // pending play task, // then paused. - // By spec, paused wins out over finished. As a consequence of this ordering, - // animations without active timelines are stuck in the paused state even if - // explicitly calling finish on the animation. - // TODO(crbug.com/967416): Address this edge case in the spec. - if (pending_pause_ || (!start_time_ && !pending_play_)) + // TODO(crbug.com/958433): Presently using a paused_ flag that tracks an + // animation being in a paused state (including a pending pause). The above + // rules do not yet work verbatim due to subtle timing discrepancies on when + // start_time gets resolved. + if (paused_) return kPaused; // 3. For animation, current time is resolved and either of the following @@ -639,41 +733,31 @@ // effect end; or // * animation’s effective playback rate < 0 and current time ≤ 0, // then finished. - if (!IsNull(current_time) && Limited(current_time)) + if (Limited()) return kFinished; // 4. Otherwise return kRunning; } -// ---------------------------------------------- -// Pending task management methods. -// ---------------------------------------------- - bool Animation::pending() const { return pending_pause_ || pending_play_; } // https://drafts.csswg.org/web-animations-1/#reset-an-animations-pending-tasks. -bool Animation::ResetPendingTasks() { - if (!pending()) - return false; - +void Animation::ResetPendingTasks() { + // We use an active playback rate instead of a pending playback rate to + // sidestep complications of maintaining correct sequencing for updating + // properties like current time and start time. Our implementation performs + // calculations based on what will happen rather than waiting on a scheduled + // task to commit the changes. + // TODO(crbug.com/960944): Bring implementation into closer alignment with the + // spec. + active_playback_rate_.reset(); pending_pause_ = false; pending_play_ = false; - ApplyPendingPlaybackRate(); - - if (ready_promise_) - RejectAndResetPromiseMaybeAsync(ready_promise_.Get()); - - return true; } -// ---------------------------------------------- -// Pause methods. -// ---------------------------------------------- - -// https://drafts.csswg.org/web-animations/#pausing-an-animation-section void Animation::pause(ExceptionState& exception_state) { // TODO(crbug.com/916117): Implement pause for scroll-linked animations. if (timeline_ && timeline_->IsScrollTimeline()) { @@ -682,176 +766,93 @@ "Scroll-linked WebAnimation currently does not support pause."); return; } - - if (CalculateAnimationPlayState() == kPaused) + if (paused_) return; - double current_time = CurrentTimeInternal(); + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand); - // Jump to the start of the animation if the current time is unresolved. - if (IsNull(current_time)) { - if (playback_rate_ > 0) { - hold_time_ = 0; - } else { - if (EffectEnd() == std::numeric_limits<double>::infinity()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kInvalidStateError, - "Cannot play reversed Animation with infinite target effect end."); - return; - } - hold_time_ = EffectEnd(); + double new_current_time = CurrentTimeInternal(); + if (CalculatePlayState() == kIdle || IsNull(new_current_time)) { + if (playback_rate_ < 0 && + EffectEnd() == std::numeric_limits<double>::infinity()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "Cannot pause, Animation has infinite target effect end."); + return; } + new_current_time = playback_rate_ < 0 ? EffectEnd() : 0; } - // Cancel pending play task. If there was a pending play task, reuse it's - // pending ready promise. - if (pending_play_) - pending_play_ = false; - else if (ready_promise_) - ready_promise_->Reset(); + internal_play_state_ = kUnset; - // Schedule suspension of the animation. + // We use two paused flags to indicate that the play state is paused, but that + // the pause has not taken affect yet (pending). On the next async update, + // paused will remain in affect, but the pending_pause_ flag will reset. The + // pending pause can be interrupted via another change to the play state ahead + // of the asynchronous update. + // TODO(crbug.com/958433): We should not require the paused_ flag based on the + // algorithm for determining play state in the spec. Currently, timing issues + // prevent direct adoption of the algorithm in the spec. + // (https://drafts.csswg.org/web-animations/#play-states). + paused_ = true; pending_pause_ = true; - SetOutdated(); - SetCompositorPending(false); - NotifyProbe(); - UpdateFinishedState(UpdateType::kContinuous, NotificationType::kAsync); + current_time_pending_ = true; + SetCurrentTimeInternal(new_current_time, kTimingUpdateOnDemand); } -void Animation::CommitPendingPause(double ready_time) { - DCHECK(pending_pause_); - pending_pause_ = false; - if (start_time_ && !hold_time_) - hold_time_ = (ready_time - start_time_.value()) * playback_rate_; - - ApplyPendingPlaybackRate(); - start_time_ = base::nullopt; - - // Resolve pending ready promise. - if (ready_promise_) - ResolvePromiseMaybeAsync(ready_promise_.Get()); - - UpdateFinishedState(UpdateType::kContinuous, NotificationType::kAsync); -} - -// ---------------------------------------------- -// Play methods. -// ---------------------------------------------- - -// Used with CSS animations. void Animation::Unpause() { - if (CalculateAnimationPlayState() != kPaused) + if (!paused_) return; - play(); + + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand); + + current_time_pending_ = true; + UnpauseInternal(); +} + +void Animation::UnpauseInternal() { + if (!paused_) + return; + paused_ = false; + SetCurrentTimeInternal(CurrentTimeInternal(), kTimingUpdateOnDemand); } // https://drafts.csswg.org/web-animations/#playing-an-animation-section void Animation::play(ExceptionState& exception_state) { - PlayInternal(AutoRewind::kEnabled, exception_state); -} + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand); -void Animation::PlayInternal(AutoRewind auto_rewind, - ExceptionState& exception_state) { - // Force an update of the animation state if idle. Handles the special case - // of restarting an animation immediately after canceling. - // TODO(crbug.com/960944): There are still a few unresolved bugs related to - // event propagation and timing immediately after canceling an animation. - // Revisit this forced updated after resolving these issues. - if (CalculateAnimationPlayState() == kIdle) { - SetOutdated(); - Update(kTimingUpdateOnDemand); - } - - bool aborted_pause = pending_pause_; - bool has_pending_ready_promise = false; - double effective_playback_rate = EffectivePlaybackRate(); - double current_time = CurrentTimeInternal(); - - // Update hold time. - if (effective_playback_rate > 0 && auto_rewind == AutoRewind::kEnabled && - (IsNull(current_time) || current_time < 0 || - current_time >= EffectEnd())) { - hold_time_ = 0; - } else if (effective_playback_rate < 0 && - auto_rewind == AutoRewind::kEnabled && - (IsNull(current_time) || current_time <= 0 || - current_time > EffectEnd())) { - if (EffectEnd() == std::numeric_limits<double>::infinity()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kInvalidStateError, - "Cannot play reversed Animation with infinite target effect end."); - return; - } - hold_time_ = EffectEnd(); - } else if (effective_playback_rate == 0 && IsNull(current_time)) { - hold_time_ = 0; - } - - // Cancel pending play and pause tasks. - if (pending_play_ || pending_pause_) { - pending_play_ = pending_pause_ = false; - has_pending_ready_promise = true; - } - - if (!hold_time_ && !aborted_pause && !pending_playback_rate_) + double current_time = this->CurrentTimeInternal(); + if (playback_rate_ < 0 && (current_time <= 0 || IsNull(current_time)) && + EffectEnd() == std::numeric_limits<double>::infinity()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "Cannot play reversed Animation with infinite target effect end."); return; - - if (hold_time_) - start_time_ = base::nullopt; - - // Reuse the pending promise. In the absence of a pending promise, create a - // new one. - if (!has_pending_ready_promise && ready_promise_) - ready_promise_->Reset(); - - // Schedule starting the animation. - pending_play_ = true; - SetOutdated(); - SetCompositorPending(false); - NotifyProbe(); - - UpdateFinishedState(UpdateType::kContinuous, NotificationType::kAsync); -} - -void Animation::CommitPendingPlay(double ready_time) { - DCHECK(start_time_ || hold_time_); - DCHECK(pending_play_); - pending_play_ = false; - - // Update hold and start time. - if (timeline_ && timeline_->IsScrollTimeline()) { - // Special handling for scroll timelines. The start time is always zero - // when the animation is playing. This forces the current time to match the - // timeline time. TODO(crbug.com/916117): Resolve in spec. - start_time_ = 0; - ApplyPendingPlaybackRate(); - if (playback_rate_ != 0) - hold_time_ = base::nullopt; - } else if (hold_time_) { - ApplyPendingPlaybackRate(); - if (playback_rate_ != 0) { - start_time_ = ready_time - hold_time_.value() / playback_rate_; - hold_time_ = base::nullopt; - } else { - start_time_ = ready_time; - } - } else if (start_time_ && pending_playback_rate_) { - double current_time_to_match = - (ready_time - start_time_.value()) * playback_rate_; - ApplyPendingPlaybackRate(); - if (playback_rate_ == 0) - hold_time_ = start_time_ = current_time_to_match; - else - start_time_ = ready_time - current_time_to_match / playback_rate_; } - // Resolve pending ready promise. - if (ready_promise_) - ResolvePromiseMaybeAsync(ready_promise_.Get()); + if (!Playing()) { + start_time_ = base::nullopt; + } - // Update finished state. - UpdateFinishedState(UpdateType::kContinuous, NotificationType::kAsync); + if (PlayStateInternal() == kIdle) { + hold_time_ = 0; + } + + internal_play_state_ = kUnset; + pending_play_ = true; + finished_ = false; + UnpauseInternal(); + + if (playback_rate_ > 0 && (IsNull(current_time) || current_time < 0 || + current_time >= EffectEnd())) { + start_time_ = base::nullopt; + SetCurrentTimeInternal(0, kTimingUpdateOnDemand); + } else if (playback_rate_ < 0 && (IsNull(current_time) || current_time <= 0 || + current_time > EffectEnd())) { + start_time_ = base::nullopt; + SetCurrentTimeInternal(EffectEnd(), kTimingUpdateOnDemand); + } } // https://drafts.csswg.org/web-animations/#reversing-an-animation-section @@ -863,159 +864,97 @@ "Scroll-linked WebAnimation currently does not support reverse."); return; } - - // Verify that the animation is associated with an active timeline. - if (!timeline_ || !timeline_->IsActive()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kInvalidStateError, - "Cannot reverse an animation with no active timeline"); + if (!playback_rate_) { return; } - if (!playback_rate_) - return; + if (!active_playback_rate_.has_value()) { + active_playback_rate_ = playback_rate_; + } - base::Optional<double> original_pending_playback_rate = - pending_playback_rate_; - pending_playback_rate_ = -EffectivePlaybackRate(); + double stored_playback_rate = playback_rate_; + SetPlaybackRateInternal(-playback_rate_); + play(exception_state); - PlayInternal(AutoRewind::kEnabled, exception_state); - - if (exception_state.HadException()) - pending_playback_rate_ = original_pending_playback_rate; + if (exception_state.HadException()) { + SetPlaybackRateInternal(stored_playback_rate); + } } -// ---------------------------------------------- -// Finish methods. -// ---------------------------------------------- - // https://drafts.csswg.org/web-animations/#finishing-an-animation-section void Animation::finish(ExceptionState& exception_state) { - if (!EffectivePlaybackRate()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kInvalidStateError, - "Cannot finish Animation with a playbackRate of 0."); - return; - } - if (EffectivePlaybackRate() > 0 && - EffectEnd() == std::numeric_limits<double>::infinity()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kInvalidStateError, - "Cannot finish Animation with an infinite target effect end."); - return; - } + // Force resolution of PlayStateUpdateScope to enable immediate queuing of + // the finished event. + { + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand); - ApplyPendingPlaybackRate(); + if (!playback_rate_) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "Cannot finish Animation with a playbackRate of 0."); + return; + } + if (playback_rate_ > 0 && + EffectEnd() == std::numeric_limits<double>::infinity()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "Cannot finish Animation with an infinite target effect end."); + return; + } - double new_current_time = playback_rate_ < 0 ? 0 : EffectEnd(); - SetCurrentTimeInternal(new_current_time); + // Avoid updating start time when already finished. + if (CalculatePlayState() == kFinished) + return; - if (!start_time_ && timeline_ && timeline_->IsActive()) + double new_current_time = playback_rate_ < 0 ? 0 : EffectEnd(); + SetCurrentTimeInternal(new_current_time, kTimingUpdateOnDemand); + paused_ = false; + current_time_pending_ = false; start_time_ = CalculateStartTime(new_current_time); - - if (pending_pause_ && start_time_) { - hold_time_ = base::nullopt; - pending_pause_ = false; - if (ready_promise_) - ResolvePromiseMaybeAsync(ready_promise_.Get()); + internal_play_state_ = kFinished; + ResetPendingTasks(); } - if (pending_play_ && start_time_) { - pending_play_ = false; - if (ready_promise_) - ResolvePromiseMaybeAsync(ready_promise_.Get()); - } - - SetOutdated(); - UpdateFinishedState(UpdateType::kDiscontinuous, NotificationType::kSync); -} - -void Animation::UpdateFinishedState(UpdateType update_type, - NotificationType notification_type) { - bool did_seek = update_type == UpdateType::kDiscontinuous; - // 1. Calculate the unconstrained current time. The dependency on did_seek is - // required to accommodate timelines that may change direction. Without this - // distinction, a once-finished animation would remain finished even when its - // timeline progresses in the opposite direction. - double unconstrained_current_time = - did_seek ? CurrentTimeInternal() : CalculateCurrentTime(); - - // 2. Conditionally update the hold time. - if (!IsNull(unconstrained_current_time) && start_time_ && !pending_play_ && - !pending_pause_) { - // Can seek outside the bounds of the active effect. Set the hold time to - // the unconstrained value of the current time in the even that this update - // this the result of explicitly setting the current time and the new time - // is out of bounds. An update due to a time tick should not snap the hold - // value back to the boundary if previously set outside the normal effect - // boundary. The value of previous current time is used to retain this - // value. - double playback_rate = EffectivePlaybackRate(); - if (playback_rate > 0 && unconstrained_current_time >= EffectEnd()) { - hold_time_ = did_seek ? unconstrained_current_time - : Max(previous_current_time_, EffectEnd()); - } else if (playback_rate < 0 && unconstrained_current_time <= 0) { - hold_time_ = did_seek ? unconstrained_current_time - : Min(previous_current_time_, 0); - // Hack for resolving precision issue at zero. - if (hold_time_.value() == -0) - hold_time_ = 0; - } else if (playback_rate != 0) { - // Update start time and reset hold time. - if (did_seek && hold_time_) - start_time_ = CalculateStartTime(hold_time_.value()); - hold_time_ = base::nullopt; - } - } - - // 3. Set the previous current time. - previous_current_time_ = ValueOrUnresolved(CurrentTimeInternal()); - - // 4. Set the current finished state. - AnimationPlayState play_state = CalculateAnimationPlayState(); - - if (play_state == kFinished) { - if (!finished_) { - // 5. Setup finished notification. - pending_finish_notification_ = true; - if (notification_type == NotificationType::kSync) { - ApplyUpdates(); - } else { - ScheduleAsyncFinish(); - } - } - } else { - // 6. If not finished but the current finished promise is already resolved, - // create a new promise. - pending_finish_notification_ = finished_ = false; - if (finished_promise_ && - finished_promise_->GetState() == AnimationPromise::kResolved) { - finished_promise_->Reset(); - } - } -} - -void Animation::CommitFinishNotification() { - DCHECK(pending_finish_notification_); - pending_finish_notification_ = false; - if (finished_) - return; - finished_ = true; - if (finished_promise_ && - finished_promise_->GetState() == AnimationPromise::kPending) { - ResolvePromiseMaybeAsync(finished_promise_.Get()); - } + // Resolve finished event immediately. QueueFinishedEvent(); } +// https://drafts.csswg.org/web-animations/#setting-the-playback-rate-of-an-animation +void Animation::updatePlaybackRate(double playback_rate, + ExceptionState& exception_state) { + // TODO(crbug.com/916117): Implement updatePlaybackRate for scroll-linked + // animations. + if (timeline_ && timeline_->IsScrollTimeline()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kNotSupportedError, + "Scroll-linked WebAnimation currently does not support" + " updatePlaybackRate."); + return; + } + // The implementation differs from the spec; however, the end result is + // consistent. Whereas Animation.playbackRate updates the playback rate + // immediately, updatePlaybackRate is to take effect on the next async cycle. + // From an implementation perspective, the difference lies in what gets + // reported by the playbackRate getter ahead of the async update cycle, as the + // Blink implementation guards against a discontinuity in current time even + // when updating via the playbackRate setter. + double stored_playback_rate = active_playback_rate_.value_or(playback_rate_); + AnimationPlayState play_state = CalculateAnimationPlayState(); + if (play_state == kRunning) + pending_play_ = true; + + setPlaybackRate(playback_rate); + + if (pending()) + active_playback_rate_ = stored_playback_rate; +} + ScriptPromise Animation::finished(ScriptState* script_state) { if (!finished_promise_) { finished_promise_ = MakeGarbageCollected<AnimationPromise>( ExecutionContext::From(script_state), this, AnimationPromise::kFinished); - if (CalculateAnimationPlayState() == kFinished && - !pending_finish_notification_) { + if (PlayStateInternal() == kFinished) finished_promise_->Resolve(this); - } } return finished_promise_->Promise(script_state->World()); } @@ -1024,7 +963,7 @@ if (!ready_promise_) { ready_promise_ = MakeGarbageCollected<AnimationPromise>( ExecutionContext::From(script_state), this, AnimationPromise::kReady); - if (!pending()) + if (PlayStateInternal() != kPending) ready_promise_->Resolve(this); } return ready_promise_->Promise(script_state->World()); @@ -1048,6 +987,8 @@ } void Animation::ContextDestroyed(ExecutionContext*) { + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand); + finished_ = true; pending_finished_event_ = nullptr; } @@ -1058,19 +999,11 @@ return EventTargetWithInlineData::DispatchEventInternal(event); } -// -------------------------------------------------- -// Speed control. -// -------------------------------------------------- - -double Animation::EffectivePlaybackRate() const { - return pending_playback_rate_.value_or(playback_rate_); -} - -void Animation::ApplyPendingPlaybackRate() { - if (pending_playback_rate_) { - playback_rate_ = pending_playback_rate_.value(); - pending_playback_rate_ = base::nullopt; - } +double Animation::playbackRate() const { + // TODO(crbug.com/960944): Deviates from spec implementation, which instead + // uses an 'effective playback rate' to be forward looking and 'playback rate' + // for its current value. + return active_playback_rate_.value_or(playback_rate_); } void Animation::setPlaybackRate(double playback_rate, @@ -1084,64 +1017,40 @@ " playback rate."); return; } + active_playback_rate_.reset(); + if (playback_rate == playback_rate_) + return; + + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand); base::Optional<double> start_time_before = start_time_; - - pending_playback_rate_ = base::nullopt; - double previous_current_time = CurrentTimeInternal(); - playback_rate_ = playback_rate; - if (!IsNull(previous_current_time)) { - setCurrentTime(SecondsToMilliseconds(previous_current_time), false, - exception_state); - } + SetPlaybackRateInternal(playback_rate); // Adds a UseCounter to check if setting playbackRate causes a compensatory // seek forcing a change in start_time_ if (start_time_before && start_time_ != start_time_before && - CalculateAnimationPlayState() != kFinished) { + internal_play_state_ != kFinished) { UseCounter::Count(GetExecutionContext(), WebFeature::kAnimationSetPlaybackRateCompensatorySeek); } - - SetCompositorPending(false); } -// https://drafts.csswg.org/web-animations/#seamlessly-updating-the-playback-rate-of-an-animation -void Animation::updatePlaybackRate(double playback_rate, - ExceptionState& exception_state) { - // TODO(crbug.com/916117): Implement updatePlaybackRate for scroll-linked - // animations. - if (timeline_ && timeline_->IsScrollTimeline()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kNotSupportedError, - "Scroll-linked WebAnimation currently does not support" - " updatePlaybackRate."); - return; - } +void Animation::SetPlaybackRateInternal(double playback_rate) { + DCHECK(std::isfinite(playback_rate)); + DCHECK_NE(playback_rate, playback_rate_); - AnimationPlayState previous_play_state = CalculateAnimationPlayState(); + if (!Limited() && !Paused() && start_time_) + current_time_pending_ = true; - pending_playback_rate_ = playback_rate; - if (pending_play_ || pending_pause_) - return; + double stored_current_time = CurrentTimeInternal(); + if ((playback_rate_ < 0 && playback_rate >= 0) || + (playback_rate_ > 0 && playback_rate <= 0)) + finished_ = false; - switch (previous_play_state) { - case kIdle: - case kPaused: - ApplyPendingPlaybackRate(); - break; - - case kFinished: - start_time_ = (playback_rate == 0) - ? ValueOrUnresolved(TimelineTime()) - : CalculateStartTime(CurrentTimeInternal()); - ApplyPendingPlaybackRate(); - UpdateFinishedState(UpdateType::kContinuous, NotificationType::kAsync); - break; - - default: - PlayInternal(AutoRewind::kDisabled, exception_state); - } + playback_rate_ = playback_rate; + start_time_ = base::nullopt; + if (!IsNull(stored_current_time)) + SetCurrentTimeInternal(stored_current_time, kTimingUpdateOnDemand); } void Animation::ClearOutdated() { @@ -1165,102 +1074,6 @@ TickingTimeline().Wake(); } -// ------------------------------------- -// Updating the state of an animation -// ------------------------------------- - -void Animation::ScheduleAsyncFinish() { - // Run a task to handle the finished promise and event as a microtask. With - // the exception of an explicit call to Animation::finish, it is important to - // apply these updates asynchronously as it is possible to enter the finished - // state temporarily. - if (!has_queued_microtask_) { - Microtask::EnqueueMicrotask( - WTF::Bind(&Animation::AsyncFinishMicrotask, WrapWeakPersistent(this))); - has_queued_microtask_ = true; - } -} - -void Animation::AsyncFinishMicrotask() { - // Resolve the finished promise and queue the finished event only if the - // animation is still in a pending finished state. It is possible that the - // transition was only temporary. - if (pending_finish_notification_) - ApplyUpdates(); - - // This is a once callback and needs to be re-armed. - has_queued_microtask_ = false; -} - -void Animation::ApplyUpdates() { - base::Optional<double> timeline_time; - if (timeline_) - timeline_time = timeline_->CurrentTimeSeconds(); - ApplyUpdates(timeline_time.value_or(NullValue())); -} - -void Animation::ApplyUpdates(double ready_time) { - // Applies all updates to an animation. The state of the animation may change - // between the time that pending updates are triggered and when the updates - // are applied. Thus, flags are used instead of directly queuing callbacks - // to enable validation that the pending state change is still relevant. - // Multiple updates may be applied with the caveat that the pending play and - // pending pause are mutually exclusive. - DCHECK(!(pending_play_ && pending_pause_)); - if (pending_play_) - CommitPendingPlay(ready_time); - else if (pending_pause_) - CommitPendingPause(ready_time); - - ApplyPendingPlaybackRate(); - - if (pending_finish_notification_) - CommitFinishNotification(); - - DCHECK(!pending_play_); - DCHECK(!pending_pause_); - DCHECK(!pending_finish_notification_); - DCHECK(!pending_playback_rate_); - - NotifyProbe(); -} - -void Animation::NotifyProbe() { - AnimationPlayState old_play_state = animation_play_state_; - // 'Pending' is not a true play state for the animation. Dev tools is relying - // on an extended play state. - // TODO(crbug.com/958433): Fix dependency on pending state. - AnimationPlayState new_play_state = - pending() ? kPending : CalculateAnimationPlayState(); - - if (old_play_state != new_play_state) { - probe::AnimationPlayStateChanged(document_, this, old_play_state, - new_play_state); - animation_play_state_ = new_play_state; - - bool was_active = old_play_state == kPending || old_play_state == kRunning; - bool is_active = new_play_state == kPending || new_play_state == kRunning; - - if (!was_active && is_active) { - TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( - "blink.animations,devtools.timeline,benchmark,rail", "Animation", - this, "data", inspector_animation_event::Data(*this)); - } else if (was_active && !is_active) { - TRACE_EVENT_NESTABLE_ASYNC_END1( - "blink.animations,devtools.timeline,benchmark,rail", "Animation", - this, "endData", inspector_animation_state_event::Data(*this)); - } else { - TRACE_EVENT_NESTABLE_ASYNC_INSTANT1( - "blink.animations,devtools.timeline,benchmark,rail", "Animation", - this, "data", inspector_animation_state_event::Data(*this)); - } - } -} - -// -------------------------------------------- -// CompositorAnimations methods -// -------------------------------------------- - CompositorAnimations::FailureReasons Animation::CheckCanStartAnimationOnCompositor( const PaintArtifactCompositor* paint_artifact_compositor) const { @@ -1368,7 +1181,6 @@ if (compositor_pending_ || is_paused_for_testing_) { return; } - // In general, we need to update the compositor-side if anything has changed // on the blink version of the animation. There is also an edge case; if // neither the compositor nor blink side have a start time we still have to @@ -1376,7 +1188,7 @@ // compositor side hadn't started on its side yet, and then the blink side // start time was cleared (e.g. by setting current time). if (!compositor_state_ || compositor_state_->effect_changed || - compositor_state_->playback_rate != EffectivePlaybackRate() || + compositor_state_->playback_rate != playback_rate_ || compositor_state_->start_time != start_time_ || !compositor_state_->start_time || !start_time_) { compositor_pending_ = true; @@ -1397,16 +1209,14 @@ if (!HasActiveAnimationsOnCompositor()) return; if (ToKeyframeEffect(content_.Get()) - ->CancelAnimationOnCompositor(GetCompositorAnimation())) { + ->CancelAnimationOnCompositor(GetCompositorAnimation())) SetCompositorPending(true); - } } void Animation::CancelIncompatibleAnimationsOnCompositor() { - if (content_ && content_->IsKeyframeEffect()) { + if (content_ && content_->IsKeyframeEffect()) ToKeyframeEffect(content_.Get()) ->CancelIncompatibleAnimationsOnCompositor(); - } } bool Animation::HasActiveAnimationsOnCompositor() { @@ -1420,19 +1230,28 @@ if (!timeline_) return false; - ExecutionContext* context = GetExecutionContext(); - if (!context || context->IsContextDestroyed()) - return false; + if (reason == kTimingUpdateForAnimationFrame) { + // Pending tasks are committed when the animation is 'ready'. This can be + // at the time of promise resolution or after a frame tick. Whereas the + // spec calls for creating scheduled tasks to commit pending changes, in the + // Blink implementation, this is an acknowledgment that the changes have + // taken affect. + // TODO(crbug.com/960944): Consider restructuring implementation to more + // closely align with the recommended algorithm in the spec. + ResetPendingTasks(); + } + + PlayStateUpdateScope update_scope(*this, reason, kDoNotSetCompositorPending); ClearOutdated(); - bool idle = CalculateAnimationPlayState() == kIdle; + bool idle = PlayStateInternal() == kIdle; if (content_) { double inherited_time = idle || !timeline_->CurrentTime() ? NullValue() : CurrentTimeInternal(); // Special case for end-exclusivity when playing backwards. - if (inherited_time == 0 && EffectivePlaybackRate() < 0) + if (inherited_time == 0 && playback_rate_ < 0) inherited_time = -1; content_->UpdateInheritedTime(inherited_time, reason); @@ -1445,23 +1264,35 @@ CancelAnimationOnCompositor(); } - bool active = true; - if (reason == kTimingUpdateForAnimationFrame) { - UpdateFinishedState(UpdateType::kContinuous, NotificationType::kAsync); - AnimationPlayState play_state = CalculateAnimationPlayState(); - active = play_state != kFinished && play_state != kIdle; - if (play_state == kFinished && pending_finish_notification_) - ApplyUpdates(); + if ((idle || Limited()) && !finished_) { + if (reason == kTimingUpdateForAnimationFrame && (idle || start_time_)) { + if (idle) { + const AtomicString& event_type = event_type_names::kCancel; + if (GetExecutionContext() && HasEventListeners(event_type)) { + double event_current_time = NullValue(); + // TODO(crbug.com/916117): Handle NaN values for scroll-linked + // animations. + pending_cancelled_event_ = + MakeGarbageCollected<AnimationPlaybackEvent>( + event_type, event_current_time, TimelineTime()); + pending_cancelled_event_->SetTarget(this); + pending_cancelled_event_->SetCurrentTarget(this); + document_->EnqueueAnimationFrameEvent(pending_cancelled_event_); + } + } else { + QueueFinishedEvent(); + } + finished_ = true; + } } - DCHECK(!outdated_); - return active || TimeToEffectChange(); + return !finished_ || TimeToEffectChange(); } void Animation::QueueFinishedEvent() { const AtomicString& event_type = event_type_names::kFinish; if (GetExecutionContext() && HasEventListeners(event_type)) { - double event_current_time = SecondsToMilliseconds(CurrentTimeInternal()); + double event_current_time = CurrentTimeInternal() * 1000; // TODO(crbug.com/916117): Handle NaN values for scroll-linked animations. pending_finished_event_ = MakeGarbageCollected<AnimationPlaybackEvent>( event_type, event_current_time, TimelineTime()); @@ -1494,7 +1325,7 @@ base::Optional<AnimationTimeDelta> Animation::TimeToEffectChange() { DCHECK(!outdated_); - if (!start_time_ || hold_time_ || !playback_rate_) + if (!start_time_ || hold_time_) return base::nullopt; if (!content_) { @@ -1502,60 +1333,28 @@ playback_rate_); } - if (!HasActiveAnimationsOnCompositor() && - content_->GetPhase() == Timing::kPhaseActive) { - return AnimationTimeDelta(); - } - double result = playback_rate_ > 0 ? content_->TimeToForwardsEffectChange() / playback_rate_ : content_->TimeToReverseEffectChange() / -playback_rate_; - if (!std::isfinite(result)) - return base::nullopt; - - return AnimationTimeDelta::FromSecondsD(result); + return !HasActiveAnimationsOnCompositor() && + content_->GetPhase() == Timing::kPhaseActive + ? AnimationTimeDelta() + : AnimationTimeDelta::FromSecondsD(result); } void Animation::cancel() { - AnimationPlayState initial_play_state = CalculateAnimationPlayState(); - if (initial_play_state != kIdle) { - ResetPendingTasks(); - if (finished_promise_) { - if (finished_promise_->GetState() == AnimationPromise::kPending) - RejectAndResetPromiseMaybeAsync(finished_promise_.Get()); - else - finished_promise_->Reset(); - } + PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand); - const AtomicString& event_type = event_type_names::kCancel; - if (GetExecutionContext() && HasEventListeners(event_type)) { - double event_current_time = NullValue(); - // TODO(crbug.com/916117): Handle NaN values for scroll-linked - // animations. - pending_cancelled_event_ = MakeGarbageCollected<AnimationPlaybackEvent>( - event_type, event_current_time, TimelineTime()); - pending_cancelled_event_->SetTarget(this); - pending_cancelled_event_->SetCurrentTarget(this); - document_->EnqueueAnimationFrameEvent(pending_cancelled_event_); - } - } else { - // Quietly reset without rejecting promises. - pending_playback_rate_ = base::nullopt; - pending_pause_ = pending_play_ = false; - } + if (PlayStateInternal() == kIdle) + return; hold_time_ = base::nullopt; + paused_ = false; + internal_play_state_ = kIdle; start_time_ = base::nullopt; - - pending_finish_notification_ = false; - - // Apply changes synchronously. - SetCompositorPending(/*effect_changed=*/false); - SetOutdated(); - ApplyUpdates(); - - // Force dispatch of canceled event. + current_time_pending_ = false; + ResetPendingTasks(); ForceServiceOnNextFrame(); } @@ -1632,6 +1431,118 @@ monotonic_time, group); } +Animation::PlayStateUpdateScope::PlayStateUpdateScope( + Animation& animation, + TimingUpdateReason reason, + CompositorPendingChange compositor_pending_change) + : animation_(animation), + initial_play_state_(animation_->PlayStateInternal()), + compositor_pending_change_(compositor_pending_change) { + DCHECK_NE(initial_play_state_, kUnset); + animation_->BeginUpdatingState(); + animation_->UpdateCurrentTimingState(reason); +} + +Animation::PlayStateUpdateScope::~PlayStateUpdateScope() { + AnimationPlayState old_play_state = initial_play_state_; + AnimationPlayState new_play_state = animation_->CalculatePlayState(); + + // TODO(crbug.com/958433): Phase out internal_play_state_ in favor of the spec + // compliant version. At present, both are needed as the web exposed play + // state cannot simply be inferred from the internal play state. + animation_->internal_play_state_ = new_play_state; + animation_->animation_play_state_ = animation_->CalculateAnimationPlayState(); + if (old_play_state != new_play_state) { + bool was_active = old_play_state == kPending || old_play_state == kRunning; + bool is_active = new_play_state == kPending || new_play_state == kRunning; + if (!was_active && is_active) { + TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( + "blink.animations,devtools.timeline,benchmark,rail", "Animation", + animation_, "data", inspector_animation_event::Data(*animation_)); + } else if (was_active && !is_active) { + TRACE_EVENT_NESTABLE_ASYNC_END1( + "blink.animations,devtools.timeline,benchmark,rail", "Animation", + animation_, "endData", + inspector_animation_state_event::Data(*animation_)); + } else { + TRACE_EVENT_NESTABLE_ASYNC_INSTANT1( + "blink.animations,devtools.timeline,benchmark,rail", "Animation", + animation_, "data", + inspector_animation_state_event::Data(*animation_)); + } + } + + // Ordering is important, the ready promise should resolve/reject before + // the finished promise. + if (animation_->ready_promise_ && new_play_state != old_play_state) { + if (new_play_state == kIdle) { + if (animation_->ready_promise_->GetState() == + AnimationPromise::kPending) { + animation_->RejectAndResetPromiseMaybeAsync( + animation_->ready_promise_.Get()); + } else { + animation_->ready_promise_->Reset(); + } + animation_->ResetPendingTasks(); + animation_->ResolvePromiseMaybeAsync(animation_->ready_promise_.Get()); + } else if (old_play_state == kPending) { + animation_->ResetPendingTasks(); + animation_->ResolvePromiseMaybeAsync(animation_->ready_promise_.Get()); + } else if (new_play_state == kPending) { + DCHECK_NE(animation_->ready_promise_->GetState(), + AnimationPromise::kPending); + animation_->ready_promise_->Reset(); + } + } + + if (animation_->finished_promise_ && new_play_state != old_play_state) { + if (new_play_state == kIdle) { + if (animation_->finished_promise_->GetState() == + AnimationPromise::kPending) { + animation_->RejectAndResetPromiseMaybeAsync( + animation_->finished_promise_.Get()); + } else { + animation_->finished_promise_->Reset(); + } + } else if (new_play_state == kFinished) { + animation_->ResetPendingTasks(); + animation_->ResolvePromiseMaybeAsync(animation_->finished_promise_.Get()); + } else if (old_play_state == kFinished) { + animation_->finished_promise_->Reset(); + } + } + + if (old_play_state != new_play_state && + (old_play_state == kIdle || new_play_state == kIdle)) { + animation_->SetOutdated(); + } + +#if DCHECK_IS_ON() + // Verify that current time is up to date. + animation_->CurrentTimeInternal(); +#endif + + switch (compositor_pending_change_) { + case kSetCompositorPending: + animation_->SetCompositorPending(); + break; + case kSetCompositorPendingWithEffectChanged: + animation_->SetCompositorPending(true); + break; + case kDoNotSetCompositorPending: + break; + default: + NOTREACHED(); + break; + } + animation_->EndUpdatingState(); + + if (old_play_state != new_play_state) { + probe::AnimationPlayStateChanged(animation_->document_, animation_, + old_play_state, new_play_state); + } +} + void Animation::AddedEventListener( const AtomicString& event_type, RegisteredEventListener& registered_listener) { @@ -1642,21 +1553,13 @@ } void Animation::PauseForTesting(double pause_time) { - // Do not restart an animation if already canceled. - if (CalculateAnimationPlayState() == kIdle) - return; - - SetCurrentTimeInternal(pause_time); + SetCurrentTimeInternal(pause_time, kTimingUpdateOnDemand); if (HasActiveAnimationsOnCompositor()) { ToKeyframeEffect(content_.Get()) - ->PauseAnimationForTestingOnCompositor(pause_time); + ->PauseAnimationForTestingOnCompositor(CurrentTimeInternal()); } is_paused_for_testing_ = true; pause(); - // Do not wait for animation ready to lock in the hold time. Otherwise, - // the pause won't take effect until the next frame and the hold time will - // potentially drift. - ApplyUpdates(); } void Animation::SetEffectSuppressed(bool suppressed) { @@ -1688,10 +1591,6 @@ } } -// ------------------------------------ -// Promise resolution -// ------------------------------------ - void Animation::ResolvePromiseMaybeAsync(AnimationPromise* promise) { if (ScriptForbiddenScope::IsScriptForbidden()) { GetExecutionContext()
diff --git a/third_party/blink/renderer/core/animation/animation.h b/third_party/blink/renderer/core/animation/animation.h index 9194ba9e..f859710 100644 --- a/third_party/blink/renderer/core/animation/animation.h +++ b/third_party/blink/renderer/core/animation/animation.h
@@ -73,9 +73,6 @@ USING_GARBAGE_COLLECTED_MIXIN(Animation); public: - // The pending state is not to spec; however, it is currently used for - // worklet-animations and dev tools. - // https://www.w3.org/TR/web-animations-1/#the-animationplaystate-enumeration enum AnimationPlayState { kUnset, kIdle, @@ -125,18 +122,14 @@ void cancel(); double currentTime(bool& is_null); - double currentTime() const; + double currentTime(); void setCurrentTime(double new_current_time, bool is_null, ExceptionState& = ASSERT_NO_EXCEPTION); double UnlimitedCurrentTimeInternal() const; - // https://drafts.csswg.org/web-animations/#play-states - AnimationPlayState CalculateAnimationPlayState() const; static const char* PlayStateString(AnimationPlayState); - String playState() const { - return PlayStateString(CalculateAnimationPlayState()); - } + String playState() const { return PlayStateString(animation_play_state_); } bool pending() const; @@ -151,16 +144,24 @@ ScriptPromise ready(ScriptState*); bool Paused() const { - return CalculateAnimationPlayState() == kPaused && !is_paused_for_testing_; + return GetPlayState() == kPaused && !is_paused_for_testing_; } bool Playing() const override { - return CalculateAnimationPlayState() == kRunning && !Limited() && - !is_paused_for_testing_; + return GetPlayState() == kRunning && !Limited() && !is_paused_for_testing_; } - bool Limited() const { return Limited(CurrentTimeInternal()); } + // Indicates if the animation is out of sync with the compositor. A change to + // the play state (running/paused) requires synchronization with the + // compositor. + bool NeedsCompositorTimeSync() const { + // TODO(crbug.com/958433): Eliminate need for pending play state. + return internal_play_state_ == kPending; + } + AnimationPlayState GetPlayState() const; + + bool Limited() const { return Limited(CurrentTimeInternal()); } bool FinishedInternal() const { return finished_; } DEFINE_ATTRIBUTE_EVENT_LISTENER(finish, kFinish) @@ -171,7 +172,7 @@ bool HasPendingActivity() const final; void ContextDestroyed(ExecutionContext*) override; - double playbackRate() const { return playback_rate_; } + double playbackRate() const; void setPlaybackRate(double, ExceptionState& = ASSERT_NO_EXCEPTION); AnimationTimeline* timeline() { return timeline_; } Document* GetDocument(); @@ -211,7 +212,7 @@ bool HasActiveAnimationsOnCompositor(); void SetCompositorPending(bool effect_changed = false); void NotifyCompositorStartTime(double timeline_time); - + void NotifyStartTime(double timeline_time); // CompositorAnimationClient implementation. CompositorAnimation* GetCompositorAnimation() const override { return compositor_animation_ ? compositor_animation_->GetAnimation() @@ -244,16 +245,20 @@ bool CompositorPendingForTesting() const { return compositor_pending_; } - void CommitAllUpdatesForTesting() { ApplyUpdates(); } - protected: DispatchEventResult DispatchEventInternal(Event&) override; void AddedEventListener(const AtomicString& event_type, RegisteredEventListener&) override; private: + // TODO(crbug.com/960944): Deprecate. This version of the play state is not to + // spec due to the inclusion of a 'pending' state. Whether or not an animation + // is pending is separate from the actual play state. + AnimationPlayState PlayStateInternal() const; + double CurrentTimeInternal() const; - void SetCurrentTimeInternal(double new_current_time); + void SetCurrentTimeInternal(double new_current_time, + TimingUpdateReason = kTimingUpdateOnDemand); void ClearOutdated(); void ForceServiceOnNextFrame(); @@ -267,10 +272,26 @@ double EffectivePlaybackRate() const; void ResolvePendingPlaybackRate(); + // https://drafts.csswg.org/web-animations/#play-states + // Per spec the viable states are: idle, running, paused and finished. + // Our implementation has an additional state called 'pending' which serves a + // similar purpose to micro-tasks in the spec. This additional state is for + // internal flow control only and should not be reported via + // animation.playState. + // TODO(crbug.com/958433): Cleanup implementation to better align with the + // spec. + AnimationPlayState CalculatePlayState() const; + // Spec compliant variant of play state calculation that is reported via + // animation.playState. + AnimationPlayState CalculateAnimationPlayState() const; + base::Optional<double> CalculateStartTime(double current_time) const; double CalculateCurrentTime() const; + void UnpauseInternal(); + void SetPlaybackRateInternal(double); void SetStartTimeInternal(base::Optional<double>); + void UpdateCurrentTimingState(TimingUpdateReason); void BeginUpdatingState(); void EndUpdatingState(); @@ -297,47 +318,28 @@ void QueueFinishedEvent(); - bool ResetPendingTasks(); + void ResetPendingTasks(); double TimelineTime() const; DocumentTimeline& TickingTimeline(); - void ScheduleAsyncFinish(); - void AsyncFinishMicrotask(); - void ApplyUpdates(); - void ApplyUpdates(double ready_time); - void ApplyPendingPlaybackRate(); - - // Updates the finished state of the animation. If the update is the result of - // a discontinuous time change then the value for current time is not bound by - // the limits of the animation. The finished notification may be synchronous - // or asynchronous. A synchronous notification is used in the case of - // explicitly calling finish on an animation. - enum class UpdateType { kContinuous, kDiscontinuous }; - enum class NotificationType { kAsync, kSync }; - void UpdateFinishedState(UpdateType update_context, - NotificationType notification_type); - - // Plays an animation. When auto_rewind is enabled, the current time can be - // adjusted to accommodate reversal of an animation or snapping to an - // endpoint. - enum class AutoRewind { kDisabled, kEnabled }; - void PlayInternal(AutoRewind auto_rewind, ExceptionState& exception_state); - - void CommitPendingPause(double ready_time); - void CommitPendingPlay(double ready_time); - void CommitFinishNotification(); - - // Tracking the state of animations in dev tools. - void NotifyProbe(); - String id_; + // Extended play state with additional pending state for managing timing of + // micro-tasks. + AnimationPlayState internal_play_state_; + // Web exposed play state, which does not have pending state. AnimationPlayState animation_play_state_; double playback_rate_; - base::Optional<double> pending_playback_rate_; + // Playback rate that is currently in effect if differing from playback_rate_. + // When playback_rate_ is modified, the new rate takes effect on the next + // async tick. The currently active value is stored for use by the + // Animation.playbackRate method. + // TODO(crbug.com/960944): Switch to using pending_playback_rate_ once the + // web-animations implementation is more closely aligned with the spec (i.e. + // supports scheduling of pending tasks). + base::Optional<double> active_playback_rate_; base::Optional<double> start_time_; base::Optional<double> hold_time_; - base::Optional<double> previous_current_time_; unsigned sequence_number_; @@ -350,28 +352,22 @@ Member<Document> document_; Member<AnimationTimeline> timeline_; - // Testing flags. + // Reflects all pausing, including via pauseForTesting(). + bool paused_; bool is_paused_for_testing_; bool is_composited_animation_disabled_for_testing_; - // Pending tasks. + // Pending micro-tasks. These flags are used for tracking purposes only for + // the Animation.pending attribute, and do not otherwise affect internal flow + // control. bool pending_pause_; bool pending_play_; - bool pending_effect_; - bool pending_finish_notification_; - bool has_queued_microtask_; // This indicates timing information relevant to the animation's effect - // has changed by means other than the ordinary progression of time. + // has changed by means other than the ordinary progression of time bool outdated_; - // Indicates if completion of the animation has already been handled. Finish - // promises and events should only be rearmed if leaving and re-entering the - // finished state. By spec, we would check if the finished promise is - // pending; however, we only create a finished promise if explicitly requested - // in the executing script. bool finished_; - // Holds a 'finished' event queued for asynchronous dispatch via the // ScriptedAnimationController. This object remains active until the // event is actually dispatched. @@ -407,6 +403,21 @@ kDoNotSetCompositorPending, }; + class PlayStateUpdateScope { + STACK_ALLOCATED(); + + public: + PlayStateUpdateScope(Animation&, + TimingUpdateReason, + CompositorPendingChange = kSetCompositorPending); + ~PlayStateUpdateScope(); + + private: + Member<Animation> animation_; + AnimationPlayState initial_play_state_; + CompositorPendingChange compositor_pending_change_; + }; + // CompositorAnimation objects need to eagerly sever their connection to their // Animation delegate; use a separate 'holder' on-heap object to accomplish // that. @@ -443,6 +454,7 @@ Member<CompositorAnimationHolder> compositor_animation_; + bool current_time_pending_; bool state_is_being_updated_; bool effect_suppressed_;
diff --git a/third_party/blink/renderer/core/animation/animation_test.cc b/third_party/blink/renderer/core/animation/animation_test.cc index e0c625c2..98853f0 100644 --- a/third_party/blink/renderer/core/animation/animation_test.cc +++ b/third_party/blink/renderer/core/animation/animation_test.cc
@@ -164,8 +164,6 @@ } bool SimulateFrame(double time_ms) { - animation->CommitAllUpdatesForTesting(); - animation->Update(kTimingUpdateForAnimationFrame); last_frame_time = time_ms; const auto* paint_artifact_compositor = GetDocument().GetFrame()->View()->GetPaintArtifactCompositor(); @@ -178,7 +176,11 @@ return animation->Update(kTimingUpdateForAnimationFrame); } - void SimulateAwaitReady() { animation->CommitAllUpdatesForTesting(); } + void SimulateAwaitReady() { + // TOOD(crbug/958433): This should trigger a call to the microtask for + // applying updates. + SimulateFrame(last_frame_time); + } Persistent<DocumentTimeline> timeline; Persistent<Animation> animation; @@ -346,33 +348,39 @@ } TEST_F(AnimationAnimationTestNoCompositing, SetStartTimeLimitsAnimation) { + // TODO(crbug/958433): Fix to align with spec. // Setting the start time is a seek operation, which is not constrained by the // normal limits on the animation. animation->setStartTime(-50000, false); EXPECT_EQ("finished", animation->playState()); EXPECT_TRUE(animation->Limited()); - EXPECT_EQ(50000, animation->currentTime()); + // This value is not to spec. Should be 50s. + EXPECT_EQ(30000, animation->currentTime()); animation->setPlaybackRate(-1); EXPECT_EQ("running", animation->playState()); animation->setStartTime(-100000, false); EXPECT_EQ("finished", animation->playState()); - EXPECT_EQ(-100000, animation->currentTime()); + // This value is not to spec. Should be -100s. + EXPECT_EQ(0, animation->currentTime()); EXPECT_TRUE(animation->Limited()); } TEST_F(AnimationAnimationTestNoCompositing, SetStartTimeOnLimitedAnimation) { + // TODO(crbug/958433): Fix to align with spec. // The setStartTime method is a seek and thus not constrained by the normal // limits on the animation. SimulateFrame(30000); animation->setStartTime(-10000, false); EXPECT_EQ("finished", animation->playState()); - EXPECT_EQ(40000, animation->currentTime()); + // This value is not to spec. Should be 40s. + EXPECT_EQ(30000, animation->currentTime()); EXPECT_TRUE(animation->Limited()); animation->setCurrentTime(50000, false); EXPECT_EQ(50000, animation->currentTime()); animation->setStartTime(-40000, false); - EXPECT_EQ(70000, animation->currentTime()); + // This value is not to spec. Should be 70s. + EXPECT_EQ(30000, animation->currentTime()); EXPECT_EQ("finished", animation->playState()); EXPECT_TRUE(animation->Limited()); } @@ -416,13 +424,14 @@ EXPECT_FALSE(animation->startTime()); } -TEST_F(AnimationAnimationTestNoCompositing, RunningWithZeroPlaybackRate) { +TEST_F(AnimationAnimationTestNoCompositing, StartTimeWithZeroPlaybackRate) { animation->setPlaybackRate(0); EXPECT_EQ("running", animation->playState()); + SimulateAwaitReady(); + EXPECT_FALSE(animation->startTime()); SimulateFrame(10000); EXPECT_EQ("running", animation->playState()); - EXPECT_EQ(0, animation->currentTime()); } TEST_F(AnimationAnimationTestNoCompositing, PausePlay) { @@ -613,8 +622,9 @@ NonThrowableExceptionState exception_state; animation->setCurrentTime(40000, false); animation->finish(exception_state); - // Finish should trigger a snap to the upper boundary. - EXPECT_EQ(30000, animation->currentTime()); + // TODO(crbug/958433): This is not to spec. Finish should trigger a snap to + // the upper boundary. + EXPECT_EQ(40000, animation->currentTime()); } TEST_F(AnimationAnimationTestNoCompositing, FinishBeforeStart) { @@ -720,11 +730,13 @@ EXPECT_EQ(30000, animation->currentTime()); EXPECT_TRUE(animation->Limited()); animation->setPlaybackRate(2); + SimulateAwaitReady(); // Already at the end of the animation. SimulateFrame(50000); EXPECT_EQ(30000, animation->currentTime()); animation->setPlaybackRate(-2); + SimulateAwaitReady(); SimulateFrame(60000); EXPECT_FALSE(animation->Limited()); @@ -1325,7 +1337,6 @@ EXPECT_FALSE(is_null); UpdateAllLifecyclePhasesForTest(); - // Verify start and current times in Playing state. EXPECT_EQ(0, scroll_animation->startTime(is_null)); EXPECT_FALSE(is_null);
diff --git a/third_party/blink/renderer/core/animation/compositor_animations.cc b/third_party/blink/renderer/core/animation/compositor_animations.cc index 1dde08b..a3f55f1 100644 --- a/third_party/blink/renderer/core/animation/compositor_animations.cc +++ b/third_party/blink/renderer/core/animation/compositor_animations.cc
@@ -74,10 +74,10 @@ if (&animation == &animation_to_add) return false; - if (animation.pending()) + if (animation.NeedsCompositorTimeSync()) return true; - switch (animation.CalculateAnimationPlayState()) { + switch (animation.GetPlayState()) { case Animation::kIdle: return false; case Animation::kRunning:
diff --git a/third_party/blink/renderer/core/animation/pending_animations.cc b/third_party/blink/renderer/core/animation/pending_animations.cc index ddc76ad8..c202e91 100644 --- a/third_party/blink/renderer/core/animation/pending_animations.cc +++ b/third_party/blink/renderer/core/animation/pending_animations.cc
@@ -77,7 +77,7 @@ started_synchronized_on_compositor = true; } - if (animation->Playing() && animation->pending() && + if (animation->Playing() && !animation->startTime() && animation->timeline() && animation->timeline()->IsActive()) { waiting_for_start_time.push_back(animation.Get()); } @@ -94,7 +94,7 @@ waiting_for_start_time); } else { for (auto& animation : waiting_for_start_time) { - DCHECK(animation->pending()); + DCHECK(!animation->startTime()); // TODO(crbug.com/916117): Handle start time of scroll-linked animations. animation->NotifyCompositorStartTime( animation->timeline()->CurrentTimeSeconds().value_or(0)); @@ -140,9 +140,10 @@ TRACE_EVENT0("blink", "PendingAnimations::notifyCompositorAnimationStarted"); HeapVector<Member<Animation>> animations; animations.swap(waiting_for_compositor_animation_start_); + for (auto animation : animations) { - if (!animation->pending() || !animation->timeline() || - !animation->timeline()->IsActive()) { + if (animation->startTime() || !animation->NeedsCompositorTimeSync() || + !animation->timeline() || !animation->timeline()->IsActive()) { // Already started or no longer relevant. continue; }
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index ec8fd53..380ba3c9 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h
@@ -42,7 +42,6 @@ #include "third_party/blink/public/platform/web_insecure_request_policy.h" #include "third_party/blink/renderer/core/accessibility/axid.h" #include "third_party/blink/renderer/core/core_export.h" -#include "third_party/blink/renderer/core/css/css_property_names.h" #include "third_party/blink/renderer/core/dom/container_node.h" #include "third_party/blink/renderer/core/dom/create_element_flags.h" #include "third_party/blink/renderer/core/dom/document_encoding_data.h" @@ -197,6 +196,7 @@ class WebMouseEvent; class WorkletAnimationController; enum ContentSecurityPolicyDisposition : uint8_t; +enum class CSSPropertyID; struct AnnotatedRegionValue; struct FocusParams; struct IconURL; @@ -1301,6 +1301,7 @@ LocalFrame* ExecutingFrame(); DocumentLifecycle& Lifecycle() { return lifecycle_; } + const DocumentLifecycle& Lifecycle() const { return lifecycle_; } bool IsActive() const { return lifecycle_.IsActive(); } bool IsDetached() const { return lifecycle_.GetState() >= DocumentLifecycle::kStopping;
diff --git a/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.cc b/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.cc index f0dcd0a..af05dba 100644 --- a/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.cc +++ b/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.cc
@@ -26,6 +26,7 @@ #include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h" +#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"
diff --git a/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h b/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h index 2607f47..7aa2c45 100644 --- a/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h +++ b/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h
@@ -27,7 +27,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_CONTEXT_LIFECYCLE_STATE_OBSERVER_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_CONTEXT_LIFECYCLE_STATE_OBSERVER_H_ -#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h" +#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink-forward.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h" #include "third_party/blink/renderer/platform/wtf/assertions.h"
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 2670a2e..4ea6e96 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2414,17 +2414,6 @@ if (auto* owner = frame_view.GetLayoutEmbeddedContent()) owner->SetShouldCheckForPaintInvalidation(); } - if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { - // For pre-CompositeAfterPaint this is done during compositing update. - // This is before PrePaintTreeWalk because it will update main thread - // scrolling reasons. - frame_view.GetScrollableArea()->UpdateCompositorScrollAnimations(); - if (const auto* animating_scrollable_areas = - frame_view.AnimatingScrollableAreas()) { - for (auto scrollable_area : *animating_scrollable_areas) - scrollable_area->UpdateCompositorScrollAnimations(); - } - } }); { @@ -2483,6 +2472,12 @@ paint_artifact_compositor_->NeedsUpdate(); PushPaintArtifactToCompositor(); ForAllNonThrottledLocalFrameViews([this](LocalFrameView& frame_view) { + frame_view.GetScrollableArea()->UpdateCompositorScrollAnimations(); + if (const auto* animating_scrollable_areas = + frame_view.AnimatingScrollableAreas()) { + for (PaintLayerScrollableArea* area : *animating_scrollable_areas) + area->UpdateCompositorScrollAnimations(); + } DocumentAnimations::UpdateAnimations( frame_view.GetLayoutView()->GetDocument(), DocumentLifecycle::kPaintClean, paint_artifact_compositor_.get());
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.cc b/third_party/blink/renderer/core/frame/visual_viewport.cc index 6ba535e..b87ef42 100644 --- a/third_party/blink/renderer/core/frame/visual_viewport.cc +++ b/third_party/blink/renderer/core/frame/visual_viewport.cc
@@ -762,6 +762,10 @@ return GetPage().GetSettings().GetViewportEnabled(); } +const Document* VisualViewport::GetDocument() const { + return MainFrame() ? MainFrame()->GetDocument() : nullptr; +} + CompositorElementId VisualViewport::GetCompositorElementId() const { return element_id_; }
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.h b/third_party/blink/renderer/core/frame/visual_viewport.h index abd3bca..3c92f0d 100644 --- a/third_party/blink/renderer/core/frame/visual_viewport.h +++ b/third_party/blink/renderer/core/frame/visual_viewport.h
@@ -262,6 +262,8 @@ ScrollbarTheme& GetPageScrollbarTheme() const override; bool VisualViewportSuppliesScrollbars() const override; + const Document* GetDocument() const override; + TransformPaintPropertyNode* GetDeviceEmulationTransformNode() const; TransformPaintPropertyNode* GetOverscrollElasticityTransformNode() const; TransformPaintPropertyNode* GetPageScaleNode() const;
diff --git a/third_party/blink/renderer/core/frame/window_post_message_options.idl b/third_party/blink/renderer/core/frame/window_post_message_options.idl index b82c6f7b..d9e0e16c 100644 --- a/third_party/blink/renderer/core/frame/window_post_message_options.idl +++ b/third_party/blink/renderer/core/frame/window_post_message_options.idl
@@ -6,9 +6,6 @@ dictionary WindowPostMessageOptions : PostMessageOptions { USVString targetOrigin = "/"; - [RuntimeEnabled = - UserActivationPostMessageTransfer] boolean transferUserActivation = - false; - [OriginTrialEnabled = - ExperimentalAutoplayDynamicDelegation] DOMString allow = ""; + [RuntimeEnabled=UserActivationPostMessageTransfer] boolean transferUserActivation = false; + [RuntimeEnabled=ExperimentalAutoplayDynamicDelegation] DOMString allow = ""; };
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc index 8757eb61..54e3515 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -1461,8 +1461,9 @@ if (image) canvas2d_bridge_->DrawFullImage(image->PaintImageForCurrentFrame()); - RestoreCanvasMatrixClipStack(canvas2d_bridge_->Canvas()); - canvas2d_bridge_->DidRestoreCanvasMatrixClipStack(canvas2d_bridge_->Canvas()); + RestoreCanvasMatrixClipStack(canvas2d_bridge_->DrawingCanvas()); + canvas2d_bridge_->DidRestoreCanvasMatrixClipStack( + canvas2d_bridge_->DrawingCanvas()); UpdateMemoryUsage(); }
diff --git a/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc b/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc index e87d0861..de72893 100644 --- a/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc
@@ -25,6 +25,7 @@ #include "third_party/blink/renderer/core/html/forms/html_opt_group_element.h" +#include "third_party/blink/renderer/core/css/css_property_names.h" #include "third_party/blink/renderer/core/dom/text.h" #include "third_party/blink/renderer/core/editing/editing_utilities.h" #include "third_party/blink/renderer/core/html/forms/html_select_element.h"
diff --git a/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc b/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc index 25d6390..bc88fa2 100644 --- a/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc +++ b/third_party/blink/renderer/core/html/media/media_remoting_interstitial.cc
@@ -5,6 +5,7 @@ #include "third_party/blink/renderer/core/html/media/media_remoting_interstitial.h" #include "third_party/blink/public/platform/web_localized_string.h" +#include "third_party/blink/renderer/core/css/css_property_names.h" #include "third_party/blink/renderer/core/css_value_keywords.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/html/html_image_element.h"
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl index 1ee3235a..f2d92ea 100644 --- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl +++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -2924,7 +2924,9 @@ command enable # Issued when the target starts or stops needing BeginFrames. - event needsBeginFramesChanged + # Deprecated. Issue beginFrame unconditionally instead and use result from + # beginFrame to detect whether the frames were suppressed. + deprecated event needsBeginFramesChanged parameters # True if BeginFrames are needed, false otherwise. boolean needsBeginFrames
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc index 7fa46d1..d6a595c 100644 --- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc +++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -864,6 +864,14 @@ UseCounter::Count(GetDocument(), WebFeature::kAspectRatioFlexItem); Length flex_basis = FlexBasisForChild(child); + // -webkit-box sizes as fit-content instead of max-content. + if (flex_basis.IsAuto() && + ((StyleRef().Display() == EDisplay::kWebkitBox || + StyleRef().Display() == EDisplay::kWebkitInlineBox) && + (StyleRef().BoxOrient() == EBoxOrient::kHorizontal || + StyleRef().BoxAlign() != EBoxAlignment::kStretch))) { + flex_basis = Length(Length::kFitContent); + } if (MainAxisLengthIsDefinite(child, flex_basis)) { return std::max(LayoutUnit(), ComputeMainAxisExtentForChild( child, kMainOrPreferredSize, flex_basis,
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc index 90c74f3a..34b87d9 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -1511,13 +1511,14 @@ ComputeCanBreakAfter(item_result, auto_wrap_, break_iterator_); } +// Returns whether this item contains only spaces that can hang. bool NGLineBreaker::ShouldHangTraillingSpaces(const NGInlineItem& item) { if (!item.Length()) return false; const ComputedStyle& style = *item.Style(); - if (!auto_wrap_ || (!style.CollapseWhiteSpace() && - style.WhiteSpace() == EWhiteSpace::kBreakSpaces)) + if (!style.AutoWrap() || (!style.CollapseWhiteSpace() && + style.WhiteSpace() == EWhiteSpace::kBreakSpaces)) return false; const String& text = Text();
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc index 1d5c512..2dd7f75 100644 --- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc +++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -269,26 +269,6 @@ if (target_state == DocumentLifecycle::kCompositingInputsClean) return; - // When printing a document, there is no use in updating composited animations - // since we won't use the results. - // - // RuntimeEnabledFeatures::PrintBrowserEnabled is a mode which runs the - // browser normally, but renders every page as if it were being printed. See - // crbug.com/667547 - if (!layout_view_.GetDocument().Printing() || - RuntimeEnabledFeatures::PrintBrowserEnabled()) { - layout_view_.GetFrameView() - ->GetScrollableArea() - ->UpdateCompositorScrollAnimations(); - if (const LocalFrameView::ScrollableAreaSet* animating_scrollable_areas = - layout_view_.GetFrameView()->AnimatingScrollableAreas()) { - for (PaintLayerScrollableArea* scrollable_area : - *animating_scrollable_areas) { - scrollable_area->UpdateCompositorScrollAnimations(); - } - } - } - #if DCHECK_IS_ON() DCHECK_EQ(Lifecycle().GetState(), DocumentLifecycle::kCompositingClean); AssertNoUnresolvedDirtyBits();
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.cc b/third_party/blink/renderer/core/scroll/scrollable_area.cc index 93340f2a..a6d73cb 100644 --- a/third_party/blink/renderer/core/scroll/scrollable_area.cc +++ b/third_party/blink/renderer/core/scroll/scrollable_area.cc
@@ -665,6 +665,12 @@ bool ScrollableArea::ShouldScrollOnMainThread() const { if (GraphicsLayer* layer = LayerForScrolling()) { + // cc::Layer state is set through PaintArtifactCompositor::Update which is + // not run until the paint lifecycle phase. + DCHECK(!GetDocument() || GetDocument()->Lifecycle().GetState() >= + DocumentLifecycle::kInPaint); + // TODO(pdr): There is no need to read this data off the cc::Layer because + // we can query the blink-side property tree instead. uint32_t reasons = layer->CcLayer()->GetMainThreadScrollingReasons(); // Should scroll on main thread unless the reason is the one that is set // by the ScrollAnimator, in which case, the animation can still be @@ -733,6 +739,10 @@ } } +const Document* ScrollableArea::GetDocument() const { + return &GetLayoutBox()->GetDocument(); +} + IntSize ScrollableArea::ClampScrollOffset(const IntSize& scroll_offset) const { return scroll_offset.ShrunkTo(MaximumScrollOffsetInt()) .ExpandedTo(MinimumScrollOffsetInt());
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.h b/third_party/blink/renderer/core/scroll/scrollable_area.h index 3fa87a3e..b4e7e37 100644 --- a/third_party/blink/renderer/core/scroll/scrollable_area.h +++ b/third_party/blink/renderer/core/scroll/scrollable_area.h
@@ -50,6 +50,7 @@ namespace blink { class ChromeClient; class CompositorAnimationTimeline; +class Document; class GraphicsLayer; class LayoutBox; class LayoutObject; @@ -470,6 +471,8 @@ bool HasBeenDisposed() const { return has_been_disposed_; } + virtual const Document* GetDocument() const; + private: FRIEND_TEST_ALL_PREFIXES(ScrollableAreaTest, PopupOverlayScrollbarShouldNotFadeOut);
diff --git a/third_party/blink/renderer/core/scroll/scrolling_test.cc b/third_party/blink/renderer/core/scroll/scrolling_test.cc index 7f74325..08845f8 100644 --- a/third_party/blink/renderer/core/scroll/scrolling_test.cc +++ b/third_party/blink/renderer/core/scroll/scrolling_test.cc
@@ -165,7 +165,7 @@ // Test that the callback of user scroll will be executed when the animation // finishes at ScrollAnimator::TickAnimation for root frame user scroll at both // the layout and visual viewport. -TEST_F(ScrollAnimatorSimTest, TestRootFrameBothViewporsUserScrollCallBack) { +TEST_F(ScrollAnimatorSimTest, TestRootFrameBothViewportsUserScrollCallBack) { GetDocument().GetFrame()->GetSettings()->SetScrollAnimatorEnabled(true); WebView().MainFrameWidget()->Resize(WebSize(800, 500)); SimRequest request("https://example.com/test.html", "text/html");
diff --git a/third_party/blink/renderer/core/svg/svg_use_element.cc b/third_party/blink/renderer/core/svg/svg_use_element.cc index eb92759..a98afa6 100644 --- a/third_party/blink/renderer/core/svg/svg_use_element.cc +++ b/third_party/blink/renderer/core/svg/svg_use_element.cc
@@ -98,7 +98,6 @@ visitor->Trace(y_); visitor->Trace(width_); visitor->Trace(height_); - visitor->Trace(target_element_instance_); visitor->Trace(target_id_observer_); SVGGraphicsElement::Trace(visitor); SVGURIReference::Trace(visitor); @@ -115,15 +114,13 @@ Node::InsertionNotificationRequest SVGUseElement::InsertedInto( ContainerNode& root_parent) { - // This functions exists to assure assumptions made in the code regarding - // SVGElementInstance creation/destruction are satisfied. SVGGraphicsElement::InsertedInto(root_parent); - if (!root_parent.isConnected()) - return kInsertionDone; + if (root_parent.isConnected()) { + InvalidateShadowTree(); #if DCHECK_IS_ON() - DCHECK(!target_element_instance_ || !IsWellFormedDocument(GetDocument())); + DCHECK(!InstanceRoot() || !IsWellFormedDocument(GetDocument())); #endif - InvalidateShadowTree(); + } return kInsertionDone; } @@ -223,11 +220,10 @@ } UpdateRelativeLengthsInformation(); - if (target_element_instance_) { - DCHECK(target_element_instance_->CorrespondingElement()); - TransferUseWidthAndHeightIfNeeded( - *this, *target_element_instance_, - *target_element_instance_->CorrespondingElement()); + if (SVGElement* instance_root = InstanceRoot()) { + DCHECK(instance_root->CorrespondingElement()); + TransferUseWidthAndHeightIfNeeded(*this, *instance_root, + *instance_root->CorrespondingElement()); } if (LayoutObject* object = GetLayoutObject()) @@ -284,13 +280,8 @@ GetDocument().UnscheduleUseShadowTreeUpdate(*this); } -void SVGUseElement::ClearInstanceRoot() { - target_element_instance_ = nullptr; -} - void SVGUseElement::ClearResourceReference() { UnobserveTarget(target_id_observer_); - ClearInstanceRoot(); RemoveAllOutgoingReferences(); } @@ -314,6 +305,12 @@ ->getElementById(element_identifier); } +SVGElement* SVGUseElement::InstanceRoot() const { + if (ShadowTreeRebuildPending()) + return nullptr; + return To<SVGElement>(UseShadowRoot().firstChild()); +} + void SVGUseElement::BuildPendingResource() { // This runs just before computed style is updated, so this SVGUseElement // should always be connected to the Document. It should also not be an @@ -342,9 +339,9 @@ // If there is no <title> child in <use>, we lookup first <title> child in // shadow tree. - if (target_element_instance_) { + if (SVGElement* instance_root = InstanceRoot()) { if (Element* title_element = - Traversal<SVGTitleElement>::FirstChild(*target_element_instance_)) + Traversal<SVGTitleElement>::FirstChild(*instance_root)) return title_element->innerText(); } // Otherwise return a null string. @@ -424,7 +421,7 @@ } void SVGUseElement::AttachShadowTree(SVGElement& target) { - DCHECK(!target_element_instance_); + DCHECK(!InstanceRoot()); DCHECK(!needs_shadow_tree_recreation_); DCHECK(!InUseShadowTree()); @@ -435,9 +432,7 @@ // Set up root SVG element in shadow tree. // Clone the target subtree into the shadow tree, not handling <use> and // <symbol> yet. - target_element_instance_ = CreateInstanceTree(target); - ShadowRoot& shadow_root = UseShadowRoot(); - shadow_root.AppendChild(target_element_instance_); + UseShadowRoot().AppendChild(CreateInstanceTree(target)); AddReferencesToFirstDegreeNestedUseElements(target); @@ -449,19 +444,14 @@ } // Assure shadow tree building was successful. - DCHECK(target_element_instance_); - DCHECK_EQ(target_element_instance_->CorrespondingUseElement(), this); - DCHECK_EQ(target_element_instance_->CorrespondingElement(), &target); + DCHECK(InstanceRoot()); + DCHECK_EQ(InstanceRoot()->CorrespondingUseElement(), this); + DCHECK_EQ(InstanceRoot()->CorrespondingElement(), &target); // Expand all <use> elements in the shadow tree. // Expand means: replace the actual <use> element by what it references. ExpandUseElementsInShadowTree(); - // If the instance root was a <use>, it could have been replaced now, so - // reset |m_targetElementInstance|. - target_element_instance_ = To<SVGElement>(shadow_root.firstChild()); - DCHECK_EQ(target_element_instance_->parentNode(), shadow_root); - PostProcessInstanceTree(); // Update relative length information. @@ -510,8 +500,7 @@ SVGGraphicsElement* SVGUseElement::VisibleTargetGraphicsElementForClipping() const { - auto* svg_graphics_element = - DynamicTo<SVGGraphicsElement>(UseShadowRoot().firstChild()); + auto* svg_graphics_element = DynamicTo<SVGGraphicsElement>(InstanceRoot()); if (!svg_graphics_element) return nullptr; @@ -634,10 +623,15 @@ } } +bool SVGUseElement::ShadowTreeRebuildPending() const { + // The shadow tree is torn down lazily, so check if there's a pending rebuild + // or if we're disconnected from the document. + return !InActiveDocument() || needs_shadow_tree_recreation_; +} + void SVGUseElement::InvalidateShadowTree() { - if (!InActiveDocument() || needs_shadow_tree_recreation_) + if (ShadowTreeRebuildPending()) return; - ClearInstanceRoot(); ScheduleShadowTreeRecreation(); InvalidateDependentShadowTrees(); } @@ -661,11 +655,8 @@ width_->CurrentValue()->IsRelative() || height_->CurrentValue()->IsRelative()) return true; - - if (!target_element_instance_) - return false; - - return target_element_instance_->HasRelativeLengths(); + SVGElement* instance_root = InstanceRoot(); + return instance_root && instance_root->HasRelativeLengths(); } FloatRect SVGUseElement::GetBBox() {
diff --git a/third_party/blink/renderer/core/svg/svg_use_element.h b/third_party/blink/renderer/core/svg/svg_use_element.h index abb15090..391a808 100644 --- a/third_party/blink/renderer/core/svg/svg_use_element.h +++ b/third_party/blink/renderer/core/svg/svg_use_element.h
@@ -22,6 +22,8 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_USE_ELEMENT_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_USE_ELEMENT_H_ +#include "base/gtest_prod_util.h" +#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/loader/resource/document_resource.h" #include "third_party/blink/renderer/core/svg/svg_animated_length.h" #include "third_party/blink/renderer/core/svg/svg_geometry_element.h" @@ -89,6 +91,7 @@ bool HaveLoadedRequiredResources() override { return !IsStructurallyExternal() || have_fired_load_event_; } + bool ShadowTreeRebuildPending() const; bool SelfHasRelativeLengths() const override; @@ -105,7 +108,7 @@ Element* ResolveTargetElement(ObserveBehavior); void AttachShadowTree(SVGElement& target); void DetachShadowTree(); - void ClearInstanceRoot(); + CORE_EXPORT SVGElement* InstanceRoot() const; SVGElement* CreateInstanceTree(SVGElement& target_root) const; void ClearResourceReference(); bool HasCycleUseReferencing(const ContainerNode& target_instance, @@ -132,8 +135,14 @@ bool element_url_is_local_; bool have_fired_load_event_; bool needs_shadow_tree_recreation_; - Member<SVGElement> target_element_instance_; Member<IdTargetObserver> target_id_observer_; + + FRIEND_TEST_ALL_PREFIXES(SVGUseElementTest, + NullInstanceRootWhenNotConnectedToDocument); + FRIEND_TEST_ALL_PREFIXES(SVGUseElementTest, + NullInstanceRootWhenConnectedToInactiveDocument); + FRIEND_TEST_ALL_PREFIXES(SVGUseElementTest, + NullInstanceRootWhenShadowTreePendingRebuild); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/svg/svg_use_element_test.cc b/third_party/blink/renderer/core/svg/svg_use_element_test.cc index 7e47765..e2f0b67 100644 --- a/third_party/blink/renderer/core/svg/svg_use_element_test.cc +++ b/third_party/blink/renderer/core/svg/svg_use_element_test.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/core/svg/svg_element.h" +#include "third_party/blink/renderer/core/dom/dom_implementation.h" #include "third_party/blink/renderer/core/dom/shadow_root.h" #include "third_party/blink/renderer/core/html/html_element.h" #include "third_party/blink/renderer/core/svg/svg_use_element.h" @@ -74,4 +75,66 @@ ASSERT_FALSE(use->GetShadowRoot()->getElementById("target")); } +TEST_F(SVGUseElementTest, NullInstanceRootWhenNotConnectedToDocument) { + GetDocument().body()->SetInnerHTMLFromString(R"HTML( + <svg> + <defs> + <rect id="r" width="100" height="100" fill="blue"/> + </defs> + <use id="target" href="#r"/> + </svg> + )HTML"); + GetDocument().View()->UpdateAllLifecyclePhases(LifecycleUpdateReason::kTest); + + auto* target = To<SVGUseElement>(GetDocument().getElementById("target")); + ASSERT_TRUE(target); + ASSERT_TRUE(target->InstanceRoot()); + + target->remove(); + + ASSERT_FALSE(target->InstanceRoot()); +} + +TEST_F(SVGUseElementTest, NullInstanceRootWhenConnectedToInactiveDocument) { + GetDocument().body()->SetInnerHTMLFromString(R"HTML( + <svg> + <defs> + <rect id="r" width="100" height="100" fill="blue"/> + </defs> + <use id="target" href="#r"/> + </svg> + )HTML"); + GetDocument().View()->UpdateAllLifecyclePhases(LifecycleUpdateReason::kTest); + + auto* target = To<SVGUseElement>(GetDocument().getElementById("target")); + ASSERT_TRUE(target); + ASSERT_TRUE(target->InstanceRoot()); + + Document* other_document = + GetDocument().implementation().createHTMLDocument(); + other_document->body()->appendChild(target); + + ASSERT_FALSE(target->InstanceRoot()); +} + +TEST_F(SVGUseElementTest, NullInstanceRootWhenShadowTreePendingRebuild) { + GetDocument().body()->SetInnerHTMLFromString(R"HTML( + <svg> + <defs> + <rect id="r" width="100" height="100" fill="blue"/> + </defs> + <use id="target" href="#r"/> + </svg> + )HTML"); + GetDocument().View()->UpdateAllLifecyclePhases(LifecycleUpdateReason::kTest); + + auto* target = To<SVGUseElement>(GetDocument().getElementById("target")); + ASSERT_TRUE(target); + ASSERT_TRUE(target->InstanceRoot()); + + GetDocument().getElementById("r")->setAttribute(html_names::kWidthAttr, "50"); + + ASSERT_FALSE(target->InstanceRoot()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/battery/battery_manager.cc b/third_party/blink/renderer/modules/battery/battery_manager.cc index 25c3e42..ca879108 100644 --- a/third_party/blink/renderer/modules/battery/battery_manager.cc +++ b/third_party/blink/renderer/modules/battery/battery_manager.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/modules/battery/battery_manager.h" +#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/dom/events/event.h"
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc index 6122da1..5df98e9f 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
@@ -441,7 +441,7 @@ if (isContextLost()) return nullptr; if (canvas()->GetOrCreateCanvas2DLayerBridge()) - return canvas()->GetCanvas2DLayerBridge()->Canvas(); + return canvas()->GetCanvas2DLayerBridge()->DrawingCanvas(); return nullptr; } @@ -449,7 +449,7 @@ if (isContextLost()) return nullptr; if (IsPaintable()) - return canvas()->GetCanvas2DLayerBridge()->Canvas(); + return canvas()->GetCanvas2DLayerBridge()->DrawingCanvas(); return nullptr; }
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc index b1f3f196..4f9835f 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
@@ -724,7 +724,8 @@ size, CanvasColorParams(), kPreferNoAcceleration); fake_deaccelerate_surface->SetCanvasResourceHost(&host); - cc::PaintCanvas* paint_canvas_ptr = fake_deaccelerate_surface->Canvas(); + cc::PaintCanvas* paint_canvas_ptr = + fake_deaccelerate_surface->DrawingCanvas(); FakeCanvas2DLayerBridge* surface_ptr = fake_deaccelerate_surface.get(); EXPECT_CALL(*fake_deaccelerate_surface, DrawFullImage(_)).Times(1);
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.cc index 8303ae3..2079c2a 100644 --- a/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.cc +++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.h" +#include "third_party/blink/renderer/core/css/css_property_names.h" #include "third_party/blink/renderer/core/css_value_keywords.h" #include "third_party/blink/renderer/core/dom/shadow_root.h" #include "third_party/blink/renderer/core/html/html_style_element.h"
diff --git a/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.cc b/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.cc index c86663a..1af6516 100644 --- a/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.cc +++ b/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.cc
@@ -310,11 +310,10 @@ void ApplyConstraintsProcessor::ApplyConstraintsSucceeded() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); task_runner_->PostTask( - FROM_HERE, - WTF::Bind(&ApplyConstraintsProcessor::CleanupRequest, - WrapWeakPersistent(this), - WTF::Bind(&RequestSucceeded, - WrapWeakPersistent(current_request_.Get())))); + FROM_HERE, WTF::Bind(&ApplyConstraintsProcessor::CleanupRequest, + WrapWeakPersistent(this), + WTF::Bind(&RequestSucceeded, + WrapPersistent(current_request_.Get())))); } void ApplyConstraintsProcessor::ApplyConstraintsFailed( @@ -324,7 +323,7 @@ FROM_HERE, WTF::Bind( &ApplyConstraintsProcessor::CleanupRequest, WrapWeakPersistent(this), - WTF::Bind(&RequestFailed, WrapWeakPersistent(current_request_.Get()), + WTF::Bind(&RequestFailed, WrapPersistent(current_request_.Get()), String(failed_constraint_name), String("Cannot satisfy constraints")))); } @@ -335,7 +334,7 @@ FROM_HERE, WTF::Bind( &ApplyConstraintsProcessor::CleanupRequest, WrapWeakPersistent(this), - WTF::Bind(&RequestFailed, WrapWeakPersistent(current_request_.Get()), + WTF::Bind(&RequestFailed, WrapPersistent(current_request_.Get()), String(), message))); }
diff --git a/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.h b/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.h index 185bf2c..96933f41 100644 --- a/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.h +++ b/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.h
@@ -82,7 +82,7 @@ // contains the request currently being processed, if any. // |video_source_| and |request_completed_cb_| are the video source and // reply callback for the current request. - WeakMember<blink::ApplyConstraintsRequest> current_request_; + Member<blink::ApplyConstraintsRequest> current_request_; // TODO(crbug.com/704136): Change to use Member. blink::MediaStreamVideoSource* video_source_ = nullptr;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc index 4bbd200..816939f 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
@@ -218,7 +218,7 @@ buffered_amount_(0U), stopped_(false), observer_(base::MakeRefCounted<Observer>( - context->GetTaskRunner(TaskType::kInternalMedia), + context->GetTaskRunner(TaskType::kNetworking), this, channel)) { DCHECK(peer_connection_handler);
diff --git a/third_party/blink/renderer/modules/quota/deprecated_storage_quota.cc b/third_party/blink/renderer/modules/quota/deprecated_storage_quota.cc index e422eaf..c7bbd67 100644 --- a/third_party/blink/renderer/modules/quota/deprecated_storage_quota.cc +++ b/third_party/blink/renderer/modules/quota/deprecated_storage_quota.cc
@@ -152,7 +152,7 @@ WrapPersistent(success_callback), WrapPersistent(error_callback)); GetQuotaHost(execution_context) - .QueryStorageUsageAndQuota( + ->QueryStorageUsageAndQuota( WrapRefCounted(security_origin), storage_type, mojo::WrapCallbackWithDefaultInvokeIfNotRun( std::move(callback), mojom::QuotaStatusCode::kErrorAbort, 0, 0, @@ -188,22 +188,21 @@ } GetQuotaHost(&execution_context) - .RequestStorageQuota( + ->RequestStorageQuota( WrapRefCounted(security_origin), storage_type, new_quota_in_bytes, mojo::WrapCallbackWithDefaultInvokeIfNotRun( std::move(callback), mojom::QuotaStatusCode::kErrorAbort, 0, 0)); } -mojom::blink::QuotaDispatcherHost& DeprecatedStorageQuota::GetQuotaHost( +mojom::blink::QuotaDispatcherHost* DeprecatedStorageQuota::GetQuotaHost( ExecutionContext* execution_context) { if (!quota_host_) { ConnectToQuotaDispatcherHost( execution_context, - mojo::MakeRequest("a_host_, - execution_context->GetTaskRunner( - blink::TaskType::kInternalDefault))); + quota_host_.BindNewPipeAndPassReceiver(execution_context->GetTaskRunner( + blink::TaskType::kInternalDefault))); } - return *quota_host_; + return quota_host_.get(); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/quota/deprecated_storage_quota.h b/third_party/blink/renderer/modules/quota/deprecated_storage_quota.h index 4f0661b..d957a33 100644 --- a/third_party/blink/renderer/modules/quota/deprecated_storage_quota.h +++ b/third_party/blink/renderer/modules/quota/deprecated_storage_quota.h
@@ -31,6 +31,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_DEPRECATED_STORAGE_QUOTA_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_DEPRECATED_STORAGE_QUOTA_H_ +#include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/public/mojom/quota/quota_dispatcher_host.mojom-blink.h" #include "third_party/blink/renderer/platform/bindings/exception_code.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" @@ -71,10 +72,10 @@ private: // Binds the interface (if not already bound) with the given interface // provider, and returns it, - mojom::blink::QuotaDispatcherHost& GetQuotaHost(ExecutionContext*); + mojom::blink::QuotaDispatcherHost* GetQuotaHost(ExecutionContext*); Type type_; - mojom::blink::QuotaDispatcherHostPtr quota_host_; + mojo::Remote<mojom::blink::QuotaDispatcherHost> quota_host_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/quota/quota_utils.cc b/third_party/blink/renderer/modules/quota/quota_utils.cc index 835d498d..a62f8d9 100644 --- a/third_party/blink/renderer/modules/quota/quota_utils.cc +++ b/third_party/blink/renderer/modules/quota/quota_utils.cc
@@ -11,9 +11,9 @@ void ConnectToQuotaDispatcherHost( ExecutionContext* execution_context, - mojom::blink::QuotaDispatcherHostRequest request) { + mojo::PendingReceiver<mojom::blink::QuotaDispatcherHost> receiver) { if (auto* interface_provider = execution_context->GetInterfaceProvider()) - interface_provider->GetInterface(std::move(request)); + interface_provider->GetInterface(std::move(receiver)); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/quota/quota_utils.h b/third_party/blink/renderer/modules/quota/quota_utils.h index 4bfae73..1fcb3f16 100644 --- a/third_party/blink/renderer/modules/quota/quota_utils.h +++ b/third_party/blink/renderer/modules/quota/quota_utils.h
@@ -5,14 +5,16 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_QUOTA_UTILS_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_QUOTA_UTILS_H_ +#include "mojo/public/cpp/bindings/pending_receiver.h" #include "third_party/blink/public/mojom/quota/quota_dispatcher_host.mojom-blink.h" namespace blink { class ExecutionContext; -void ConnectToQuotaDispatcherHost(ExecutionContext*, - mojom::blink::QuotaDispatcherHostRequest); +void ConnectToQuotaDispatcherHost( + ExecutionContext*, + mojo::PendingReceiver<mojom::blink::QuotaDispatcherHost>); } // namespace blink
diff --git a/third_party/blink/renderer/modules/quota/storage_manager.cc b/third_party/blink/renderer/modules/quota/storage_manager.cc index 8b2e76d..7f487fb 100644 --- a/third_party/blink/renderer/modules/quota/storage_manager.cc +++ b/third_party/blink/renderer/modules/quota/storage_manager.cc
@@ -143,7 +143,7 @@ auto callback = WTF::Bind(&QueryStorageUsageAndQuotaCallback, WrapPersistent(resolver)); GetQuotaHost(execution_context) - .QueryStorageUsageAndQuota( + ->QueryStorageUsageAndQuota( WrapRefCounted(security_origin), mojom::StorageType::kTemporary, mojo::WrapCallbackWithDefaultInvokeIfNotRun( std::move(callback), mojom::QuotaStatusCode::kErrorAbort, 0, 0, @@ -177,15 +177,15 @@ resolver->Resolve(status == PermissionStatus::GRANTED); } -mojom::blink::QuotaDispatcherHost& StorageManager::GetQuotaHost( +mojom::blink::QuotaDispatcherHost* StorageManager::GetQuotaHost( ExecutionContext* execution_context) { if (!quota_host_) { ConnectToQuotaDispatcherHost( execution_context, - mojo::MakeRequest("a_host_, execution_context->GetTaskRunner( - TaskType::kMiscPlatformAPI))); + quota_host_.BindNewPipeAndPassReceiver( + execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI))); } - return *quota_host_; + return quota_host_.get(); } STATIC_ASSERT_ENUM(mojom::QuotaStatusCode::kErrorNotSupported,
diff --git a/third_party/blink/renderer/modules/quota/storage_manager.h b/third_party/blink/renderer/modules/quota/storage_manager.h index 1ebee48..7ec91e7 100644 --- a/third_party/blink/renderer/modules/quota/storage_manager.h +++ b/third_party/blink/renderer/modules/quota/storage_manager.h
@@ -35,10 +35,10 @@ // Binds the interface (if not already bound) with the given interface // provider, and returns it, - mojom::blink::QuotaDispatcherHost& GetQuotaHost(ExecutionContext*); + mojom::blink::QuotaDispatcherHost* GetQuotaHost(ExecutionContext*); mojo::Remote<mojom::blink::PermissionService> permission_service_; - mojom::blink::QuotaDispatcherHostPtr quota_host_; + mojo::Remote<mojom::blink::QuotaDispatcherHost> quota_host_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/vr/vr_controller.cc b/third_party/blink/renderer/modules/vr/vr_controller.cc index 6614e4b..139896f 100644 --- a/third_party/blink/renderer/modules/vr/vr_controller.cc +++ b/third_party/blink/renderer/modules/vr/vr_controller.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/modules/vr/vr_controller.h" +#include "device/vr/public/mojom/vr_service.mojom-blink.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "services/metrics/public/cpp/ukm_builders.h" #include "services/service_manager/public/cpp/interface_provider.h" @@ -105,11 +106,10 @@ listening_for_activate_ = listening; - if (listening) { + if (listening) service_->SetListeningForActivate(display_->GetDisplayClient()); - } else { - service_->SetListeningForActivate(nullptr); - } + else + service_->SetListeningForActivate(mojo::NullRemote()); } void VRController::OnDeviceChanged() {
diff --git a/third_party/blink/renderer/modules/vr/vr_display.cc b/third_party/blink/renderer/modules/vr/vr_display.cc index fd299be7..0cd2492b 100644 --- a/third_party/blink/renderer/modules/vr/vr_display.cc +++ b/third_party/blink/renderer/modules/vr/vr_display.cc
@@ -106,17 +106,16 @@ SessionClientBinding::SessionClientBinding( VRDisplay* display, SessionClientBinding::SessionBindingType immersive, - device::mojom::blink::XRSessionClientRequest request) + mojo::PendingReceiver<device::mojom::blink::XRSessionClient> receiver) : display_(display), is_immersive_(immersive == SessionClientBinding::SessionBindingType::kImmersive), - client_binding_(this, std::move(request)) {} + client_receiver_(this, std::move(receiver)) {} SessionClientBinding::~SessionClientBinding() = default; void SessionClientBinding::Close() { - DCHECK(client_binding_); - client_binding_.Close(); + client_receiver_.reset(); } void SessionClientBinding::OnChanged( device::mojom::blink::VRDisplayInfoPtr ptr) { @@ -138,8 +137,7 @@ VRDisplay::VRDisplay(NavigatorVR* navigator_vr) : ContextLifecycleStateObserver(navigator_vr->GetDocument()), navigator_vr_(navigator_vr), - capabilities_(MakeGarbageCollected<VRDisplayCapabilities>()), - display_client_binding_(this) {} + capabilities_(MakeGarbageCollected<VRDisplayCapabilities>()) {} VRDisplay::~VRDisplay() = default; @@ -871,15 +869,11 @@ return navigator_vr_->GetDocument(); } -device::mojom::blink::VRDisplayClientPtr VRDisplay::GetDisplayClient() { - display_client_binding_.Close(); - device::mojom::blink::VRDisplayClientPtr client; +mojo::PendingRemote<device::mojom::blink::VRDisplayClient> +VRDisplay::GetDisplayClient() { // See https://bit.ly/2S0zRAS for task types. - scoped_refptr<base::SingleThreadTaskRunner> task_runner = - GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI); - display_client_binding_.Bind(mojo::MakeRequest(&client, task_runner), - task_runner); - return client; + return display_client_receiver_.BindNewPipeAndPassRemote( + GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI)); } void VRDisplay::OnPresentChange() {
diff --git a/third_party/blink/renderer/modules/vr/vr_display.h b/third_party/blink/renderer/modules/vr/vr_display.h index 62bafdab..b03e6b3 100644 --- a/third_party/blink/renderer/modules/vr/vr_display.h +++ b/third_party/blink/renderer/modules/vr/vr_display.h
@@ -9,7 +9,7 @@ #include <utility> #include "device/vr/public/mojom/vr_service.mojom-blink.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "third_party/blink/public/platform/web_graphics_context_3d_provider.h" #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" #include "third_party/blink/renderer/bindings/core/v8/v8_frame_request_callback.h" @@ -54,9 +54,10 @@ kNonImmersive = 1, }; - SessionClientBinding(VRDisplay* display, - SessionBindingType immersive, - device::mojom::blink::XRSessionClientRequest request); + SessionClientBinding( + VRDisplay* display, + SessionBindingType immersive, + mojo::PendingReceiver<device::mojom::blink::XRSessionClient> receiver); ~SessionClientBinding() override; void Close(); @@ -72,7 +73,7 @@ // VRDisplay is destroyed, so is the SessionClientBinding. Member<VRDisplay> display_; bool is_immersive_; - mojo::Binding<device::mojom::blink::XRSessionClient> client_binding_; + mojo::Receiver<device::mojom::blink::XRSessionClient> client_receiver_; }; enum VREye { kVREyeNone, kVREyeLeft, kVREyeRight }; @@ -127,7 +128,7 @@ void submitFrame(); Document* GetDocument(); - device::mojom::blink::VRDisplayClientPtr GetDisplayClient(); + mojo::PendingRemote<device::mojom::blink::VRDisplayClient> GetDisplayClient(); // EventTarget overrides: ExecutionContext* GetExecutionContext() const override; @@ -267,7 +268,8 @@ Member<SessionClientBinding> non_immersive_client_binding_; Member<SessionClientBinding> immersive_client_binding_; - mojo::Binding<device::mojom::blink::VRDisplayClient> display_client_binding_; + mojo::Receiver<device::mojom::blink::VRDisplayClient> + display_client_receiver_{this}; device::mojom::blink::XRFrameDataProviderPtr vr_presentation_data_provider_; device::mojom::blink::XRPresentationProviderPtr vr_presentation_provider_;
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc index 6829acc..98b9377 100644 --- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc +++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -609,6 +609,10 @@ RuntimeEnabledFeatures::SetDisplayCutoutAPIEnabled(enable); } +void WebRuntimeFeatures::EnableDocumentPolicy(bool enable) { + RuntimeEnabledFeatures::SetDocumentPolicyEnabled(enable); +} + void WebRuntimeFeatures::EnableAutoplayIgnoresWebAudio(bool enable) { RuntimeEnabledFeatures::SetAutoplayIgnoresWebAudioEnabled(enable); }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc index 1b18109..777a3ed 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -351,7 +351,7 @@ return resource_provider; } -cc::PaintCanvas* Canvas2DLayerBridge::Canvas() { +cc::PaintCanvas* Canvas2DLayerBridge::DrawingCanvas() { DCHECK(resource_host_); if (is_deferral_enabled_) return recorder_->getRecordingCanvas(); @@ -423,7 +423,7 @@ } void Canvas2DLayerBridge::DrawFullImage(const cc::PaintImage& image) { - Canvas()->drawImage(image, 0, 0); + DrawingCanvas()->drawImage(image, 0, 0); } bool Canvas2DLayerBridge::WritePixels(const SkImageInfo& orig_info,
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h index 1556ab74e..3bc812c 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h +++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
@@ -112,7 +112,7 @@ virtual void DidRestoreCanvasMatrixClipStack(cc::PaintCanvas*) {} virtual bool IsAccelerated() const; - cc::PaintCanvas* Canvas(); + cc::PaintCanvas* DrawingCanvas(); bool IsValid(); bool WritePixels(const SkImageInfo&, const void* pixels,
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc index 6434b096..1d34f5b1 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
@@ -225,7 +225,7 @@ EXPECT_TRUE(bridge->IsValid()); PaintFlags flags; uint32_t gen_id = bridge->GetOrCreateResourceProvider()->ContentUniqueID(); - bridge->Canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags); + bridge->DrawingCanvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags); EXPECT_EQ(gen_id, bridge->GetOrCreateResourceProvider()->ContentUniqueID()); gl_.SetIsContextLost(true); EXPECT_EQ(nullptr, bridge->GetOrCreateResourceProvider()); @@ -345,7 +345,7 @@ MakeBridge(IntSize(300, 300), Canvas2DLayerBridge::kEnableAcceleration, CanvasColorParams()); PaintFlags flags; - bridge->Canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags); + bridge->DrawingCanvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags); scoped_refptr<StaticBitmapImage> image = bridge->NewImageSnapshot(kPreferAcceleration); EXPECT_TRUE(bridge->IsValid()); @@ -357,7 +357,7 @@ MakeBridge(IntSize(300, 300), Canvas2DLayerBridge::kEnableAcceleration, CanvasColorParams()); PaintFlags flags; - bridge->Canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags); + bridge->DrawingCanvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags); scoped_refptr<StaticBitmapImage> image = bridge->NewImageSnapshot(kPreferNoAcceleration); EXPECT_TRUE(bridge->IsValid()); @@ -369,7 +369,7 @@ MakeBridge(IntSize(300, 300), Canvas2DLayerBridge::kDisableAcceleration, CanvasColorParams()); PaintFlags flags; - bridge->Canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags); + bridge->DrawingCanvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags); scoped_refptr<StaticBitmapImage> image = bridge->NewImageSnapshot(kPreferAcceleration); EXPECT_TRUE(bridge->IsValid()); @@ -381,7 +381,7 @@ MakeBridge(IntSize(300, 300), Canvas2DLayerBridge::kDisableAcceleration, CanvasColorParams()); PaintFlags flags; - bridge->Canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags); + bridge->DrawingCanvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags); scoped_refptr<StaticBitmapImage> image = bridge->NewImageSnapshot(kPreferNoAcceleration); EXPECT_TRUE(bridge->IsValid()); @@ -1207,8 +1207,8 @@ SkIRect::MakeWH(5, 5), kNone_SkFilterQuality, SkMatrix::I(), 0u, expected_color_space)}; - bridge->Canvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr); - bridge->Canvas()->drawImageRect( + bridge->DrawingCanvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr); + bridge->DrawingCanvas()->drawImageRect( images[1].paint_image(), SkRect::MakeWH(5u, 5u), SkRect::MakeWH(5u, 5u), nullptr, cc::PaintCanvas::kFast_SrcRectConstraint); bridge->NewImageSnapshot(kPreferAcceleration); @@ -1230,8 +1230,8 @@ SkIRect::MakeWH(5, 5), kNone_SkFilterQuality, SkMatrix::I(), 0u, color_params.GetStorageGfxColorSpace())}; - bridge->Canvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr); - bridge->Canvas()->drawImageRect( + bridge->DrawingCanvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr); + bridge->DrawingCanvas()->drawImageRect( images[1].paint_image(), SkRect::MakeWH(5u, 5u), SkRect::MakeWH(5u, 5u), nullptr, cc::PaintCanvas::kFast_SrcRectConstraint); bridge->NewImageSnapshot(kPreferAcceleration); @@ -1258,14 +1258,14 @@ 0u, color_params.GetStorageGfxColorSpace())}; // First 2 images are budgeted, they should remain locked after the op. - bridge->Canvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr); - bridge->Canvas()->drawImage(images[1].paint_image(), 0u, 0u, nullptr); + bridge->DrawingCanvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr); + bridge->DrawingCanvas()->drawImage(images[1].paint_image(), 0u, 0u, nullptr); EXPECT_EQ(image_decode_cache_.num_locked_images(), 2); // Next image is not budgeted, we should unlock all images other than the last // image. image_decode_cache_.set_budget_exceeded(true); - bridge->Canvas()->drawImage(images[2].paint_image(), 0u, 0u, nullptr); + bridge->DrawingCanvas()->drawImage(images[2].paint_image(), 0u, 0u, nullptr); EXPECT_EQ(image_decode_cache_.num_locked_images(), 1); // Ask the provider to release everything, no locked images should remain. @@ -1284,7 +1284,7 @@ cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(10, 10)), SkIRect::MakeWH(10, 10), kNone_SkFilterQuality, SkMatrix::I(), 0u, color_params.GetStorageGfxColorSpace()); - bridge->Canvas()->drawImage(image.paint_image(), 0u, 0u, nullptr); + bridge->DrawingCanvas()->drawImage(image.paint_image(), 0u, 0u, nullptr); EXPECT_EQ(image_decode_cache_.num_locked_images(), 1); base::RunLoop().RunUntilIdle(); @@ -1305,14 +1305,14 @@ cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(20, 20)), SkIRect::MakeWH(5, 5), kNone_SkFilterQuality, SkMatrix::I(), 0u, color_params.GetStorageGfxColorSpace())}; - bridge->Canvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr); + bridge->DrawingCanvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr); // Lose the context and ensure that the image provider is not used. bridge->GetOrCreateResourceProvider()->OnContextDestroyed(); // We should unref all images on the cache when the context is destroyed. EXPECT_EQ(image_decode_cache_.num_locked_images(), 0); image_decode_cache_.set_disallow_cache_use(true); - bridge->Canvas()->drawImage(images[1].paint_image(), 0u, 0u, &flags); + bridge->DrawingCanvas()->drawImage(images[1].paint_image(), 0u, 0u, &flags); } class Canvas2DLayerBridgeTestNoMockGL : public Canvas2DLayerBridgeTest { @@ -1326,7 +1326,7 @@ size, Canvas2DLayerBridge::kEnableAcceleration, CanvasColorParams()); host_->set_provider_type(CanvasResourceProvider::kSharedImage); - bridge->Canvas()->clear(SK_ColorRED); + bridge->DrawingCanvas()->clear(SK_ColorRED); DrawSomething(bridge.get()); ASSERT_TRUE(bridge->layer_for_testing());
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc index 4696d3a..e06decf 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -162,6 +162,18 @@ return true; } +bool RequestContextObserveResponse(mojom::RequestContextType type) { + switch (type) { + case mojom::RequestContextType::PING: + case mojom::RequestContextType::BEACON: + case mojom::RequestContextType::CSP_REPORT: + return true; + + default: + return false; + } +} + } // namespace // CodeCacheRequest handles the requests to fetch data from code cache. @@ -369,10 +381,17 @@ DCHECK(resource_); DCHECK(fetcher_); - if (FrameScheduler* frame_scheduler = fetcher->GetFrameScheduler()) { - feature_handle_for_scheduler_ = frame_scheduler->RegisterFeature( - SchedulingPolicy::Feature::kOutstandingNetworkRequest, - {SchedulingPolicy::RecordMetricsForBackForwardCache()}); + // Some requests should not block the page from entering the BackForwardCache. + // If they are keepalive request && their responses are not observable to web + // content, we can have them survive without breaking web content when the + // page is put into BackForwardCache. + auto request = resource_->GetResourceRequest(); + if (!RequestContextObserveResponse(request.GetRequestContext())) { + if (FrameScheduler* frame_scheduler = fetcher->GetFrameScheduler()) { + feature_handle_for_scheduler_ = frame_scheduler->RegisterFeature( + SchedulingPolicy::Feature::kOutstandingNetworkRequest, + {SchedulingPolicy::RecordMetricsForBackForwardCache()}); + } } resource_->SetLoader(this);
diff --git a/third_party/blink/renderer/platform/mojo/kurl_security_origin_test.cc b/third_party/blink/renderer/platform/mojo/kurl_security_origin_test.cc index 19f164d4..408d261 100644 --- a/third_party/blink/renderer/platform/mojo/kurl_security_origin_test.cc +++ b/third_party/blink/renderer/platform/mojo/kurl_security_origin_test.cc
@@ -4,7 +4,7 @@ #include "base/macros.h" #include "base/test/task_environment.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/mojom/url_test.mojom-blink.h" #include "url/url_constants.h" @@ -14,8 +14,9 @@ class UrlTestImpl : public url::mojom::blink::UrlTest { public: - explicit UrlTestImpl(url::mojom::blink::UrlTestRequest request) - : binding_(this, std::move(request)) {} + explicit UrlTestImpl( + mojo::PendingReceiver<url::mojom::blink::UrlTest> receiver) + : receiver_(this, std::move(receiver)) {} // UrlTest: void BounceUrl(const KURL& in, BounceUrlCallback callback) override { @@ -28,7 +29,7 @@ } private: - mojo::Binding<UrlTest> binding_; + mojo::Receiver<UrlTest> receiver_; }; } // namespace
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 5fbc621d..e897cfd 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -525,6 +525,9 @@ name: "DocumentDomain", }, { + name: "DocumentPolicy", + }, + { name: "DocumentWrite", }, {
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index c852383..69698be 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -3099,6 +3099,7 @@ crbug.com/849859 virtual/threaded/external/wpt/css/css-animations/CSSAnimation-pausing.tentative.html [ Failure ] crbug.com/849859 external/wpt/css/css-animations/Element-getAnimations-dynamic-changes.tentative.html [ Failure ] crbug.com/849859 virtual/threaded/external/wpt/css/css-animations/Element-getAnimations-dynamic-changes.tentative.html [ Failure ] +crbug.com/849859 external/wpt/web-animations/timing-model/animations/pausing-an-animation.html [ Failure ] crbug.com/332189 external/wpt/css/css-transitions/no-transition-from-ua-to-blocking-stylesheet.html [ Pass Failure ] @@ -5953,16 +5954,6 @@ # Marking them as Failure/Pass to collect data on bots. Once confirmed they are # no longer flaky we can re-enable. crbug.com/986018 fast/scroll-snap/snaps-for-different-key-granularity.html [ Failure Pass ] -crbug.com/991565 animations/direction-and-fill/fill-mode-iteration-count-non-integer.html [ Failure Pass ] -crbug.com/991565 animations/direction-and-fill/fill-mode-missing-from-to-keyframes.html [ Failure Pass ] -crbug.com/991565 animations/direction-and-fill/fill-mode-transform.html [ Failure Pass ] -crbug.com/991565 animations/direction-and-fill/fill-mode.html [ Failure Pass ] -crbug.com/991565 virtual/threaded/animations/direction-and-fill/fill-mode-iteration-count-non-integer.html [ Failure Pass ] -crbug.com/991565 virtual/threaded/animations/direction-and-fill/fill-mode-missing-from-to-keyframes.html [ Failure Pass ] -crbug.com/991565 virtual/threaded/animations/direction-and-fill/fill-mode.html [ Failure Pass ] -crbug.com/991565 svg/animations/dynamic-modify-transform-without-baseval.html [ Failure Pass ] -crbug.com/991565 svg/animations/target-condition-crash.html [ Failure Pass ] - # Race: The RTCIceConnectionState can become "connected" before getStats() # returns candidate-pair whose state is "succeeded", this sounds like a @@ -6525,3 +6516,6 @@ crbug.com/1000051 [ Mac ] virtual/audio-service/media/controls/volume-slider.html [ Failure Timeout Pass ] crbug.com/1000124 [ Mac ] compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers.html [ Crash ] + +# Sheriff 2019-09-03 +crbug.com/999799 [ Mac Linux ] external/wpt/html/rendering/dimension-attributes.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/WebDriverExpectations b/third_party/blink/web_tests/WebDriverExpectations index 8de08f6..0b122d3 100644 --- a/third_party/blink/web_tests/WebDriverExpectations +++ b/third_party/blink/web_tests/WebDriverExpectations
@@ -69,6 +69,16 @@ crbug.com/977228 [ Linux ] external/wpt/webdriver/tests/element_click/scroll_into_view.py>>test_partially_visible_does_not_scroll[8] [ Failure Pass ] crbug.com/977228 [ Linux ] external/wpt/webdriver/tests/element_click/scroll_into_view.py>>test_partially_visible_does_not_scroll[9] [ Failure Pass ] crbug.com/977228 [ Linux ] external/wpt/webdriver/tests/element_click/scroll_into_view.py>>test_scroll_into_view [ Failure Pass ] +crbug.com/999814 [ Linux ] external/wpt/webdriver/tests/perform_actions/pointer_origin.py>>test_viewport_inside [ Failure Pass ] +crbug.com/999814 [ Linux ] external/wpt/webdriver/tests/perform_actions/pointer_origin.py>>test_viewport_outside [ Failure Pass ] +crbug.com/999814 [ Linux ] external/wpt/webdriver/tests/perform_actions/pointer_origin.py>>test_pointer_inside [ Failure Pass ] +crbug.com/999814 [ Linux ] external/wpt/webdriver/tests/perform_actions/pointer_origin.py>>test_pointer_outside [ Failure Pass ] +crbug.com/999814 [ Linux ] external/wpt/webdriver/tests/perform_actions/pointer_origin.py>>test_element_center_point [ Failure Pass ] +crbug.com/999814 [ Linux ] external/wpt/webdriver/tests/perform_actions/pointer_origin.py>>test_element_center_point_with_offset [ Failure Pass ] +crbug.com/999814 [ Linux ] external/wpt/webdriver/tests/perform_actions/pointer_origin.py>>test_element_in_view_center_point_partly_visible [ Failure Pass ] +crbug.com/999814 [ Linux ] external/wpt/webdriver/tests/perform_actions/pointer_origin.py>>test_element_larger_than_viewport [ Failure Pass ] +crbug.com/999814 [ Linux ] external/wpt/webdriver/tests/perform_actions/pointer_origin.py>>test_element_outside_of_view_port [ Failure Pass ] + # ====== New tests from wpt-importer added here ====== crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/interface.html [ Failure ] crbug.com/626703 [ Mac ] external/wpt/webdriver/tests/interface.html [ Failure ]
diff --git a/third_party/blink/web_tests/animations/web-animations/animation-null-timeline.html b/third_party/blink/web_tests/animations/web-animations/animation-null-timeline.html index 2fbe4cd..a3ad3f9 100644 --- a/third_party/blink/web_tests/animations/web-animations/animation-null-timeline.html +++ b/third_party/blink/web_tests/animations/web-animations/animation-null-timeline.html
@@ -16,9 +16,7 @@ animation.finish(); assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 1000); - // The paused state wins out over the finished state in the absence of an - // active timeline. This holds true even if finsih is explicitly called. - assert_equals(animation.playState, 'paused'); + assert_equals(animation.playState, 'finished'); }, 'Animation finished with a null timeline'); // crbug.com/967507 @@ -35,8 +33,6 @@ animation1.effect = effect; assert_false(!!animation1.effect.target); assert_false(!!animation2.effect); - // Setting an effect does not cancel the animation previously associated with - // the effect. - assert_equals(animation2.playState, 'paused'); + assert_equals(animation2.playState, 'idle'); }, 'Set effect with a null timeline'); </script>
diff --git a/third_party/blink/web_tests/animations/web-animations/animation-state-changes-negative-playback-rate.html b/third_party/blink/web_tests/animations/web-animations/animation-state-changes-negative-playback-rate.html index 5ebab03..1f9c92c 100644 --- a/third_party/blink/web_tests/animations/web-animations/animation-state-changes-negative-playback-rate.html +++ b/third_party/blink/web_tests/animations/web-animations/animation-state-changes-negative-playback-rate.html
@@ -13,10 +13,6 @@ assert_equals(value, null); } -function assert_resolved(value) { - assert_true(value != null); -} - function idleAnimation() { var animation = document.documentElement.animate([], duration); animation.reverse(); @@ -27,8 +23,6 @@ function runningAnimation() { var animation = idleAnimation(); animation.play(); - animation.currentTime = duration / 2; - // Explicitly setting the start time resolves the pending play. animation.startTime = document.timeline.currentTime + duration / 2; return animation; } @@ -42,8 +36,6 @@ function pausedAnimation() { var animation = idleAnimation(); animation.pause(); - // Explicitly setting the current time synchronously resolves the pending - // pause. animation.currentTime = duration; return animation; } @@ -59,34 +51,22 @@ var animation = idleAnimation(); assert_unresolved(animation.startTime); assert_unresolved(animation.currentTime); - // Cancel is synchronous. assert_false(animation.pending); assert_equals(animation.playState, 'idle'); -}, "Play state is idle after canceling a reversed animation"); +}, "Play state is idle after cancelling a reversed animation"); -async_test(function(t) { +test(function() { var animation = pendingAnimation(); assert_unresolved(animation.startTime); assert_equals(animation.currentTime, duration); - // Pending play is asynchronous. assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_equals(animation.currentTime, duration); - assert_false(animation.pending); - assert_equals(animation.playState, 'running'); - }); - t.done(); - }); }, "Play state is running after playing a canceled reversed animation"); test(function() { var animation = runningAnimation(); assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); assert_times_equal(animation.currentTime, duration / 2); - // Setting the start time synchronously updates a play-pending animation. assert_false(animation.pending); assert_equals(animation.playState, 'running'); }, "Play state is running after playing and setting start time of a canceled reversed animation"); @@ -95,56 +75,34 @@ var animation = pausedAnimation(); assert_unresolved(animation.startTime); assert_equals(animation.currentTime, duration); - // Setting the current time of a pause-pending animation applies a synchronous update. - assert_false(animation.pending); + assert_true(animation.pending); assert_equals(animation.playState, 'paused'); }, "Play state is paused after pausing and setting current time of a canceled reversed animation"); test(function() { var animation = finishedAnimation(); - assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); + assert_equals(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); assert_equals(animation.currentTime, 0); - // The finish method updates synchronously. assert_false(animation.pending); assert_equals(animation.playState, 'finished'); }, "Play state is finished after playing and finishing a cancelled reversed animation"); -async_test(function(t) { +test(function() { var animation = idleAnimation(); animation.play(); assert_unresolved(animation.startTime); assert_equals(animation.currentTime, duration); - // Transition from idle to running updates asynchronously. assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_equals(animation.currentTime, duration); - assert_false(animation.pending); - assert_equals(animation.playState, 'running'); - }); - t.done(); - }); }, "Calling play() on an idle animation"); -async_test(function(t) { +test(function() { var animation = idleAnimation(); animation.pause(); assert_unresolved(animation.startTime); assert_equals(animation.currentTime, duration); - // Transition from idle to paused updates synchronously. assert_true(animation.pending); assert_equals(animation.playState, 'paused'); - animation.ready.then(() => { - t.step(() => { - assert_unresolved(animation.startTime); - assert_equals(animation.currentTime, duration); - assert_false(animation.pending); - assert_equals(animation.playState, 'paused'); - }); - t.done(); - }); }, "Calling pause() on an idle animation"); test(function() { @@ -152,7 +110,6 @@ animation.cancel(); assert_unresolved(animation.startTime); assert_unresolved(animation.currentTime); - // Cancel updates synchronously. assert_false(animation.pending); assert_equals(animation.playState, 'idle'); }, "Calling cancel() on an idle animation"); @@ -160,32 +117,19 @@ test(function() { var animation = idleAnimation(); animation.finish(); - assert_times_equal( - animation.startTime, - document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); + assert_equals(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); assert_equals(animation.currentTime, 0); - // The finish method updates synchronously. assert_false(animation.pending); assert_equals(animation.playState, 'finished'); }, "Calling finish() on an idle animation"); -async_test(function(t) { +test(function() { var animation = idleAnimation(); animation.reverse(); assert_unresolved(animation.startTime); assert_equals(animation.currentTime, 0); - // A transition from idle to running updates asynchronously. assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_equals(animation.currentTime, 0); - assert_false(animation.pending); - assert_equals(animation.playState, 'running'); - }); - t.done(); - }); }, "Calling reverse() on an idle animation"); test(function() { @@ -206,40 +150,22 @@ assert_equals(animation.playState, 'running'); }, "Setting startTime on an idle animation"); -async_test(function(t) { +test(function() { var animation = pendingAnimation(); animation.play(); assert_unresolved(animation.startTime); assert_equals(animation.currentTime, duration); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_equals(animation.currentTime, duration); - assert_false(animation.pending); - assert_equals(animation.playState, 'running'); - }); - t.done(); - }); }, "Calling play() on a pending animation"); -async_test(function(t) { +test(function() { var animation = pendingAnimation(); animation.pause(); assert_unresolved(animation.startTime); assert_equals(animation.currentTime, duration); assert_true(animation.pending); assert_equals(animation.playState, 'paused'); - animation.ready.then(() => { - t.step(() => { - assert_unresolved(animation.startTime); - assert_equals(animation.currentTime, duration); - assert_false(animation.pending); - assert_equals(animation.playState, 'paused'); - }); - t.done(); - }); }, "Calling pause() on a pending animation"); test(function() { @@ -260,40 +186,22 @@ assert_equals(animation.playState, 'finished'); }, "Calling finish() on a pending animation"); -async_test(function(t) { +test(function() { var animation = pendingAnimation(); animation.reverse(); assert_unresolved(animation.startTime); assert_equals(animation.currentTime, 0); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_equals(animation.currentTime, 0); - assert_false(animation.pending); - assert_equals(animation.playState, 'running'); - }); - t.done(); - }); }, "Calling reverse() on a pending animation"); -async_test(function(t) { +test(function() { var animation = pendingAnimation(); animation.currentTime = 1000; assert_unresolved(animation.startTime); assert_equals(animation.currentTime, 1000); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_times_equal(animation.currentTime, 1000); - assert_false(animation.pending); - assert_equals(animation.playState, 'running'); - }); - t.done(); - }); }, "Setting currentTime on a pending animation"); test(function() { @@ -309,29 +217,20 @@ var animation = runningAnimation(); var startTime = animation.startTime; var currentTime = animation.currentTime; - // The animation is already playing and is current. No pending play task is - // created. animation.play(); assert_equals(animation.startTime, startTime); assert_equals(animation.currentTime, currentTime); - assert_false(animation.pending); + assert_true(animation.pending); assert_equals(animation.playState, 'running'); }, "Calling play() on a running animation"); -async_test(function(t) { +test(function() { var animation = runningAnimation(); animation.pause(); - assert_true(animation.pending); + assert_unresolved(animation.startTime); assert_times_equal(animation.currentTime, duration / 2); + assert_true(animation.pending); assert_equals(animation.playState, 'paused'); - animation.ready.then(() => { - t.step(() => { - assert_unresolved(animation.startTime); - assert_false(animation.pending); - assert_equals(animation.playState, 'paused'); - }); - t.done(); - }); }, "Calling pause() on a running animation"); test(function() { @@ -346,39 +245,25 @@ test(function() { var animation = runningAnimation(); animation.finish(); - assert_times_equal( - animation.startTime, - document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); + assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); assert_equals(animation.currentTime, 0); assert_false(animation.pending); assert_equals(animation.playState, 'finished'); }, "Calling finish() on a running animation"); -async_test(function(t) { +test(function() { var animation = runningAnimation(); - assert_equals(animation.playbackRate, -1); animation.reverse(); - assert_true(animation.pending); + assert_unresolved(animation.startTime); assert_times_equal(animation.currentTime, duration / 2); - assert_equals(animation.playbackRate, -1); + assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_false(animation.pending); - assert_resolved(animation.startTime); - assert_equals(animation.playbackRate, 1); - assert_equals(animation.playState, 'running'); - }); - t.done(); - }); }, "Calling reverse() on a running animation"); test(function() { var animation = runningAnimation(); animation.currentTime = 1000; - assert_times_equal( - animation.startTime, - document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); + assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); assert_times_equal(animation.currentTime, 1000); assert_false(animation.pending); assert_equals(animation.playState, 'running'); @@ -393,32 +278,21 @@ assert_equals(animation.playState, 'running'); }, "Setting startTime on a running animation"); -async_test(function(t) { +test(function() { var animation = pausedAnimation(); animation.play(); assert_unresolved(animation.startTime); assert_equals(animation.currentTime, duration); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_equals(animation.currentTime, duration); - assert_false(animation.pending); - assert_equals(animation.playState, 'running'); - }); - t.done(); - }); }, "Calling play() on a paused animation"); test(function() { var animation = pausedAnimation(); - // Calling pause on an animation that is already paused or pause-pending is - // a no-op. animation.pause(); assert_unresolved(animation.startTime); assert_equals(animation.currentTime, duration); - assert_false(animation.pending); + assert_true(animation.pending); assert_equals(animation.playState, 'paused'); }, "Calling pause() on a paused animation"); @@ -434,40 +308,27 @@ test(function() { var animation = pausedAnimation(); animation.finish(); - assert_times_equal( - animation.startTime, - document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); + assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); assert_equals(animation.currentTime, 0); assert_false(animation.pending); assert_equals(animation.playState, 'finished'); }, "Calling finish() on a paused animation"); -async_test(function(t) { +test(function() { var animation = pausedAnimation(); animation.reverse(); assert_unresolved(animation.startTime); assert_equals(animation.currentTime, 0); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_equals(animation.currentTime, 0); - assert_false(animation.pending); - assert_equals(animation.playState, 'running'); - }); - t.done(); - }); }, "Calling reverse() on a paused animation"); test(function() { var animation = pausedAnimation(); - // Setting the current time on a paused or pause-pending animation gets - // resolved synchronously. animation.currentTime = 1000; assert_unresolved(animation.startTime); assert_times_equal(animation.currentTime, 1000); - assert_false(animation.pending); + assert_true(animation.pending); assert_equals(animation.playState, 'paused'); }, "Setting currentTime on a paused animation"); @@ -480,41 +341,22 @@ assert_equals(animation.playState, 'running'); }, "Setting startTime on a paused animation"); -async_test(function(t) { +test(function() { var animation = finishedAnimation(); - // Play resets the previously resolved ready promise and creates a new pending - // task. animation.play(); assert_unresolved(animation.startTime); assert_equals(animation.currentTime, duration); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_equals(animation.currentTime, duration); - assert_false(animation.pending); - assert_equals(animation.playState, 'running'); - }); - t.done(); - }); }, "Calling play() on a finished animation"); -async_test(function(t) { +test(function() { var animation = finishedAnimation(); animation.pause(); + assert_unresolved(animation.startTime); assert_equals(animation.currentTime, 0); assert_true(animation.pending); assert_equals(animation.playState, 'paused'); - animation.ready.then(() => { - t.step(() => { - assert_unresolved(animation.startTime); - assert_equals(animation.currentTime, 0); - assert_false(animation.pending); - assert_equals(animation.playState, 'paused'); - }); - t.done(); - }); }, "Calling pause() on a finished animation"); test(function() { @@ -529,41 +371,27 @@ test(function() { var animation = finishedAnimation(); animation.finish(); - assert_times_equal( - animation.startTime, - document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); + assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); assert_equals(animation.currentTime, 0); assert_false(animation.pending); assert_equals(animation.playState, 'finished'); }, "Calling finish() on a finished animation"); -async_test(function(t) { +test(function() { var animation = finishedAnimation(); animation.reverse(); assert_unresolved(animation.startTime); assert_equals(animation.currentTime, 0); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_equals(animation.currentTime, 0); - assert_false(animation.pending); - assert_equals(animation.playState, 'running'); - }); - t.done(); - }); }, "Calling reverse() on a finished animation"); test(function() { var animation = finishedAnimation(); animation.currentTime = 1000; - assert_times_equal( - animation.startTime, - document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); + assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime)); assert_times_equal(animation.currentTime, 1000); assert_false(animation.pending); assert_equals(animation.playState, 'running'); }, "Setting currentTime on a finished animation"); - </script>
diff --git a/third_party/blink/web_tests/animations/web-animations/animation-state-changes-positive-playback-rate.html b/third_party/blink/web_tests/animations/web-animations/animation-state-changes-positive-playback-rate.html index bc2282a..0bc33e64 100644 --- a/third_party/blink/web_tests/animations/web-animations/animation-state-changes-positive-playback-rate.html +++ b/third_party/blink/web_tests/animations/web-animations/animation-state-changes-positive-playback-rate.html
@@ -8,15 +8,6 @@ <body> <script> 'use strict'; - -function assert_unresolved(value) { - assert_equals(value, null); -} - -function assert_resolved(value) { - assert_true(value != null); -} - function createIdleAnimation(t) { var animation = createDiv(t).animate([], 100000); animation.cancel(); @@ -59,26 +50,17 @@ assert_equals(animation.playState, 'idle'); }, "Play state is idle after canceling an animation"); -async_test(function(t) { +test(function(t) { var animation = createPendingStartTimeAnimation(t); - assert_unresolved(animation.startTime, null); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 0); - assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); }, "Play state is running after playing a canceled animation"); test(function(t) { var animation = createRunningAnimation(t); assert_times_equal(animation.startTime, document.timeline.currentTime - animation.currentTime); assert_equals(animation.currentTime, 0); - assert_false(animation.pending); assert_equals(animation.playState, 'running'); }, "Play state is running after playing and setting start time of a canceled animation"); @@ -86,7 +68,6 @@ var animation = createPausedAnimation(t); assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 0); - assert_false(animation.pending); assert_equals(animation.playState, 'paused'); }, "Play state is paused after pausing and setting current time of a canceled animation"); @@ -94,41 +75,26 @@ var animation = createFinishedAnimation(t); assert_times_equal(animation.startTime, document.timeline.currentTime - animation.currentTime); assert_equals(animation.currentTime, 100000); - assert_false(animation.pending); assert_equals(animation.playState, 'finished'); -}, "Play state is finished after playing and finishing a canceled animation"); +}, "Play state is finished after playing and finishing a cancelled animation"); // Changed animation states -async_test(function(t) { +test(function(t) { var animation = createIdleAnimation(t); animation.play(); - assert_unresolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 0); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); }, "Calling play() on an idle animation"); -async_test(function(t) { +test(function(t) { var animation = createIdleAnimation(t); animation.pause(); - assert_unresolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 0); assert_true(animation.pending); assert_equals(animation.playState, 'paused'); - animation.ready.then(() => { - t.step(() => { - assert_unresolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); }, "Calling pause() on an idle animation"); test(function(t) { @@ -149,20 +115,13 @@ assert_equals(animation.playState, 'finished'); }, "Calling finish() on an idle animation"); -async_test(function(t) { +test(function(t) { var animation = createIdleAnimation(t); animation.reverse(); - assert_unresolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 100000); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); }, "Calling reverse() on an idle animation"); test(function(t) { @@ -183,37 +142,23 @@ assert_equals(animation.playState, 'running'); }, "Setting startTime on an idle animation"); -async_test(function(t) { +test(function(t) { var animation = createPendingStartTimeAnimation(t); animation.play(); - assert_unresolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 0); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); -}, "Calling play() on a pending start-time animation"); +}, "Calling play() on a pending starttime animation"); -async_test(function(t) { +test(function(t) { var animation = createPendingStartTimeAnimation(t); animation.pause(); - assert_unresolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 0); assert_true(animation.pending); assert_equals(animation.playState, 'paused'); - animation.ready.then(() => { - t.step(() => { - assert_unresolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); -}, "Calling pause() on a pending start-time animation"); +}, "Calling pause() on a pending starttime animation"); test(function(t) { var animation = createPendingStartTimeAnimation(t); @@ -222,7 +167,7 @@ assert_equals(animation.currentTime, null); assert_false(animation.pending); assert_equals(animation.playState, 'idle'); -}, "Calling cancel() on a pending start-time animation"); +}, "Calling cancel() on a pending starttime animation"); test(function(t) { var animation = createPendingStartTimeAnimation(t); @@ -231,39 +176,25 @@ assert_equals(animation.currentTime, 100000); assert_false(animation.pending); assert_equals(animation.playState, 'finished'); -}, "Calling finish() on a pending start-time animation"); +}, "Calling finish() on a pending starttime animation"); -async_test(function(t) { +test(function(t) { var animation = createPendingStartTimeAnimation(t); animation.reverse(); - assert_unresolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 100000); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); -}, "Calling reverse() on a pending start-time animation"); +}, "Calling reverse() on a pending starttime animation"); -async_test(function(t) { +test(function(t) { var animation = createPendingStartTimeAnimation(t); animation.currentTime = 1000; - assert_unresolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 1000); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); -}, "Setting currentTime on a pending start-time animation"); +}, "Setting currentTime on a pending starttime animation"); test(function(t) { var animation = createPendingStartTimeAnimation(t); @@ -272,7 +203,7 @@ assert_times_equal(animation.currentTime, 1000); assert_false(animation.pending); assert_equals(animation.playState, 'running'); -}, "Setting startTime on a pending start-time animation"); +}, "Setting startTime on a pending starttime animation"); test(function(t) { var animation = createRunningAnimation(t); @@ -281,30 +212,24 @@ animation.play(); assert_equals(animation.startTime, startTime); assert_equals(animation.currentTime, currentTime); - assert_false(animation.pending); + assert_true(animation.pending); + assert_equals(animation.playState, 'running'); }, "Setting play() on a running animation"); -async_test(function(t) { +test(function(t) { var animation = createRunningAnimation(t); animation.pause(); - assert_resolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 0); assert_true(animation.pending); assert_equals(animation.playState, 'paused'); - animation.ready.then(() => { - t.step(() => { - assert_unresolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); }, "Setting pause() on a running animation"); test(function(t) { var animation = createRunningAnimation(t); animation.cancel(); - assert_unresolved(animation.startTime); - assert_unresolved(animation.currentTime); + assert_equals(animation.startTime, null); + assert_equals(animation.currentTime, null); assert_false(animation.pending); assert_equals(animation.playState, 'idle'); }, "Setting cancel() on a running animation"); @@ -318,20 +243,13 @@ assert_equals(animation.playState, 'finished'); }, "Setting finish() on a running animation"); -async_test(function(t) { +test(function(t) { var animation = createRunningAnimation(t); animation.reverse(); - assert_unresolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 100000); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); }, "Setting reverse() on a running animation"); @@ -353,39 +271,29 @@ assert_equals(animation.playState, 'running'); }, "Setting startTime on a running animation"); -async_test(function(t) { +test(function(t) { var animation = createPausedAnimation(t); animation.play(); - assert_unresolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 0); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); }, "Calling play() on a paused animation"); test(function(t) { var animation = createPausedAnimation(t); - // Calling pause on an animation that is already paused or pause-pending is a - // no-op., animation.pause(); - assert_unresolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 0); - assert_false(animation.pending); + assert_true(animation.pending); assert_equals(animation.playState, 'paused'); }, "Calling pause() on a paused animation"); test(function(t) { var animation = createPausedAnimation(t); animation.cancel(); - assert_unresolved(animation.startTime); - assert_unresolved(animation.currentTime); - assert_false(animation.pending); + assert_equals(animation.startTime, null); + assert_equals(animation.currentTime, null); assert_equals(animation.playState, 'idle'); }, "Calling cancel() on a paused animation"); @@ -394,24 +302,16 @@ animation.finish(); assert_times_equal(animation.startTime, document.timeline.currentTime - animation.currentTime); assert_equals(animation.currentTime, 100000); - assert_false(animation.pending); assert_equals(animation.playState, 'finished'); }, "Calling finish() on a paused animation"); -async_test(function(t) { +test(function(t) { var animation = createPausedAnimation(t); animation.reverse(); - assert_unresolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 100000); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); }, "Calling reverse() on a paused animation"); test(function(t) { @@ -419,7 +319,6 @@ animation.currentTime = 1000; assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 1000); - assert_false(animation.pending); assert_equals(animation.playState, 'paused'); }, "Setting currentTime on a paused animation"); @@ -431,36 +330,22 @@ assert_equals(animation.playState, 'running'); }, "Setting startTime on a paused animation"); -async_test(function(t) { +test(function(t) { var animation = createFinishedAnimation(t); animation.play(); - assert_unresolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 0); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); }, "Calling play() on a finished animation"); -async_test(function(t) { +test(function(t) { var animation = createFinishedAnimation(t); animation.pause(); - assert_resolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 100000); assert_true(animation.pending); assert_equals(animation.playState, 'paused'); - animation.ready.then(() => { - t.step(() => { - assert_unresolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); }, "Calling pause() on a finished animation"); test(function(t) { @@ -481,20 +366,13 @@ assert_equals(animation.playState, 'finished'); }, "Calling finish() on a finished animation"); -async_test(function(t) { +test(function(t) { var animation = createFinishedAnimation(t); animation.reverse(); - assert_unresolved(animation.startTime); + assert_equals(animation.startTime, null); assert_equals(animation.currentTime, 100000); assert_true(animation.pending); assert_equals(animation.playState, 'running'); - animation.ready.then(() => { - t.step(() => { - assert_resolved(animation.startTime); - assert_false(animation.pending); - }); - t.done(); - }); }, "Calling reverse() on a finished animation"); test(function(t) { @@ -511,7 +389,6 @@ animation.play(); var animationCurrentTime = animation.currentTime; var timelineCurrentTime = document.timeline.currentTime; - assert_true(animation.pending); animation.ready.then(() => { t.step(() => { assert_equals(animation.playState, 'running'); @@ -520,13 +397,12 @@ }); t.done(); }); -}, "PlayState is 'running' while playing a canceled animation"); +}, "PlayState is 'running' while playing a cancelled animation"); async_test(function(t) { let animation = createRunningAnimation(t); animation.pause(); let animationCurrentTime = animation.currentTime; - assert_true(animation.pending); animation.ready.then(() => { t.step(() => { assert_equals(animation.playState, 'paused');
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-white-space-crash.html b/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-white-space-crash.html new file mode 100644 index 0000000..2bea6ae --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-white-space-crash.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>CSS Text Test: A combination of `overflow-wrap: break-word` and `white-space` should not crash</title> +<link rel="help" href="https://crbug.com/988832"> +<link rel="author" title="Koji Ishii" href="mailto:kojii@chromium.org"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> +div { + width: 10ch; + border: 1px blue solid; + overflow-wrap: break-word; +} +inline-block { + display: inline-block; + position: relative; + width: 3ch; + height: 1em; + background: orange; +} +</style> +<body> +<div> + 123 56 <span style="white-space: pre"><inline-block></inline-block> <span style="white-space: normal">Flash</span></span> and +</div> +<script> +test(() => { }); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/event-dispatch.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-transitions/event-dispatch.tentative-expected.txt index c8c022a..3216888a 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-transitions/event-dispatch.tentative-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/event-dispatch.tentative-expected.txt
@@ -20,7 +20,7 @@ PASS Calculating the interval start and end time with negative start delay. FAIL Calculating the interval start and end time with negative end delay. assert_true: Timed out waiting for transitioncancel, transitionrun, transitionstart expected true got false PASS Call Animation.cancel after canceling transition. -PASS Restart transition after canceling transition immediately +FAIL Restart transition after canceling transition immediately assert_true: Timed out waiting for transitioncancel, transitionrun expected true got false PASS Call Animation.cancel after restarting transition immediately FAIL Set timeline and play transition after clear the timeline promise_test: Unhandled rejection with value: object "TypeError: Cannot assign to read only property 'timeline' of object '#<CSSTransition>'" PASS Set null target effect after canceling the transition
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawupdate.html b/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawupdate.html index 0d31701..0f46583c 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawupdate.html +++ b/third_party/blink/web_tests/external/wpt/pointerevents/extension/pointerevent_pointerrawupdate.html
@@ -20,6 +20,7 @@ <div id="target0"></div> <script> var test_pointerrawupdate = async_test("pointerrawupdate event received"); + var actions_promise; var pointerrawupdateReceived = false; var pointerdownReceived = false; @@ -47,10 +48,13 @@ assert_true(pointerrawupdateFromButtonChangeReceived, "Pointerrawupdate event should have been received from chorded button changes."); }, "Pointerrawupdate event should have been received from chorded button changes."); - test_pointerrawupdate.done(); + // Make sure the test finishes after all the input actions are completed. + actions_promise.then( () => { + test_pointerrawupdate.done(); + }); }); var actions = new test_driver.Actions(); - actions.pointerMove(0, 0, {origin: target0, button: actions.ButtonType.LEFT}) + actions_promise = actions.pointerMove(0, 0, {origin: target0, button: actions.ButtonType.LEFT}) .pointerDown({button: actions.ButtonType.LEFT}) .pointerDown({button: actions.ButtonType.MIDDLE}) .pointerUp({button: actions.ButtonType.MIDDLE})
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_releasepointercapture_events_to_original_target.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_releasepointercapture_events_to_original_target.html index 12e31cdb..6f6d30e 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_releasepointercapture_events_to_original_target.html +++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_releasepointercapture_events_to_original_target.html
@@ -22,6 +22,8 @@ var outLeaveEventsFail = false; var f_gotPointerCapture = false; var f_lostPointerCapture = false; + var index = 0; + var actions_promise; function resetTestState() { captured_event = null; @@ -98,7 +100,16 @@ }); if (event.type == "pointerup") { test_done = true; - test_pointerEvent.done(); // complete test + // Make sure the test finishes after all the input actions are completed. + actions_promise.then( () => { + if (index == 0) { + actions_promise = pointerDragInTarget('touch', target0, 'right'); + } else if (index == 1) { + actions_promise = pointerDragInTarget('pen', target0, 'right'); + } + index++; + test_pointerEvent.done(); + }); } } } @@ -116,11 +127,7 @@ } // Inject pointer inputs. - pointerDragInTarget('mouse', target0, 'right').then(function() { - return pointerDragInTarget('touch', target0, 'right'); - }).then(function() { - return pointerDragInTarget('pen', target0, 'right'); - }); + actions_promise = pointerDragInTarget('mouse', target0, 'right'); } </script> </head>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_sequence_at_implicit_release_on_click.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_sequence_at_implicit_release_on_click.html index 0c6e2c5..4b424f2 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_sequence_at_implicit_release_on_click.html +++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_sequence_at_implicit_release_on_click.html
@@ -16,6 +16,8 @@ var detected_pointertypes = {}; var event_log = []; var start_logging = false; + var actions_promise; + var index = 0; function resetTestState() { detected_eventTypes = {}; @@ -31,7 +33,20 @@ var expected_events = "pointerup, lostpointercapture, pointerout, pointerleave"; assert_equals(event_log.join(", "), expected_events); }); - test_pointer_event.done(); + // Make sure the test finishes after all the input actions are completed. + actions_promise.then( () => { + if (index == 0) { + actions_promise = clickInTarget("touch", target).then(function() { + return clickInTarget("touch", button); + }); + } else if (index == 1) { + actions_promise = clickInTarget("pen", target).then(function() { + return clickInTarget("pen", button); + }); + } + index++; + test_pointer_event.done(); + }); }); var target = document.getElementById("target"); @@ -54,16 +69,8 @@ }); // Inject pointer inputs. - clickInTarget("mouse", target).then(function() { + actions_promise = clickInTarget("mouse", target).then(function() { return clickInTarget("mouse", button); - }).then(function() { - return clickInTarget("touch", target); - }).then(function() { - return clickInTarget("touch", button); - }).then(function() { - return clickInTarget("pen", target); - }).then(function() { - return clickInTarget("pen", button); }); } </script>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_setpointercapture_inactive_button_mouse.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_setpointercapture_inactive_button_mouse.html index 7d0b00d..fa9a5fb 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_setpointercapture_inactive_button_mouse.html +++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_setpointercapture_inactive_button_mouse.html
@@ -32,16 +32,19 @@ function run() { var target0 = document.getElementById("target0"); + var actions_promise; on_event(target0, "pointerover", function (event) { detected_pointertypes[event.pointerType] = true; target0.setPointerCapture(event.pointerId); // After we receive a pointerover event, dispatch a pointer move to move out of target0. - new test_driver.Actions().pointerMove(0, 0).send(); + actions_promise.then(function() { + return new test_driver.Actions().pointerMove(0, 0).send(); + }); }); // First dispatch a pointer move to target0. - new test_driver.Actions().pointerMove(0, 0, {origin: target0}).send(); + actions_promise = new test_driver.Actions().pointerMove(0, 0, {origin: target0}).send(); // When the setPointerCapture method is invoked, if the specified pointer is not in active button state, then the method must have no effect on subsequent pointer events. // TA: 13.2 @@ -49,7 +52,10 @@ test(function() { assert_false(captureGot, "pointer capture is not set while button state is inactive") }, "pointer capture is not set while button state is inactive"); - done(); + // Make sure the test finishes after all the input actions are completed. + actions_promise.then( () => { + done(); + }); }); on_event(target0, 'gotpointercapture', function(e) {
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_suppress_compat_events_on_click.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_suppress_compat_events_on_click.html index 341a82d..2f99e7a 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_suppress_compat_events_on_click.html +++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_suppress_compat_events_on_click.html
@@ -15,6 +15,7 @@ <script type="text/javascript"> var test_pointerEvent = async_test("Suppress compat mouse events on click"); add_completion_callback(end_of_test); + var actions_promise; var detected_pointertypes = {}; var event_log = []; @@ -30,11 +31,15 @@ "click@target0, mousedown@target1, mouseup@target1, click@target1"); }, "Event log"); - test_pointerEvent.done(); // complete test + // Make sure the test finishes after all the input actions are completed. + actions_promise.then( () => { + test_pointerEvent.done(); + }); } function run() { - on_event(document.getElementById("done"), "click", end_of_interaction); + var targetDone = document.getElementById('done'); + on_event(targetDone, "click", end_of_interaction); var target_list = ["target0", "target1"]; var pointer_event_list = ["pointerdown"]; @@ -65,10 +70,7 @@ }); // Inject mouse inputs. - var target0 = document.getElementById('target0'); - var target1 = document.getElementById('target1'); - var targetDone = document.getElementById('done'); - new test_driver.Actions() + actions_promise = new test_driver.Actions() .pointerMove(0, 0, {origin: target0}) .pointerDown() .pointerUp()
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_suppress_compat_events_on_drag_mouse.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_suppress_compat_events_on_drag_mouse.html index 6ed75ab..6ed19c2 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_suppress_compat_events_on_drag_mouse.html +++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_suppress_compat_events_on_drag_mouse.html
@@ -15,6 +15,7 @@ <script type="text/javascript"> var test_pointerEvent = async_test("Suppress compat mouse events on drag"); add_completion_callback(end_of_test); + var actions_promise; var detected_pointertypes = {}; var event_log = []; @@ -37,11 +38,15 @@ "mousedown@target1, mousemove@target1, mouseup@target1"); }, "Event log"); - test_pointerEvent.done(); // complete test + // Make sure the test finishes after all the input actions are completed. + actions_promise.then( () => { + test_pointerEvent.done(); + }); } function run() { - on_event(document.getElementById("done"), "click", end_of_interaction); + var targetDone = document.getElementById('done'); + on_event(targetDone, "click", end_of_interaction); var target_list = ["target0", "target1"]; var pointer_event_list = ["pointerdown" , "pointermove", "pointerup"]; @@ -79,10 +84,7 @@ }); // Inject mouse inputs. - var target0 = document.getElementById('target0'); - var target1 = document.getElementById('target1'); - var targetDone = document.getElementById('done'); - new test_driver.Actions() + actions_promise = new test_driver.Actions() .pointerMove(0, 0, {origin: target0}) .pointerDown() .pointerMove(10, 0, {origin: target0})
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animation/finished-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animation/finished-expected.txt index 9f0b8e6..32a633f 100644 --- a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animation/finished-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animation/finished-expected.txt
@@ -8,7 +8,7 @@ PASS The finished promise is fulfilled with its Animation PASS finished promise is rejected when an animation is canceled by calling cancel() PASS canceling an already-finished animation replaces the finished promise -FAIL Test finished promise changes for animation duration changes assert_not_equals: Finished promise should change after lengthening the duration causes the animation to become active got disallowed value object "[object Promise]" +FAIL Test finished promise changes for animation duration changes assert_false: shortening of the animation duration should resolve the finished promise expected false got true PASS Test finished promise changes when playbackRate == 0 PASS Test finished promise resolves when reaching to the natural boundary. PASS Test finished promise changes when a prior finished promise resolved and the animation falls out finished state @@ -16,8 +16,8 @@ PASS Test new finished promise generated when finished state is checked synchronously PASS Test synchronous finished promise resolved even if finished state is changed soon PASS Test synchronous finished promise resolved even if asynchronous finished promise happens just before synchronous promise -PASS Test finished promise is not resolved when the animation falls out finished state immediately -PASS Test finished promise is not resolved once the animation falls out finished state even though the current finished promise is generated soon after animation state became finished +FAIL Test finished promise is not resolved when the animation falls out finished state immediately assert_unreached: Animation.finished should not be resolved Reached unreachable code +FAIL Test finished promise is not resolved once the animation falls out finished state even though the current finished promise is generated soon after animation state became finished assert_unreached: Animation.finished should not be resolved Reached unreachable code PASS Finished promise should be resolved after the ready promise is resolved PASS Finished promise should be rejected after the ready promise is rejected Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/pausing-an-animation-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/pausing-an-animation-expected.txt new file mode 100644 index 0000000..7872703 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/pausing-an-animation-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL A pending ready promise should be resolved and not replaced when the animation is paused assert_false: No longer pause-pending expected false got undefined +FAIL A pause-pending animation maintains the current time when applying a pending playback rate promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/reversing-an-animation-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/reversing-an-animation-expected.txt new file mode 100644 index 0000000..227a28ac --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/reversing-an-animation-expected.txt
@@ -0,0 +1,21 @@ +This is a testharness.js-based test. +PASS Reversing an animation inverts the playback rate +PASS Reversing an animation plays a pausing animation +PASS Reversing an animation maintains the same current time +PASS Reversing an animation does not cause it to leave the pending state +PASS Reversing an animation does not cause it to resolve the ready promise +PASS Reversing an animation when playbackRate > 0 and currentTime > effect end should make it play from the end +PASS Reversing an animation when playbackRate > 0 and currentTime < 0 should make it play from the end +PASS Reversing an animation when playbackRate < 0 and currentTime < 0 should make it play from the start +PASS Reversing an animation when playbackRate < 0 and currentTime > effect end should make it play from the start +PASS Reversing an animation when playbackRate > 0 and currentTime < 0 and the target effect end is positive infinity should throw an exception +PASS When reversing throws an exception, the playback rate remains unchanged +PASS Reversing animation when playbackRate = 0 and currentTime < 0 and the target effect end is positive infinity should NOT throw an exception +PASS Reversing an animation when playbackRate < 0 and currentTime < 0 and the target effect end is positive infinity should make it play from the start +PASS Reversing when when playbackRate == 0 should preserve the current time and playback rate +PASS Reversing an idle animation from starts playing the animation +FAIL Reversing an animation without an active timeline throws an InvalidStateError assert_throws: function "() => { animation.reverse(); }" did not throw +PASS Reversing should use the negative pending playback rate +PASS When reversing fails, it should restore any previous pending playback rate +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-start-time-of-an-animation-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-start-time-of-an-animation-expected.txt new file mode 100644 index 0000000..5677028 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-start-time-of-an-animation-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +PASS Setting the start time of an animation without an active timeline +PASS Setting an unresolved start time an animation without an active timeline does not clear the current time +PASS Setting the start time clears the hold time +PASS Setting an unresolved start time sets the hold time +PASS Setting the start time resolves a pending ready promise +PASS Setting the start time resolves a pending pause task +PASS Setting an unresolved start time on a play-pending animation makes it paused +FAIL Setting the start time updates the finished state assert_greater_than: Setting the start time updated the finished state with the 'did seek' flag set to true expected a number greater than 100000 but got 100000 +PASS Setting the start time of a play-pending animation applies a pending playback rate +PASS Setting the start time of a playing animation applies a pending playback rate +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-target-effect-of-an-animation-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-target-effect-of-an-animation-expected.txt new file mode 100644 index 0000000..5f0650b0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-target-effect-of-an-animation-expected.txt
@@ -0,0 +1,10 @@ +This is a testharness.js-based test. +PASS If new effect is null and old effect is not null the animation becomes finish-pending +PASS If animation has a pending pause task, reschedule that task to run as soon as animation is ready. +PASS If animation has a pending play task, reschedule that task to run as soon as animation is ready to play new effect. +PASS The pending play task should be rescheduled even after temporarily setting the effect to null +FAIL When setting the effect of an animation to the effect of an existing animation, the existing animation's target effect should be set to null. assert_equals: expected "finished" but got "idle" +PASS After setting the target effect of animation to the target effect of an existing animation, the target effect's timing is updated to reflect the current time of the new animation. +PASS Setting the target effect to null causes a pending playback rate to be applied +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/transitions/interrupt-zero-duration-expected.txt b/third_party/blink/web_tests/transitions/interrupt-zero-duration-expected.txt index a941eb5..ac3a52dd 100644 --- a/third_party/blink/web_tests/transitions/interrupt-zero-duration-expected.txt +++ b/third_party/blink/web_tests/transitions/interrupt-zero-duration-expected.txt
@@ -1,3 +1,3 @@ PASS - "left" property for "box" element at 0.5s saw something close to: 100 -PASS - "left" property for "box" element at 0.7s saw something close to: 10 +PASS - "left" property for "box" element at 0.7s saw something close to: 0
diff --git a/third_party/blink/web_tests/transitions/interrupt-zero-duration.html b/third_party/blink/web_tests/transitions/interrupt-zero-duration.html index 11b1cafb..599feef 100644 --- a/third_party/blink/web_tests/transitions/interrupt-zero-duration.html +++ b/third_party/blink/web_tests/transitions/interrupt-zero-duration.html
@@ -14,7 +14,7 @@ <body> <p> This tests changing a transitioning property while running and resetting its duration to 0. -The box should start moving left and after 600ms snap back to 10</p> +The box should start moving left and after 600ms snap back to 0</p> <div id="box"> </div> <script src="../animations/resources/animation-test-helpers.js"></script> @@ -22,7 +22,7 @@ function reset() { document.getElementById('box').style.transitionDuration = "0s"; - document.getElementById('box').style.left = "10px"; + document.getElementById('box').style.left = "0px"; } function trigger() @@ -32,7 +32,7 @@ var expectations = [ [0.5, 'box', 'left', 100, 50], - [0.7, 'box', 'left', 10, 0], + [0.7, 'box', 'left', 0, 0], ]; var callbacks = {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 4f49aa3..83ddb4e 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -1791,6 +1791,18 @@ </int> </enum> +<enum name="AndroidWebViewProxySchemeFilterType"> + <int value="0" label="HTTP"/> + <int value="1" label="HTTPS"/> + <int value="2" label="ALL"/> +</enum> + +<enum name="AndroidWebViewProxyUrlType"> + <int value="0" label="HTTP"/> + <int value="1" label="HTTPS"/> + <int value="2" label="DIRECT"/> +</enum> + <enum name="AndroidWebViewSslErrorType"> <int value="0" label="SSL_NOTYETVALID">The certificate is not yet valid.</int> <int value="1" label="SSL_EXPIRED">The certificate has expired.</int> @@ -19020,6 +19032,7 @@ <int value="439" label="ACCESSIBILITY_PRIVATE_ON_SWITCH_ACCESS_COMMAND"/> <int value="440" label="ACCESSIBILITY_PRIVATE_FIND_SCROLLABLE_BOUNDS_FOR_POINT"/> + <int value="441" label="LOGIN_STATE_ON_SESSION_STATE_CHANGED"/> </enum> <enum name="ExtensionFileWriteResult"> @@ -20462,6 +20475,8 @@ <int value="1376" label="AUTOTESTPRIVATE_GETALLINSTALLEDAPPS"/> <int value="1377" label="AUTOTESTPRIVATE_SWAPWINDOWSINSPLITVIEW"/> <int value="1378" label="AUTOTESTPRIVATE_SETARCAPPWINDOWFOCUS"/> + <int value="1379" label="LOGINSTATE_GETPROFILETYPE"/> + <int value="1380" label="LOGINSTATE_GETSESSIONSTATE"/> </enum> <enum name="ExtensionIconState"> @@ -21004,6 +21019,7 @@ <int value="219" label="kTransientBackground"/> <int value="220" label="kLogin"/> <int value="221" label="kLoginScreenStorage"/> + <int value="222" label="kLoginState"/> </enum> <enum name="ExtensionServiceVerifyAllSuccess"> @@ -35067,6 +35083,7 @@ <int value="-1278796760" label="QueryInOmnibox:enabled"/> <int value="-1276912933" label="enable-quick-unlock-pin"/> <int value="-1276579737" label="PictureInPictureAPI:disabled"/> + <int value="-1274502866" label="AllowDisableMouseAcceleration:enabled"/> <int value="-1272593346" label="NewTabLoadingAnimation:disabled"/> <int value="-1271563519" label="enable-appcontainer"/> <int value="-1269962982" label="SyncUSSPasswords:disabled"/> @@ -35319,6 +35336,7 @@ <int value="-964676765" label="enable-accelerated-mjpeg-decode"/> <int value="-962030536" label="ChromeDuetLabeled:enabled"/> <int value="-960077963" label="EnableAuraTooltipsOnWindows:enabled"/> + <int value="-958950214" label="AllowDisableMouseAcceleration:disabled"/> <int value="-957200826" label="enable-spdy-proxy-auth"/> <int value="-956696029" label="scheduler-configuration"/> <int value="-953215709" label="StorageAccessAPI:enabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 92c1456..a1ed523 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -3856,6 +3856,12 @@ <summary>Records the invocation count of WebView callbacks.</summary> </histogram> +<histogram name="Android.WebView.ClearProxyOverride" expires_after="2020-08-13"> + <owner>laisminchillo@chromium.org</owner> + <owner>tobiasjs@chromium.org</owner> + <summary>Records ClearProxyOverride calls.</summary> +</histogram> + <histogram name="Android.WebView.Gfx.FunctorStencilEnabled" enum="BooleanEnabled" expires_after="M78"> <owner>boliu@chromium.org</owner> @@ -3978,6 +3984,31 @@ </summary> </histogram> +<histogram name="Android.WebView.SetProxyOverride.BypassRules" + enum="BooleanPresent" expires_after="2020-08-13"> + <owner>laisminchillo@chromium.org</owner> + <owner>tobiasjs@chromium.org</owner> + <summary> + Records whether bypass rules were present in SetProxyOverride calls. + </summary> +</histogram> + +<histogram name="Android.WebView.SetProxyOverride.ProxySchemeFilterType" + enum="AndroidWebViewProxySchemeFilterType" expires_after="2020-08-13"> + <owner>laisminchillo@chromium.org</owner> + <owner>tobiasjs@chromium.org</owner> + <summary> + Records the type of scheme filter in SetProxyOverride calls. + </summary> +</histogram> + +<histogram name="Android.WebView.SetProxyOverride.ProxyUrlType" + enum="AndroidWebViewProxyUrlType" expires_after="2020-08-13"> + <owner>laisminchillo@chromium.org</owner> + <owner>tobiasjs@chromium.org</owner> + <summary>Records the type of url in SetProxyOverride calls.</summary> +</histogram> + <histogram name="Android.WebView.ShouldInterceptRequest.InterceptionType" enum="InterceptionType" expires_after="2020-02-11"> <owner>timvolodine@chromium.org</owner> @@ -68060,6 +68091,20 @@ </summary> </histogram> +<histogram name="Mouse.Acceleration.Changed" enum="BooleanEnabled" + expires_after="M87"> + <owner>zentaro@chromium.org</owner> + <owner>cros-peripherals@chromium.org</owner> + <summary>Tracks mouse acceleration setting changes by the user.</summary> +</histogram> + +<histogram name="Mouse.Acceleration.Started" enum="BooleanEnabled" + expires_after="M87"> + <owner>zentaro@chromium.org</owner> + <owner>cros-peripherals@chromium.org</owner> + <summary>Tracks mouse acceleration setting on startup.</summary> +</histogram> + <histogram name="Mouse.PointerSensitivity.Changed" enum="PointerSensitivity" expires_after="2018-08-30"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> @@ -78763,6 +78808,16 @@ </summary> </histogram> +<histogram name="Net.RestrictedCookieManager.SetCanonicalCookieDomainMatch" + enum="Boolean" expires_after="2020-08-30"> + <owner>chlily@chromium.org</owner> + <owner>morlovich@chromium.org</owner> + <summary> + Logged whenever the RestrictedCookieManager sets a CanonicalCookie. True if + the domain of the cookie matches the domain of the URL, false otherwise. + </summary> +</histogram> + <histogram name="Net.Socket.IdleSocketFate" enum="IdleSocketFate" expires_after="2017-09-21"> <obsolete> @@ -129484,14 +129539,20 @@ </histogram> <histogram name="Signin.DiceResponseHeader" enum="SigninDiceResponseHeader" - expires_after="M77"> + expires_after="never"> +<!-- expires-never: used to monitor the health of the Dice feature and for troubleshooting. --> + <owner>droger@chromium.org</owner> + <owner>msarda@chromium.org</owner> <summary>Records Dice responses (signin and signout).</summary> </histogram> <histogram name="Signin.DiceTokenFetchResult" enum="SigninDiceTokenFetchResult" - expires_after="M77"> + expires_after="never"> +<!-- expires-never: used to monitor the health of the Dice feature and for troubleshooting. --> + <owner>droger@chromium.org</owner> + <owner>msarda@chromium.org</owner> <summary>Outcome of the token fetch in Dice signin.</summary> </histogram> @@ -129580,8 +129641,11 @@ </histogram> <histogram name="Signin.InvalidGaiaCredentialsReason" - enum="SigninInvalidGaiaCredentialsReason" expires_after="M77"> + enum="SigninInvalidGaiaCredentialsReason" expires_after="never"> +<!-- expires-never: used to monitor the health of the signin feature and for troubleshooting. --> + <owner>droger@chromium.org</owner> + <owner>msarda@chromium.org</owner> <summary> Reason for invalid Gaia credentials. Recorded when Signin.AuthError records invalid credentials. @@ -129668,8 +129732,11 @@ </histogram> <histogram name="Signin.LoadTokenFromDB" enum="SigninLoadTokenFromDB" - expires_after="M77"> + expires_after="never"> +<!-- expires-never: used to monitor the health of the signin feature and for troubleshooting. --> + <owner>droger@chromium.org</owner> + <owner>msarda@chromium.org</owner> <summary> Action taken for tokens being loaded from the token database, at Chrome startup. Tokens can be either loaded into Chrome's token service or revoked. @@ -129983,7 +130050,9 @@ </histogram> <histogram name="Signin.SigninAllowed" units="BooleanEnabled" - expires_after="2019-10-01"> + expires_after="never"> +<!-- expires-never: used to monitor the health of the signin feature. --> + <owner>droger@chromium.org</owner> <owner>msarda@chromium.org</owner> <owner>tangltom@chromium.org</owner> @@ -144330,6 +144399,20 @@ <summary>Tracks the usage of the default touch bar buttons.</summary> </histogram> +<histogram name="Touchpad.Acceleration.Changed" enum="BooleanEnabled" + expires_after="M87"> + <owner>zentaro@chromium.org</owner> + <owner>cros-peripherals@chromium.org</owner> + <summary>Tracks touchpad acceleration setting changes by the user.</summary> +</histogram> + +<histogram name="Touchpad.Acceleration.Started" enum="BooleanEnabled" + expires_after="M87"> + <owner>zentaro@chromium.org</owner> + <owner>cros-peripherals@chromium.org</owner> + <summary>Tracks touchpad acceleration setting on startup.</summary> +</histogram> + <histogram name="Touchpad.Device" enum="TouchpadDeviceState"> <owner>jhawkins@chromium.org</owner> <summary>Tracks touchpad device state.</summary>
diff --git a/tools/perf/benchmarks/v8_browsing.py b/tools/perf/benchmarks/v8_browsing.py index 308d18d..916556b 100644 --- a/tools/perf/benchmarks/v8_browsing.py +++ b/tools/perf/benchmarks/v8_browsing.py
@@ -27,10 +27,6 @@ def V8BrowsingShouldAddValue(name): - # TODO(crbug.com/775942): The "unknown_browser" is needed because of a race - # condition in the memory dump manager. Remove this once the bug is fixed. - if 'memory:chrome' in name or 'memory:unknown_browser' in name: - return 'renderer_processes' in name if 'v8-gc' in name: return (_V8_GC_HIGH_LEVEL_STATS_RE.search(name) and not _IGNORED_V8_STATS_RE.search(name))
diff --git a/tools/perf/core/results_processor/processor.py b/tools/perf/core/results_processor/processor.py index 8bd0205..73bcd7685 100644 --- a/tools/perf/core/results_processor/processor.py +++ b/tools/perf/core/results_processor/processor.py
@@ -112,8 +112,9 @@ else: options.upload_bucket = None - chosen_formats = options.output_formats - if not chosen_formats: + if options.output_formats: + chosen_formats = sorted(set(options.output_formats)) + else: chosen_formats = ['html'] options.output_formats = []
diff --git a/tools/perf/core/results_processor/processor_unittest.py b/tools/perf/core/results_processor/processor_unittest.py index 47ce73d..a6e7c25 100644 --- a/tools/perf/core/results_processor/processor_unittest.py +++ b/tools/perf/core/results_processor/processor_unittest.py
@@ -140,6 +140,15 @@ self.assertEqual(options.output_formats, ['new-format']) self.assertEqual(options.legacy_output_formats, ['old-format']) + @mock.patch.dict(module('SUPPORTED_FORMATS'), {'new-format': None}) + def testNoDuplicateOutputFormats(self): + self.legacy_formats = ['old-format'] + options = self.ParseArgs( + ['--output-format', 'new-format', '--output-format', 'old-format', + '--output-format', 'new-format', '--output-format', 'old-format']) + self.assertEqual(options.output_formats, ['new-format']) + self.assertEqual(options.legacy_output_formats, ['old-format']) + class StandaloneTestProcessOptions(ProcessOptionsTestCase): def setUp(self):
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index 0e8f556..4a7a8bbd 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -334,6 +334,7 @@ crbug.com/959418 [ chromeos ] system_health.memory_desktop/long_running:tools:gmail-background [ Skip ] crbug.com/959418 [ chromeos ] system_health.memory_desktop/load:games:spychase:2018 [ Skip ] crbug.com/959418 [ chromeos ] system_health.memory_desktop/long_running:tools:gmail-foreground [ Skip ] +crbug.com/999004 [ linux ] system_health.memory_desktop/load:news:bbc:2018 [ Skip ] # Benchmark: system_health.memory_mobile crbug.com/914390 [ android-nexus-5 ] system_health.memory_mobile/browse:chrome:newtab [ Skip ]
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index f7e77e46..53d4f4b4 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -70,9 +70,9 @@ <item id="desktop_ios_promotion" hash_code="13694792" type="0" deprecated="2018-11-04" content_hash_code="19776951" file_path=""/> <item id="device_geolocation_request" hash_code="77673751" type="0" deprecated="2017-10-20" content_hash_code="97181773" file_path=""/> <item id="device_management_service" hash_code="117782019" type="0" content_hash_code="104419970" os_list="linux,windows" file_path="components/policy/core/common/cloud/device_management_service.cc"/> - <item id="devtools_free_data_source" hash_code="22774132" type="0" content_hash_code="35733000" os_list="linux,windows" file_path="chrome/browser/ui/webui/devtools_ui.cc"/> + <item id="devtools_free_data_source" hash_code="22774132" type="0" content_hash_code="35733000" os_list="linux,windows" file_path="chrome/browser/ui/webui/devtools_ui_data_source.cc"/> <item id="devtools_handle_front_end_messages" hash_code="135636011" type="0" content_hash_code="76808593" os_list="linux,windows" file_path="content/shell/browser/shell_devtools_bindings.cc"/> - <item id="devtools_hard_coded_data_source" hash_code="111565057" type="0" content_hash_code="75183720" os_list="linux,windows" file_path="chrome/browser/ui/webui/devtools_ui.cc"/> + <item id="devtools_hard_coded_data_source" hash_code="111565057" type="0" content_hash_code="75183720" os_list="linux,windows" file_path="chrome/browser/ui/webui/devtools_ui_data_source.cc"/> <item id="devtools_http_handler" hash_code="49160454" type="0" content_hash_code="88414393" os_list="linux,windows" file_path="content/browser/devtools/devtools_http_handler.cc"/> <item id="devtools_interceptor" hash_code="98123737" type="0" deprecated="2019-07-31" content_hash_code="64591843" file_path=""/> <item id="devtools_network_resource" hash_code="129652775" type="0" content_hash_code="32810159" os_list="linux,windows" file_path="chrome/browser/devtools/devtools_ui_bindings.cc"/>
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn index bc50666..355a279 100644 --- a/ui/aura/BUILD.gn +++ b/ui/aura/BUILD.gn
@@ -251,6 +251,10 @@ } sources += [ "test/ui_controls_factory_ozone.cc" ] } + + if (is_linux) { + deps += [ "//ui/platform_window/common" ] + } } executable("aura_demo") {
diff --git a/ui/aura/test/aura_test_helper.cc b/ui/aura/test/aura_test_helper.cc index 3a2e00b..d17f4de8 100644 --- a/ui/aura/test/aura_test_helper.cc +++ b/ui/aura/test/aura_test_helper.cc
@@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/run_loop.h" +#include "build/build_config.h" #include "ui/aura/client/default_capture_client.h" #include "ui/aura/client/focus_client.h" #include "ui/aura/env.h" @@ -21,13 +22,16 @@ #include "ui/aura/window_targeter.h" #include "ui/base/ime/init/input_method_factory.h" #include "ui/base/ime/init/input_method_initializer.h" -#include "ui/base/platform_window_defaults.h" #include "ui/compositor/compositor.h" #include "ui/compositor/layer_animator.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/display/screen.h" #include "ui/wm/core/wm_state.h" +#if defined(OS_LINUX) +#include "ui/platform_window/common/platform_window_defaults.h" // nogncheck +#endif + #if defined(USE_X11) #include "ui/base/x/x11_util.h" // nogncheck #endif @@ -47,7 +51,9 @@ // Disable animations during tests. zero_duration_mode_ = std::make_unique<ui::ScopedAnimationDurationScaleMode>( ui::ScopedAnimationDurationScaleMode::ZERO_DURATION); +#if defined(OS_LINUX) ui::test::EnableTestConfigForPlatformWindows(); +#endif } AuraTestHelper::~AuraTestHelper() {
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc index 17c00c0..afa9987 100644 --- a/ui/aura/window_tree_host.cc +++ b/ui/aura/window_tree_host.cc
@@ -379,12 +379,11 @@ //window()->RemoveOrDestroyChildren(); } -void WindowTreeHost::CreateCompositor( - const viz::FrameSinkId& frame_sink_id, - bool force_software_compositor, - ui::ExternalBeginFrameClient* external_begin_frame_client, - bool are_events_in_pixels, - const char* trace_environment_name) { +void WindowTreeHost::CreateCompositor(const viz::FrameSinkId& frame_sink_id, + bool force_software_compositor, + bool use_external_begin_frame_control, + bool are_events_in_pixels, + const char* trace_environment_name) { Env* env = Env::GetInstance(); ui::ContextFactory* context_factory = env->context_factory(); DCHECK(context_factory); @@ -396,7 +395,7 @@ : context_factory_private->AllocateFrameSinkId(), context_factory, context_factory_private, base::ThreadTaskRunnerHandle::Get(), ui::IsPixelCanvasRecordingEnabled(), - external_begin_frame_client, force_software_compositor, + use_external_begin_frame_control, force_software_compositor, trace_environment_name); #if defined(OS_CHROMEOS) compositor_->AddObserver(this);
diff --git a/ui/aura/window_tree_host.h b/ui/aura/window_tree_host.h index 1b5360da..cbc990d 100644 --- a/ui/aura/window_tree_host.h +++ b/ui/aura/window_tree_host.h
@@ -263,7 +263,7 @@ void CreateCompositor( const viz::FrameSinkId& frame_sink_id = viz::FrameSinkId(), bool force_software_compositor = false, - ui::ExternalBeginFrameClient* external_begin_frame_client = nullptr, + bool use_external_begin_frame_control = false, bool are_events_in_pixels = true, const char* trace_environment_name = nullptr);
diff --git a/ui/aura/window_tree_host_platform.cc b/ui/aura/window_tree_host_platform.cc index fe8e2ba..5a9c6679 100644 --- a/ui/aura/window_tree_host_platform.cc +++ b/ui/aura/window_tree_host_platform.cc
@@ -34,7 +34,7 @@ #endif #if defined(USE_X11) -#include "ui/platform_window/x11/x11_window.h" +#include "ui/platform_window/x11/x11_window.h" // nogncheck #endif namespace aura { @@ -51,12 +51,12 @@ ui::PlatformWindowInitProperties properties, std::unique_ptr<Window> window, const char* trace_environment_name, - ui::ExternalBeginFrameClient* external_begin_frame_client) + bool use_external_begin_frame_control) : WindowTreeHost(std::move(window)) { bounds_in_pixels_ = properties.bounds; CreateCompositor(viz::FrameSinkId(), /* force_software_compositor */ false, - external_begin_frame_client, + use_external_begin_frame_control, /* are_events_in_pixels */ true, trace_environment_name); CreateAndSetPlatformWindow(std::move(properties)); } @@ -72,9 +72,11 @@ platform_window_ = ui::OzonePlatform::GetInstance()->CreatePlatformWindow( this, std::move(properties)); #elif defined(OS_WIN) - platform_window_ = std::make_unique<ui::WinWindow>(this, properties.bounds); + platform_window_.reset(new ui::WinWindow(this, properties.bounds)); #elif defined(USE_X11) - platform_window_ = std::make_unique<ui::X11Window>(this, properties.bounds); + auto x11_window = std::make_unique<ui::X11Window>(this, nullptr); + x11_window->Initialize(std::move(properties)); + SetPlatformWindow(std::move(x11_window)); #else NOTIMPLEMENTED(); #endif @@ -269,7 +271,6 @@ widget_ = gfx::kNullAcceleratedWidget; } -void WindowTreeHostPlatform::OnActivationChanged(bool active) { -} +void WindowTreeHostPlatform::OnActivationChanged(bool active) {} } // namespace aura
diff --git a/ui/aura/window_tree_host_platform.h b/ui/aura/window_tree_host_platform.h index 73f55f4c..7483b1f 100644 --- a/ui/aura/window_tree_host_platform.h +++ b/ui/aura/window_tree_host_platform.h
@@ -19,7 +19,6 @@ namespace ui { enum class DomCode; -class ExternalBeginFrameClient; class KeyboardHook; struct PlatformWindowInitProperties; } // namespace ui @@ -36,7 +35,7 @@ ui::PlatformWindowInitProperties properties, std::unique_ptr<Window> = nullptr, const char* trace_environment_name = nullptr, - ui::ExternalBeginFrameClient* external_begin_frame_client = nullptr); + bool use_external_begin_frame_control = false); ~WindowTreeHostPlatform() override; // WindowTreeHost:
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn index 234227d..0a3994c 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn
@@ -218,8 +218,6 @@ "nine_image_painter_factory.h", "page_transition_types.cc", "page_transition_types.h", - "platform_window_defaults.cc", - "platform_window_defaults.h", "resource/resource_bundle.cc", "resource/resource_bundle.h", "resource/resource_bundle_android.cc",
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc index 6934dac..835d14a 100644 --- a/ui/base/ui_base_features.cc +++ b/ui/base/ui_base_features.cc
@@ -56,20 +56,10 @@ #endif }; -// Enables out-of-process rasterization for all UI drawing (where not -// blacklisted). If both GPU and OOP rasterization for UI are enabled then -// OOP-R will take precedence. -const base::Feature kUiOopRasterization{"UiOopRasterization", - base::FEATURE_DISABLED_BY_DEFAULT}; - bool IsUiGpuRasterizationEnabled() { return base::FeatureList::IsEnabled(kUiGpuRasterization); } -bool IsUiOopRasterizationEnabled() { - return base::FeatureList::IsEnabled(kUiOopRasterization); -} - // Enables scrolling with layers under ui using the ui::Compositor. const base::Feature kUiCompositorScrollWithLayers = { "UiCompositorScrollWithLayers",
diff --git a/ui/base/ui_base_features.h b/ui/base/ui_base_features.h index e8e2f96..e7deb66 100644 --- a/ui/base/ui_base_features.h +++ b/ui/base/ui_base_features.h
@@ -36,7 +36,6 @@ COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsNotificationIndicatorEnabled(); COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsUiGpuRasterizationEnabled(); -COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsUiOopRasterizationEnabled(); #if defined(OS_WIN) COMPONENT_EXPORT(UI_BASE_FEATURES)
diff --git a/ui/base/x/BUILD.gn b/ui/base/x/BUILD.gn index f0175b4..d94dae6 100644 --- a/ui/base/x/BUILD.gn +++ b/ui/base/x/BUILD.gn
@@ -47,5 +47,6 @@ "//ui/events/x:x", "//ui/gfx", "//ui/gfx/x", + "//ui/platform_window/common", ] }
diff --git a/ui/base/x/DEPS b/ui/base/x/DEPS new file mode 100644 index 0000000..edeb0030 --- /dev/null +++ b/ui/base/x/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+ui/platform_window/common/platform_window_defaults.h", +]
diff --git a/ui/base/x/x11_window.cc b/ui/base/x/x11_window.cc index fb188e0..1bb97da 100644 --- a/ui/base/x/x11_window.cc +++ b/ui/base/x/x11_window.cc
@@ -26,6 +26,7 @@ #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_rep.h" #include "ui/gfx/x/x11_atom_cache.h" +#include "ui/platform_window/common/platform_window_defaults.h" namespace ui { @@ -104,11 +105,9 @@ XWindow::Configuration::~Configuration() = default; -XWindow::XWindow(Delegate* delegate) - : delegate_(delegate), - xdisplay_(gfx::GetXDisplay()), +XWindow::XWindow() + : xdisplay_(gfx::GetXDisplay()), x_root_window_(DefaultRootWindow(xdisplay_)) { - DCHECK(delegate_); DCHECK(xdisplay_); DCHECK_NE(x_root_window_, x11::None); } @@ -153,6 +152,21 @@ if (!activatable_) swa.override_redirect = x11::True; +#if !defined(USE_X11) + // It seems like there is a difference how tests are instantiated in case of + // non-Ozone X11 and Ozone. See more details in + // EnableTestConfigForPlatformWindows. The reason why this must be here is + // that we removed X11WindowBase in favor of the XWindow. The X11WindowBase + // was only used with PlatformWindow, which meant non-Ozone X11 did not use it + // and set override_redirect based only on |activatable_| variable or + // WindowType. But now as XWindow is subclassed by X11Window, which is also a + // PlatformWindow, and non-Ozone X11 uses it, we have to add this workaround + // here. Otherwise, tests for non-Ozone X11 fail. + // TODO(msisov): figure out usage of this for non-Ozone X11. + if (UseTestConfigForPlatformWindows()) + swa.override_redirect = true; +#endif + override_redirect_ = swa.override_redirect == x11::True; if (override_redirect_) attribute_mask |= CWOverrideRedirect; @@ -197,8 +211,7 @@ bounds_in_pixels_.height(), 0, // border width depth, InputOutput, visual, attribute_mask, &swa); - - delegate_->OnXWindowCreated(); + OnXWindowCreated(); // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL(). @@ -753,7 +766,7 @@ workspace_ = base::nullopt; if (workspace_ != old_workspace) - delegate_->OnXWindowWorkspaceChanged(); + OnXWindowWorkspaceChanged(); } void XWindow::SetAlwaysOnTop(bool always_on_top) { @@ -782,21 +795,22 @@ } void XWindow::UpdateMinAndMaxSize() { - gfx::Size minimum_in_pixels = delegate_->GetMinimumSizeForXWindow(); - gfx::Size maximum_in_pixels = delegate_->GetMaximumSizeForXWindow(); - if (min_size_in_pixels_ == minimum_in_pixels && - max_size_in_pixels_ == maximum_in_pixels) + base::Optional<gfx::Size> minimum_in_pixels = GetMinimumSizeForXWindow(); + base::Optional<gfx::Size> maximum_in_pixels = GetMaximumSizeForXWindow(); + if ((!minimum_in_pixels || + min_size_in_pixels_ == minimum_in_pixels.value()) && + (!maximum_in_pixels || max_size_in_pixels_ == maximum_in_pixels.value())) return; - min_size_in_pixels_ = minimum_in_pixels; - max_size_in_pixels_ = maximum_in_pixels; + min_size_in_pixels_ = minimum_in_pixels.value(); + max_size_in_pixels_ = maximum_in_pixels.value(); XSizeHints hints; hints.flags = 0; long supplied_return; XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return); - if (minimum_in_pixels.IsEmpty()) { + if (min_size_in_pixels_.IsEmpty()) { hints.flags &= ~PMinSize; } else { hints.flags |= PMinSize; @@ -804,7 +818,7 @@ hints.min_height = min_size_in_pixels_.height(); } - if (maximum_in_pixels.IsEmpty()) { + if (max_size_in_pixels_.IsEmpty()) { hints.flags &= ~PMaxSize; } else { hints.flags |= PMaxSize; @@ -824,19 +838,19 @@ void XWindow::AfterActivationStateChanged() { if (had_pointer_grab_ && !has_pointer_grab_) - delegate_->OnXWindowLostPointerGrab(); + OnXWindowLostPointerGrab(); bool had_pointer_capture = had_pointer_ || had_pointer_grab_; bool has_pointer_capture = has_pointer_ || has_pointer_grab_; if (had_pointer_capture && !has_pointer_capture) - delegate_->OnXWindowLostCapture(); + OnXWindowLostCapture(); bool is_active = IsActive(); if (!was_active_ && is_active) FlashFrame(false); if (was_active_ != is_active) - delegate_->OnXWindowIsActiveChanged(is_active); + OnXWindowIsActiveChanged(is_active); } void XWindow::SetUseNativeFrame(bool use_native_frame) { @@ -1036,7 +1050,7 @@ gfx::Point window_origin = gfx::Point() + (root_point - window_point); if (bounds_in_pixels_.origin() != window_origin) { bounds_in_pixels_.set_origin(window_origin); - delegate_->OnXWindowMoved(window_origin); + OnXWindowBoundsChanged(bounds_in_pixels_); } } @@ -1045,11 +1059,16 @@ switch (xev->type) { case EnterNotify: case LeaveNotify: { +#if defined(USE_X11) // Ignore EventNotify and LeaveNotify events from children of |xwindow_|. // NativeViewGLSurfaceGLX adds a child to |xwindow_|. if (xev->xcrossing.detail != NotifyInferior) { - delegate_->OnXWindowChildCrossingEvent(xev); - } else { + DCHECK(xev); + ui::MouseEvent mouse_event(xev); + OnXWindowEvent(&mouse_event); + } else +#endif + { bool is_enter = xev->type == EnterNotify; OnCrossingEvent(is_enter, xev->xcrossing.focus, xev->xcrossing.mode, xev->xcrossing.detail); @@ -1059,13 +1078,13 @@ case Expose: { gfx::Rect damage_rect_in_pixels(xev->xexpose.x, xev->xexpose.y, xev->xexpose.width, xev->xexpose.height); - delegate_->OnXWindowDamageEvent(damage_rect_in_pixels); + OnXWindowDamageEvent(damage_rect_in_pixels); break; } #if !defined(USE_OZONE) case KeyPress: case KeyRelease: - delegate_->OnXWindowRawKeyEvent(xev); + OnXWindowRawKeyEvent(xev); break; case ButtonPress: case ButtonRelease: { @@ -1073,13 +1092,13 @@ switch (event_type) { case ui::ET_MOUSEWHEEL: { ui::MouseWheelEvent mouseev(xev); - delegate_->OnXWindowMouseEvent(&mouseev); + OnXWindowEvent(&mouseev); break; } case ui::ET_MOUSE_PRESSED: case ui::ET_MOUSE_RELEASED: { ui::MouseEvent mouseev(xev); - delegate_->OnXWindowMouseEvent(&mouseev); + OnXWindowEvent(&mouseev); break; } case ui::ET_UNKNOWN: @@ -1137,7 +1156,7 @@ case ui::ET_TOUCH_PRESSED: case ui::ET_TOUCH_RELEASED: { ui::TouchEvent touchev(xev); - delegate_->OnXWindowTouchEvent(&touchev); + OnXWindowEvent(&touchev); break; } case ui::ET_MOUSE_MOVED: @@ -1162,12 +1181,12 @@ // DT_CMT_SCROLL_ data. See more discussion in // https://crrev.com/c/853953 if (mouseev.type() != ui::ET_UNKNOWN) - delegate_->OnXWindowMouseEvent(&mouseev); + OnXWindowEvent(&mouseev); break; } case ui::ET_MOUSEWHEEL: { ui::MouseWheelEvent mouseev(xev); - delegate_->OnXWindowMouseEvent(&mouseev); + OnXWindowEvent(&mouseev); break; } case ui::ET_SCROLL_FLING_START: @@ -1179,13 +1198,13 @@ // event and we need delta to determine which element to scroll on // phaseBegan. if (scrollev.x_offset() != 0.0 || scrollev.y_offset() != 0.0) - delegate_->OnXWindowScrollEvent(&scrollev); + OnXWindowEvent(&scrollev); break; } case ui::ET_KEY_PRESSED: case ui::ET_KEY_RELEASED: { ui::KeyEvent key_event(xev); - delegate_->OnXWindowKeyEvent(&key_event); + OnXWindowEvent(&key_event); break; } case ui::ET_UNKNOWN: @@ -1211,7 +1230,7 @@ has_pointer_grab_ = false; has_pointer_focus_ = false; has_window_focus_ = false; - delegate_->OnXWindowUnmapped(); + OnXWindowUnmapped(); break; } case ClientMessage: { @@ -1220,7 +1239,7 @@ Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]); if (protocol == gfx::GetAtom("WM_DELETE_WINDOW")) { // We have received a close message from the window manager. - delegate_->OnXWindowCloseRequested(); + OnXWindowCloseRequested(); } else if (protocol == gfx::GetAtom("_NET_WM_PING")) { XEvent reply_event = *xev; reply_event.xclient.window = x_root_window_; @@ -1235,7 +1254,7 @@ pending_counter_value_is_extended_ = xev->xclient.data.l[4] != 0; } } else { - delegate_->OnXWindowDragDropEvent(xev); + OnXWindowDragDropEvent(xev); } break; } @@ -1274,7 +1293,7 @@ } ui::MouseEvent mouseev(xev); - delegate_->OnXWindowMouseEvent(&mouseev); + OnXWindowEvent(&mouseev); break; } #endif @@ -1290,7 +1309,7 @@ break; } case SelectionNotify: { - delegate_->OnXWindowSelectionEvent(xev); + OnXWindowSelectionEvent(xev); break; } } @@ -1314,7 +1333,7 @@ void XWindow::OnWindowMapped() { window_mapped_in_server_ = true; - delegate_->OnXWindowMapped(); + OnXWindowMapped(); // Some WMs only respect maximize hints after the window has been mapped. // Check whether we need to re-do a maximization. if (should_maximize_after_map_) { @@ -1353,11 +1372,10 @@ previous_bounds_in_pixels_ = bounds_in_pixels_; bounds_in_pixels_ = bounds_in_pixels; - if (origin_changed) - delegate_->OnXWindowMoved(bounds_in_pixels_.origin()); - if (size_changed) - delegate_->OnXWindowSizeChanged(bounds_in_pixels_.size()); + DispatchResize(); + else if (origin_changed) + OnXWindowBoundsChanged(bounds_in_pixels_); } void XWindow::SetWMSpecState(bool enabled, XAtom state1, XAtom state2) { @@ -1403,8 +1421,7 @@ is_always_on_top_ = ui::HasWMSpecProperty( window_properties_, gfx::GetAtom("_NET_WM_STATE_ABOVE")); - - delegate_->OnXWindowStateChanged(); + OnXWindowStateChanged(); } void XWindow::OnFrameExtentsUpdated() { @@ -1448,7 +1465,7 @@ // compositor. delayed_resize_task_.Reset(base::BindOnce(&XWindow::DelayedResize, weak_factory_.GetWeakPtr(), - bounds_in_pixels_.size())); + bounds_in_pixels_)); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, delayed_resize_task_.callback()); return; @@ -1465,10 +1482,10 @@ // If _NET_WM_SYNC_REQUEST is used to synchronize with compositor during // resizing, the compositor will not resize the window, until last resize is // handled, so we don't need accumulate resize events. - DelayedResize(bounds_in_pixels_.size()); + DelayedResize(bounds_in_pixels_); } -void XWindow::DelayedResize(const gfx::Size& size_in_pixels) { +void XWindow::DelayedResize(const gfx::Rect& bounds_in_pixels) { if (configure_counter_value_is_extended_ && (current_counter_value_ % 2) == 0) { // Increase the |extended_update_counter_|, so the compositor will know we @@ -1478,7 +1495,7 @@ SyncSetCounter(xdisplay_, extended_update_counter_, ++current_counter_value_); } - delegate_->OnXWindowSizeChanged(size_in_pixels); + OnXWindowBoundsChanged(bounds_in_pixels); CancelResize(); } @@ -1525,43 +1542,4 @@ has_pointer_barriers_ = false; } -// Empty/stub implementation of XWindow::Delegate methods, which are considered -// optional for ui::XWindow users, making it possible to handle only events of -// interest. -void XWindow::Delegate::OnXWindowMapped() {} - -void XWindow::Delegate::OnXWindowUnmapped() {} - -void XWindow::Delegate::OnXWindowMoved(const gfx::Point&) {} - -void XWindow::Delegate::OnXWindowWorkspaceChanged() {} - -void XWindow::Delegate::OnXWindowLostPointerGrab() {} - -void XWindow::Delegate::OnXWindowLostCapture() {} - -void XWindow::Delegate::OnXWindowKeyEvent(ui::KeyEvent*) {} - -void XWindow::Delegate::OnXWindowMouseEvent(ui::MouseEvent*) {} - -void XWindow::Delegate::OnXWindowTouchEvent(ui::TouchEvent*) {} - -void XWindow::Delegate::OnXWindowScrollEvent(ui::ScrollEvent*) {} - -void XWindow::Delegate::OnXWindowSelectionEvent(XEvent*) {} - -void XWindow::Delegate::OnXWindowDragDropEvent(XEvent*) {} - -void XWindow::Delegate::OnXWindowChildCrossingEvent(XEvent*) {} - -void XWindow::Delegate::OnXWindowRawKeyEvent(XEvent*) {} - -gfx::Size XWindow::Delegate::GetMinimumSizeForXWindow() { - return gfx::Size(); -} - -gfx::Size XWindow::Delegate::GetMaximumSizeForXWindow() { - return gfx::Size(); -} - } // namespace ui
diff --git a/ui/base/x/x11_window.h b/ui/base/x/x11_window.h index 8d2e1384..9db97d2f 100644 --- a/ui/base/x/x11_window.h +++ b/ui/base/x/x11_window.h
@@ -29,10 +29,7 @@ namespace ui { -class KeyEvent; -class MouseEvent; -class TouchEvent; -class ScrollEvent; +class Event; class XScopedEventSelector; //////////////////////////////////////////////////////////////////////////////// @@ -88,7 +85,7 @@ std::string wm_role_name; }; - explicit XWindow(Delegate* delegate); + XWindow(); virtual ~XWindow(); void Init(const Configuration& config); @@ -188,7 +185,7 @@ // Handle the state change since BeforeActivationStateChanged(). void AfterActivationStateChanged(); - void DelayedResize(const gfx::Size& size_in_pixels); + void DelayedResize(const gfx::Rect& bounds_in_pixels); // Updates |xwindow_|'s _NET_WM_USER_TIME if |xwindow_| is active. void UpdateWMUserTime(XEvent* event); @@ -209,7 +206,25 @@ void UnconfineCursor(); - Delegate* delegate_; + // Interface that must be used by a class that inherits the XWindow to receive + // different messages from X Server. + virtual void OnXWindowCreated() = 0; + virtual void OnXWindowStateChanged() = 0; + virtual void OnXWindowDamageEvent(const gfx::Rect& damage_rect) = 0; + virtual void OnXWindowBoundsChanged(const gfx::Rect& size) = 0; + virtual void OnXWindowCloseRequested() = 0; + virtual void OnXWindowIsActiveChanged(bool active) = 0; + virtual void OnXWindowMapped() = 0; + virtual void OnXWindowUnmapped() = 0; + virtual void OnXWindowWorkspaceChanged() = 0; + virtual void OnXWindowLostPointerGrab() = 0; + virtual void OnXWindowLostCapture() = 0; + virtual void OnXWindowEvent(ui::Event* event) = 0; + virtual void OnXWindowSelectionEvent(XEvent* xev) = 0; + virtual void OnXWindowDragDropEvent(XEvent* xev) = 0; + virtual void OnXWindowRawKeyEvent(XEvent* xev) = 0; + virtual base::Optional<gfx::Size> GetMinimumSizeForXWindow() = 0; + virtual base::Optional<gfx::Size> GetMaximumSizeForXWindow() = 0; // The display and the native X window hosting the root window. XDisplay* xdisplay_ = nullptr; @@ -347,44 +362,6 @@ DISALLOW_COPY_AND_ASSIGN(XWindow); }; -// Delegate interface used to communicate the XWindow API client about events -// of interest and request information which depends on external components. -class COMPONENT_EXPORT(UI_BASE_X) XWindow::Delegate { - public: - virtual void OnXWindowCreated() = 0; - virtual void OnXWindowStateChanged() = 0; - virtual void OnXWindowDamageEvent(const gfx::Rect& damage_rect) = 0; - virtual void OnXWindowSizeChanged(const gfx::Size& size) = 0; - virtual void OnXWindowCloseRequested() = 0; - virtual void OnXWindowIsActiveChanged(bool active) = 0; - - // Optional Hooks - virtual void OnXWindowMapped(); - virtual void OnXWindowUnmapped(); - virtual void OnXWindowMoved(const gfx::Point& window_origin); - virtual void OnXWindowWorkspaceChanged(); - virtual void OnXWindowLostPointerGrab(); - virtual void OnXWindowLostCapture(); - - // TODO(crbug.com/981606): Consider unifying event handling functions - virtual void OnXWindowKeyEvent(ui::KeyEvent* key_event); - virtual void OnXWindowMouseEvent(ui::MouseEvent* event); - virtual void OnXWindowTouchEvent(ui::TouchEvent* event); - virtual void OnXWindowScrollEvent(ui::ScrollEvent* event); - - virtual void OnXWindowSelectionEvent(XEvent* xev); - virtual void OnXWindowDragDropEvent(XEvent* xev); - virtual void OnXWindowChildCrossingEvent(XEvent* xev); - - // TODO(crbug.com/981606): DesktopWindowTreeHostX11 forward raw |XEvent|s to - // ATK components that currently live in views layer. Remove once ATK code - // is reworked to be reusable. - virtual void OnXWindowRawKeyEvent(XEvent* xev); - - virtual gfx::Size GetMinimumSizeForXWindow(); - virtual gfx::Size GetMaximumSizeForXWindow(); -}; - } // namespace ui #endif // UI_BASE_X_X11_WINDOW_H_
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn index 41119f7..c88c59d7 100644 --- a/ui/compositor/BUILD.gn +++ b/ui/compositor/BUILD.gn
@@ -29,7 +29,6 @@ "debug_utils.h", "dip_util.cc", "dip_util.h", - "external_begin_frame_client.h", "float_animation_curve_adapter.cc", "float_animation_curve_adapter.h", "layer.cc",
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index ab21624..18984aa0 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -45,7 +45,6 @@ #include "ui/compositor/compositor_observer.h" #include "ui/compositor/compositor_switches.h" #include "ui/compositor/dip_util.h" -#include "ui/compositor/external_begin_frame_client.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_animator_collection.h" #include "ui/compositor/overscroll/scroll_input_handler.h" @@ -62,20 +61,19 @@ } // namespace -Compositor::Compositor( - const viz::FrameSinkId& frame_sink_id, - ui::ContextFactory* context_factory, - ui::ContextFactoryPrivate* context_factory_private, - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - bool enable_pixel_canvas, - ui::ExternalBeginFrameClient* external_begin_frame_client, - bool force_software_compositor, - const char* trace_environment_name) +Compositor::Compositor(const viz::FrameSinkId& frame_sink_id, + ui::ContextFactory* context_factory, + ui::ContextFactoryPrivate* context_factory_private, + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + bool enable_pixel_canvas, + bool use_external_begin_frame_control, + bool force_software_compositor, + const char* trace_environment_name) : context_factory_(context_factory), context_factory_private_(context_factory_private), frame_sink_id_(frame_sink_id), task_runner_(task_runner), - external_begin_frame_client_(external_begin_frame_client), + use_external_begin_frame_control_(use_external_begin_frame_control), force_software_compositor_(force_software_compositor), layer_animator_collection_(this), is_pixel_canvas_(enable_pixel_canvas), @@ -225,9 +223,7 @@ cc::AnimationTimeline::Create(cc::AnimationIdProvider::NextTimelineId()); animation_host_->AddAnimationTimeline(animation_timeline_.get()); - bool gpu_raster_trigger = features::IsUiGpuRasterizationEnabled() || - features::IsUiOopRasterizationEnabled(); - host_->SetHasGpuRasterizationTrigger(gpu_raster_trigger); + host_->SetHasGpuRasterizationTrigger(features::IsUiGpuRasterizationEnabled()); host_->SetRootLayer(root_web_layer_); // This shouldn't be done in the constructor in order to match Widget.
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index 359e7d21..09bedf9 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h
@@ -31,7 +31,6 @@ #include "ui/compositor/compositor_export.h" #include "ui/compositor/compositor_lock.h" #include "ui/compositor/compositor_observer.h" -#include "ui/compositor/external_begin_frame_client.h" #include "ui/compositor/layer_animator_collection.h" #include "ui/gfx/color_space.h" #include "ui/gfx/geometry/size.h" @@ -73,7 +72,6 @@ namespace ui { class Compositor; -class ExternalBeginFrameClient; class LatencyInfo; class Layer; class Reflector; @@ -145,8 +143,12 @@ virtual void SetDisplayVSyncParameters(ui::Compositor* compositor, base::TimeTicks timebase, base::TimeDelta interval) = 0; - virtual void IssueExternalBeginFrame(ui::Compositor* compositor, - const viz::BeginFrameArgs& args) = 0; + + virtual void IssueExternalBeginFrame( + ui::Compositor* compositor, + const viz::BeginFrameArgs& args, + bool force, + base::OnceCallback<void(const viz::BeginFrameAck&)> callback) = 0; virtual void SetOutputIsSecure(Compositor* compositor, bool secure) = 0; @@ -211,7 +213,7 @@ ui::ContextFactoryPrivate* context_factory_private, scoped_refptr<base::SingleThreadTaskRunner> task_runner, bool enable_pixel_canvas, - ExternalBeginFrameClient* external_begin_frame_client = nullptr, + bool use_external_begin_frame_control = false, bool force_software_compositor = false, const char* trace_environment_name = nullptr); ~Compositor() override; @@ -425,8 +427,8 @@ int activated_frame_count() const { return activated_frame_count_; } float refresh_rate() const { return refresh_rate_; } - ExternalBeginFrameClient* external_begin_frame_client() { - return external_begin_frame_client_; + bool use_external_begin_frame_control() const { + return use_external_begin_frame_control_; } void SetAllowLocksToExtendTimeout(bool allowed) { @@ -477,8 +479,7 @@ base::TimeTicks vsync_timebase_; base::TimeDelta vsync_interval_; - ExternalBeginFrameClient* const external_begin_frame_client_; - + const bool use_external_begin_frame_control_; const bool force_software_compositor_; // The device scale factor of the monitor that this compositor is compositing
diff --git a/ui/compositor/external_begin_frame_client.h b/ui/compositor/external_begin_frame_client.h deleted file mode 100644 index 7083c6e..0000000 --- a/ui/compositor/external_begin_frame_client.h +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_COMPOSITOR_EXTERNAL_BEGIN_FRAME_CLIENT_H_ -#define UI_COMPOSITOR_EXTERNAL_BEGIN_FRAME_CLIENT_H_ - -#include "components/viz/common/frame_sinks/begin_frame_args.h" -#include "ui/compositor/compositor_export.h" - -namespace ui { - -class COMPOSITOR_EXPORT ExternalBeginFrameClient { - public: - virtual ~ExternalBeginFrameClient() {} - - // Called when a BeginFrame was completed by the Display. - virtual void OnDisplayDidFinishFrame(const viz::BeginFrameAck& ack) = 0; - // Called to signal whether the client should generate BeginFrames. - virtual void OnNeedsExternalBeginFrames(bool needs_begin_frames) = 0; -}; - -} // namespace ui - -#endif // UI_COMPOSITOR_EXTERNAL_BEGIN_FRAME_CLIENT_H_
diff --git a/ui/compositor/host/BUILD.gn b/ui/compositor/host/BUILD.gn index 1fad890..21b1752 100644 --- a/ui/compositor/host/BUILD.gn +++ b/ui/compositor/host/BUILD.gn
@@ -5,34 +5,25 @@ import("//build/config/ui.gni") source_set("host") { - public = [ - "external_begin_frame_controller_client_impl.h", - ] - sources = [ - "external_begin_frame_controller_client_impl.cc", - ] - - deps = [ - "//mojo/public/cpp/bindings", - "//ui/compositor", - ] - - public_deps = [ - "//services/viz/privileged/mojom/compositing", - ] - if (use_aura || is_mac) { - public += [ "host_context_factory_private.h" ] - sources += [ "host_context_factory_private.cc" ] + public = [ + "host_context_factory_private.h", + ] + sources = [ + "host_context_factory_private.cc", + ] - deps += [ + deps = [ "//cc/mojo_embedder", "//components/viz/client", "//components/viz/common", "//components/viz/host", + "//ui/compositor", "//ui/gfx", ] - public_deps += [ "//services/viz/public/mojom" ] + public_deps = [ + "//services/viz/public/mojom", + ] } }
diff --git a/ui/compositor/host/external_begin_frame_controller_client_impl.cc b/ui/compositor/host/external_begin_frame_controller_client_impl.cc deleted file mode 100644 index 964ca2f..0000000 --- a/ui/compositor/host/external_begin_frame_controller_client_impl.cc +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2018 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/compositor/host/external_begin_frame_controller_client_impl.h" - -#include "ui/compositor/compositor.h" - -namespace ui { - -ExternalBeginFrameControllerClientImpl::ExternalBeginFrameControllerClientImpl( - ui::ExternalBeginFrameClient* client) - : client_(client), binding_(this) {} - -ExternalBeginFrameControllerClientImpl:: - ~ExternalBeginFrameControllerClientImpl() = default; - -viz::mojom::ExternalBeginFrameControllerClientPtr -ExternalBeginFrameControllerClientImpl::GetBoundPtr() { - viz::mojom::ExternalBeginFrameControllerClientPtr ptr; - binding_.Bind(mojo::MakeRequest(&ptr)); - return ptr; -} - -viz::mojom::ExternalBeginFrameControllerAssociatedRequest -ExternalBeginFrameControllerClientImpl::GetControllerRequest() { - return mojo::MakeRequest(&controller_); -} - -viz::mojom::ExternalBeginFrameControllerAssociatedPtr& -ExternalBeginFrameControllerClientImpl::GetController() { - return controller_; -} - -void ExternalBeginFrameControllerClientImpl::OnNeedsBeginFrames( - bool needs_begin_frames) { - client_->OnNeedsExternalBeginFrames(needs_begin_frames); -} - -void ExternalBeginFrameControllerClientImpl::OnDisplayDidFinishFrame( - const viz::BeginFrameAck& ack) { - client_->OnDisplayDidFinishFrame(ack); -} - -} // namespace ui
diff --git a/ui/compositor/host/external_begin_frame_controller_client_impl.h b/ui/compositor/host/external_begin_frame_controller_client_impl.h deleted file mode 100644 index c238f6dc..0000000 --- a/ui/compositor/host/external_begin_frame_controller_client_impl.h +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_COMPOSITOR_HOST_EXTERNAL_BEGIN_FRAME_CONTROLLER_CLIENT_IMPL_H_ -#define UI_COMPOSITOR_HOST_EXTERNAL_BEGIN_FRAME_CONTROLLER_CLIENT_IMPL_H_ - -#include "mojo/public/cpp/bindings/binding.h" -#include "services/viz/privileged/mojom/compositing/external_begin_frame_controller.mojom.h" - -namespace ui { - -class ExternalBeginFrameClient; - -// ExternalBeginFrameControllerClient implementation that notifies an -// ExternalBeginFrameClient about BeginFrame events. -class ExternalBeginFrameControllerClientImpl - : public viz::mojom::ExternalBeginFrameControllerClient { - public: - explicit ExternalBeginFrameControllerClientImpl( - ui::ExternalBeginFrameClient* client); - ~ExternalBeginFrameControllerClientImpl() override; - - viz::mojom::ExternalBeginFrameControllerClientPtr GetBoundPtr(); - - viz::mojom::ExternalBeginFrameControllerAssociatedRequest - GetControllerRequest(); - - viz::mojom::ExternalBeginFrameControllerAssociatedPtr& GetController(); - - private: - // viz::ExternalBeginFrameControllerClient implementation. - void OnNeedsBeginFrames(bool needs_begin_frames) override; - void OnDisplayDidFinishFrame(const viz::BeginFrameAck& ack) override; - - ui::ExternalBeginFrameClient* client_; - - mojo::Binding<viz::mojom::ExternalBeginFrameControllerClient> binding_; - viz::mojom::ExternalBeginFrameControllerAssociatedPtr controller_; -}; - -} // namespace ui - -#endif // UI_COMPOSITOR_HOST_EXTERNAL_BEGIN_FRAME_CONTROLLER_CLIENT_IMPL_H_
diff --git a/ui/compositor/host/host_context_factory_private.cc b/ui/compositor/host/host_context_factory_private.cc index d32c154..6743045a 100644 --- a/ui/compositor/host/host_context_factory_private.cc +++ b/ui/compositor/host/host_context_factory_private.cc
@@ -17,7 +17,6 @@ #include "services/viz/privileged/mojom/compositing/frame_sink_manager.mojom.h" #include "services/viz/privileged/mojom/compositing/vsync_parameter_observer.mojom.h" #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h" -#include "ui/compositor/host/external_begin_frame_controller_client_impl.h" #include "ui/compositor/reflector.h" #if defined(OS_WIN) @@ -104,18 +103,9 @@ compositor_data.display_client->GetBoundPtr(resize_task_runner_) .PassInterface(); - // Initialize ExternalBeginFrameController client if enabled. - compositor_data.external_begin_frame_controller_client.reset(); - if (compositor->external_begin_frame_client()) { - compositor_data.external_begin_frame_controller_client = - std::make_unique<ExternalBeginFrameControllerClientImpl>( - compositor->external_begin_frame_client()); + if (compositor->use_external_begin_frame_control()) { root_params->external_begin_frame_controller = - compositor_data.external_begin_frame_controller_client - ->GetControllerRequest(); - root_params->external_begin_frame_controller_client = - compositor_data.external_begin_frame_controller_client->GetBoundPtr() - .PassInterface(); + mojo::MakeRequest(&compositor_data.external_begin_frame_controller); } root_params->frame_sink_id = compositor->frame_sink_id(); @@ -261,14 +251,14 @@ void HostContextFactoryPrivate::IssueExternalBeginFrame( Compositor* compositor, - const viz::BeginFrameArgs& args) { + const viz::BeginFrameArgs& args, + bool force, + base::OnceCallback<void(const viz::BeginFrameAck&)> callback) { auto iter = compositor_data_map_.find(compositor); - if (iter == compositor_data_map_.end() || !iter->second.display_private) - return; + DCHECK(iter != compositor_data_map_.end() && iter->second.display_private); - DCHECK(iter->second.external_begin_frame_controller_client); - iter->second.external_begin_frame_controller_client->GetController() - ->IssueExternalBeginFrame(args); + iter->second.external_begin_frame_controller->IssueExternalBeginFrame( + args, force, std::move(callback)); } void HostContextFactoryPrivate::SetOutputIsSecure(Compositor* compositor,
diff --git a/ui/compositor/host/host_context_factory_private.h b/ui/compositor/host/host_context_factory_private.h index 113f4a5..c0b5293 100644 --- a/ui/compositor/host/host_context_factory_private.h +++ b/ui/compositor/host/host_context_factory_private.h
@@ -14,6 +14,7 @@ #include "components/viz/common/display/renderer_settings.h" #include "components/viz/common/surfaces/frame_sink_id_allocator.h" #include "services/viz/privileged/mojom/compositing/display_private.mojom.h" +#include "services/viz/privileged/mojom/compositing/external_begin_frame_controller.mojom.h" #include "ui/compositor/compositor.h" namespace base { @@ -28,8 +29,6 @@ namespace ui { -class ExternalBeginFrameControllerClientImpl; - class HostContextFactoryPrivate : public ContextFactoryPrivate { public: HostContextFactoryPrivate( @@ -80,8 +79,11 @@ void SetDisplayVSyncParameters(Compositor* compositor, base::TimeTicks timebase, base::TimeDelta interval) override; - void IssueExternalBeginFrame(Compositor* compositor, - const viz::BeginFrameArgs& args) override; + void IssueExternalBeginFrame( + Compositor* compositor, + const viz::BeginFrameArgs& args, + bool force, + base::OnceCallback<void(const viz::BeginFrameAck&)> callback) override; void SetOutputIsSecure(Compositor* compositor, bool secure) override; void AddVSyncParameterObserver( Compositor* compositor, @@ -98,11 +100,8 @@ // CompositorFrameSink. viz::mojom::DisplayPrivateAssociatedPtr display_private; std::unique_ptr<viz::HostDisplayClient> display_client; - - // Controls external BeginFrames for the display. Only set if external - // BeginFrames are enabled for the compositor. - std::unique_ptr<ExternalBeginFrameControllerClientImpl> - external_begin_frame_controller_client; + viz::mojom::ExternalBeginFrameControllerAssociatedPtr + external_begin_frame_controller; // SetOutputIsSecure is called before the compositor is ready, so remember // the status and apply it during configuration.
diff --git a/ui/compositor/test/in_process_context_factory.h b/ui/compositor/test/in_process_context_factory.h index ce639df..b03851f 100644 --- a/ui/compositor/test/in_process_context_factory.h +++ b/ui/compositor/test/in_process_context_factory.h
@@ -90,8 +90,11 @@ void SetDisplayVSyncParameters(ui::Compositor* compositor, base::TimeTicks timebase, base::TimeDelta interval) override {} - void IssueExternalBeginFrame(ui::Compositor* compositor, - const viz::BeginFrameArgs& args) override {} + void IssueExternalBeginFrame( + ui::Compositor* compositor, + const viz::BeginFrameArgs& args, + bool force, + base::OnceCallback<void(const viz::BeginFrameAck&)> callback) override {} void SetOutputIsSecure(ui::Compositor* compositor, bool secure) override {} void AddVSyncParameterObserver( ui::Compositor* compositor,
diff --git a/ui/events/ozone/evdev/input_controller_evdev.cc b/ui/events/ozone/evdev/input_controller_evdev.cc index d8a96f8..a7ef8810 100644 --- a/ui/events/ozone/evdev/input_controller_evdev.cc +++ b/ui/events/ozone/evdev/input_controller_evdev.cc
@@ -157,6 +157,16 @@ ScheduleUpdateDeviceSettings(); } +void InputControllerEvdev::SetMouseAcceleration(bool enabled) { + input_device_settings_.mouse_acceleration_enabled = enabled; + ScheduleUpdateDeviceSettings(); +} + +void InputControllerEvdev::SetTouchpadAcceleration(bool enabled) { + input_device_settings_.touchpad_acceleration_enabled = enabled; + ScheduleUpdateDeviceSettings(); +} + void InputControllerEvdev::SetTapToClickPaused(bool state) { input_device_settings_.tap_to_click_paused = state; ScheduleUpdateDeviceSettings();
diff --git a/ui/events/ozone/evdev/input_controller_evdev.h b/ui/events/ozone/evdev/input_controller_evdev.h index 1bfd81b..e57becf 100644 --- a/ui/events/ozone/evdev/input_controller_evdev.h +++ b/ui/events/ozone/evdev/input_controller_evdev.h
@@ -58,6 +58,8 @@ void SetMouseSensitivity(int value) override; void SetPrimaryButtonRight(bool right) override; void SetMouseReverseScroll(bool enabled) override; + void SetMouseAcceleration(bool enabled) override; + void SetTouchpadAcceleration(bool enabled) override; void SetTapToClickPaused(bool state) override; void GetTouchDeviceStatus(GetTouchDeviceStatusReply reply) override; void GetTouchEventLog(const base::FilePath& out_dir,
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.cc b/ui/events/ozone/evdev/input_device_factory_evdev.cc index 91440c1f..fb7fd06 100644 --- a/ui/events/ozone/evdev/input_device_factory_evdev.cc +++ b/ui/events/ozone/evdev/input_device_factory_evdev.cc
@@ -317,6 +317,9 @@ input_device_settings_.touchpad_sensitivity); SetIntPropertyForOneType(DT_TOUCHPAD, "Scroll Sensitivity", input_device_settings_.touchpad_sensitivity); + SetBoolPropertyForOneType( + DT_TOUCHPAD, "Pointer Acceleration", + input_device_settings_.touchpad_acceleration_enabled); SetBoolPropertyForOneType(DT_TOUCHPAD, "Tap Enable", input_device_settings_.tap_to_click_enabled); @@ -332,6 +335,8 @@ input_device_settings_.mouse_sensitivity); SetIntPropertyForOneType(DT_MOUSE, "Scroll Sensitivity", input_device_settings_.mouse_sensitivity); + SetBoolPropertyForOneType(DT_MOUSE, "Pointer Acceleration", + input_device_settings_.mouse_acceleration_enabled); SetBoolPropertyForOneType( DT_MOUSE, "Mouse Reverse Scrolling", input_device_settings_.mouse_reverse_scroll_enabled);
diff --git a/ui/events/ozone/evdev/input_device_settings_evdev.h b/ui/events/ozone/evdev/input_device_settings_evdev.h index 8b3c9a0..a08f3ab8 100644 --- a/ui/events/ozone/evdev/input_device_settings_evdev.h +++ b/ui/events/ozone/evdev/input_device_settings_evdev.h
@@ -27,6 +27,8 @@ bool tap_to_click_paused = false; bool touch_event_logging_enabled = true; bool mouse_reverse_scroll_enabled = false; + bool mouse_acceleration_enabled = true; + bool touchpad_acceleration_enabled = true; int touchpad_sensitivity = kDefaultSensitivity; int mouse_sensitivity = kDefaultSensitivity;
diff --git a/ui/events/platform/x11/x11_event_source.h b/ui/events/platform/x11/x11_event_source.h index e44fb018..a655cc82 100644 --- a/ui/events/platform/x11/x11_event_source.h +++ b/ui/events/platform/x11/x11_event_source.h
@@ -160,8 +160,8 @@ // State necessary for UpdateLastSeenServerTime bool dummy_initialized_; - XWindow dummy_window_; - XAtom dummy_atom_; + ::XWindow dummy_window_; + ::XAtom dummy_atom_; std::unique_ptr<XScopedEventSelector> dummy_window_events_; // Keeps track of whether this source should continue to dispatch all the
diff --git a/ui/gfx/platform_font_mac.mm b/ui/gfx/platform_font_mac.mm index 1f57c28..4a07886 100644 --- a/ui/gfx/platform_font_mac.mm +++ b/ui/gfx/platform_font_mac.mm
@@ -126,11 +126,13 @@ // Documentation is vague about what sized floating point type should be used. // However, numeric_limits::epsilon() for 64-bit types is too small to match - // the above table, so use 32-bit float. + // the above table, so use 32-bit float. Do not check for the success of + // CFNumberGetValue(). CFNumberGetValue() returns false for *any* loss of + // value, and a float is used here deliberately to coarsen the accuracy. + // There's no guarantee that any particular value for the kCTFontWeightTrait + // will be able to be accurately represented with a float. float weight_value; - Boolean success = - CFNumberGetValue(cf_weight, kCFNumberFloatType, &weight_value); - DCHECK(success); + CFNumberGetValue(cf_weight, kCFNumberFloatType, &weight_value); for (const auto& item : weight_map) { if (weight_value - item.ct_weight <= std::numeric_limits<float>::epsilon()) return item.gfx_weight;
diff --git a/ui/gfx/platform_font_mac_unittest.mm b/ui/gfx/platform_font_mac_unittest.mm index 422e242..8df42d81 100644 --- a/ui/gfx/platform_font_mac_unittest.mm +++ b/ui/gfx/platform_font_mac_unittest.mm
@@ -165,19 +165,22 @@ // Each typeface maps weight notches differently, and the weight is actually a // floating point value that may not map directly to a gfx::Font::Weight. For - // example San Francisco on macOS 10.12 goes up from 0 in the sequence: - // [0.23, 0.23, 0.3, 0.4, 0.56, 0.62, 0.62, ...] and has no "thin" weights. - // But also iterating over weights does weird stuff sometimes - occasionally - // the font goes italic, but going up another step goes back to non-italic, - // at a heavier weight. + // example San Francisco on macOS 10.12 goes up from 0 in the sequence: [0.23, + // 0.23, 0.3, 0.4, 0.56, 0.62, 0.62, ...] and has no "thin" weights. But also + // iterating over weights does weird stuff sometimes - before macOS 10.15, + // occasionally the font goes italic, but going up another step goes back to + // non-italic, at a heavier weight. // NSCTFontUIUsageAttribute = CTFontMediumUsage. ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.23. EXPECT_EQ(Font::Weight::MEDIUM, Font(ns_font).GetWeight()); // Row 6. - // Goes italic: NSCTFontUIUsageAttribute = CTFontMediumItalicUsage. - ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.23. - EXPECT_EQ(Font::Weight::MEDIUM, Font(ns_font).GetWeight()); // Row 7. + // 10.15 fixed the bug where the step up from medium created a medium italic. + if (base::mac::IsAtMostOS10_14()) { + // Goes italic: NSCTFontUIUsageAttribute = CTFontMediumItalicUsage. + ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.23. + EXPECT_EQ(Font::Weight::MEDIUM, Font(ns_font).GetWeight()); // Row 7. + } // NSCTFontUIUsageAttribute = CTFontDemiUsage. ns_font = [manager convertWeight:up ofFont:ns_font]; // 0.3.
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn index fa26af6..4657246 100644 --- a/ui/gl/BUILD.gn +++ b/ui/gl/BUILD.gn
@@ -474,6 +474,10 @@ "//ui/base", ] + if (is_linux) { + deps += [ "//ui/platform_window/common" ] + } + if (use_x11) { configs += [ "//build/config/linux:x11" ] deps += [ "//ui/platform_window/x11" ]
diff --git a/ui/gl/test/DEPS b/ui/gl/test/DEPS index 8330a13..0349f94 100644 --- a/ui/gl/test/DEPS +++ b/ui/gl/test/DEPS
@@ -5,4 +5,5 @@ "+mojo/core/embedder", "+services/service_manager/public", "+services/viz/public", + "+ui/platform_window/common/platform_window_defaults.h", ]
diff --git a/ui/gl/test/gl_surface_test_support.cc b/ui/gl/test/gl_surface_test_support.cc index b2e456b..0b446da9 100644 --- a/ui/gl/test/gl_surface_test_support.cc +++ b/ui/gl/test/gl_surface_test_support.cc
@@ -9,12 +9,15 @@ #include "base/command_line.h" #include "base/logging.h" #include "build/build_config.h" -#include "ui/base/platform_window_defaults.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_switches.h" #include "ui/gl/init/gl_factory.h" +#if defined(OS_LINUX) +#include "ui/platform_window/common/platform_window_defaults.h" // nogncheck +#endif + #if defined(USE_OZONE) #include "ui/ozone/public/ozone_platform.h" #endif @@ -40,7 +43,9 @@ ui::OzonePlatform::GetInstance()->AfterSandboxEntry(); #endif +#if defined(OS_LINUX) ui::test::EnableTestConfigForPlatformWindows(); +#endif bool use_software_gl = true;
diff --git a/ui/ozone/platform/cast/platform_window_cast.cc b/ui/ozone/platform/cast/platform_window_cast.cc index 697a3e3..84b68c8 100644 --- a/ui/ozone/platform/cast/platform_window_cast.cc +++ b/ui/ozone/platform/cast/platform_window_cast.cc
@@ -10,7 +10,6 @@ #include "ui/events/platform/platform_event_source.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" -#include "ui/platform_window/platform_window_delegate.h" namespace ui {
diff --git a/ui/ozone/platform/cast/platform_window_cast.h b/ui/ozone/platform/cast/platform_window_cast.h index 500a5bf8..35fb374 100644 --- a/ui/ozone/platform/cast/platform_window_cast.h +++ b/ui/ozone/platform/cast/platform_window_cast.h
@@ -7,12 +7,11 @@ #include "base/macros.h" #include "ui/events/platform/platform_event_dispatcher.h" +#include "ui/platform_window/platform_window_delegate.h" #include "ui/platform_window/stub/stub_window.h" namespace ui { -class PlatformWindowDelegate; - class PlatformWindowCast : public StubWindow, public PlatformEventDispatcher { public: PlatformWindowCast(PlatformWindowDelegate* delegate, const gfx::Rect& bounds);
diff --git a/ui/ozone/platform/drm/host/drm_window_host.cc b/ui/ozone/platform/drm/host/drm_window_host.cc index e76d4d4..4c5a1b2 100644 --- a/ui/ozone/platform/drm/host/drm_window_host.cc +++ b/ui/ozone/platform/drm/host/drm_window_host.cc
@@ -17,7 +17,6 @@ #include "ui/ozone/platform/drm/host/drm_display_host_manager.h" #include "ui/ozone/platform/drm/host/drm_window_host_manager.h" #include "ui/ozone/platform/drm/host/gpu_thread_adapter.h" -#include "ui/platform_window/platform_window_delegate.h" namespace ui {
diff --git a/ui/ozone/platform/drm/host/drm_window_host.h b/ui/ozone/platform/drm/host/drm_window_host.h index b4374978..2524f21 100644 --- a/ui/ozone/platform/drm/host/drm_window_host.h +++ b/ui/ozone/platform/drm/host/drm_window_host.h
@@ -16,6 +16,7 @@ #include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/drm/host/gpu_thread_observer.h" #include "ui/platform_window/platform_window.h" +#include "ui/platform_window/platform_window_delegate.h" namespace ui { @@ -25,7 +26,6 @@ class DrmWindowHostManager; class EventFactoryEvdev; class GpuThreadAdapter; -class PlatformWindowDelegate; // Implementation of the platform window. This object and its handle |widget_| // uniquely identify a window. Since the DRI/GBM platform is split into 2
diff --git a/ui/ozone/platform/headless/headless_window.cc b/ui/ozone/platform/headless/headless_window.cc index 3e38770..d4444e3 100644 --- a/ui/ozone/platform/headless/headless_window.cc +++ b/ui/ozone/platform/headless/headless_window.cc
@@ -9,7 +9,6 @@ #include "build/build_config.h" #include "ui/events/platform/platform_event_source.h" #include "ui/ozone/platform/headless/headless_window_manager.h" -#include "ui/platform_window/platform_window_delegate.h" namespace ui {
diff --git a/ui/ozone/platform/headless/headless_window.h b/ui/ozone/platform/headless/headless_window.h index 0690480..d13c5c7 100644 --- a/ui/ozone/platform/headless/headless_window.h +++ b/ui/ozone/platform/headless/headless_window.h
@@ -8,11 +8,11 @@ #include "base/macros.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" +#include "ui/platform_window/platform_window_delegate.h" #include "ui/platform_window/stub/stub_window.h" namespace ui { -class PlatformWindowDelegate; class HeadlessWindowManager; class HeadlessWindow : public StubWindow {
diff --git a/ui/ozone/platform/magma/magma_window.cc b/ui/ozone/platform/magma/magma_window.cc index 4b7d841..3e63cd6 100644 --- a/ui/ozone/platform/magma/magma_window.cc +++ b/ui/ozone/platform/magma/magma_window.cc
@@ -9,7 +9,6 @@ #include "build/build_config.h" #include "ui/events/platform/platform_event_source.h" #include "ui/ozone/platform/magma/magma_window_manager.h" -#include "ui/platform_window/platform_window_delegate.h" namespace ui {
diff --git a/ui/ozone/platform/magma/magma_window.h b/ui/ozone/platform/magma/magma_window.h index 94847f99..fc7186f 100644 --- a/ui/ozone/platform/magma/magma_window.h +++ b/ui/ozone/platform/magma/magma_window.h
@@ -8,11 +8,11 @@ #include "base/macros.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" +#include "ui/platform_window/platform_window_delegate.h" #include "ui/platform_window/stub/stub_window.h" namespace ui { -class PlatformWindowDelegate; class MagmaWindowManager; class MagmaWindow : public StubWindow {
diff --git a/ui/ozone/platform/scenic/scenic_window.cc b/ui/ozone/platform/scenic/scenic_window.cc index 2599ee7..b89d38b 100644 --- a/ui/ozone/platform/scenic/scenic_window.cc +++ b/ui/ozone/platform/scenic/scenic_window.cc
@@ -18,7 +18,6 @@ #include "ui/events/ozone/events_ozone.h" #include "ui/events/platform/platform_event_source.h" #include "ui/ozone/platform/scenic/scenic_window_manager.h" -#include "ui/platform_window/platform_window_delegate.h" namespace ui {
diff --git a/ui/ozone/platform/scenic/scenic_window.h b/ui/ozone/platform/scenic/scenic_window.h index e8f85db5..9376a08 100644 --- a/ui/ozone/platform/scenic/scenic_window.h +++ b/ui/ozone/platform/scenic/scenic_window.h
@@ -22,11 +22,11 @@ #include "ui/gfx/geometry/size_f.h" #include "ui/gfx/native_widget_types.h" #include "ui/platform_window/platform_window.h" +#include "ui/platform_window/platform_window_delegate.h" namespace ui { class ScenicWindowManager; -class PlatformWindowDelegate; class COMPONENT_EXPORT(OZONE) ScenicWindow : public PlatformWindow,
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc index 4909a5d..6d5533a 100644 --- a/ui/ozone/platform/wayland/host/wayland_window.cc +++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -166,6 +166,10 @@ is_tooltip_ = true; break; case ui::PlatformWindowType::kWindow: + case ui::PlatformWindowType::kBubble: + case ui::PlatformWindowType::kDrag: + // TODO(msisov): Figure out what kind of surface we need to create for + // bubble and drag windows. CreateXdgSurface(); break; }
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h index c5f4e556..0548cbc 100644 --- a/ui/ozone/platform/wayland/host/wayland_window.h +++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -31,7 +31,6 @@ class BitmapCursorOzone; class OSExchangeData; -class PlatformWindowDelegate; class WaylandConnection; class XDGPopupWrapper; class XDGSurfaceWrapper;
diff --git a/ui/ozone/platform/windows/windows_window.cc b/ui/ozone/platform/windows/windows_window.cc index 8da06d17..1e0ecdc 100644 --- a/ui/ozone/platform/windows/windows_window.cc +++ b/ui/ozone/platform/windows/windows_window.cc
@@ -9,7 +9,6 @@ #include "build/build_config.h" #include "ui/events/platform/platform_event_source.h" #include "ui/ozone/platform/windows/windows_window_manager.h" -#include "ui/platform_window/platform_window_delegate.h" namespace ui {
diff --git a/ui/ozone/platform/windows/windows_window.h b/ui/ozone/platform/windows/windows_window.h index 87935e2c..fe5049d 100644 --- a/ui/ozone/platform/windows/windows_window.h +++ b/ui/ozone/platform/windows/windows_window.h
@@ -8,12 +8,11 @@ #include "base/macros.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" +#include "ui/platform_window/platform_window_delegate.h" #include "ui/platform_window/win/win_window.h" namespace ui { -class PlatformWindowDelegate; - class WindowsWindow : public WinWindow { public: WindowsWindow(PlatformWindowDelegate* delegate, const gfx::Rect& bounds);
diff --git a/ui/ozone/platform/x11/ozone_platform_x11.cc b/ui/ozone/platform/x11/ozone_platform_x11.cc index 470673d..ed98346 100644 --- a/ui/ozone/platform/x11/ozone_platform_x11.cc +++ b/ui/ozone/platform/x11/ozone_platform_x11.cc
@@ -83,8 +83,9 @@ std::unique_ptr<PlatformWindow> CreatePlatformWindow( PlatformWindowDelegate* delegate, PlatformWindowInitProperties properties) override { - std::unique_ptr<X11WindowOzone> window = std::make_unique<X11WindowOzone>( - delegate, properties, window_manager_.get()); + std::unique_ptr<X11WindowOzone> window = + std::make_unique<X11WindowOzone>(delegate, window_manager_.get()); + window->Initialize(std::move(properties)); window->SetTitle(base::ASCIIToUTF16("Ozone X11")); return std::move(window); }
diff --git a/ui/ozone/platform/x11/x11_screen_ozone.cc b/ui/ozone/platform/x11/x11_screen_ozone.cc index d3b1f25..54a8a076 100644 --- a/ui/ozone/platform/x11/x11_screen_ozone.cc +++ b/ui/ozone/platform/x11/x11_screen_ozone.cc
@@ -88,7 +88,7 @@ if (!window_bounds.Contains(screen_point_in_pixels_)) return false; - ::Region shape = window->GetShape(); + ::Region shape = window->shape(); if (!shape) return true;
diff --git a/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc b/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc index b1bfba5b..2a4b035 100644 --- a/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc +++ b/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc
@@ -103,8 +103,10 @@ EXPECT_CALL(*delegate, OnAcceleratedWidgetAvailable(_)) .WillOnce(StoreWidget(widget)); PlatformWindowInitProperties init_params(bounds); - return std::make_unique<X11WindowOzone>(delegate, init_params, - window_manager_.get()); + auto window = + std::make_unique<X11WindowOzone>(delegate, window_manager_.get()); + window->Initialize(std::move(init_params)); + return window; } MockDisplayObserver display_observer_;
diff --git a/ui/ozone/platform/x11/x11_window_ozone.cc b/ui/ozone/platform/x11/x11_window_ozone.cc index 5f2b621..f62b39e 100644 --- a/ui/ozone/platform/x11/x11_window_ozone.cc +++ b/ui/ozone/platform/x11/x11_window_ozone.cc
@@ -10,7 +10,6 @@ #include "base/bind.h" #include "base/strings/utf_string_conversions.h" -#include "ui/base/platform_window_defaults.h" #include "ui/base/x/x11_util.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" @@ -24,71 +23,14 @@ namespace ui { -namespace { - -ui::XWindow::Configuration ConvertInitPropertiesToXWindowConfig( - const PlatformWindowInitProperties& properties) { - using WindowType = ui::XWindow::WindowType; - using WindowOpacity = ui::XWindow::WindowOpacity; - ui::XWindow::Configuration config; - - switch (properties.type) { - case PlatformWindowType::kWindow: - config.type = WindowType::kWindow; - break; - case PlatformWindowType::kMenu: - config.type = WindowType::kMenu; - break; - case PlatformWindowType::kTooltip: - config.type = WindowType::kTooltip; - break; - case PlatformWindowType::kPopup: - config.type = WindowType::kPopup; - break; - } - - switch (properties.opacity) { - case PlatformWindowOpacity::kInferOpacity: - config.opacity = WindowOpacity::kInferOpacity; - break; - case PlatformWindowOpacity::kOpaqueWindow: - config.opacity = WindowOpacity::kOpaqueWindow; - break; - case PlatformWindowOpacity::kTranslucentWindow: - config.opacity = WindowOpacity::kTranslucentWindow; - break; - } - - config.bounds = properties.bounds; - config.force_show_in_taskbar = properties.force_show_in_taskbar; - config.keep_on_top = properties.keep_on_top; - config.visible_on_all_workspaces = properties.visible_on_all_workspaces; - config.remove_standard_frame = properties.remove_standard_frame; - config.workspace = properties.workspace; - config.wm_class_name = properties.wm_class_name; - config.wm_class_class = properties.wm_class_class; - config.wm_role_name = properties.wm_role_name; - - // TODO(nickdiego): {Use,Enable}TestConfigForPlatformWindows are used by test - // infra to disable platform windows activation. Figure out another way to do - // this in case Widget::InitParams::activation is needed in the future. - config.activatable = - properties.activatable && !UseTestConfigForPlatformWindows(); - - return config; -} - -} // namespace - X11WindowOzone::X11WindowOzone(PlatformWindowDelegate* delegate, - const PlatformWindowInitProperties& properties, X11WindowManagerOzone* window_manager) - : delegate_(delegate), - window_manager_(window_manager), - x11_window_(std::make_unique<ui::XWindow>(this)) { - DCHECK(delegate_); + : X11Window(delegate, nullptr), window_manager_(window_manager) { DCHECK(window_manager_); - Init(properties); + + // Set a class property key, which allows |this| to be used for interactive + // events, e.g. move or resize. + SetWmMoveResizeHandler(this, static_cast<WmMoveResizeHandler*>(this)); } X11WindowOzone::~X11WindowOzone() { @@ -96,21 +38,8 @@ Close(); } -void X11WindowOzone::Init(const PlatformWindowInitProperties& params) { - XWindow::Configuration config = ConvertInitPropertiesToXWindowConfig(params); - x11_window_->Init(config); - - // Set a class property key, which allows |this| to be used for interactive - // events, e.g. move or resize. - SetWmMoveResizeHandler(this, static_cast<WmMoveResizeHandler*>(this)); -} - -void X11WindowOzone::Show() { - x11_window_->Map(); -} - -void X11WindowOzone::Hide() { - x11_window_->Hide(); +void X11WindowOzone::OnLostCapture() { + X11Window::OnXWindowLostCapture(); } void X11WindowOzone::Close() { @@ -121,39 +50,14 @@ RemoveFromWindowManager(); SetWidget(x11::None); - x11_window_->Close(); - delegate_->OnClosed(); -} - -void X11WindowOzone::SetBounds(const gfx::Rect& bounds) { - DCHECK(!bounds.size().IsEmpty()); - - // Assume that the resize will go through as requested, which should be the - // case if we're running without a window manager. If there's a window - // manager, it can modify or ignore the request, but (per ICCCM) we'll get a - // (possibly synthetic) ConfigureNotify about the actual size and correct - // |bounds_| later. - x11_window_->SetBounds(bounds); - - // Even if the pixel bounds didn't change this call to the delegate should - // still happen. The device scale factor may have changed which effectively - // changes the bounds. - delegate_->OnBoundsChanged(bounds); -} - -gfx::Rect X11WindowOzone::GetBounds() { - return x11_window_->bounds(); -} - -void X11WindowOzone::SetTitle(const base::string16& title) { - x11_window_->SetTitle(title); + X11Window::Close(); } void X11WindowOzone::SetCapture() { if (HasCapture()) return; - x11_window_->GrabPointer(); + X11Window::SetCapture(); window_manager_->GrabEvents(this); } @@ -161,90 +65,13 @@ if (!HasCapture()) return; - x11_window_->ReleasePointerGrab(); + X11Window::ReleasePointerGrab(); window_manager_->UngrabEvents(this); } bool X11WindowOzone::HasCapture() const { return window_manager_->event_grabber() == this; } - -void X11WindowOzone::OnLostCapture() { - delegate_->OnLostCapture(); -} - -void X11WindowOzone::ToggleFullscreen() { - bool is_fullscreen = state_ == PlatformWindowState::kFullScreen; - x11_window_->SetFullscreen(!is_fullscreen); -} - -void X11WindowOzone::Maximize() { - if (state_ == PlatformWindowState::kFullScreen) - ToggleFullscreen(); - - x11_window_->Maximize(); -} - -void X11WindowOzone::Minimize() { - x11_window_->Minimize(); -} - -void X11WindowOzone::Restore() { - if (state_ == PlatformWindowState::kFullScreen) - ToggleFullscreen(); - - if (state_ == PlatformWindowState::kMaximized) { - x11_window_->Unmaximize(); - } -} - -PlatformWindowState X11WindowOzone::GetPlatformWindowState() const { - return state_; -} - -void X11WindowOzone::Activate() { - x11_window_->Activate(); -} - -void X11WindowOzone::Deactivate() { - x11_window_->Deactivate(); -} - -void X11WindowOzone::SetUseNativeFrame(bool use_native_frame) { - x11_window_->SetUseNativeFrame(use_native_frame); -} - -void X11WindowOzone::MoveCursorTo(const gfx::Point& location) { - x11_window_->MoveCursorTo(location); -} - -void X11WindowOzone::ConfineCursorToBounds(const gfx::Rect& bounds) { - x11_window_->ConfineCursorTo(bounds); -} - -void X11WindowOzone::SetRestoredBoundsInPixels(const gfx::Rect& bounds) { - // TODO(crbug.com/848131): Restore bounds on restart - NOTIMPLEMENTED_LOG_ONCE(); -} - -gfx::Rect X11WindowOzone::GetRestoredBoundsInPixels() const { - // TODO(crbug.com/848131): Restore bounds on restart - NOTIMPLEMENTED_LOG_ONCE(); - return gfx::Rect(); -} - -bool X11WindowOzone::IsVisible() const { - return x11_window_->IsVisible(); -} - -gfx::Rect X11WindowOzone::GetOutterBounds() const { - return x11_window_->GetOutterBounds(); -} - -::Region X11WindowOzone::GetShape() const { - return x11_window_->shape(); -} - void X11WindowOzone::PrepareForShutdown() { DCHECK(X11EventSource::GetInstance()); X11EventSource::GetInstance()->RemoveXEventDispatcher(this); @@ -252,7 +79,7 @@ void X11WindowOzone::SetCursor(PlatformCursor cursor) { X11CursorOzone* cursor_ozone = static_cast<X11CursorOzone*>(cursor); - x11_window_->SetCursor(cursor_ozone->xcursor()); + XWindow::SetCursor(cursor_ozone->xcursor()); } void X11WindowOzone::RemoveFromWindowManager() { @@ -271,7 +98,7 @@ if (is_shutting_down_) return; - handle_next_event_ = x11_window_->IsTargetedBy(*xev); + handle_next_event_ = XWindow::IsTargetedBy(*xev); } void X11WindowOzone::PlatformEventDispatchFinished() { @@ -283,20 +110,20 @@ } bool X11WindowOzone::DispatchXEvent(XEvent* xev) { - if (!x11_window_->IsTargetedBy(*xev)) + if (!XWindow::IsTargetedBy(*xev)) return false; - x11_window_->ProcessEvent(xev); + XWindow::ProcessEvent(xev); return true; } bool X11WindowOzone::CanDispatchEvent(const PlatformEvent& event) { - DCHECK_NE(x11_window_->window(), x11::None); + DCHECK_NE(XWindow::window(), x11::None); return handle_next_event_; } uint32_t X11WindowOzone::DispatchEvent(const PlatformEvent& event) { - DCHECK_NE(x11_window_->window(), x11::None); + DCHECK_NE(XWindow::window(), x11::None); if (!window_manager_->event_grabber() || window_manager_->event_grabber() == this) { @@ -304,7 +131,7 @@ // (eg. double click) are broken. DispatchEventFromNativeUiEvent( event, base::BindOnce(&PlatformWindowDelegate::DispatchEvent, - base::Unretained(delegate_))); + base::Unretained(platform_window_delegate()))); return POST_DISPATCH_STOP_PROPAGATION; } @@ -321,7 +148,7 @@ void X11WindowOzone::DispatchHostWindowDragMovement( int hittest, const gfx::Point& pointer_location) { - x11_window_->WmMoveResize(hittest, pointer_location); + XWindow::WmMoveResize(hittest, pointer_location); } void X11WindowOzone::SetWidget(XID xid) { @@ -330,58 +157,19 @@ // than 32 bits values on the wire (see https://crbug.com/607014 for more // details). So, It's safe to use static_cast here. widget_ = static_cast<gfx::AcceleratedWidget>(xid); - if (widget_ != gfx::kNullAcceleratedWidget) - delegate_->OnAcceleratedWidgetAvailable(widget_); } void X11WindowOzone::OnXWindowCreated() { - DCHECK_NE(x11_window_->window(), x11::None); - SetWidget(x11_window_->window()); + DCHECK_NE(XWindow::window(), x11::None); + SetWidget(XWindow::window()); window_manager_->AddWindow(this); + X11Window::OnXWindowCreated(); +} +void X11WindowOzone::SetPlatformEventDispatcher() { DCHECK(X11EventSource::GetInstance()); X11EventSource::GetInstance()->AddXEventDispatcher(this); } -void X11WindowOzone::OnXWindowStateChanged() { - // Propagate the window state information to the client. Note that the order - // of checks is important here, because window can have several proprties at - // the same time. - PlatformWindowState old_state = state_; - if (x11_window_->IsMinimized()) { - state_ = PlatformWindowState::kMinimized; - } else if (x11_window_->IsFullscreen()) { - state_ = PlatformWindowState::kFullScreen; - } else if (x11_window_->IsMaximized()) { - state_ = PlatformWindowState::kMaximized; - } else { - state_ = PlatformWindowState::kNormal; - } - - if (old_state != state_) - delegate_->OnWindowStateChanged(state_); -} - -void X11WindowOzone::OnXWindowDamageEvent( - const gfx::Rect& damage_rect_in_pixels) { - delegate_->OnDamageRect(damage_rect_in_pixels); -} - -void X11WindowOzone::OnXWindowSizeChanged(const gfx::Size&) { - delegate_->OnBoundsChanged(x11_window_->bounds()); -} - -void X11WindowOzone::OnXWindowCloseRequested() { - delegate_->OnCloseRequest(); -} - -void X11WindowOzone::OnXWindowLostCapture() { - OnLostCapture(); -} - -void X11WindowOzone::OnXWindowIsActiveChanged(bool active) { - delegate_->OnActivationChanged(active); -} - } // namespace ui
diff --git a/ui/ozone/platform/x11/x11_window_ozone.h b/ui/ozone/platform/x11/x11_window_ozone.h index 33e60a8..8b66d6ef 100644 --- a/ui/ozone/platform/x11/x11_window_ozone.h +++ b/ui/ozone/platform/x11/x11_window_ozone.h
@@ -16,8 +16,8 @@ #include "ui/events/x/x11_window_event_manager.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/x/x11_types.h" -#include "ui/platform_window/platform_window.h" #include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h" +#include "ui/platform_window/x11/x11_window.h" namespace ui { @@ -25,44 +25,21 @@ struct PlatformWindowInitProperties; // PlatformWindow implementation for X11 Ozone. PlatformEvents are ui::Events. -class X11WindowOzone : public PlatformWindow, - public PlatformEventDispatcher, +class X11WindowOzone : public X11Window, public WmMoveResizeHandler, - public XEventDispatcher, - public XWindow::Delegate { + public XEventDispatcher { public: X11WindowOzone(PlatformWindowDelegate* delegate, - const PlatformWindowInitProperties& properties, X11WindowManagerOzone* window_manager); ~X11WindowOzone() override; gfx::AcceleratedWidget widget() const { return widget_; } - bool IsVisible() const; - gfx::Rect GetOutterBounds() const; - ::Region GetShape() const; // Called by |window_manager_| once capture is set to another X11WindowOzone. void OnLostCapture(); // Overridden from PlatformWindow: - void Show() override; - void Hide() override; void Close() override; - void SetBounds(const gfx::Rect& bounds) override; - gfx::Rect GetBounds() override; - void SetTitle(const base::string16& title) override; - void ToggleFullscreen() override; - void Maximize() override; - void Minimize() override; - void Restore() override; - void Activate() override; - void Deactivate() override; - void SetUseNativeFrame(bool use_native_frame) override; - PlatformWindowState GetPlatformWindowState() const override; - void MoveCursorTo(const gfx::Point& location) override; - void ConfineCursorToBounds(const gfx::Rect& bounds) override; - void SetRestoredBoundsInPixels(const gfx::Rect& bounds) override; - gfx::Rect GetRestoredBoundsInPixels() const override; void PrepareForShutdown() override; void SetCapture() override; void ReleaseCapture() override; @@ -76,14 +53,11 @@ bool DispatchXEvent(XEvent* event) override; private: - // Overridden from ui::XWindow::Delegate + // XWindow overrides: void OnXWindowCreated() override; - void OnXWindowStateChanged() override; - void OnXWindowDamageEvent(const gfx::Rect& damage_rect) override; - void OnXWindowSizeChanged(const gfx::Size& size) override; - void OnXWindowCloseRequested() override; - void OnXWindowLostCapture() override; - void OnXWindowIsActiveChanged(bool active) override; + + // X11Window overrides: + void SetPlatformEventDispatcher() override; // PlatformEventDispatcher: bool CanDispatchEvent(const PlatformEvent& event) override; @@ -98,14 +72,10 @@ void SetWidget(XID xwindow); void RemoveFromWindowManager(); - PlatformWindowDelegate* const delegate_; X11WindowManagerOzone* const window_manager_; - PlatformWindowState state_ = PlatformWindowState::kUnknown; gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget; - std::unique_ptr<ui::XWindow> x11_window_; - bool is_shutting_down_ = false; // Tells if this dispatcher can process next translated event based on a
diff --git a/ui/ozone/platform/x11/x11_window_ozone_unittest.cc b/ui/ozone/platform/x11/x11_window_ozone_unittest.cc index edbc7738..0d11004 100644 --- a/ui/ozone/platform/x11/x11_window_ozone_unittest.cc +++ b/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
@@ -61,8 +61,9 @@ EXPECT_CALL(*delegate, OnAcceleratedWidgetAvailable(_)) .WillOnce(StoreWidget(widget)); PlatformWindowInitProperties init_params(bounds); - auto window = std::make_unique<X11WindowOzone>(delegate, init_params, - window_manager_.get()); + auto window = + std::make_unique<X11WindowOzone>(delegate, window_manager_.get()); + window->Initialize(std::move(init_params)); return std::move(window); }
diff --git a/ui/ozone/public/input_controller.cc b/ui/ozone/public/input_controller.cc index e7443f8..31895888 100644 --- a/ui/ozone/public/input_controller.cc +++ b/ui/ozone/public/input_controller.cc
@@ -43,6 +43,8 @@ void SetMouseSensitivity(int value) override {} void SetPrimaryButtonRight(bool right) override {} void SetMouseReverseScroll(bool enabled) override {} + void SetMouseAcceleration(bool enabled) override {} + void SetTouchpadAcceleration(bool enabled) override {} void SetTapToClickPaused(bool state) override {} void GetTouchDeviceStatus(GetTouchDeviceStatusReply reply) override { std::move(reply).Run(std::string());
diff --git a/ui/ozone/public/input_controller.h b/ui/ozone/public/input_controller.h index 8ceb3c8..6584525 100644 --- a/ui/ozone/public/input_controller.h +++ b/ui/ozone/public/input_controller.h
@@ -62,11 +62,13 @@ virtual void SetThreeFingerClick(bool enabled) = 0; virtual void SetTapDragging(bool enabled) = 0; virtual void SetNaturalScroll(bool enabled) = 0; + virtual void SetTouchpadAcceleration(bool enabled) = 0; // Mouse settings. virtual void SetMouseSensitivity(int value) = 0; virtual void SetPrimaryButtonRight(bool right) = 0; virtual void SetMouseReverseScroll(bool enabled) = 0; + virtual void SetMouseAcceleration(bool enabled) = 0; // Touch log collection. virtual void GetTouchDeviceStatus(GetTouchDeviceStatusReply reply) = 0;
diff --git a/ui/ozone/public/ozone_platform.h b/ui/ozone/public/ozone_platform.h index c345533..0e9d076d 100644 --- a/ui/ozone/public/ozone_platform.h +++ b/ui/ozone/public/ozone_platform.h
@@ -14,6 +14,7 @@ #include "base/message_loop/message_pump_type.h" #include "services/service_manager/public/cpp/binder_registry.h" #include "ui/gfx/buffer_types.h" +#include "ui/platform_window/platform_window_delegate.h" namespace display { class NativeDisplayDelegate; @@ -31,7 +32,6 @@ class OverlayManagerOzone; class PlatformScreen; class PlatformWindow; -class PlatformWindowDelegate; class SurfaceFactoryOzone; class SystemInputInjector; class PlatformClipboard;
diff --git a/ui/platform_window/BUILD.gn b/ui/platform_window/BUILD.gn index 21f48b5..dea6ac2 100644 --- a/ui/platform_window/BUILD.gn +++ b/ui/platform_window/BUILD.gn
@@ -8,6 +8,8 @@ sources = [ "platform_window.h", "platform_window_delegate.h", + "platform_window_delegate_base.cc", + "platform_window_delegate_base.h", "platform_window_init_properties.cc", "platform_window_init_properties.h", ] @@ -30,6 +32,13 @@ "//third_party/fuchsia-sdk/sdk:ui_views", ] } + + if (is_linux) { + sources += [ + "platform_window_delegate_linux.cc", + "platform_window_delegate_linux.h", + ] + } } group("platform_impls") {
diff --git a/ui/platform_window/common/BUILD.gn b/ui/platform_window/common/BUILD.gn new file mode 100644 index 0000000..ce68072a --- /dev/null +++ b/ui/platform_window/common/BUILD.gn
@@ -0,0 +1,12 @@ +# 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/ui.gni") + +source_set("common") { + sources = [ + "platform_window_defaults.cc", + "platform_window_defaults.h", + ] +}
diff --git a/ui/base/platform_window_defaults.cc b/ui/platform_window/common/platform_window_defaults.cc similarity index 87% rename from ui/base/platform_window_defaults.cc rename to ui/platform_window/common/platform_window_defaults.cc index 6f87bf7e..59208f4 100644 --- a/ui/base/platform_window_defaults.cc +++ b/ui/platform_window/common/platform_window_defaults.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 "ui/base/platform_window_defaults.h" +#include "ui/platform_window/common/platform_window_defaults.h" namespace ui { namespace {
diff --git a/ui/base/platform_window_defaults.h b/ui/platform_window/common/platform_window_defaults.h similarity index 76% rename from ui/base/platform_window_defaults.h rename to ui/platform_window/common/platform_window_defaults.h index 7e4dedf..fdb4a1c2 100644 --- a/ui/base/platform_window_defaults.h +++ b/ui/platform_window/common/platform_window_defaults.h
@@ -2,17 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_BASE_PLATFORM_WINDOW_DEFAULTS_H_ -#define UI_BASE_PLATFORM_WINDOW_DEFAULTS_H_ - -#include "ui/base/ui_base_export.h" +#ifndef UI_PLATFORM_WINDOW_COMMON_PLATFORM_WINDOW_DEFAULTS_H_ +#define UI_PLATFORM_WINDOW_COMMON_PLATFORM_WINDOW_DEFAULTS_H_ namespace ui { // Returns true if PlatformWindow should use test configuration. Will return // false by default, unless test::EnableTestConfigForPlatformWindows() has been // called, then it will return true. -UI_BASE_EXPORT bool UseTestConfigForPlatformWindows(); +bool UseTestConfigForPlatformWindows(); namespace test { @@ -24,9 +22,9 @@ // various tests, otherwise the call to Show() blocks because it never receives // the MapNotify event. It is unclear why this is necessary, but might be // related to calls to XInitThreads(). -UI_BASE_EXPORT void EnableTestConfigForPlatformWindows(); +void EnableTestConfigForPlatformWindows(); } // namespace test } // namespace ui -#endif // UI_BASE_PLATFORM_WINDOW_DEFAULTS_H_ +#endif // UI_PLATFORM_WINDOW_COMMON_PLATFORM_WINDOW_DEFAULTS_H_
diff --git a/ui/platform_window/platform_window_delegate.h b/ui/platform_window/platform_window_delegate.h index 0b6bdb8..fe4059ff 100644 --- a/ui/platform_window/platform_window_delegate.h +++ b/ui/platform_window/platform_window_delegate.h
@@ -5,53 +5,23 @@ #ifndef UI_PLATFORM_WINDOW_PLATFORM_WINDOW_DELEGATE_H_ #define UI_PLATFORM_WINDOW_PLATFORM_WINDOW_DELEGATE_H_ -#include "ui/gfx/native_widget_types.h" +#include "build/build_config.h" -namespace gfx { -class Rect; -} +// By default, PlatformWindowDelegateBase is used. However, different platforms +// should specify what delegate they would like to use if needed. +#if defined(OS_LINUX) +#include "ui/platform_window/platform_window_delegate_linux.h" +#else +#include "ui/platform_window/platform_window_delegate_base.h" +#endif namespace ui { -class Event; - -enum class PlatformWindowState { - kUnknown, - kMaximized, - kMinimized, - kNormal, - kFullScreen, -}; - -class PlatformWindowDelegate { - public: - virtual ~PlatformWindowDelegate() {} - - // Note that |new_bounds| is in physical screen coordinates. - virtual void OnBoundsChanged(const gfx::Rect& new_bounds) = 0; - - // Note that |damaged_region| is in the platform-window's coordinates, in - // physical pixels. - virtual void OnDamageRect(const gfx::Rect& damaged_region) = 0; - - virtual void DispatchEvent(Event* event) = 0; - - virtual void OnCloseRequest() = 0; - virtual void OnClosed() = 0; - - virtual void OnWindowStateChanged(PlatformWindowState new_state) = 0; - - virtual void OnLostCapture() = 0; - - virtual void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) = 0; - - // Notifies the delegate that the widget cannot be used anymore until - // a new widget is made available through OnAcceleratedWidgetAvailable(). - // Must not be called when the PlatformWindow is being destroyed. - virtual void OnAcceleratedWidgetDestroyed() = 0; - - virtual void OnActivationChanged(bool active) = 0; -}; +#if defined(OS_LINUX) +using PlatformWindowDelegate = PlatformWindowDelegateLinux; +#else +using PlatformWindowDelegate = PlatformWindowDelegateBase; +#endif } // namespace ui
diff --git a/ui/platform_window/platform_window_delegate_base.cc b/ui/platform_window/platform_window_delegate_base.cc new file mode 100644 index 0000000..cb3a992 --- /dev/null +++ b/ui/platform_window/platform_window_delegate_base.cc
@@ -0,0 +1,25 @@ +// 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/platform_window/platform_window_delegate_base.h" + +#include "ui/gfx/geometry/size.h" + +namespace ui { + +PlatformWindowDelegateBase::PlatformWindowDelegateBase() = default; + +PlatformWindowDelegateBase::~PlatformWindowDelegateBase() = default; + +base::Optional<gfx::Size> +PlatformWindowDelegateBase::GetMinimumSizeForWindow() { + return base::nullopt; +} + +base::Optional<gfx::Size> +PlatformWindowDelegateBase::GetMaximumSizeForWindow() { + return base::nullopt; +} + +} // namespace ui
diff --git a/ui/platform_window/platform_window_delegate_base.h b/ui/platform_window/platform_window_delegate_base.h new file mode 100644 index 0000000..e76ae56 --- /dev/null +++ b/ui/platform_window/platform_window_delegate_base.h
@@ -0,0 +1,68 @@ +// 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 UI_PLATFORM_WINDOW_PLATFORM_WINDOW_DELEGATE_BASE_H_ +#define UI_PLATFORM_WINDOW_PLATFORM_WINDOW_DELEGATE_BASE_H_ + +#include "base/optional.h" +#include "ui/gfx/native_widget_types.h" + +namespace gfx { +class Rect; +class Size; +} // namespace gfx + +namespace ui { + +class Event; + +enum class PlatformWindowState { + kUnknown, + kMaximized, + kMinimized, + kNormal, + kFullScreen, +}; + +// This is the bare minimum for PlatformWindowDeelegate, but some platforms may +// require more, and should do so in a subclass. Please refer to +// PlatformWindowDelegateLinux for an example. +class PlatformWindowDelegateBase { + public: + PlatformWindowDelegateBase(); + virtual ~PlatformWindowDelegateBase(); + + // Note that |new_bounds| is in physical screen coordinates. + virtual void OnBoundsChanged(const gfx::Rect& new_bounds) = 0; + + // Note that |damaged_region| is in the platform-window's coordinates, in + // physical pixels. + virtual void OnDamageRect(const gfx::Rect& damaged_region) = 0; + + virtual void DispatchEvent(Event* event) = 0; + + virtual void OnCloseRequest() = 0; + virtual void OnClosed() = 0; + + virtual void OnWindowStateChanged(PlatformWindowState new_state) = 0; + + virtual void OnLostCapture() = 0; + + virtual void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) = 0; + + // Notifies the delegate that the widget cannot be used anymore until + // a new widget is made available through OnAcceleratedWidgetAvailable(). + // Must not be called when the PlatformWindow is being destroyed. + virtual void OnAcceleratedWidgetDestroyed() = 0; + + virtual void OnActivationChanged(bool active) = 0; + + // Requests size constraints for the PlatformWindow. + virtual base::Optional<gfx::Size> GetMinimumSizeForWindow(); + virtual base::Optional<gfx::Size> GetMaximumSizeForWindow(); +}; + +} // namespace ui + +#endif // UI_PLATFORM_WINDOW_PLATFORM_WINDOW_DELEGATE_BASE_H_
diff --git a/ui/platform_window/platform_window_delegate_linux.cc b/ui/platform_window/platform_window_delegate_linux.cc new file mode 100644 index 0000000..c66e2ca --- /dev/null +++ b/ui/platform_window/platform_window_delegate_linux.cc
@@ -0,0 +1,31 @@ +// 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/platform_window/platform_window_delegate_linux.h" + +#include "base/logging.h" + +namespace ui { + +PlatformWindowDelegateLinux::PlatformWindowDelegateLinux() = default; + +PlatformWindowDelegateLinux::~PlatformWindowDelegateLinux() = default; + +void PlatformWindowDelegateLinux::OnXWindowMapped() { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void PlatformWindowDelegateLinux::OnXWindowUnmapped() { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void PlatformWindowDelegateLinux::OnLostMouseGrab() { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void PlatformWindowDelegateLinux::OnWorkspaceChanged() { + NOTIMPLEMENTED_LOG_ONCE(); +} + +} // namespace ui
diff --git a/ui/platform_window/platform_window_delegate_linux.h b/ui/platform_window/platform_window_delegate_linux.h new file mode 100644 index 0000000..6290c69 --- /dev/null +++ b/ui/platform_window/platform_window_delegate_linux.h
@@ -0,0 +1,39 @@ +// 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 UI_PLATFORM_WINDOW_PLATFORM_WINDOW_DELEGATE_LINUX_H_ +#define UI_PLATFORM_WINDOW_PLATFORM_WINDOW_DELEGATE_LINUX_H_ + +#include "ui/platform_window/platform_window_delegate_base.h" + +namespace ui { + +// This is an optional linux delegate interface, which should be implemented by +// linux-based platforms. It contains both Wayland and X11 specific and common +// interfaces. +class PlatformWindowDelegateLinux : public PlatformWindowDelegateBase { + public: + PlatformWindowDelegateLinux(); + ~PlatformWindowDelegateLinux() override; + + // Notifies the delegate that the window got mapped in the X server. Wayland + // does not support this interface. + virtual void OnXWindowMapped(); + virtual void OnXWindowUnmapped(); + + // Notifies if the PlatformWindow looses a mouse grab. This can be useful for + // Wayland or X11. Both of them provide pointer enter and leave notifications, + // which non-ozone X11 (just an example) use to be using to notify about lost + // pointer grab along with explicit grabs. Wayland also has this technique. + // However, explicit grab is available only for popup (menu) windows. + virtual void OnLostMouseGrab(); + + // Notifies the delegate if the PlatformWindow has changed the workspace it is + // located in. + virtual void OnWorkspaceChanged(); +}; + +} // namespace ui + +#endif // UI_PLATFORM_WINDOW_PLATFORM_WINDOW_DELEGATE_LINUX_H_
diff --git a/ui/platform_window/platform_window_init_properties.h b/ui/platform_window/platform_window_init_properties.h index 46af9ec..38e5382 100644 --- a/ui/platform_window/platform_window_init_properties.h +++ b/ui/platform_window/platform_window_init_properties.h
@@ -7,6 +7,7 @@ #include <string> +#include "base/optional.h" #include "build/build_config.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" @@ -16,6 +17,10 @@ #include <lib/ui/scenic/cpp/view_ref_pair.h> #endif +namespace gfx { +class ImageSkia; +} + namespace ui { enum class PlatformWindowType { @@ -23,6 +28,8 @@ kPopup, kMenu, kTooltip, + kDrag, + kBubble, }; enum class PlatformWindowOpacity { @@ -66,7 +73,13 @@ bool remove_standard_frame = false; std::string workspace; - // Only used by X11. Specifies the res_name and res_class fields, +#if defined(USE_X11) + // Only used by X11: + bool prefer_dark_theme = false; + gfx::ImageSkia* icon = nullptr; + base::Optional<int> background_color; +#endif + // Specifies the res_name and res_class fields, // respectively, of the WM_CLASS window property. Controls window grouping // and desktop file matching in Linux window managers. std::string wm_role_name;
diff --git a/ui/platform_window/stub/stub_window.h b/ui/platform_window/stub/stub_window.h index 0593f4db..0574b19 100644 --- a/ui/platform_window/stub/stub_window.h +++ b/ui/platform_window/stub/stub_window.h
@@ -9,12 +9,11 @@ #include "base/macros.h" #include "ui/gfx/geometry/rect.h" #include "ui/platform_window/platform_window.h" +#include "ui/platform_window/platform_window_delegate.h" #include "ui/platform_window/stub/stub_window_export.h" namespace ui { -class PlatformWindowDelegate; - // StubWindow is useful for tests, as well as implementations that only care // about bounds. class STUB_WINDOW_EXPORT StubWindow : public PlatformWindow {
diff --git a/ui/platform_window/win/win_window.cc b/ui/platform_window/win/win_window.cc index 8cd1ce8..548f56a1 100644 --- a/ui/platform_window/win/win_window.cc +++ b/ui/platform_window/win/win_window.cc
@@ -11,7 +11,6 @@ #include "ui/events/event.h" #include "ui/events/event_utils.h" #include "ui/gfx/win/msg_util.h" -#include "ui/platform_window/platform_window_delegate.h" #include <windows.h>
diff --git a/ui/platform_window/win/win_window.h b/ui/platform_window/win/win_window.h index 1e4bd938..f74cddb0 100644 --- a/ui/platform_window/win/win_window.h +++ b/ui/platform_window/win/win_window.h
@@ -10,14 +10,13 @@ #include "base/memory/weak_ptr.h" #include "ui/gfx/win/window_impl.h" #include "ui/platform_window/platform_window.h" +#include "ui/platform_window/platform_window_delegate.h" #include "ui/platform_window/win/win_window_export.h" #include <windows.h> namespace ui { -class PlatformWindowDelegate; - class WIN_WINDOW_EXPORT WinWindow : public PlatformWindow, public gfx::WindowImpl { public:
diff --git a/ui/platform_window/x11/BUILD.gn b/ui/platform_window/x11/BUILD.gn index f0d40e73..64259a6 100644 --- a/ui/platform_window/x11/BUILD.gn +++ b/ui/platform_window/x11/BUILD.gn
@@ -30,15 +30,8 @@ defines = [ "X11_WINDOW_IMPLEMENTATION" ] sources = [ - "x11_window_base.cc", - "x11_window_base.h", + "x11_window.cc", + "x11_window.h", "x11_window_export.h", ] - - if (use_x11) { - sources += [ - "x11_window.cc", - "x11_window.h", - ] - } }
diff --git a/ui/platform_window/x11/x11_window.cc b/ui/platform_window/x11/x11_window.cc index c466ef0e..b0a7365 100644 --- a/ui/platform_window/x11/x11_window.cc +++ b/ui/platform_window/x11/x11_window.cc
@@ -4,146 +4,326 @@ #include "ui/platform_window/x11/x11_window.h" +#include "base/trace_event/trace_event.h" #include "ui/events/devices/x11/touch_factory_x11.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" #include "ui/events/platform/platform_event_source.h" #include "ui/events/platform/x11/x11_event_source.h" #include "ui/gfx/x/x11.h" -#include "ui/platform_window/platform_window_delegate.h" +#include "ui/platform_window/platform_window_delegate_linux.h" namespace ui { -X11Window::X11Window(PlatformWindowDelegate* delegate, const gfx::Rect& bounds) - : X11WindowBase(delegate, bounds) { - DCHECK(PlatformEventSource::GetInstance()); - PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); +namespace { + +ui::XWindow::Configuration ConvertInitPropertiesToXWindowConfig( + const PlatformWindowInitProperties& properties) { + using WindowType = ui::XWindow::WindowType; + using WindowOpacity = ui::XWindow::WindowOpacity; + ui::XWindow::Configuration config; + + switch (properties.type) { + case PlatformWindowType::kWindow: + config.type = WindowType::kWindow; + break; + case PlatformWindowType::kMenu: + config.type = WindowType::kMenu; + break; + case PlatformWindowType::kTooltip: + config.type = WindowType::kTooltip; + break; + case PlatformWindowType::kPopup: + config.type = WindowType::kPopup; + break; + case PlatformWindowType::kDrag: + config.type = WindowType::kDrag; + break; + case PlatformWindowType::kBubble: + config.type = WindowType::kBubble; + break; + } + + switch (properties.opacity) { + case PlatformWindowOpacity::kInferOpacity: + config.opacity = WindowOpacity::kInferOpacity; + break; + case PlatformWindowOpacity::kOpaqueWindow: + config.opacity = WindowOpacity::kOpaqueWindow; + break; + case PlatformWindowOpacity::kTranslucentWindow: + config.opacity = WindowOpacity::kTranslucentWindow; + break; + } + + config.bounds = properties.bounds; + config.force_show_in_taskbar = properties.force_show_in_taskbar; + config.keep_on_top = properties.keep_on_top; + config.visible_on_all_workspaces = properties.visible_on_all_workspaces; + config.remove_standard_frame = properties.remove_standard_frame; + config.workspace = properties.workspace; + config.wm_class_name = properties.wm_class_name; + config.wm_class_class = properties.wm_class_class; + config.wm_role_name = properties.wm_role_name; + config.activatable = properties.activatable; + return config; } +} // namespace + +X11Window::X11Window(PlatformWindowDelegateLinux* platform_window_delegate, + XEventDelegate* x_event_delegate) + : platform_window_delegate_(platform_window_delegate), + x_event_delegate_(x_event_delegate) {} + X11Window::~X11Window() { - X11Window::PrepareForShutdown(); + PrepareForShutdown(); + Close(); +} + +void X11Window::Initialize(PlatformWindowInitProperties properties) { + XWindow::Configuration config = + ConvertInitPropertiesToXWindowConfig(properties); + Init(config); +} + +void X11Window::Show() { + // TODO(msisov): pass inactivity to PlatformWindow::Show. + XWindow::Map(false /* inactive */); +} + +void X11Window::Hide() { + XWindow::Hide(); +} + +void X11Window::Close() { + if (is_shutting_down_) + return; + + is_shutting_down_ = true; + XWindow::Close(); + platform_window_delegate_->OnClosed(); } void X11Window::PrepareForShutdown() { PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); } -void X11Window::SetUseNativeFrame(bool use_native_frame) { +void X11Window::SetBounds(const gfx::Rect& bounds) { + // Assume that the resize will go through as requested, which should be the + // case if we're running without a window manager. If there's a window + // manager, it can modify or ignore the request, but (per ICCCM) we'll get a + // (possibly synthetic) ConfigureNotify about the actual size and correct + // |bounds_| later. + XWindow::SetBounds(bounds); + + // Even if the pixel bounds didn't change this call to the delegate should + // still happen. The device scale factor may have changed which effectively + // changes the bounds. + platform_window_delegate_->OnBoundsChanged(bounds); +} + +gfx::Rect X11Window::GetBounds() { + return XWindow::bounds(); +} + +void X11Window::SetTitle(const base::string16& title) { + XWindow::SetTitle(title); +} + +void X11Window::SetCapture() { + XWindow::GrabPointer(); +} + +void X11Window::ReleaseCapture() { + XWindow::ReleasePointerGrab(); +} + +bool X11Window::HasCapture() const { NOTIMPLEMENTED_LOG_ONCE(); + return false; +} + +void X11Window::ToggleFullscreen() { + bool is_fullscreen = IsFullscreen(); + SetFullscreen(!is_fullscreen); +} + +void X11Window::Maximize() { + if (IsFullscreen()) + SetFullscreen(false); + XWindow::Maximize(); +} + +void X11Window::Minimize() { + XWindow::Minimize(); +} + +void X11Window::Restore() { + if (IsFullscreen()) + ToggleFullscreen(); + if (IsMaximized()) + Unmaximize(); +} + +PlatformWindowState X11Window::GetPlatformWindowState() const { + return state_; +} + +void X11Window::Activate() { + XWindow::Activate(); +} + +void X11Window::Deactivate() { + XWindow::Deactivate(); +} + +void X11Window::SetUseNativeFrame(bool use_native_frame) { + XWindow::SetUseNativeFrame(use_native_frame); } void X11Window::SetCursor(PlatformCursor cursor) { - XDefineCursor(xdisplay(), xwindow(), cursor); + // X11PlatformWindowOzone has different type of PlatformCursor. Thus, use this + // only for X11 and Ozone will manage this by itself. +#if defined(USE_X11) + XWindow::SetCursor(cursor); +#endif } -void X11Window::ProcessXInput2Event(XEvent* xev) { - if (!TouchFactory::GetInstance()->ShouldProcessXI2Event(xev)) - return; - EventType event_type = EventTypeFromNative(xev); - switch (event_type) { - case ET_KEY_PRESSED: - case ET_KEY_RELEASED: { - KeyEvent key_event(xev); - delegate()->DispatchEvent(&key_event); - break; - } - case ET_MOUSE_PRESSED: - case ET_MOUSE_MOVED: - case ET_MOUSE_DRAGGED: - case ET_MOUSE_RELEASED: { - MouseEvent mouse_event(xev); - delegate()->DispatchEvent(&mouse_event); - break; - } - case ET_MOUSEWHEEL: { - MouseWheelEvent wheel_event(xev); - delegate()->DispatchEvent(&wheel_event); - break; - } - case ET_SCROLL_FLING_START: - case ET_SCROLL_FLING_CANCEL: - case ET_SCROLL: { - ScrollEvent scroll_event(xev); - delegate()->DispatchEvent(&scroll_event); - break; - } - case ET_TOUCH_MOVED: - case ET_TOUCH_PRESSED: - case ET_TOUCH_CANCELLED: - case ET_TOUCH_RELEASED: { - TouchEvent touch_event(xev); - delegate()->DispatchEvent(&touch_event); - break; - } - default: - break; - } +void X11Window::MoveCursorTo(const gfx::Point& location) { + XWindow::MoveCursorTo(location); +} + +void X11Window::ConfineCursorToBounds(const gfx::Rect& bounds) { + XWindow::ConfineCursorTo(bounds); +} + +void X11Window::SetRestoredBoundsInPixels(const gfx::Rect& bounds) { + // TODO(crbug.com/848131): Restore bounds on restart + NOTIMPLEMENTED_LOG_ONCE(); +} + +gfx::Rect X11Window::GetRestoredBoundsInPixels() const { + // TODO(crbug.com/848131): Restore bounds on restart + NOTIMPLEMENTED_LOG_ONCE(); + return gfx::Rect(); +} + +void X11Window::SetPlatformEventDispatcher() { + DCHECK(PlatformEventSource::GetInstance()); + PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); } bool X11Window::CanDispatchEvent(const PlatformEvent& xev) { - return IsEventForXWindow(*xev); +#if defined(USE_X11) + return XWindow::IsTargetedBy(*xev); +#else + NOTREACHED() << "Ozone must use own dispatcher as it has different type of " + "PlatformEvent"; + return false; +#endif } uint32_t X11Window::DispatchEvent(const PlatformEvent& event) { - XEvent* xev = event; - switch (xev->type) { - case EnterNotify: { - MouseEvent mouse_event(xev); - CHECK_EQ(ET_MOUSE_MOVED, mouse_event.type()); - delegate()->DispatchEvent(&mouse_event); - break; - } - case LeaveNotify: { - MouseEvent mouse_event(xev); - delegate()->DispatchEvent(&mouse_event); - break; - } +#if defined(USE_X11) + TRACE_EVENT1("views", "X11PlatformWindow::Dispatch", "event->type", + event->type); - case KeyPress: - case KeyRelease: { - KeyEvent key_event(xev); - delegate()->DispatchEvent(&key_event); - break; - } - - case ButtonPress: - case ButtonRelease: { - switch (EventTypeFromNative(xev)) { - case ET_MOUSEWHEEL: { - MouseWheelEvent mouseev(xev); - delegate()->DispatchEvent(&mouseev); - break; - } - case ET_MOUSE_PRESSED: - case ET_MOUSE_RELEASED: { - MouseEvent mouseev(xev); - delegate()->DispatchEvent(&mouseev); - break; - } - case ET_UNKNOWN: - // No event is created for X11-release events for mouse-wheel - // buttons. - break; - default: - NOTREACHED(); - } - break; - } - - case Expose: - case x11::FocusOut: - case ConfigureNotify: - case ClientMessage: { - ProcessXWindowEvent(xev); - break; - } - - case GenericEvent: { - ProcessXInput2Event(xev); - break; - } - } + ProcessEvent(event); return POST_DISPATCH_STOP_PROPAGATION; +#else + NOTREACHED() << "Ozone must use own dispatcher as it has different type of " + "PlatformEvent"; + return false; +#endif +} + +void X11Window::OnXWindowCreated() { + // X11WindowOzone overrides this method and manages events by itself. + SetPlatformEventDispatcher(); + platform_window_delegate_->OnAcceleratedWidgetAvailable(window()); +} + +void X11Window::OnXWindowStateChanged() { + // Propagate the window state information to the client. Note that the order + // of checks is important here, because window can have several properties + // at the same time. + PlatformWindowState old_state = state_; + if (IsMinimized()) { + state_ = PlatformWindowState::kMinimized; + } else if (IsFullscreen()) { + state_ = PlatformWindowState::kFullScreen; + } else if (IsMaximized()) { + state_ = PlatformWindowState::kMaximized; + } else { + state_ = PlatformWindowState::kNormal; + } + + if (old_state != state_) + platform_window_delegate_->OnWindowStateChanged(state_); +} + +void X11Window::OnXWindowDamageEvent(const gfx::Rect& damage_rect) { + platform_window_delegate_->OnDamageRect(damage_rect); +} + +void X11Window::OnXWindowBoundsChanged(const gfx::Rect& bounds) { + platform_window_delegate_->OnBoundsChanged(bounds); +} + +void X11Window::OnXWindowCloseRequested() { + platform_window_delegate_->OnCloseRequest(); +} + +void X11Window::OnXWindowIsActiveChanged(bool active) { + platform_window_delegate_->OnActivationChanged(active); +} + +void X11Window::OnXWindowMapped() { + platform_window_delegate_->OnXWindowMapped(); +} + +void X11Window::OnXWindowUnmapped() { + platform_window_delegate_->OnXWindowUnmapped(); +} + +void X11Window::OnXWindowWorkspaceChanged() { + platform_window_delegate_->OnWorkspaceChanged(); +} + +void X11Window::OnXWindowLostPointerGrab() { + platform_window_delegate_->OnLostMouseGrab(); +} + +void X11Window::OnXWindowLostCapture() { + platform_window_delegate_->OnLostCapture(); +} + +void X11Window::OnXWindowEvent(ui::Event* event) { + platform_window_delegate_->DispatchEvent(event); +} + +void X11Window::OnXWindowSelectionEvent(XEvent* xev) { + if (x_event_delegate_) + x_event_delegate_->OnXWindowSelectionEvent(xev); +} + +void X11Window::OnXWindowDragDropEvent(XEvent* xev) { + if (x_event_delegate_) + x_event_delegate_->OnXWindowDragDropEvent(xev); +} + +void X11Window::OnXWindowRawKeyEvent(XEvent* xev) { + if (x_event_delegate_) + x_event_delegate_->OnXWindowRawKeyEvent(xev); +} + +base::Optional<gfx::Size> X11Window::GetMinimumSizeForXWindow() { + return platform_window_delegate_->GetMinimumSizeForWindow(); +} + +base::Optional<gfx::Size> X11Window::GetMaximumSizeForXWindow() { + return platform_window_delegate_->GetMaximumSizeForWindow(); } } // namespace ui
diff --git a/ui/platform_window/x11/x11_window.h b/ui/platform_window/x11/x11_window.h index 2b91e5c..62ae8fb 100644 --- a/ui/platform_window/x11/x11_window.h +++ b/ui/platform_window/x11/x11_window.h
@@ -6,23 +6,77 @@ #define UI_PLATFORM_WINDOW_X11_X11_WINDOW_H_ #include "base/macros.h" +#include "ui/base/x/x11_window.h" #include "ui/events/platform/platform_event_dispatcher.h" -#include "ui/platform_window/x11/x11_window_base.h" +#include "ui/platform_window/platform_window.h" +#include "ui/platform_window/platform_window_init_properties.h" #include "ui/platform_window/x11/x11_window_export.h" namespace ui { +class PlatformWindowDelegateLinux; + +// Delegate interface used to communicate the X11PlatformWindow API client about +// XEvents of interest. +class X11_WINDOW_EXPORT XEventDelegate { + public: + virtual ~XEventDelegate() {} + + // TODO(crbug.com/990756): We need to implement/reuse ozone interface for + // these. + virtual void OnXWindowSelectionEvent(XEvent* xev) = 0; + virtual void OnXWindowDragDropEvent(XEvent* xev) = 0; + + // TODO(crbug.com/981606): DesktopWindowTreeHostX11 forward raw |XEvent|s to + // ATK components that currently live in views layer. Remove once ATK code + // is reworked to be reusable. + virtual void OnXWindowRawKeyEvent(XEvent* xev) = 0; +}; + // PlatformWindow implementation for X11. PlatformEvents are XEvents. -class X11_WINDOW_EXPORT X11Window : public X11WindowBase, +class X11_WINDOW_EXPORT X11Window : public PlatformWindow, + public XWindow, public PlatformEventDispatcher { public: - X11Window(PlatformWindowDelegate* delegate, const gfx::Rect& bounds); + X11Window(PlatformWindowDelegateLinux* platform_window_delegate, + XEventDelegate* x_event_delegate); ~X11Window() override; + void Initialize(PlatformWindowInitProperties properties); + // PlatformWindow: + void Show() override; + void Hide() override; + void Close() override; void PrepareForShutdown() override; + void SetBounds(const gfx::Rect& bounds) override; + gfx::Rect GetBounds() override; + void SetTitle(const base::string16& title) override; + void SetCapture() override; + void ReleaseCapture() override; + bool HasCapture() const override; + void ToggleFullscreen() override; + void Maximize() override; + void Minimize() override; + void Restore() override; + PlatformWindowState GetPlatformWindowState() const override; + void Activate() override; + void Deactivate() override; void SetUseNativeFrame(bool use_native_frame) override; void SetCursor(PlatformCursor cursor) override; + void MoveCursorTo(const gfx::Point& location) override; + void ConfineCursorToBounds(const gfx::Rect& bounds) override; + void SetRestoredBoundsInPixels(const gfx::Rect& bounds) override; + gfx::Rect GetRestoredBoundsInPixels() const override; + + protected: + PlatformWindowDelegateLinux* platform_window_delegate() const { + return platform_window_delegate_; + } + + // XWindow: + void OnXWindowCreated() override; + void OnXWindowLostCapture() override; private: void ProcessXInput2Event(XEvent* xev); @@ -31,6 +85,36 @@ bool CanDispatchEvent(const PlatformEvent& event) override; uint32_t DispatchEvent(const PlatformEvent& event) override; + // XWindow: + void OnXWindowStateChanged() override; + void OnXWindowDamageEvent(const gfx::Rect& damage_rect) override; + void OnXWindowBoundsChanged(const gfx::Rect& size) override; + void OnXWindowCloseRequested() override; + void OnXWindowIsActiveChanged(bool active) override; + void OnXWindowMapped() override; + void OnXWindowUnmapped() override; + void OnXWindowWorkspaceChanged() override; + void OnXWindowLostPointerGrab() override; + void OnXWindowEvent(ui::Event* event) override; + void OnXWindowSelectionEvent(XEvent* xev) override; + void OnXWindowDragDropEvent(XEvent* xev) override; + void OnXWindowRawKeyEvent(XEvent* xev) override; + base::Optional<gfx::Size> GetMinimumSizeForXWindow() override; + base::Optional<gfx::Size> GetMaximumSizeForXWindow() override; + + // X11WindowOzone sets own event dispatcher now. + virtual void SetPlatformEventDispatcher(); + + // Stores current state of this window. + PlatformWindowState state_ = PlatformWindowState::kUnknown; + + PlatformWindowDelegateLinux* const platform_window_delegate_; + + XEventDelegate* const x_event_delegate_; + + // Tells if the window got a ::Close call. + bool is_shutting_down_ = false; + DISALLOW_COPY_AND_ASSIGN(X11Window); };
diff --git a/ui/platform_window/x11/x11_window_base.cc b/ui/platform_window/x11/x11_window_base.cc deleted file mode 100644 index 221ad511..0000000 --- a/ui/platform_window/x11/x11_window_base.cc +++ /dev/null
@@ -1,437 +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. - -#include "ui/platform_window/x11/x11_window_base.h" - -#include <string> - -#include "base/strings/utf_string_conversions.h" -#include "ui/base/platform_window_defaults.h" -#include "ui/base/x/x11_util.h" -#include "ui/events/event.h" -#include "ui/events/event_utils.h" -#include "ui/events/platform/platform_event_dispatcher.h" -#include "ui/events/platform/platform_event_source.h" -#include "ui/events/platform/x11/x11_event_source.h" -#include "ui/events/x/x11_window_event_manager.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/x/x11_atom_cache.h" -#include "ui/platform_window/platform_window_delegate.h" - -namespace ui { - -namespace { - -XID FindXEventTarget(const XEvent& xev) { - XID target = xev.xany.window; - if (xev.type == GenericEvent) - target = static_cast<XIDeviceEvent*>(xev.xcookie.data)->event; - return target; -} - -} // namespace - -X11WindowBase::X11WindowBase(PlatformWindowDelegate* delegate, - const gfx::Rect& bounds) - : delegate_(delegate), - xdisplay_(gfx::GetXDisplay()), - xroot_window_(DefaultRootWindow(xdisplay_)), - bounds_(bounds), - state_(PlatformWindowState::kUnknown) { - DCHECK(delegate_); - Create(); - pointer_barriers_.fill(x11::None); -} - -X11WindowBase::~X11WindowBase() { - UnConfineCursor(); - Destroy(); -} - -void X11WindowBase::Destroy() { - if (xwindow_ == x11::None) - return; - - // Stop processing events. - XID xwindow = xwindow_; - XDisplay* xdisplay = xdisplay_; - xwindow_ = x11::None; - delegate_->OnClosed(); - // |this| might be deleted because of the above call. - - XDestroyWindow(xdisplay, xwindow); -} - -void X11WindowBase::Create() { - DCHECK(!bounds_.size().IsEmpty()); - - XSetWindowAttributes swa; - memset(&swa, 0, sizeof(swa)); - swa.background_pixmap = x11::None; - swa.bit_gravity = NorthWestGravity; - swa.override_redirect = UseTestConfigForPlatformWindows(); - xwindow_ = - XCreateWindow(xdisplay_, xroot_window_, bounds_.x(), bounds_.y(), - bounds_.width(), bounds_.height(), - 0, // border width - CopyFromParent, // depth - InputOutput, - CopyFromParent, // visual - CWBackPixmap | CWBitGravity | CWOverrideRedirect, &swa); - - // Setup XInput event mask. - long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask | - KeyPressMask | KeyReleaseMask | EnterWindowMask | - LeaveWindowMask | ExposureMask | VisibilityChangeMask | - StructureNotifyMask | PropertyChangeMask | - PointerMotionMask; - xwindow_events_ = - std::make_unique<ui::XScopedEventSelector>(xwindow_, event_mask); - - // Setup XInput2 event mask. - unsigned char mask[XIMaskLen(XI_LASTEVENT)]; - memset(mask, 0, sizeof(mask)); - - XISetMask(mask, XI_TouchBegin); - XISetMask(mask, XI_TouchUpdate); - XISetMask(mask, XI_TouchEnd); - XISetMask(mask, XI_ButtonPress); - XISetMask(mask, XI_ButtonRelease); - XISetMask(mask, XI_Motion); - XISetMask(mask, XI_KeyPress); - XISetMask(mask, XI_KeyRelease); - XISetMask(mask, XI_HierarchyChanged); - - XIEventMask evmask; - evmask.deviceid = XIAllDevices; - evmask.mask_len = sizeof(mask); - evmask.mask = mask; - XISelectEvents(xdisplay_, xwindow_, &evmask, 1); - XFlush(xdisplay_); - - ::Atom protocols[2]; - protocols[0] = gfx::GetAtom("WM_DELETE_WINDOW"); - protocols[1] = gfx::GetAtom("_NET_WM_PING"); - XSetWMProtocols(xdisplay_, xwindow_, protocols, 2); - - // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with - // the desktop environment. - XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL); - - // Likewise, the X server needs to know this window's pid so it knows which - // program to kill if the window hangs. - // XChangeProperty() expects "pid" to be long. - static_assert(sizeof(long) >= sizeof(pid_t), - "pid_t should not be larger than long"); - long pid = getpid(); - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_PID"), XA_CARDINAL, - 32, PropModeReplace, reinterpret_cast<unsigned char*>(&pid), - 1); - // Before we map the window, set size hints. Otherwise, some window managers - // will ignore toplevel XMoveWindow commands. - XSizeHints size_hints; - size_hints.flags = PPosition | PWinGravity; - size_hints.x = bounds_.x(); - size_hints.y = bounds_.y(); - // Set StaticGravity so that the window position is not affected by the - // frame width when running with window manager. - size_hints.win_gravity = StaticGravity; - XSetWMNormalHints(xdisplay_, xwindow_, &size_hints); - - delegate_->OnAcceleratedWidgetAvailable(xwindow_); -} - -void X11WindowBase::Show() { - if (window_mapped_) - return; - - XMapWindow(xdisplay_, xwindow_); - // TODO(thomasanderson): Find out why this flush is necessary. - XFlush(xdisplay_); - window_mapped_ = true; -} - -void X11WindowBase::Hide() { - if (!window_mapped_) - return; - - XWithdrawWindow(xdisplay_, xwindow_, 0); - window_mapped_ = false; -} - -void X11WindowBase::Close() { - Destroy(); -} - -void X11WindowBase::SetBounds(const gfx::Rect& bounds) { - DCHECK(!bounds.size().IsEmpty()); - - if (xwindow_ != x11::None) { - XWindowChanges changes = {0}; - unsigned value_mask = 0; - - if (bounds_.size() != bounds.size()) { - changes.width = bounds.width(); - changes.height = bounds.height(); - value_mask |= CWHeight | CWWidth; - } - - if (bounds_.origin() != bounds.origin()) { - changes.x = bounds.x(); - changes.y = bounds.y(); - value_mask |= CWX | CWY; - } - - if (value_mask) - XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes); - } - - // Assume that the resize will go through as requested, which should be the - // case if we're running without a window manager. If there's a window - // manager, it can modify or ignore the request, but (per ICCCM) we'll get a - // (possibly synthetic) ConfigureNotify about the actual size and correct - // |bounds_| later. - bounds_ = bounds; - - // Even if the pixel bounds didn't change this call to the delegate should - // still happen. The device scale factor may have changed which effectively - // changes the bounds. - delegate_->OnBoundsChanged(bounds_); -} - -gfx::Rect X11WindowBase::GetBounds() { - return bounds_; -} - -void X11WindowBase::SetTitle(const base::string16& title) { - if (window_title_ == title) - return; - window_title_ = title; - std::string utf8str = base::UTF16ToUTF8(title); - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_NAME"), - gfx::GetAtom("UTF8_STRING"), 8, PropModeReplace, - reinterpret_cast<const unsigned char*>(utf8str.c_str()), - utf8str.size()); - XTextProperty xtp; - char* c_utf8_str = const_cast<char*>(utf8str.c_str()); - if (Xutf8TextListToTextProperty(xdisplay_, &c_utf8_str, 1, XUTF8StringStyle, - &xtp) == x11::Success) { - XSetWMName(xdisplay_, xwindow_, &xtp); - XFree(xtp.value); - } -} - -void X11WindowBase::SetCapture() {} - -void X11WindowBase::ReleaseCapture() {} - -bool X11WindowBase::HasCapture() const { - return false; -} - -void X11WindowBase::ToggleFullscreen() { - ui::SetWMSpecState(xwindow_, !IsFullscreen(), - gfx::GetAtom("_NET_WM_STATE_FULLSCREEN"), x11::None); -} - -void X11WindowBase::Maximize() { - if (IsFullscreen()) - ToggleFullscreen(); - - ui::SetWMSpecState(xwindow_, true, - gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"), - gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ")); -} - -void X11WindowBase::Minimize() { - XIconifyWindow(xdisplay_, xwindow_, 0); -} - -void X11WindowBase::Restore() { - if (IsFullscreen()) - ToggleFullscreen(); - - if (IsMaximized()) { - ui::SetWMSpecState(xwindow_, false, - gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"), - gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ")); - } -} - -PlatformWindowState X11WindowBase::GetPlatformWindowState() const { - return state_; -} - -void X11WindowBase::Activate() { - NOTIMPLEMENTED_LOG_ONCE(); -} - -void X11WindowBase::Deactivate() { - NOTIMPLEMENTED_LOG_ONCE(); -} - -void X11WindowBase::MoveCursorTo(const gfx::Point& location) { - XWarpPointer(xdisplay_, x11::None, xroot_window_, 0, 0, 0, 0, - bounds_.x() + location.x(), bounds_.y() + location.y()); -} - -void X11WindowBase::ConfineCursorToBounds(const gfx::Rect& bounds) { - UnConfineCursor(); - - if (bounds.IsEmpty()) - return; - - gfx::Rect barrier = bounds + bounds_.OffsetFromOrigin(); - - // Top horizontal barrier. - pointer_barriers_[0] = XFixesCreatePointerBarrier( - xdisplay_, xroot_window_, barrier.x(), barrier.y(), barrier.right(), - barrier.y(), BarrierPositiveY, 0, XIAllDevices); - // Bottom horizontal barrier. - pointer_barriers_[1] = XFixesCreatePointerBarrier( - xdisplay_, xroot_window_, barrier.x(), barrier.bottom(), barrier.right(), - barrier.bottom(), BarrierNegativeY, 0, XIAllDevices); - // Left vertical barrier. - pointer_barriers_[2] = XFixesCreatePointerBarrier( - xdisplay_, xroot_window_, barrier.x(), barrier.y(), barrier.x(), - barrier.bottom(), BarrierPositiveX, 0, XIAllDevices); - // Right vertical barrier. - pointer_barriers_[3] = XFixesCreatePointerBarrier( - xdisplay_, xroot_window_, barrier.right(), barrier.y(), barrier.right(), - barrier.bottom(), BarrierNegativeX, 0, XIAllDevices); - - has_pointer_barriers_ = true; -} - -void X11WindowBase::SetRestoredBoundsInPixels(const gfx::Rect& bounds) { - // TODO: https://crbug.com/848131 - NOTIMPLEMENTED(); -} - -gfx::Rect X11WindowBase::GetRestoredBoundsInPixels() const { - // TODO: https://crbug.com/848131 - NOTIMPLEMENTED(); - return gfx::Rect(); -} - -void X11WindowBase::UnConfineCursor() { - if (!has_pointer_barriers_) - return; - - for (XID pointer_barrier : pointer_barriers_) - XFixesDestroyPointerBarrier(xdisplay_, pointer_barrier); - pointer_barriers_.fill(x11::None); - - has_pointer_barriers_ = false; -} - -bool X11WindowBase::IsEventForXWindow(const XEvent& xev) const { - return xwindow_ != x11::None && FindXEventTarget(xev) == xwindow_; -} - -void X11WindowBase::ProcessXWindowEvent(XEvent* xev) { - switch (xev->type) { - case Expose: { - gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y, xev->xexpose.width, - xev->xexpose.height); - delegate_->OnDamageRect(damage_rect); - break; - } - - case x11::FocusOut: - if (xev->xfocus.mode != NotifyGrab) - delegate_->OnLostCapture(); - break; - - case ConfigureNotify: { - DCHECK_EQ(xwindow_, xev->xconfigure.event); - DCHECK_EQ(xwindow_, xev->xconfigure.window); - // It's possible that the X window may be resized by some other means than - // from within aura (e.g. the X window manager can change the size). Make - // sure the root window size is maintained properly. - int translated_x_in_pixels = xev->xconfigure.x; - int translated_y_in_pixels = xev->xconfigure.y; - if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) { - Window unused; - XTranslateCoordinates(xdisplay_, xwindow_, xroot_window_, 0, 0, - &translated_x_in_pixels, &translated_y_in_pixels, - &unused); - } - gfx::Rect bounds(translated_x_in_pixels, translated_y_in_pixels, - xev->xconfigure.width, xev->xconfigure.height); - if (bounds_ != bounds) { - bounds_ = bounds; - delegate_->OnBoundsChanged(bounds_); - } - break; - } - - case ClientMessage: { - Atom message = static_cast<Atom>(xev->xclient.data.l[0]); - if (message == gfx::GetAtom("WM_DELETE_WINDOW")) { - delegate_->OnCloseRequest(); - } else if (message == gfx::GetAtom("_NET_WM_PING")) { - XEvent reply_event = *xev; - reply_event.xclient.window = xroot_window_; - - XSendEvent(xdisplay_, reply_event.xclient.window, x11::False, - SubstructureRedirectMask | SubstructureNotifyMask, - &reply_event); - XFlush(xdisplay_); - } - break; - } - case PropertyNotify: { - ::Atom changed_atom = xev->xproperty.atom; - if (changed_atom == gfx::GetAtom("_NET_WM_STATE")) - OnWMStateUpdated(); - break; - } - } -} - -void X11WindowBase::OnWMStateUpdated() { - std::vector<::Atom> atom_list; - // Ignore the return value of ui::GetAtomArrayProperty(). Fluxbox removes the - // _NET_WM_STATE property when no _NET_WM_STATE atoms are set. - ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list); - - window_properties_.clear(); - std::copy(atom_list.begin(), atom_list.end(), - inserter(window_properties_, window_properties_.begin())); - - // Propagate the window state information to the client. - // Note that the order of checks is important here, because window can have - // several proprties at the same time. - PlatformWindowState old_state = state_; - if (ui::HasWMSpecProperty(window_properties_, - gfx::GetAtom("_NET_WM_STATE_HIDDEN"))) { - state_ = PlatformWindowState::kMinimized; - } else if (ui::HasWMSpecProperty(window_properties_, - gfx::GetAtom("_NET_WM_STATE_FULLSCREEN"))) { - state_ = PlatformWindowState::kFullScreen; - } else if (ui::HasWMSpecProperty( - window_properties_, - gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT")) && - ui::HasWMSpecProperty( - window_properties_, - gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"))) { - state_ = PlatformWindowState::kMaximized; - } else { - state_ = PlatformWindowState::kNormal; - } - - if (old_state != state_) - delegate_->OnWindowStateChanged(state_); -} - -bool X11WindowBase::IsMaximized() const { - return state_ == PlatformWindowState::kMaximized; -} - -bool X11WindowBase::IsFullscreen() const { - return state_ == PlatformWindowState::kFullScreen; -} - -} // namespace ui
diff --git a/ui/platform_window/x11/x11_window_base.h b/ui/platform_window/x11/x11_window_base.h deleted file mode 100644 index 05b8dd1..0000000 --- a/ui/platform_window/x11/x11_window_base.h +++ /dev/null
@@ -1,109 +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 UI_PLATFORM_WINDOW_X11_X11_WINDOW_BASE_H_ -#define UI_PLATFORM_WINDOW_X11_X11_WINDOW_BASE_H_ - -#include <stdint.h> - -#include <array> - -#include "base/callback.h" -#include "base/containers/flat_set.h" -#include "base/macros.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/x/x11.h" -#include "ui/gfx/x/x11_types.h" -#include "ui/platform_window/platform_window.h" -#include "ui/platform_window/platform_window_delegate.h" -#include "ui/platform_window/x11/x11_window_export.h" - -namespace ui { - -class XScopedEventSelector; - -// Abstract base implementation for a X11 based PlatformWindow. Methods that -// are platform specific are left unimplemented. -class X11_WINDOW_EXPORT X11WindowBase : public PlatformWindow { - public: - X11WindowBase(PlatformWindowDelegate* delegate, const gfx::Rect& bounds); - ~X11WindowBase() override; - - // PlatformWindow: - void Show() override; - void Hide() override; - void Close() override; - void SetBounds(const gfx::Rect& bounds) override; - gfx::Rect GetBounds() override; - void SetTitle(const base::string16& title) override; - void SetCapture() override; - void ReleaseCapture() override; - bool HasCapture() const override; - void ToggleFullscreen() override; - void Maximize() override; - void Minimize() override; - void Restore() override; - PlatformWindowState GetPlatformWindowState() const override; - void Activate() override; - void Deactivate() override; - void MoveCursorTo(const gfx::Point& location) override; - void ConfineCursorToBounds(const gfx::Rect& bounds) override; - void SetRestoredBoundsInPixels(const gfx::Rect& bounds) override; - gfx::Rect GetRestoredBoundsInPixels() const override; - - protected: - // Creates new underlying XWindow. Does not map XWindow. - void Create(); - - void Destroy(); - - PlatformWindowDelegate* delegate() { return delegate_; } - XDisplay* xdisplay() { return xdisplay_; } - XID xwindow() const { return xwindow_; } - - void UnConfineCursor(); - - // Checks if XEvent is for this XWindow. - bool IsEventForXWindow(const XEvent& xev) const; - - // Processes events for this XWindow. - void ProcessXWindowEvent(XEvent* xev); - - private: - // Called when WM_STATE property is changed. - void OnWMStateUpdated(); - - bool IsMaximized() const; - bool IsFullscreen() const; - - PlatformWindowDelegate* const delegate_; - - XDisplay* xdisplay_; - XID xwindow_ = x11::None; - XID xroot_window_; - std::unique_ptr<ui::XScopedEventSelector> xwindow_events_; - - base::string16 window_title_; - - // The bounds of |xwindow_|. - gfx::Rect bounds_; - - // The window manager state bits. - base::flat_set<::Atom> window_properties_; - - // Stores current state of this window. - PlatformWindowState state_; - - // Keep track of barriers to confine cursor. - bool has_pointer_barriers_ = false; - std::array<XID, 4> pointer_barriers_; - - bool window_mapped_ = false; - - DISALLOW_COPY_AND_ASSIGN(X11WindowBase); -}; - -} // namespace ui - -#endif // UI_PLATFORM_WINDOW_X11_X11_WINDOW_BASE_H_
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index e585e00..7872cc6 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn
@@ -707,6 +707,7 @@ "widget/desktop_aura/desktop_window_tree_host.cc", ] if (use_x11) { + deps += [ "//ui/platform_window/x11" ] public += [ "widget/desktop_aura/desktop_drag_drop_client_aurax11.h", "widget/desktop_aura/desktop_screen_x11.h", @@ -762,7 +763,7 @@ ] deps += [ "//ui/base:hit_test" ] } - if ((is_linux && !use_x11) || is_fuchsia) { + if (is_linux || is_fuchsia) { public += [ "widget/desktop_aura/desktop_window_tree_host_platform.h" ] sources += [ "widget/desktop_aura/desktop_window_tree_host_platform.cc" ]
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc index 4331c2a2..f494d1f 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -26,62 +26,6 @@ namespace views { -namespace { - -ui::PlatformWindowInitProperties ConvertWidgetInitParamsToInitProperties( - const Widget::InitParams& params) { - ui::PlatformWindowInitProperties properties; - - switch (params.type) { - case Widget::InitParams::TYPE_WINDOW: - properties.type = ui::PlatformWindowType::kWindow; - break; - - case Widget::InitParams::TYPE_MENU: - properties.type = ui::PlatformWindowType::kMenu; - break; - - case Widget::InitParams::TYPE_TOOLTIP: - properties.type = ui::PlatformWindowType::kTooltip; - break; - - default: - properties.type = ui::PlatformWindowType::kPopup; - break; - } - - properties.bounds = params.bounds; - properties.activatable = - params.activatable == Widget::InitParams::ACTIVATABLE_YES; - properties.force_show_in_taskbar = params.force_show_in_taskbar; - properties.keep_on_top = - params.EffectiveZOrderLevel() != ui::ZOrderLevel::kNormal; - properties.visible_on_all_workspaces = params.visible_on_all_workspaces; - properties.remove_standard_frame = params.remove_standard_frame; - properties.workspace = params.workspace; - properties.wm_class_name = params.wm_class_name; - properties.wm_class_class = params.wm_class_class; - properties.wm_role_name = params.wm_role_name; - - if (params.parent && params.parent->GetHost()) - properties.parent_widget = params.parent->GetHost()->GetAcceleratedWidget(); - - switch (params.opacity) { - case Widget::InitParams::WindowOpacity::INFER_OPACITY: - properties.opacity = ui::PlatformWindowOpacity::kInferOpacity; - break; - case Widget::InitParams::WindowOpacity::OPAQUE_WINDOW: - properties.opacity = ui::PlatformWindowOpacity::kOpaqueWindow; - break; - case Widget::InitParams::WindowOpacity::TRANSLUCENT_WINDOW: - properties.opacity = ui::PlatformWindowOpacity::kTranslucentWindow; - break; - } - - return properties; -} - -} // namespace //////////////////////////////////////////////////////////////////////////////// // DesktopWindowTreeHostPlatform: @@ -92,9 +36,13 @@ desktop_native_widget_aura_(desktop_native_widget_aura) {} DesktopWindowTreeHostPlatform::~DesktopWindowTreeHostPlatform() { +// TODO(msisov): Once destruction goes from DWTHX11 to DWTHPlatform, remove this +// guard. +#if !defined(USE_X11) DCHECK(got_on_closed_); desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this); DestroyDispatcher(); +#endif } void DesktopWindowTreeHostPlatform::Init(const Widget::InitParams& params) { @@ -138,6 +86,18 @@ void DesktopWindowTreeHostPlatform::OnActiveWindowChanged(bool active) {} +base::Optional<gfx::Size> +DesktopWindowTreeHostPlatform::GetMinimumSizeForWindow() { + return ToPixelRect(gfx::Rect(native_widget_delegate()->GetMinimumSize())) + .size(); +} + +base::Optional<gfx::Size> +DesktopWindowTreeHostPlatform::GetMaximumSizeForWindow() { + return ToPixelRect(gfx::Rect(native_widget_delegate()->GetMaximumSize())) + .size(); +} + std::unique_ptr<corewm::Tooltip> DesktopWindowTreeHostPlatform::CreateTooltip() { return std::make_unique<corewm::TooltipAura>(); @@ -146,6 +106,7 @@ std::unique_ptr<aura::client::DragDropClient> DesktopWindowTreeHostPlatform::CreateDragDropClient( DesktopNativeCursorManager* cursor_manager) { +#if !defined(USE_X11) ui::WmDragHandler* drag_handler = ui::GetWmDragHandler(*(platform_window())); std::unique_ptr<DesktopDragDropClientOzone> drag_drop_client = std::make_unique<DesktopDragDropClientOzone>(window(), cursor_manager, @@ -154,6 +115,11 @@ // drop action. SetWmDropHandler(platform_window(), drag_drop_client.get()); return std::move(drag_drop_client); +#else + // TODO(https://crbug.com/990756): Move the X11 initialization of dnd here. + NOTIMPLEMENTED_LOG_ONCE(); + return nullptr; +#endif } void DesktopWindowTreeHostPlatform::Close() { @@ -571,6 +537,72 @@ desktop_native_widget_aura_->HandleActivationChanged(active); } +ui::PlatformWindowInitProperties +DesktopWindowTreeHostPlatform::ConvertWidgetInitParamsToInitProperties( + const Widget::InitParams& params) { + ui::PlatformWindowInitProperties properties; + + switch (params.type) { + case Widget::InitParams::TYPE_WINDOW: + properties.type = ui::PlatformWindowType::kWindow; + break; + + case Widget::InitParams::TYPE_MENU: + properties.type = ui::PlatformWindowType::kMenu; + break; + + case Widget::InitParams::TYPE_TOOLTIP: + properties.type = ui::PlatformWindowType::kTooltip; + break; + + case Widget::InitParams::TYPE_DRAG: + properties.type = ui::PlatformWindowType::kDrag; + break; + + case Widget::InitParams::TYPE_BUBBLE: + properties.type = ui::PlatformWindowType::kBubble; + break; + + default: + properties.type = ui::PlatformWindowType::kPopup; + break; + } + + properties.bounds = params.bounds; + properties.activatable = + params.activatable == Widget::InitParams::ACTIVATABLE_YES; + properties.force_show_in_taskbar = params.force_show_in_taskbar; + properties.keep_on_top = + params.EffectiveZOrderLevel() != ui::ZOrderLevel::kNormal; + properties.visible_on_all_workspaces = params.visible_on_all_workspaces; + properties.remove_standard_frame = params.remove_standard_frame; + properties.workspace = params.workspace; + properties.wm_class_name = params.wm_class_name; + properties.wm_class_class = params.wm_class_class; + properties.wm_role_name = params.wm_role_name; + + if (params.parent && params.parent->GetHost()) + properties.parent_widget = params.parent->GetHost()->GetAcceleratedWidget(); + + switch (params.opacity) { + case Widget::InitParams::WindowOpacity::INFER_OPACITY: + properties.opacity = ui::PlatformWindowOpacity::kInferOpacity; + break; + case Widget::InitParams::WindowOpacity::OPAQUE_WINDOW: + properties.opacity = ui::PlatformWindowOpacity::kOpaqueWindow; + break; + case Widget::InitParams::WindowOpacity::TRANSLUCENT_WINDOW: + properties.opacity = ui::PlatformWindowOpacity::kTranslucentWindow; + break; + } + + return properties; +} + +aura::Window* DesktopWindowTreeHostPlatform::content_window() { + return desktop_native_widget_aura_->content_window(); +} + void DesktopWindowTreeHostPlatform::Relayout() { Widget* widget = native_widget_delegate_->AsWidget(); NonClientView* non_client_view = widget->non_client_view(); @@ -612,6 +644,11 @@ //////////////////////////////////////////////////////////////////////////////// // DesktopWindowTreeHost: +// As DWTHX11 subclasses DWTHPlatform now (during transition period. see +// https://crbug.com/990756), we need to guard this factory method. +// TODO(msisov): remove this guard once DWTHX11 is finally merged into +// DWTHPlatform. +#if !defined(USE_X11) // static DesktopWindowTreeHost* DesktopWindowTreeHost::Create( internal::NativeWidgetDelegate* native_widget_delegate, @@ -619,5 +656,6 @@ return new DesktopWindowTreeHostPlatform(native_widget_delegate, desktop_native_widget_aura); } +#endif } // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h index d826f85..f3f9ace 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -90,12 +90,29 @@ bool ShouldUseDesktopNativeCursorManager() const override; bool ShouldCreateVisibilityController() const override; - // WindowTreeHostPlatform: + // PlatformWindowDelegateBase: void DispatchEvent(ui::Event* event) override; void OnClosed() override; void OnWindowStateChanged(ui::PlatformWindowState new_state) override; void OnCloseRequest() override; void OnActivationChanged(bool active) override; + base::Optional<gfx::Size> GetMinimumSizeForWindow() override; + base::Optional<gfx::Size> GetMaximumSizeForWindow() override; + + protected: + // TODO(https://crbug.com/990756): move this back to unnamed namespace, when + // DWTHX11 stops initialization of the PlatformWindow. Also, remove these + // accessor methods. + ui::PlatformWindowInitProperties ConvertWidgetInitParamsToInitProperties( + const Widget::InitParams& params); + internal::NativeWidgetDelegate* native_widget_delegate() { + return native_widget_delegate_; + } + DesktopNativeWidgetAura* desktop_native_widget_aura() { + return desktop_native_widget_aura_; + } + // Accessor for DesktopNativeWidgetAura::content_window(). + aura::Window* content_window(); private: FRIEND_TEST_ALL_PREFIXES(DesktopWindowTreeHostPlatformTest, HitTest);
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc index d47565e..312df3e9 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -22,7 +22,6 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" -#include "base/trace_event/trace_event.h" #include "third_party/skia/include/core/SkPath.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/cursor_client.h" @@ -54,6 +53,7 @@ #include "ui/gfx/path_x11.h" #include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_atom_cache.h" +#include "ui/platform_window/x11/x11_window.h" #include "ui/views/corewm/tooltip_aura.h" #include "ui/views/linux_ui/linux_ui.h" #include "ui/views/views_delegate.h" @@ -88,61 +88,6 @@ namespace { -ui::XWindow::Configuration ConvertInitParamsToX11WindowConfig( - const Widget::InitParams& params) { - using WindowType = ui::XWindow::WindowType; - using WindowOpacity = ui::XWindow::WindowOpacity; - ui::XWindow::Configuration config; - - switch (params.type) { - case Widget::InitParams::TYPE_WINDOW: - config.type = WindowType::kWindow; - break; - case Widget::InitParams::TYPE_MENU: - config.type = WindowType::kMenu; - break; - case Widget::InitParams::TYPE_TOOLTIP: - config.type = WindowType::kTooltip; - break; - case Widget::InitParams::TYPE_DRAG: - config.type = WindowType::kDrag; - break; - case Widget::InitParams::TYPE_BUBBLE: - config.type = WindowType::kBubble; - break; - default: - config.type = WindowType::kPopup; - break; - } - - switch (params.opacity) { - case Widget::InitParams::WindowOpacity::INFER_OPACITY: - config.opacity = WindowOpacity::kInferOpacity; - break; - case Widget::InitParams::WindowOpacity::OPAQUE_WINDOW: - config.opacity = WindowOpacity::kOpaqueWindow; - break; - case Widget::InitParams::WindowOpacity::TRANSLUCENT_WINDOW: - config.opacity = WindowOpacity::kTranslucentWindow; - break; - } - - config.activatable = - params.activatable == Widget::InitParams::ACTIVATABLE_YES; - config.force_show_in_taskbar = params.force_show_in_taskbar; - config.keep_on_top = - params.EffectiveZOrderLevel() != ui::ZOrderLevel::kNormal; - config.visible_on_all_workspaces = params.visible_on_all_workspaces; - config.remove_standard_frame = params.remove_standard_frame; - - config.workspace = params.workspace; - config.wm_class_name = params.wm_class_name; - config.wm_class_class = params.wm_class_class; - config.wm_role_name = params.wm_role_name; - - return config; -} - // Returns the whole path from |window| to the root. std::vector<::Window> GetParentsList(XDisplay* xdisplay, ::Window window) { ::Window parent_win, root_win; @@ -152,8 +97,8 @@ while (window) { result.push_back(window); - if (!XQueryTree(xdisplay, window, - &root_win, &parent_win, &child_windows, &num_child_windows)) + if (!XQueryTree(xdisplay, window, &root_win, &parent_win, &child_windows, + &num_child_windows)) break; if (child_windows) XFree(child_windows); @@ -210,14 +155,14 @@ DesktopWindowTreeHostX11::DesktopWindowTreeHostX11( internal::NativeWidgetDelegate* native_widget_delegate, DesktopNativeWidgetAura* desktop_native_widget_aura) - : native_widget_delegate_(native_widget_delegate), - desktop_native_widget_aura_(desktop_native_widget_aura), - x11_window_(std::make_unique<ui::XWindow>(this)) {} + : DesktopWindowTreeHostPlatform(native_widget_delegate, + desktop_native_widget_aura), + x11_window_(std::make_unique<ui::X11Window>(this, this)) {} DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() { window()->ClearProperty(kHostForRootWindow); wm::SetWindowMoveClient(window(), nullptr); - desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this); + desktop_native_widget_aura()->OnDesktopWindowTreeHostDestroyed(this); DestroyDispatcher(); } @@ -238,9 +183,7 @@ // static std::vector<aura::Window*> DesktopWindowTreeHostX11::GetAllOpenWindows() { std::vector<aura::Window*> windows(open_windows().size()); - std::transform(open_windows().begin(), - open_windows().end(), - windows.begin(), + std::transform(open_windows().begin(), open_windows().end(), windows.begin(), GetContentWindowForXID); return windows; } @@ -327,7 +270,7 @@ SetWindowTransparency(); - native_widget_delegate_->OnNativeWidgetCreated(); + native_widget_delegate()->OnNativeWidgetCreated(); } void DesktopWindowTreeHostX11::OnWidgetInitDone() {} @@ -367,10 +310,11 @@ void DesktopWindowTreeHostX11::CloseNow() { if (x11_window_->window() == x11::None) return; + x11_window_->PrepareForShutdown(); ReleaseCapture(); RemoveNonClientEventFilter(); - native_widget_delegate_->OnNativeWidgetDestroying(); + native_widget_delegate()->OnNativeWidgetDestroying(); // If we have children, close them. Use a copy for iteration because they'll // remove themselves. @@ -391,12 +335,8 @@ DestroyCompositor(); open_windows().remove(x11_window_->window()); - // Actually free our native resources. - if (auto* source = ui::PlatformEventSource::GetInstance()) - source->RemovePlatformEventDispatcher(this); x11_window_->Close(); - desktop_native_widget_aura_->OnHostClosed(); } aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() { @@ -430,7 +370,7 @@ break; } - native_widget_delegate_->AsWidget()->SetInitialFocus(show_state); + native_widget_delegate()->AsWidget()->SetInitialFocus(show_state); content_window()->Show(); } @@ -695,7 +635,7 @@ if (compositor()) compositor()->SetVisible(visible); - native_widget_delegate_->OnNativeWidgetVisibilityChanged(visible); + native_widget_delegate()->OnNativeWidgetVisibilityChanged(visible); } void DesktopWindowTreeHostX11::SetVisibleOnAllWorkspaces(bool always_visible) { @@ -707,7 +647,9 @@ } bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) { - return x11_window_->SetTitle(title); + auto* x_window = static_cast<ui::XWindow*>(x11_window_.get()); + DCHECK(x_window); + return x_window->SetTitle(title); } void DesktopWindowTreeHostX11::ClearNativeFocus() { @@ -748,7 +690,7 @@ NonClientFrameView* DesktopWindowTreeHostX11::CreateNonClientFrameView() { return ShouldUseNativeFrame() - ? new NativeFrameView(native_widget_delegate_->AsWidget()) + ? new NativeFrameView(native_widget_delegate()->AsWidget()) : nullptr; } @@ -762,7 +704,7 @@ void DesktopWindowTreeHostX11::FrameTypeChanged() { Widget::FrameType new_type = - native_widget_delegate_->AsWidget()->frame_type(); + native_widget_delegate()->AsWidget()->frame_type(); if (new_type == Widget::FrameType::kDefault) { // The default is determined by Widget::InitParams::remove_standard_frame // and does not change. @@ -841,8 +783,8 @@ x11_window_->SetAspectRatio(aspect_ratio); } -void DesktopWindowTreeHostX11::SetWindowIcons( - const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) { +void DesktopWindowTreeHostX11::SetWindowIcons(const gfx::ImageSkia& window_icon, + const gfx::ImageSkia& app_icon) { x11_window_->SetWindowIcons(window_icon, app_icon); } @@ -918,7 +860,9 @@ } void DesktopWindowTreeHostX11::HideImpl() { - if (x11_window_->Hide()) + auto* x_window = static_cast<ui::XWindow*>(x11_window_.get()); + DCHECK(x_window); + if (x_window->Hide()) SetVisible(false); } @@ -932,7 +876,6 @@ gfx::Rect bounds_in_pixels(requested_bounds_in_pixel.origin(), AdjustSize(requested_bounds_in_pixel.size())); - bool origin_changed = bounds.origin() != bounds_in_pixels.origin(); bool size_changed = bounds.size() != bounds_in_pixels.size(); if (size_changed) { @@ -942,14 +885,6 @@ } x11_window_->SetBounds(bounds_in_pixels); - - if (origin_changed) - native_widget_delegate_->AsWidget()->OnNativeWidgetMove(); - - if (size_changed) { - OnHostResizedInPixels(bounds_in_pixels.size()); - ResetWindowRegion(); - } } gfx::Point DesktopWindowTreeHostX11::GetLocationOnScreenInPixels() const { @@ -1046,204 +981,16 @@ } } -void DesktopWindowTreeHostX11::OnXWindowCreated() { - if (auto* source = ui::PlatformEventSource::GetInstance()) - source->AddPlatformEventDispatcher(this); - - open_windows().push_front(x11_window_->window()); -} - -void DesktopWindowTreeHostX11::OnXWindowMapped() { - for (DesktopWindowTreeHostObserverX11& observer : observer_list_) - observer.OnWindowMapped(x11_window_->window()); -} - -void DesktopWindowTreeHostX11::OnXWindowUnmapped() { - for (DesktopWindowTreeHostObserverX11& observer : observer_list_) - observer.OnWindowUnmapped(x11_window_->window()); -} - -void DesktopWindowTreeHostX11::OnXWindowStateChanged() { - bool was_minimized = x11_window_->was_minimized(); - bool is_minimized = IsMinimized(); - - // Propagate the window minimization information to the content window, so - // the render side can update its visibility properly. OnWMStateUpdated() is - // called by PropertyNofify event from DispatchEvent() when the browser is - // minimized or shown from minimized state. On Windows, this is realized by - // calling OnHostResizedInPixels() with an empty size. In particular, - // HWNDMessageHandler::GetClientAreaBounds() returns an empty size when the - // window is minimized. On Linux, returning empty size in GetBounds() or - // SetBoundsInPixels() does not work. - // We also propagate the minimization to the compositor, to makes sure that we - // don't draw any 'blank' frames that could be noticed in applications such as - // window manager previews, which show content even when a window is - // minimized. - if (is_minimized != was_minimized) { - if (is_minimized) { - SetVisible(false); - content_window()->Hide(); - } else { - content_window()->Show(); - SetVisible(true); - } - } - - if (restored_bounds_in_pixels_.IsEmpty()) { - if (IsMaximized()) { - // The request that we become maximized originated from a different - // process. |bounds_in_pixels_| already contains our maximized bounds. Do - // a best effort attempt to get restored bounds by setting it to our - // previously set bounds (and if we get this wrong, we aren't any worse - // off since we'd otherwise be returning our maximized bounds). - restored_bounds_in_pixels_ = x11_window_->previous_bounds(); - } - } else if (!IsMaximized() && !IsFullscreen()) { - // If we have restored bounds, but WM_STATE no longer claims to be - // maximized or fullscreen, we should clear our restored bounds. - restored_bounds_in_pixels_ = gfx::Rect(); - } - - // Now that we have different window properties, we may need to relayout the - // window. (The windows code doesn't need this because their window change is - // synchronous.) - Relayout(); - ResetWindowRegion(); -} - -void DesktopWindowTreeHostX11::OnXWindowWorkspaceChanged() { - OnHostWorkspaceChanged(); -} - -void DesktopWindowTreeHostX11::OnXWindowDamageEvent( - const gfx::Rect& damage_rect_in_pixels) { - compositor()->ScheduleRedrawRect(damage_rect_in_pixels); -} - -void DesktopWindowTreeHostX11::OnXWindowKeyEvent(ui::KeyEvent* key_event) { - DispatchKeyEvent(key_event); -} - -void DesktopWindowTreeHostX11::OnXWindowMouseEvent(ui::MouseEvent* mouseev) { - DispatchMouseEvent(mouseev); -} - -void DesktopWindowTreeHostX11::OnXWindowTouchEvent( - ui::TouchEvent* touch_event) { - DispatchTouchEvent(touch_event); -} - -void DesktopWindowTreeHostX11::OnXWindowScrollEvent( - ui::ScrollEvent* scroll_event) { - SendEventToSink(scroll_event); -} - -void DesktopWindowTreeHostX11::OnXWindowSelectionEvent(XEvent* xev) { - DCHECK(xev); - DCHECK(drag_drop_client_); - drag_drop_client_->OnSelectionNotify(xev->xselection); -} - -void DesktopWindowTreeHostX11::OnXWindowDragDropEvent(XEvent* xev) { - DCHECK(xev); - DCHECK(drag_drop_client_); - - ::Atom message_type = xev->xclient.message_type; - if (message_type == gfx::GetAtom("XdndEnter")) { - drag_drop_client_->OnXdndEnter(xev->xclient); - } else if (message_type == gfx::GetAtom("XdndLeave")) { - drag_drop_client_->OnXdndLeave(xev->xclient); - } else if (message_type == gfx::GetAtom("XdndPosition")) { - drag_drop_client_->OnXdndPosition(xev->xclient); - } else if (message_type == gfx::GetAtom("XdndStatus")) { - drag_drop_client_->OnXdndStatus(xev->xclient); - } else if (message_type == gfx::GetAtom("XdndFinished")) { - drag_drop_client_->OnXdndFinished(xev->xclient); - } else if (message_type == gfx::GetAtom("XdndDrop")) { - drag_drop_client_->OnXdndDrop(xev->xclient); - } -} - -void DesktopWindowTreeHostX11::OnXWindowRawKeyEvent(XEvent* xev) { - switch (xev->type) { - case KeyPress: - if (!ShouldDiscardKeyEvent(xev)) { - ui::KeyEvent keydown_event(xev); - DispatchKeyEvent(&keydown_event); - } - break; - case KeyRelease: - - // There is no way to deactivate a window in X11 so ignore input if - // window is supposed to be 'inactive'. - if (!IsActive() && !HasCapture()) - break; - - if (!ShouldDiscardKeyEvent(xev)) { - ui::KeyEvent keyup_event(xev); - DispatchKeyEvent(&keyup_event); - } - break; - default: - NOTREACHED() << xev->type; - break; - } -} - -void DesktopWindowTreeHostX11::OnXWindowChildCrossingEvent(XEvent* xev) { - DCHECK(xev); - ui::MouseEvent mouse_event(xev); - DispatchMouseEvent(&mouse_event); -} - -void DesktopWindowTreeHostX11::OnXWindowSizeChanged( - const gfx::Size& size_in_pixels) { - OnHostResizedInPixels(size_in_pixels); - ResetWindowRegion(); -} - -void DesktopWindowTreeHostX11::OnXWindowCloseRequested() { - OnHostCloseRequested(); -} - -void DesktopWindowTreeHostX11::OnXWindowMoved(const gfx::Point& window_origin) { - OnHostMovedInPixels(window_origin); -} - -void DesktopWindowTreeHostX11::OnXWindowLostPointerGrab() { - dispatcher()->OnHostLostMouseGrab(); -} - -void DesktopWindowTreeHostX11::OnXWindowLostCapture() { - OnHostLostWindowCapture(); -} - -void DesktopWindowTreeHostX11::OnXWindowIsActiveChanged(bool active) { - if (active) { - // TODO(thomasanderson): Remove this window shuffling and use XWindowCache - // instead. - ::Window xwindow = x11_window_->window(); - open_windows().remove(xwindow); - open_windows().insert(open_windows().begin(), xwindow); - } - desktop_native_widget_aura_->HandleActivationChanged(active); - native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint(); -} - -gfx::Size DesktopWindowTreeHostX11::GetMinimumSizeForXWindow() { - return ToPixelRect(gfx::Rect(native_widget_delegate_->GetMinimumSize())) - .size(); -} - -gfx::Size DesktopWindowTreeHostX11::GetMaximumSizeForXWindow() { - return ToPixelRect(gfx::Rect(native_widget_delegate_->GetMaximumSize())) - .size(); -} - //////////////////////////////////////////////////////////////////////////////// // DesktopWindowTreeHostX11, private: void DesktopWindowTreeHostX11::InitX11Window(const Widget::InitParams& params) { + // Disable compositing on tooltips as a workaround for + // https://crbug.com/442111. + CreateCompositor(viz::FrameSinkId(), + params.force_software_compositing || + params.type == Widget::InitParams::TYPE_TOOLTIP); + // Calculate initial bounds gfx::Rect bounds_in_pixels = ToPixelRect(params.bounds); gfx::Size adjusted_size = AdjustSize(bounds_in_pixels.size()); @@ -1272,20 +1019,14 @@ background_color = theme->GetSystemColor(target_color); } - // Create window configuration and initialize it - ui::XWindow::Configuration config = - ConvertInitParamsToX11WindowConfig(params); - config.bounds = bounds_in_pixels; - config.background_color = background_color; - config.prefer_dark_theme = linux_ui && linux_ui->PreferDarkTheme(); - config.icon = ViewsDelegate::GetInstance()->GetDefaultWindowIcon(); - x11_window_->Init(config); - - // Disable compositing on tooltips as a workaround for - // https://crbug.com/442111. - CreateCompositor(viz::FrameSinkId(), - params.force_software_compositing || - params.type == Widget::InitParams::TYPE_TOOLTIP); + // Create PlatformWindowInitProperties and initialize it + ui::PlatformWindowInitProperties properties = + ConvertWidgetInitParamsToInitProperties(params); + properties.bounds = bounds_in_pixels; + properties.background_color = background_color; + properties.prefer_dark_theme = linux_ui && linux_ui->PreferDarkTheme(); + properties.icon = ViewsDelegate::GetInstance()->GetDefaultWindowIcon(); + x11_window_->Initialize(std::move(properties)); if (ui::IsSyncExtensionAvailable()) { compositor_observer_ = std::make_unique<SwapWithNewSizeObserverHelper>( @@ -1293,7 +1034,6 @@ &DesktopWindowTreeHostX11::OnCompleteSwapWithNewSize, base::Unretained(this))); } - OnAcceleratedWidgetAvailable(); } void DesktopWindowTreeHostX11::DispatchHostWindowDragMovement( @@ -1388,7 +1128,7 @@ } void DesktopWindowTreeHostX11::DispatchKeyEvent(ui::KeyEvent* event) { - if (native_widget_delegate_->AsWidget()->IsActive()) + if (native_widget_delegate()->AsWidget()->IsActive()) SendEventToSink(event); } @@ -1396,7 +1136,7 @@ _XRegion* xregion = nullptr; if (!x11_window_->use_custom_shape() && !IsMaximized() && !IsFullscreen()) { SkPath window_mask; - Widget* widget = native_widget_delegate_->AsWidget(); + Widget* widget = native_widget_delegate()->AsWidget(); if (widget->non_client_view()) { // Some frame views define a custom (non-rectangular) window mask. If // so, use it to define the window shape. If not, fall through. @@ -1410,7 +1150,6 @@ x11_window_->UpdateWindowRegion(xregion); } - std::list<XID>& DesktopWindowTreeHostX11::open_windows() { if (!open_windows_) open_windows_ = new std::list<XID>(); @@ -1443,7 +1182,7 @@ } void DesktopWindowTreeHostX11::Relayout() { - Widget* widget = native_widget_delegate_->AsWidget(); + Widget* widget = native_widget_delegate()->AsWidget(); NonClientView* non_client_view = widget->non_client_view(); // non_client_view may be NULL, especially during creation. if (non_client_view) { @@ -1453,30 +1192,14 @@ } //////////////////////////////////////////////////////////////////////////////// -// DesktopWindowTreeHostX11, ui::PlatformEventDispatcher implementation: - -bool DesktopWindowTreeHostX11::CanDispatchEvent( - const ui::PlatformEvent& event) { - return x11_window_->IsTargetedBy(*event); -} - -uint32_t DesktopWindowTreeHostX11::DispatchEvent( - const ui::PlatformEvent& event) { - XEvent* xev = event; - - TRACE_EVENT1("views", "DesktopWindowTreeHostX11::Dispatch", - "event->type", event->type); - - x11_window_->ProcessEvent(xev); - return ui::POST_DISPATCH_STOP_PROPAGATION; -} +// DesktopWindowTreeHostX11 implementation: void DesktopWindowTreeHostX11::DelayedChangeFrameType(Widget::FrameType type) { SetUseNativeFrame(type == Widget::FrameType::kForceNative); // Replace the frame and layout the contents. Even though we don't have a // swappable glass frame like on Windows, we still replace the frame because // the button assets don't update otherwise. - native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame(); + native_widget_delegate()->AsWidget()->non_client_view()->UpdateFrame(); } gfx::Rect DesktopWindowTreeHostX11::ToDIPRect( @@ -1513,10 +1236,6 @@ targeter_for_modal_.reset(); } -aura::Window* DesktopWindowTreeHostX11::content_window() { - return desktop_native_widget_aura_->content_window(); -} - void DesktopWindowTreeHostX11::OnCompleteSwapWithNewSize( const gfx::Size& size) { x11_window_->NotifySwapAfterResize(); @@ -1534,6 +1253,165 @@ x11_window_->set_visual_id(visual_id); } +void DesktopWindowTreeHostX11::OnBoundsChanged(const gfx::Rect& new_bounds) { + ResetWindowRegion(); + WindowTreeHostPlatform::OnBoundsChanged(new_bounds); +} + +void DesktopWindowTreeHostX11::DispatchEvent(ui::Event* event) { + if (event->IsKeyEvent()) + DispatchKeyEvent(event->AsKeyEvent()); + else if (event->IsMouseEvent()) + DispatchMouseEvent(event->AsMouseEvent()); + else if (event->IsTouchEvent()) + DispatchTouchEvent(event->AsTouchEvent()); + else + SendEventToSink(event); +} + +void DesktopWindowTreeHostX11::OnClosed() { + desktop_native_widget_aura()->OnHostClosed(); +} + +void DesktopWindowTreeHostX11::OnWindowStateChanged( + ui::PlatformWindowState new_state) { + bool was_minimized = x11_window_->was_minimized(); + bool is_minimized = IsMinimized(); + + // Propagate the window minimization information to the content window, so + // the render side can update its visibility properly. OnWMStateUpdated() is + // called by PropertyNofify event from DispatchEvent() when the browser is + // minimized or shown from minimized state. On Windows, this is realized by + // calling OnHostResizedInPixels() with an empty size. In particular, + // HWNDMessageHandler::GetClientAreaBounds() returns an empty size when the + // window is minimized. On Linux, returning empty size in GetBounds() or + // SetBoundsInPixels() does not work. + // We also propagate the minimization to the compositor, to makes sure that we + // don't draw any 'blank' frames that could be noticed in applications such as + // window manager previews, which show content even when a window is + // minimized. + if (is_minimized != was_minimized) { + if (is_minimized) { + SetVisible(false); + content_window()->Hide(); + } else { + content_window()->Show(); + SetVisible(true); + } + } + + if (restored_bounds_in_pixels_.IsEmpty()) { + if (IsMaximized()) { + // The request that we become maximized originated from a different + // process. |bounds_in_pixels_| already contains our maximized bounds. Do + // a best effort attempt to get restored bounds by setting it to our + // previously set bounds (and if we get this wrong, we aren't any worse + // off since we'd otherwise be returning our maximized bounds). + restored_bounds_in_pixels_ = x11_window_->previous_bounds(); + } + } else if (!IsMaximized() && !IsFullscreen()) { + // If we have restored bounds, but WM_STATE no longer claims to be + // maximized or fullscreen, we should clear our restored bounds. + restored_bounds_in_pixels_ = gfx::Rect(); + } + + // Now that we have different window properties, we may need to relayout the + // window. (The windows code doesn't need this because their window change is + // synchronous.) + Relayout(); + ResetWindowRegion(); +} + +void DesktopWindowTreeHostX11::OnAcceleratedWidgetAvailable( + gfx::AcceleratedWidget widget) { + open_windows().push_front(x11_window_->window()); + WindowTreeHost::OnAcceleratedWidgetAvailable(); +} + +void DesktopWindowTreeHostX11::OnAcceleratedWidgetDestroyed() {} + +void DesktopWindowTreeHostX11::OnActivationChanged(bool active) { + if (active) { + // TODO(thomasanderson): Remove this window shuffling and use XWindowCache + // instead. + ::Window xwindow = x11_window_->window(); + open_windows().remove(xwindow); + open_windows().insert(open_windows().begin(), xwindow); + } + desktop_native_widget_aura()->HandleActivationChanged(active); + native_widget_delegate()->AsWidget()->GetRootView()->SchedulePaint(); +} + +void DesktopWindowTreeHostX11::OnXWindowMapped() { + for (DesktopWindowTreeHostObserverX11& observer : observer_list_) + observer.OnWindowMapped(x11_window_->window()); +} + +void DesktopWindowTreeHostX11::OnXWindowUnmapped() { + for (DesktopWindowTreeHostObserverX11& observer : observer_list_) + observer.OnWindowUnmapped(x11_window_->window()); +} + +void DesktopWindowTreeHostX11::OnLostMouseGrab() { + dispatcher()->OnHostLostMouseGrab(); +} + +void DesktopWindowTreeHostX11::OnWorkspaceChanged() { + OnHostWorkspaceChanged(); +} + +void DesktopWindowTreeHostX11::OnXWindowSelectionEvent(XEvent* xev) { + DCHECK(xev); + DCHECK(drag_drop_client_); + drag_drop_client_->OnSelectionNotify(xev->xselection); +} + +void DesktopWindowTreeHostX11::OnXWindowDragDropEvent(XEvent* xev) { + DCHECK(xev); + DCHECK(drag_drop_client_); + + ::Atom message_type = xev->xclient.message_type; + if (message_type == gfx::GetAtom("XdndEnter")) { + drag_drop_client_->OnXdndEnter(xev->xclient); + } else if (message_type == gfx::GetAtom("XdndLeave")) { + drag_drop_client_->OnXdndLeave(xev->xclient); + } else if (message_type == gfx::GetAtom("XdndPosition")) { + drag_drop_client_->OnXdndPosition(xev->xclient); + } else if (message_type == gfx::GetAtom("XdndStatus")) { + drag_drop_client_->OnXdndStatus(xev->xclient); + } else if (message_type == gfx::GetAtom("XdndFinished")) { + drag_drop_client_->OnXdndFinished(xev->xclient); + } else if (message_type == gfx::GetAtom("XdndDrop")) { + drag_drop_client_->OnXdndDrop(xev->xclient); + } +} + +void DesktopWindowTreeHostX11::OnXWindowRawKeyEvent(XEvent* xev) { + switch (xev->type) { + case KeyPress: + if (!ShouldDiscardKeyEvent(xev)) { + ui::KeyEvent keydown_event(xev); + DispatchKeyEvent(&keydown_event); + } + break; + case KeyRelease: + + // There is no way to deactivate a window in X11 so ignore input if + // window is supposed to be 'inactive'. + if (!IsActive() && !HasCapture()) + break; + + if (!ShouldDiscardKeyEvent(xev)) { + ui::KeyEvent keyup_event(xev); + DispatchKeyEvent(&keyup_event); + } + break; + default: + NOTREACHED() << xev->type; + break; + } +} + //////////////////////////////////////////////////////////////////////////////// // DesktopWindowTreeHost, public:
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h index f180625..4a9949a 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -20,14 +20,14 @@ #include "base/observer_list.h" #include "ui/aura/scoped_window_targeter.h" #include "ui/aura/window_tree_host.h" -#include "ui/base/x/x11_window.h" -#include "ui/events/platform/platform_event_dispatcher.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/x/x11_types.h" +#include "ui/platform_window/platform_window_delegate.h" #include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h" +#include "ui/platform_window/x11/x11_window.h" #include "ui/views/views_export.h" -#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h" +#include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h" namespace gfx { class ImageSkia; @@ -39,8 +39,8 @@ class KeyEvent; class MouseEvent; class TouchEvent; -class ScrollEvent; -} +class X11Window; +} // namespace ui namespace views { class DesktopDragDropClientAuraX11; @@ -50,11 +50,9 @@ class WindowEventFilter; class VIEWS_EXPORT DesktopWindowTreeHostX11 - : public DesktopWindowTreeHost, - public aura::WindowTreeHost, - public ui::PlatformEventDispatcher, + : public DesktopWindowTreeHostPlatform, public ui::WmMoveResizeHandler, - public ui::XWindow::Delegate { + public ui::XEventDelegate { public: DesktopWindowTreeHostX11( internal::NativeWidgetDelegate* native_widget_delegate, @@ -195,30 +193,6 @@ void OnDisplayMetricsChanged(const display::Display& display, uint32_t changed_metrics) override; - // Overridden from ui::XWindow::Delegate - void OnXWindowCreated() override; - void OnXWindowMapped() override; - void OnXWindowUnmapped() override; - void OnXWindowStateChanged() override; - void OnXWindowWorkspaceChanged() override; - void OnXWindowKeyEvent(ui::KeyEvent* key_event) override; - void OnXWindowMouseEvent(ui::MouseEvent* mouseev) override; - void OnXWindowTouchEvent(ui::TouchEvent* touch_event) override; - void OnXWindowScrollEvent(ui::ScrollEvent* scroll_event) override; - void OnXWindowSelectionEvent(XEvent* xev) override; - void OnXWindowDragDropEvent(XEvent* xev) override; - void OnXWindowChildCrossingEvent(XEvent* xev) override; - void OnXWindowRawKeyEvent(XEvent* xev) override; - void OnXWindowSizeChanged(const gfx::Size& size) override; - void OnXWindowCloseRequested() override; - void OnXWindowMoved(const gfx::Point& window_origin) override; - void OnXWindowDamageEvent(const gfx::Rect& damage_rect) override; - void OnXWindowLostPointerGrab() override; - void OnXWindowLostCapture() override; - void OnXWindowIsActiveChanged(bool active) override; - gfx::Size GetMinimumSizeForXWindow() override; - gfx::Size GetMaximumSizeForXWindow() override; - private: friend class DesktopWindowTreeHostX11HighDPITest; @@ -270,10 +244,6 @@ // Relayout the widget's client and non-client views. void Relayout(); - // ui::PlatformEventDispatcher: - bool CanDispatchEvent(const ui::PlatformEvent& event) override; - uint32_t DispatchEvent(const ui::PlatformEvent& event) override; - void DelayedChangeFrameType(Widget::FrameType new_type); gfx::Rect ToDIPRect(const gfx::Rect& rect_in_pixels) const; @@ -285,12 +255,31 @@ // Set visibility and fire OnNativeWidgetVisibilityChanged() if it changed. void SetVisible(bool visible); - // Accessor for DesktopNativeWidgetAura::content_window(). - aura::Window* content_window(); - // Callback for a swapbuffer after resize. void OnCompleteSwapWithNewSize(const gfx::Size& size); + // PlatformWindowDelegate overrides: + // + // DWTHX11 temporarily overrides the PlatformWindowDelegate methods instead of + // underlying DWTHPlatform and WTHPlatform. Eventually, these will be removed + // from here as we progress in https://crbug.com/990756. + void OnBoundsChanged(const gfx::Rect& new_bounds) override; + void DispatchEvent(ui::Event* event) override; + void OnClosed() override; + void OnWindowStateChanged(ui::PlatformWindowState new_state) override; + void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) override; + void OnAcceleratedWidgetDestroyed() override; + void OnActivationChanged(bool active) override; + void OnXWindowMapped() override; + void OnXWindowUnmapped() override; + void OnLostMouseGrab() override; + void OnWorkspaceChanged() override; + + // Overridden from ui::XEventDelegate. + void OnXWindowSelectionEvent(XEvent* xev) override; + void OnXWindowDragDropEvent(XEvent* xev) override; + void OnXWindowRawKeyEvent(XEvent* xev) override; + // The bounds of our window before we were maximized. gfx::Rect restored_bounds_in_pixels_; @@ -306,12 +295,6 @@ std::unique_ptr<WindowEventFilter> non_client_event_filter_; std::unique_ptr<X11DesktopWindowMoveClient> x11_window_move_client_; - // TODO(beng): Consider providing an interface to DesktopNativeWidgetAura - // instead of providing this route back to Widget. - internal::NativeWidgetDelegate* native_widget_delegate_; - - DesktopNativeWidgetAura* desktop_native_widget_aura_; - // We can optionally have a parent which can order us to close, or own // children who we're responsible for closing when we CloseNow(). DesktopWindowTreeHostX11* window_parent_ = nullptr; @@ -340,7 +323,7 @@ std::unique_ptr<CompositorObserver> compositor_observer_; - std::unique_ptr<ui::XWindow> x11_window_; + std::unique_ptr<ui::X11Window> x11_window_; // The display and the native X window hosting the root window. base::WeakPtrFactory<DesktopWindowTreeHostX11> close_widget_factory_{this};
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc index 5f154118..8bd27d2 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
@@ -14,6 +14,7 @@ #include "ui/base/x/x11_util.h" #include "ui/events/event_handler.h" #include "ui/events/platform/x11/x11_event_source.h" +#include "ui/events/platform/x11/x11_event_source_glib.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_atom_cache.h" @@ -106,7 +107,8 @@ xev.xmotion.is_hint = NotifyNormal; xev.xmotion.same_screen = x11::True; - static_cast<ui::PlatformEventDispatcher*>(desktop_host)->DispatchEvent(&xev); + static_cast<ui::X11EventSourceGlib*>(ui::PlatformEventSource::GetInstance()) + ->ProcessXEvent(&xev); } } // namespace
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index 5c57a25..e1c2c17 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc
@@ -834,10 +834,8 @@ } gfx::Size NativeWidgetAura::GetMaximumSize() const { - // A window should not have a maximum size and also be maximizable. - DCHECK(delegate_->GetMaximumSize().IsEmpty() || - !(window_->GetProperty(aura::client::kResizeBehaviorKey) & - aura::client::kResizeBehaviorCanMaximize)); + // Do no check maximizability as EXO clients can have maximum size and be + // maximizable at the same time. return delegate_->GetMaximumSize(); }