diff --git a/DEPS b/DEPS index df90ad5..169c18f 100644 --- a/DEPS +++ b/DEPS
@@ -100,7 +100,7 @@ # 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': '558cf7d7ae9f4dda0bb1cad06be5275b891c9bb7', + 'v8_revision': 'df9ba269106f9660bbfdcf71e7b68b906e9339da', # 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. @@ -968,7 +968,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '7c0541da63f571512c49758cbc0767117997a270', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '739351d4760f1d442caf23e8296c99ff290ff9bd', # commit position 21742 + Var('webrtc_git') + '/src.git' + '@' + '5702736f7e46383dcb5b5386608a8ad3fbc551c5', # commit position 21742 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebMessageBoundaryInterface.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebMessageBoundaryInterface.java index 56038eb..dff79906 100644 --- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebMessageBoundaryInterface.java +++ b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebMessageBoundaryInterface.java
@@ -9,7 +9,7 @@ /** * Boundary interface for WebMessage. */ -public interface WebMessageBoundaryInterface { +public interface WebMessageBoundaryInterface extends FeatureFlagHolderBoundaryInterface { String getData(); /* WebMessagePort */ InvocationHandler[] getPorts();
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebMessageCallbackBoundaryInterface.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebMessageCallbackBoundaryInterface.java index c13ed4f..acac2dc 100644 --- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebMessageCallbackBoundaryInterface.java +++ b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebMessageCallbackBoundaryInterface.java
@@ -9,7 +9,7 @@ /** * Boundary interface for WebMessagePort.WebMessageCallback. */ -public interface WebMessageCallbackBoundaryInterface { +public interface WebMessageCallbackBoundaryInterface extends FeatureFlagHolderBoundaryInterface { void onMessage(/* WebMessagePort */ InvocationHandler port, /* WebMessage */ InvocationHandler message); }
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java index e214471..caba2bed 100644 --- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java +++ b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java
@@ -98,4 +98,24 @@ // SafeBrowsingResponse.showInterstitial public static final String SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL = "SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL"; + + // WebMessagePortCompat.postMessage + public static final String WEB_MESSAGE_PORT_POST_MESSAGE = "WEB_MESSAGE_PORT_POST_MESSAGE"; + + // WebMessagePortCompat.close + public static final String WEB_MESSAGE_PORT_CLOSE = "WEB_MESSAGE_PORT_CLOSE"; + + // WebMessagePortCompat.setWebMessageCallback(WebMessageCallbackCompat) + // WebMessagePortCompat.setWebMessageCallback(WebMessageCallbackCompat, Handler) + public static final String WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK = + "WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK"; + + // WebViewCompat.createWebMessageChannel + public static final String CREATE_WEB_MESSAGE_CHANNEL = "CREATE_WEB_MESSAGE_CHANNEL"; + + // WebViewCompat.postWebMessage + public static final String POST_WEB_MESSAGE = "POST_WEB_MESSAGE"; + + // WebMessageCallbackCompat.onMessage + public static final String WEB_MESSAGE_CALLBACK_ON_MESSAGE = "WEB_MESSAGE_CALLBACK_ON_MESSAGE"; }
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessageCallbackAdapter.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessageCallbackAdapter.java index dd26c0e..d307c3c0 100644 --- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessageCallbackAdapter.java +++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessageCallbackAdapter.java
@@ -8,6 +8,7 @@ import org.chromium.support_lib_boundary.WebMessageCallbackBoundaryInterface; import org.chromium.support_lib_boundary.WebMessagePortBoundaryInterface; import org.chromium.support_lib_boundary.util.BoundaryInterfaceReflectionUtil; +import org.chromium.support_lib_boundary.util.Features; /** * Adapter working on top of WebMessageCallbackBoundaryInterface to provide methods using boundary @@ -22,7 +23,13 @@ public void onMessage( WebMessagePortBoundaryInterface port, WebMessageBoundaryInterface message) { - mImpl.onMessage(BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(port), - BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(message)); + // Ensure WebMessageCallbackCompat.onMessage() is supported by the support library before + // calling it. + String[] supportedFeatures = mImpl.getSupportedFeatures(); + if (BoundaryInterfaceReflectionUtil.containsFeature( + supportedFeatures, Features.WEB_MESSAGE_CALLBACK_ON_MESSAGE)) { + mImpl.onMessage(BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(port), + BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(message)); + } } }
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessagePortAdapter.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessagePortAdapter.java index 8d912633..c111f10 100644 --- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessagePortAdapter.java +++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessagePortAdapter.java
@@ -84,6 +84,12 @@ public /* WebMessagePort */ InvocationHandler[] getPorts() { return SupportLibWebMessagePortAdapter.fromMessagePorts(mPorts); } + + @Override + public String[] getSupportedFeatures() { + // getData() and getPorts() are not covered by feature flags. + return new String[0]; + } } public static /* WebMessagePort */ InvocationHandler[] fromMessagePorts(
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java index 22972b6..5a9b65a 100644 --- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java +++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java
@@ -54,7 +54,13 @@ Features.WEB_RESOURCE_ERROR_GET_CODE, Features.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY, Features.SAFE_BROWSING_RESPONSE_PROCEED, - Features.SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL + Features.SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL, + Features.WEB_MESSAGE_PORT_POST_MESSAGE, + Features.WEB_MESSAGE_PORT_CLOSE, + Features.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, + Features.CREATE_WEB_MESSAGE_CHANNEL, + Features.POST_WEB_MESSAGE, + Features.WEB_MESSAGE_CALLBACK_ON_MESSAGE }; // clang-format on
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java index 57d3e79..15a2a91 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
@@ -47,7 +47,7 @@ import org.chromium.chrome.browser.tab.AuthenticatorNavigationInterceptor; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.webapps.GooglePlayWebApkInstallDelegate; -import org.chromium.chrome.browser.webauth.Fido2ApiHandler; +import org.chromium.chrome.browser.webauth.U2fApiHandler; import org.chromium.components.signin.AccountManagerDelegate; import org.chromium.components.signin.SystemAccountManagerDelegate; import org.chromium.policy.AppRestrictionsProvider; @@ -337,9 +337,9 @@ } /** - * @return a new {@link Fido2ApiHandler} instance. + * @return a new {@link U2fApiHandler} instance. */ - public Fido2ApiHandler createFido2ApiHandler() { - return new Fido2ApiHandler(); + public U2fApiHandler createU2fApiHandler() { + return new U2fApiHandler(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseCheckBoxPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseCheckBoxPreference.java index 70d76531..7b9e1151 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseCheckBoxPreference.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseCheckBoxPreference.java
@@ -29,19 +29,19 @@ */ public void setManagedPreferenceDelegate(ManagedPreferenceDelegate delegate) { mManagedPrefDelegate = delegate; - if (mManagedPrefDelegate != null) mManagedPrefDelegate.initPreference(this); + ManagedPreferencesUtils.initPreference(mManagedPrefDelegate, this); } @Override protected void onBindView(View view) { super.onBindView(view); ((TextView) view.findViewById(android.R.id.title)).setSingleLine(false); - if (mManagedPrefDelegate != null) mManagedPrefDelegate.onBindViewToPreference(this, view); + ManagedPreferencesUtils.onBindViewToPreference(mManagedPrefDelegate, this, view); } @Override protected void onClick() { - if (mManagedPrefDelegate != null && mManagedPrefDelegate.onClickPreference(this)) return; + if (ManagedPreferencesUtils.onClickPreference(mManagedPrefDelegate, this)) return; super.onClick(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseListPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseListPreference.java index 7ef2b2af..864c539 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseListPreference.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseListPreference.java
@@ -31,19 +31,19 @@ */ public void setManagedPreferenceDelegate(ManagedPreferenceDelegate delegate) { mManagedPrefDelegate = delegate; - if (mManagedPrefDelegate != null) mManagedPrefDelegate.initPreference(this); + ManagedPreferencesUtils.initPreference(mManagedPrefDelegate, this); } @Override protected void onBindView(View view) { super.onBindView(view); ((TextView) view.findViewById(android.R.id.title)).setSingleLine(false); - if (mManagedPrefDelegate != null) mManagedPrefDelegate.onBindViewToPreference(this, view); + ManagedPreferencesUtils.onBindViewToPreference(mManagedPrefDelegate, this, view); } @Override protected void onClick() { - if (mManagedPrefDelegate != null && mManagedPrefDelegate.onClickPreference(this)) return; + if (ManagedPreferencesUtils.onClickPreference(mManagedPrefDelegate, this)) return; super.onClick(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBasePreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBasePreference.java index d84631d8..400970b1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBasePreference.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBasePreference.java
@@ -41,19 +41,19 @@ */ public void setManagedPreferenceDelegate(ManagedPreferenceDelegate delegate) { mManagedPrefDelegate = delegate; - if (mManagedPrefDelegate != null) mManagedPrefDelegate.initPreference(this); + ManagedPreferencesUtils.initPreference(mManagedPrefDelegate, this); } @Override protected void onBindView(View view) { super.onBindView(view); ((TextView) view.findViewById(android.R.id.title)).setSingleLine(false); - if (mManagedPrefDelegate != null) mManagedPrefDelegate.onBindViewToPreference(this, view); + ManagedPreferencesUtils.onBindViewToPreference(mManagedPrefDelegate, this, view); } @Override protected void onClick() { - if (mManagedPrefDelegate != null && mManagedPrefDelegate.onClickPreference(this)) return; + if (ManagedPreferencesUtils.onClickPreference(mManagedPrefDelegate, this)) return; super.onClick(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeSwitchPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeSwitchPreference.java index 087eba3..43f861d9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeSwitchPreference.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeSwitchPreference.java
@@ -47,7 +47,7 @@ */ public void setManagedPreferenceDelegate(ManagedPreferenceDelegate delegate) { mManagedPrefDelegate = delegate; - if (mManagedPrefDelegate != null) mManagedPrefDelegate.initPreference(this); + ManagedPreferencesUtils.initPreference(mManagedPrefDelegate, this); } /** @@ -90,12 +90,12 @@ summary.setVisibility(View.GONE); } - if (mManagedPrefDelegate != null) mManagedPrefDelegate.onBindViewToPreference(this, view); + ManagedPreferencesUtils.onBindViewToPreference(mManagedPrefDelegate, this, view); } @Override protected void onClick() { - if (mManagedPrefDelegate != null && mManagedPrefDelegate.onClickPreference(this)) return; + if (ManagedPreferencesUtils.onClickPreference(mManagedPrefDelegate, this)) return; super.onClick(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegate.java index ffb00f0..0b6f31837 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegate.java
@@ -5,10 +5,6 @@ package org.chromium.chrome.browser.preferences; import android.preference.Preference; -import android.view.View; - -import org.chromium.chrome.R; -import org.chromium.chrome.browser.util.ViewUtils; /** * A delegate that determines whether a Preference is managed by enterprise policy. This is used @@ -56,72 +52,7 @@ */ // TODO(bauerb): Rename to isPreferenceClickDisabled. default boolean isPreferenceClickDisabledByPolicy(Preference preference) { - return isPreferenceControlledByPolicy(preference) || - isPreferenceControlledByCustodian(preference); - } - - /** - * Initializes the Preference based on the state of any policies that may affect it, - * e.g. by showing a managed icon or disabling clicks on the preference. - * - * This should be called once, before the preference is displayed. - */ - default void initPreference(Preference preference) { - if (isPreferenceControlledByPolicy(preference)) { - preference.setIcon(ManagedPreferencesUtils.getManagedByEnterpriseIconId()); - } else if (isPreferenceControlledByCustodian(preference)) { - preference.setIcon(R.drawable.ic_account_child_grey600_36dp); - } - - if (isPreferenceClickDisabledByPolicy(preference)) { - // Disable the views and prevent the Preference from mucking with the enabled state. - preference.setShouldDisableView(false); - - // Prevent default click behavior. - preference.setFragment(null); - preference.setIntent(null); - preference.setOnPreferenceClickListener(null); - } - } - - /** - * Disables the Preference's views if the preference is not clickable. - * - * Note: this disables the View instead of disabling the Preference, so that the Preference - * still receives click events, which will trigger a "Managed by your administrator" toast. - * - * This should be called from the Preference's onBindView() method. - * - * @param preference The Preference that owns the view - * @param view The View that was bound to the Preference - */ - default void onBindViewToPreference(Preference preference, View view) { - if (isPreferenceClickDisabledByPolicy(preference)) { - ViewUtils.setEnabledRecursive(view, false); - } - } - - /** - * Intercepts the click event if the given Preference is managed and shows a toast in that case. - * - * This should be called from the Preference's onClick() method. - * - * @param preference The Preference that was clicked. - * @return true if the click event was handled by this helper and shouldn't be further - * propagated; false otherwise. - */ - default boolean onClickPreference(Preference preference) { - if (!isPreferenceClickDisabledByPolicy(preference)) return false; - - if (isPreferenceControlledByPolicy(preference)) { - ManagedPreferencesUtils.showManagedByAdministratorToast(preference.getContext()); - } else if (isPreferenceControlledByCustodian(preference)) { - ManagedPreferencesUtils.showManagedByParentToast(preference.getContext()); - } else { - // If the preference is disabled, it should be either because it's managed by enterprise - // policy or by the custodian. - assert false; - } - return true; + return isPreferenceControlledByPolicy(preference) + || isPreferenceControlledByCustodian(preference); } } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferencesUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferencesUtils.java index 657459d6..923db29 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferencesUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferencesUtils.java
@@ -5,8 +5,12 @@ package org.chromium.chrome.browser.preferences; import android.content.Context; +import android.preference.Preference; +import android.support.annotation.Nullable; +import android.view.View; import org.chromium.chrome.R; +import org.chromium.chrome.browser.util.ViewUtils; import org.chromium.ui.widget.Toast; /** @@ -46,4 +50,84 @@ public static int getManagedByEnterpriseIconId() { return R.drawable.controlled_setting_mandatory; } + + /** + * Initializes the Preference based on the state of any policies that may affect it, + * e.g. by showing a managed icon or disabling clicks on the preference. + * + * This should be called once, before the preference is displayed. + * + * @param delegate The delegate that controls whether the preference is managed. May be null, + * then this method does nothing. + * @param preference The Preference that is being initialized + */ + public static void initPreference( + @Nullable ManagedPreferenceDelegate delegate, Preference preference) { + if (delegate == null) return; + + if (delegate.isPreferenceControlledByPolicy(preference)) { + preference.setIcon(getManagedByEnterpriseIconId()); + } else if (delegate.isPreferenceControlledByCustodian(preference)) { + preference.setIcon(R.drawable.ic_account_child_grey600_36dp); + } + + if (delegate.isPreferenceClickDisabledByPolicy(preference)) { + // Disable the views and prevent the Preference from mucking with the enabled state. + preference.setShouldDisableView(false); + + // Prevent default click behavior. + preference.setFragment(null); + preference.setIntent(null); + preference.setOnPreferenceClickListener(null); + } + } + + /** + * Disables the Preference's views if the preference is not clickable. + * + * Note: this disables the View instead of disabling the Preference, so that the Preference + * still receives click events, which will trigger a "Managed by your administrator" toast. + * + * This should be called from the Preference's onBindView() method. + * + * @param delegate The delegate that controls whether the preference is managed. May be null, + * then this method does nothing. + * @param preference The Preference that owns the view + * @param view The View that was bound to the Preference + */ + public static void onBindViewToPreference( + @Nullable ManagedPreferenceDelegate delegate, Preference preference, View view) { + if (delegate != null && delegate.isPreferenceClickDisabledByPolicy(preference)) { + ViewUtils.setEnabledRecursive(view, false); + } + } + + /** + * Intercepts the click event if the given Preference is managed and shows a toast in that case. + * + * This should be called from the Preference's onClick() method. + * + * @param delegate The delegate that controls whether the preference is managed. May be null, + * then this method does nothing and returns false. + * @param preference The Preference that was clicked. + * @return true if the click event was handled by this helper and shouldn't be further + * propagated; false otherwise. + */ + public static boolean onClickPreference( + @Nullable ManagedPreferenceDelegate delegate, Preference preference) { + if (delegate == null || !delegate.isPreferenceClickDisabledByPolicy(preference)) { + return false; + } + + if (delegate.isPreferenceControlledByPolicy(preference)) { + showManagedByAdministratorToast(preference.getContext()); + } else if (delegate.isPreferenceControlledByCustodian(preference)) { + showManagedByParentToast(preference.getContext()); + } else { + // If the preference is disabled, it should be either because it's managed by enterprise + // policy or by the custodian. + assert false; + } + return true; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java deleted file mode 100644 index aec6802b..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java +++ /dev/null
@@ -1,35 +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. - -package org.chromium.chrome.browser.webauth; - -import org.chromium.base.ThreadUtils; -import org.chromium.chrome.browser.AppHooks; -import org.chromium.webauth.mojom.PublicKeyCredentialCreationOptions; -import org.chromium.webauth.mojom.PublicKeyCredentialRequestOptions; - -/** - * Android implementation of the Authenticator service defined in - * components/webauth/authenticator.mojom. - */ -public class Fido2ApiHandler { - private static Fido2ApiHandler sInstance; - - /** - * @return The Fido2ApiHandler for use during the lifetime of the browser process. - */ - public static Fido2ApiHandler getInstance() { - ThreadUtils.checkUiThread(); - if (sInstance == null) { - sInstance = AppHooks.get().createFido2ApiHandler(); - } - return sInstance; - } - - protected void makeCredential( - PublicKeyCredentialCreationOptions options, HandlerResponseCallback callback) {} - - protected void getAssertion( - PublicKeyCredentialRequestOptions options, HandlerResponseCallback callback) {} -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/U2fApiHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/webauth/U2fApiHandler.java index b58b0b7..d9447fd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webauth/U2fApiHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webauth/U2fApiHandler.java
@@ -27,9 +27,9 @@ return sInstance; } - protected void makeCredential( + protected void u2fRegister( PublicKeyCredentialCreationOptions options, HandlerResponseCallback callback) {} - protected void getAssertion( + protected void u2fSign( PublicKeyCredentialRequestOptions options, HandlerResponseCallback callback) {} }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 984990d8..4b6c2bf2 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -1404,7 +1404,7 @@ "java/src/org/chromium/chrome/browser/webauth/AuthenticatorFactory.java", "java/src/org/chromium/chrome/browser/webauth/AuthenticatorImpl.java", "java/src/org/chromium/chrome/browser/webauth/HandlerResponseCallback.java", - "java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java", + "java/src/org/chromium/chrome/browser/webauth/U2fApiHandler.java", "java/src/org/chromium/chrome/browser/webshare/ShareServiceImpl.java", "java/src/org/chromium/chrome/browser/webshare/ShareServiceImplementationFactory.java", "java/src/org/chromium/chrome/browser/widget/AlertDialogEditText.java",
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index aac3d0f..547979b 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-68.0.3431.0_rc-r1.afdo.bz2 \ No newline at end of file +chromeos-chrome-amd64-68.0.3431.0_rc-r2.afdo.bz2 \ No newline at end of file
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc index 9055636..fdd51be 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -16,14 +16,30 @@ namespace file_manager { -// FileManagerBrowserTest parameters: first controls IN_GUEST_MODE or not, the -// second is the JS test case name. -typedef std::tuple<GuestMode, const char*> TestParameter; +// TestCase: FileManagerBrowserTest parameters. +struct TestCase { + TestCase(const char* name, GuestMode mode) + : test_name(name), guest_mode(mode) {} -// FileManager browser test class. -class FileManagerBrowserTest : - public FileManagerBrowserTestBase, - public ::testing::WithParamInterface<TestParameter> { + explicit TestCase(const char* name) + : test_name(name) {} + + const char* GetTestName() const { + CHECK(test_name) << "FATAL: no test name"; + return test_name; + } + + GuestMode GetGuestMode() const { + return guest_mode; + } + + const char* test_name = nullptr; + GuestMode guest_mode = NOT_IN_GUEST_MODE; +}; + +// FileManager browser test. +class FileManagerBrowserTest : public FileManagerBrowserTestBase, + public ::testing::WithParamInterface<TestCase> { public: FileManagerBrowserTest() = default; @@ -38,11 +54,11 @@ } GuestMode GetGuestMode() const override { - return std::get<0>(GetParam()); + return GetParam().GetGuestMode(); } const char* GetTestCaseName() const override { - return std::get<1>(GetParam()); + return GetParam().GetTestName(); } const char* GetTestExtensionManifestName() const override { @@ -98,20 +114,20 @@ WRAPPED_INSTANTIATE_TEST_CASE_P( FileDisplay, FileManagerBrowserTest, - ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "fileDisplayDownloads"), - TestParameter(IN_GUEST_MODE, "fileDisplayDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "fileDisplayDrive"), - TestParameter(NOT_IN_GUEST_MODE, "fileDisplayMtp"), - TestParameter(NOT_IN_GUEST_MODE, "fileSearch"), - TestParameter(NOT_IN_GUEST_MODE, "fileSearchCaseInsensitive"), - TestParameter(NOT_IN_GUEST_MODE, "fileSearchNotFound"))); + ::testing::Values(TestCase("fileDisplayDownloads"), + TestCase("fileDisplayDownloads", IN_GUEST_MODE), + TestCase("fileDisplayDrive"), + TestCase("fileDisplayMtp"), + TestCase("fileSearch"), + TestCase("fileSearchCaseInsensitive"), + TestCase("fileSearchNotFound"))); WRAPPED_INSTANTIATE_TEST_CASE_P( OpenVideoFiles, FileManagerBrowserTest, - ::testing::Values(TestParameter(IN_GUEST_MODE, "videoOpenDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "videoOpenDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "videoOpenDrive"))); + ::testing::Values(TestCase("videoOpenDownloads", IN_GUEST_MODE), + TestCase("videoOpenDownloads"), + TestCase("videoOpenDrive"))); // TIMEOUT PASS on MSAN, https://crbug.com/836254 #if defined(MEMORY_SANITIZER) @@ -123,17 +139,16 @@ MAYBE_OpenAudioFiles, FileManagerBrowserTest, ::testing::Values( - TestParameter(IN_GUEST_MODE, "audioOpenDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "audioOpenDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "audioOpenDrive"), - TestParameter(NOT_IN_GUEST_MODE, "audioAutoAdvanceDrive"), - TestParameter(NOT_IN_GUEST_MODE, "audioRepeatAllModeSingleFileDrive"), - TestParameter(NOT_IN_GUEST_MODE, "audioNoRepeatModeSingleFileDrive"), - TestParameter(NOT_IN_GUEST_MODE, "audioRepeatOneModeSingleFileDrive"), - TestParameter(NOT_IN_GUEST_MODE, "audioRepeatAllModeMultipleFileDrive"), - TestParameter(NOT_IN_GUEST_MODE, "audioNoRepeatModeMultipleFileDrive"), - TestParameter(NOT_IN_GUEST_MODE, - "audioRepeatOneModeMultipleFileDrive"))); + TestCase("audioOpenDownloads", IN_GUEST_MODE), + TestCase("audioOpenDownloads"), + TestCase("audioOpenDrive"), + TestCase("audioAutoAdvanceDrive"), + TestCase("audioRepeatAllModeSingleFileDrive"), + TestCase("audioNoRepeatModeSingleFileDrive"), + TestCase("audioRepeatOneModeSingleFileDrive"), + TestCase("audioRepeatAllModeMultipleFileDrive"), + TestCase("audioNoRepeatModeMultipleFileDrive"), + TestCase("audioRepeatOneModeMultipleFileDrive"))); // Fails on the MSAN bots, https://crbug.com/837551 #if defined(MEMORY_SANITIZER) @@ -144,263 +159,258 @@ WRAPPED_INSTANTIATE_TEST_CASE_P( MAYBE_OpenImageFiles, FileManagerBrowserTest, - ::testing::Values(TestParameter(IN_GUEST_MODE, "imageOpenDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "imageOpenDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "imageOpenDrive"))); + ::testing::Values(TestCase("imageOpenDownloads", IN_GUEST_MODE), + TestCase("imageOpenDownloads"), + TestCase("imageOpenDrive"))); WRAPPED_INSTANTIATE_TEST_CASE_P( CreateNewFolder, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "selectCreateFolderDownloads"), - TestParameter(IN_GUEST_MODE, "createFolderDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "createFolderDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "createFolderDrive"))); + TestCase("selectCreateFolderDownloads"), + TestCase("createFolderDownloads", IN_GUEST_MODE), + TestCase("createFolderDownloads"), + TestCase("createFolderDrive"))); WRAPPED_INSTANTIATE_TEST_CASE_P( KeyboardOperations, FileManagerBrowserTest, ::testing::Values( - TestParameter(IN_GUEST_MODE, "keyboardDeleteDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "keyboardDeleteDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "keyboardDeleteDrive"), - TestParameter(IN_GUEST_MODE, "keyboardCopyDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "keyboardCopyDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "keyboardCopyDrive"), - TestParameter(IN_GUEST_MODE, "renameFileDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "renameFileDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "renameFileDrive"), - TestParameter(IN_GUEST_MODE, "renameNewFolderDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "renameNewFolderDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "renameNewFolderDrive"))); + TestCase("keyboardDeleteDownloads", IN_GUEST_MODE), + TestCase("keyboardDeleteDownloads"), + TestCase("keyboardDeleteDrive"), + TestCase("keyboardCopyDownloads", IN_GUEST_MODE), + TestCase("keyboardCopyDownloads"), + TestCase("keyboardCopyDrive"), + TestCase("renameFileDownloads", IN_GUEST_MODE), + TestCase("renameFileDownloads"), + TestCase("renameFileDrive"), + TestCase("renameNewFolderDownloads", IN_GUEST_MODE), + TestCase("renameNewFolderDownloads"), + TestCase("renameNewFolderDrive"))); WRAPPED_INSTANTIATE_TEST_CASE_P( Delete, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "deleteMenuItemNoEntrySelected"), - TestParameter(NOT_IN_GUEST_MODE, "deleteEntryWithToolbar"))); + TestCase("deleteMenuItemNoEntrySelected"), + TestCase("deleteEntryWithToolbar"))); WRAPPED_INSTANTIATE_TEST_CASE_P( QuickView, FileManagerBrowserTest, - ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "openQuickView"), - TestParameter(NOT_IN_GUEST_MODE, "closeQuickView"))); + ::testing::Values(TestCase("openQuickView"), + TestCase("closeQuickView"))); WRAPPED_INSTANTIATE_TEST_CASE_P( DirectoryTreeContextMenu, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "dirCopyWithContextMenu"), - TestParameter(IN_GUEST_MODE, "dirCopyWithContextMenu"), - TestParameter(NOT_IN_GUEST_MODE, "dirCopyWithKeyboard"), - TestParameter(IN_GUEST_MODE, "dirCopyWithKeyboard"), - TestParameter(NOT_IN_GUEST_MODE, "dirCopyWithoutChangingCurrent"), - TestParameter(NOT_IN_GUEST_MODE, "dirCutWithContextMenu"), - TestParameter(IN_GUEST_MODE, "dirCutWithContextMenu"), - TestParameter(NOT_IN_GUEST_MODE, "dirCutWithKeyboard"), - TestParameter(IN_GUEST_MODE, "dirCutWithKeyboard"), - TestParameter(NOT_IN_GUEST_MODE, "dirPasteWithoutChangingCurrent"), - TestParameter(NOT_IN_GUEST_MODE, "dirPasteWithContextMenu"), - TestParameter(IN_GUEST_MODE, "dirPasteWithContextMenu"), - TestParameter(NOT_IN_GUEST_MODE, "dirPasteWithoutChangingCurrent"), - TestParameter(NOT_IN_GUEST_MODE, "dirRenameWithContextMenu"), - TestParameter(IN_GUEST_MODE, "dirRenameWithContextMenu"), - TestParameter(NOT_IN_GUEST_MODE, "dirRenameWithKeyboard"), - TestParameter(IN_GUEST_MODE, "dirRenameWithKeyboard"), - TestParameter(NOT_IN_GUEST_MODE, "dirRenameWithoutChangingCurrent"), - TestParameter(NOT_IN_GUEST_MODE, "dirRenameToEmptyString"), - TestParameter(IN_GUEST_MODE, "dirRenameToEmptyString"), - TestParameter(NOT_IN_GUEST_MODE, "dirRenameToExisting"), - TestParameter(IN_GUEST_MODE, "dirRenameToExisting"), - TestParameter(NOT_IN_GUEST_MODE, "dirCreateWithContextMenu"), - TestParameter(NOT_IN_GUEST_MODE, "dirCreateWithKeyboard"), - TestParameter(NOT_IN_GUEST_MODE, "dirCreateWithoutChangingCurrent"))); + TestCase("dirCopyWithContextMenu"), + TestCase("dirCopyWithContextMenu", IN_GUEST_MODE), + TestCase("dirCopyWithKeyboard"), + TestCase("dirCopyWithKeyboard", IN_GUEST_MODE), + TestCase("dirCopyWithoutChangingCurrent"), + TestCase("dirCutWithContextMenu"), + TestCase("dirCutWithContextMenu", IN_GUEST_MODE), + TestCase("dirCutWithKeyboard"), + TestCase("dirCutWithKeyboard", IN_GUEST_MODE), + TestCase("dirPasteWithoutChangingCurrent"), + TestCase("dirPasteWithContextMenu"), + TestCase("dirPasteWithContextMenu", IN_GUEST_MODE), + TestCase("dirPasteWithoutChangingCurrent"), + TestCase("dirRenameWithContextMenu"), + TestCase("dirRenameWithContextMenu", IN_GUEST_MODE), + TestCase("dirRenameWithKeyboard"), + TestCase("dirRenameWithKeyboard", IN_GUEST_MODE), + TestCase("dirRenameWithoutChangingCurrent"), + TestCase("dirRenameToEmptyString"), + TestCase("dirRenameToEmptyString", IN_GUEST_MODE), + TestCase("dirRenameToExisting"), + TestCase("dirRenameToExisting", IN_GUEST_MODE), + TestCase("dirCreateWithContextMenu"), + TestCase("dirCreateWithKeyboard"), + TestCase("dirCreateWithoutChangingCurrent"))); WRAPPED_INSTANTIATE_TEST_CASE_P( DriveSpecific, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "driveOpenSidebarOffline"), - TestParameter(NOT_IN_GUEST_MODE, "driveOpenSidebarSharedWithMe"), - TestParameter(NOT_IN_GUEST_MODE, "driveAutoCompleteQuery"), - TestParameter(NOT_IN_GUEST_MODE, "drivePinFileMobileNetwork"), - TestParameter(NOT_IN_GUEST_MODE, "driveClickFirstSearchResult"), - TestParameter(NOT_IN_GUEST_MODE, "drivePressEnterToSearch"))); + TestCase("driveOpenSidebarOffline"), + TestCase("driveOpenSidebarSharedWithMe"), + TestCase("driveAutoCompleteQuery"), + TestCase("drivePinFileMobileNetwork"), + TestCase("driveClickFirstSearchResult"), + TestCase("drivePressEnterToSearch"))); WRAPPED_INSTANTIATE_TEST_CASE_P( Transfer, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "transferFromDriveToDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "transferFromDownloadsToDrive"), - TestParameter(NOT_IN_GUEST_MODE, "transferFromSharedToDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "transferFromSharedToDrive"), - TestParameter(NOT_IN_GUEST_MODE, "transferFromOfflineToDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "transferFromOfflineToDrive"))); + TestCase("transferFromDriveToDownloads"), + TestCase("transferFromDownloadsToDrive"), + TestCase("transferFromSharedToDownloads"), + TestCase("transferFromSharedToDrive"), + TestCase("transferFromOfflineToDownloads"), + TestCase("transferFromOfflineToDrive"))); WRAPPED_INSTANTIATE_TEST_CASE_P( RestorePrefs, FileManagerBrowserTest, - ::testing::Values(TestParameter(IN_GUEST_MODE, "restoreSortColumn"), - TestParameter(NOT_IN_GUEST_MODE, "restoreSortColumn"), - TestParameter(IN_GUEST_MODE, "restoreCurrentView"), - TestParameter(NOT_IN_GUEST_MODE, "restoreCurrentView"))); + ::testing::Values(TestCase("restoreSortColumn", IN_GUEST_MODE), + TestCase("restoreSortColumn"), + TestCase("restoreCurrentView", IN_GUEST_MODE), + TestCase("restoreCurrentView"))); WRAPPED_INSTANTIATE_TEST_CASE_P( ShareDialog, FileManagerBrowserTest, - ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "shareFile"), - TestParameter(NOT_IN_GUEST_MODE, "shareDirectory"))); + ::testing::Values(TestCase("shareFile"), + TestCase("shareDirectory"))); WRAPPED_INSTANTIATE_TEST_CASE_P( RestoreGeometry, FileManagerBrowserTest, - ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "restoreGeometry"), - TestParameter(IN_GUEST_MODE, "restoreGeometry"), - TestParameter(NOT_IN_GUEST_MODE, - "restoreGeometryMaximized"))); + ::testing::Values(TestCase("restoreGeometry"), + TestCase("restoreGeometry", IN_GUEST_MODE), + TestCase("restoreGeometryMaximized"))); WRAPPED_INSTANTIATE_TEST_CASE_P( Traverse, FileManagerBrowserTest, - ::testing::Values(TestParameter(IN_GUEST_MODE, "traverseDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "traverseDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "traverseDrive"))); + ::testing::Values(TestCase("traverseDownloads", IN_GUEST_MODE), + TestCase("traverseDownloads"), + TestCase("traverseDrive"))); WRAPPED_INSTANTIATE_TEST_CASE_P( SuggestAppDialog, FileManagerBrowserTest, - ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "suggestAppDialog"))); + ::testing::Values(TestCase("suggestAppDialog"))); WRAPPED_INSTANTIATE_TEST_CASE_P( ExecuteDefaultTaskOnDownloads, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "executeDefaultTaskDownloads"), - TestParameter(IN_GUEST_MODE, "executeDefaultTaskDownloads"))); + TestCase("executeDefaultTaskDownloads"), + TestCase("executeDefaultTaskDownloads",IN_GUEST_MODE))); WRAPPED_INSTANTIATE_TEST_CASE_P( ExecuteDefaultTaskOnDrive, FileManagerBrowserTest, - ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, - "executeDefaultTaskDrive"))); + ::testing::Values(TestCase("executeDefaultTaskDrive"))); WRAPPED_INSTANTIATE_TEST_CASE_P( DefaultTaskDialog, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "defaultTaskDialogDownloads"), - TestParameter(IN_GUEST_MODE, "defaultTaskDialogDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "defaultTaskDialogDrive"))); + TestCase("defaultTaskDialogDownloads"), + TestCase("defaultTaskDialogDownloads", IN_GUEST_MODE), + TestCase("defaultTaskDialogDrive"))); WRAPPED_INSTANTIATE_TEST_CASE_P( GenericTask, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "genericTaskIsNotExecuted"), - TestParameter(NOT_IN_GUEST_MODE, "genericTaskAndNonGenericTask"))); + TestCase("genericTaskIsNotExecuted"), + TestCase("genericTaskAndNonGenericTask"))); WRAPPED_INSTANTIATE_TEST_CASE_P( FolderShortcuts, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "traverseFolderShortcuts"), - TestParameter(NOT_IN_GUEST_MODE, "addRemoveFolderShortcuts"))); + TestCase("traverseFolderShortcuts"), + TestCase("addRemoveFolderShortcuts"))); WRAPPED_INSTANTIATE_TEST_CASE_P( SortColumns, FileManagerBrowserTest, - ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "sortColumns"), - TestParameter(IN_GUEST_MODE, "sortColumns"))); + ::testing::Values(TestCase("sortColumns"), + TestCase("sortColumns",IN_GUEST_MODE))); WRAPPED_INSTANTIATE_TEST_CASE_P( TabIndex, FileManagerBrowserTestWithLegacyEventDispatch, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "tabindexSearchBoxFocus"))); + TestCase("tabindexSearchBoxFocus"))); WRAPPED_INSTANTIATE_TEST_CASE_P( TabindexFocus, FileManagerBrowserTestWithLegacyEventDispatch, - ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "tabindexFocus"))); + ::testing::Values(TestCase("tabindexFocus"))); WRAPPED_INSTANTIATE_TEST_CASE_P( TabindexFocusDownloads, FileManagerBrowserTestWithLegacyEventDispatch, - ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, - "tabindexFocusDownloads"), - TestParameter(IN_GUEST_MODE, "tabindexFocusDownloads"))); + ::testing::Values(TestCase("tabindexFocusDownloads"), + TestCase("tabindexFocusDownloads", IN_GUEST_MODE))); WRAPPED_INSTANTIATE_TEST_CASE_P( TabindexFocusDirectorySelected, FileManagerBrowserTestWithLegacyEventDispatch, - ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, - "tabindexFocusDirectorySelected"))); + ::testing::Values(TestCase("tabindexFocusDirectorySelected"))); WRAPPED_INSTANTIATE_TEST_CASE_P( TabindexOpenDialog, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "tabindexOpenDialogDrive"), - TestParameter(NOT_IN_GUEST_MODE, "tabindexOpenDialogDownloads"), - TestParameter(IN_GUEST_MODE, "tabindexOpenDialogDownloads"))); + TestCase("tabindexOpenDialogDrive"), + TestCase("tabindexOpenDialogDownloads"), + TestCase("tabindexOpenDialogDownloads", IN_GUEST_MODE))); WRAPPED_INSTANTIATE_TEST_CASE_P( TabindexSaveFileDialog, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "tabindexSaveFileDialogDrive"), - TestParameter(NOT_IN_GUEST_MODE, "tabindexSaveFileDialogDownloads"), - TestParameter(IN_GUEST_MODE, "tabindexSaveFileDialogDownloads"))); + TestCase("tabindexSaveFileDialogDrive"), + TestCase("tabindexSaveFileDialogDownloads"), + TestCase("tabindexSaveFileDialogDownloads", IN_GUEST_MODE))); WRAPPED_INSTANTIATE_TEST_CASE_P( OpenFileDialog, FileManagerBrowserTest, - ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, - "openFileDialogDownloads"), - TestParameter(IN_GUEST_MODE, "openFileDialogDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "openFileDialogDrive"), - TestParameter(IN_INCOGNITO, "openFileDialogDownloads"), - TestParameter(IN_INCOGNITO, "openFileDialogDrive"), - TestParameter(NOT_IN_GUEST_MODE, "openFileDialogUnload"))); + ::testing::Values(TestCase("openFileDialogDownloads"), + TestCase("openFileDialogDownloads", IN_GUEST_MODE), + TestCase("openFileDialogDrive"), + TestCase("openFileDialogDownloads", IN_INCOGNITO), + TestCase("openFileDialogDrive", IN_INCOGNITO), + TestCase("openFileDialogUnload"))); // Test does too much? Flaky on all bots: http://crbug.com/500966 WRAPPED_INSTANTIATE_TEST_CASE_P( DISABLED_CopyBetweenWindows, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "copyBetweenWindowsLocalToDrive"), - TestParameter(NOT_IN_GUEST_MODE, "copyBetweenWindowsLocalToUsb"), - TestParameter(NOT_IN_GUEST_MODE, "copyBetweenWindowsUsbToDrive"), - TestParameter(NOT_IN_GUEST_MODE, "copyBetweenWindowsDriveToLocal"), - TestParameter(NOT_IN_GUEST_MODE, "copyBetweenWindowsDriveToUsb"), - TestParameter(NOT_IN_GUEST_MODE, "copyBetweenWindowsUsbToLocal"))); + TestCase("copyBetweenWindowsLocalToDrive"), + TestCase("copyBetweenWindowsLocalToUsb"), + TestCase("copyBetweenWindowsUsbToDrive"), + TestCase("copyBetweenWindowsDriveToLocal"), + TestCase("copyBetweenWindowsDriveToUsb"), + TestCase("copyBetweenWindowsUsbToLocal"))); WRAPPED_INSTANTIATE_TEST_CASE_P( ShowGridView, FileManagerBrowserTest, - ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "showGridViewDownloads"), - TestParameter(IN_GUEST_MODE, "showGridViewDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "showGridViewDrive"))); + ::testing::Values(TestCase("showGridViewDownloads"), + TestCase("showGridViewDownloads", IN_GUEST_MODE), + TestCase("showGridViewDrive"))); WRAPPED_INSTANTIATE_TEST_CASE_P( Providers, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "requestMount"), - TestParameter(NOT_IN_GUEST_MODE, "requestMountMultipleMounts"), - TestParameter(NOT_IN_GUEST_MODE, "requestMountSourceDevice"), - TestParameter(NOT_IN_GUEST_MODE, "requestMountSourceFile"))); + TestCase("requestMount"), + TestCase("requestMountMultipleMounts"), + TestCase("requestMountSourceDevice"), + TestCase("requestMountSourceFile"))); WRAPPED_INSTANTIATE_TEST_CASE_P( GearMenu, FileManagerBrowserTest, ::testing::Values( - TestParameter(NOT_IN_GUEST_MODE, "showHiddenFilesDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "showHiddenFilesDrive"), - TestParameter(NOT_IN_GUEST_MODE, "toogleGoogleDocsDrive"), - TestParameter(NOT_IN_GUEST_MODE, "showPasteIntoCurrentFolder"))); + TestCase("showHiddenFilesDownloads"), + TestCase("showHiddenFilesDrive"), + TestCase("toogleGoogleDocsDrive"), + TestCase("showPasteIntoCurrentFolder"))); // Structure to describe an account info. struct TestAccountInfo {
diff --git a/chrome/browser/conflicts/enumerate_input_method_editors_win.cc b/chrome/browser/conflicts/enumerate_input_method_editors_win.cc index cf54d54..c441c8a5 100644 --- a/chrome/browser/conflicts/enumerate_input_method_editors_win.cc +++ b/chrome/browser/conflicts/enumerate_input_method_editors_win.cc
@@ -48,7 +48,7 @@ L"{fa445657-9379-11d6-b41a-00065b83ee53}", }; - constexpr auto comp = [](const wchar_t* lhs, const wchar_t* rhs) -> bool { + auto comp = [](const wchar_t* lhs, const wchar_t* rhs) -> bool { return base::CompareCaseInsensitiveASCII(lhs, rhs) == -1; };
diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc index aa74cab..21257bf 100644 --- a/chrome/browser/net/predictor.cc +++ b/chrome/browser/net/predictor.cc
@@ -661,8 +661,6 @@ DnsPrefetchMotivatedList(startup_urls, UrlInfo::STARTUP_LIST_MOTIVATED); DeserializeReferrers(*referral_list); - - LogStartupMetrics(); } //----------------------------------------------------------------------------- @@ -809,8 +807,6 @@ if (!getter) return; - UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation, - UrlInfo::MAX_MOTIVATED); content::PreconnectUrl(getter, url, site_for_cookies, count, allow_credentials); } @@ -893,14 +889,9 @@ UrlInfo::LEARNED_REFERAL_MOTIVATED; for (std::map<GURL, ReferrerValue>::iterator future_url = referrer->begin(); future_url != referrer->end();) { - SubresourceValue evalution(TOO_NEW); double connection_expectation = future_url->second.subresource_use_rate(); - UMA_HISTOGRAM_CUSTOM_COUNTS("Net.PreconnectSubresourceExpectation", - static_cast<int>(connection_expectation * 100), - 10, 5000, 50); future_url->second.ReferrerWasObserved(); if (connection_expectation > kPreconnectWorthyExpectedValue) { - evalution = PRECONNECTION; future_url->second.IncrementPreconnectionCount(); int count = static_cast<int>(std::ceil(connection_expectation)); if (url.host_piece() == future_url->first.host_piece()) @@ -908,7 +899,6 @@ PreconnectUrlOnIOThread(future_url->first, site_for_cookies, motivation, kAllowCredentialsOnPreconnectByDefault, count); } else if (connection_expectation > kDNSPreresolutionWorthyExpectedValue) { - evalution = PRERESOLUTION; future_url->second.preresolution_increment(); AppendToResolutionQueue(future_url->first, motivation); } @@ -920,8 +910,6 @@ } else { ++future_url; } - UMA_HISTOGRAM_ENUMERATION("Net.PreconnectSubresourceEval", evalution, - SUBRESOURCE_VALUE_MAX); } // If the Referrer has no URLs associated with it, remove it from the map. if (referrer->empty()) @@ -1066,21 +1054,6 @@ return url.ReplaceComponents(replacements); } -void Predictor::LogStartupMetrics() { - size_t total_bytes = 0; - for (const auto& referrer : referrers_) { - total_bytes += referrer.first.spec().size(); - total_bytes += sizeof(Referrer); - for (const auto& subresource : referrer.second) { - total_bytes += subresource.first.spec().size(); - total_bytes += sizeof(ReferrerValue); - } - } - UMA_HISTOGRAM_CUSTOM_COUNTS("Net.Predictor.Startup.DBSize", total_bytes, 1, - 10 * 1000 * 1000, 50); -} - - // ---------------------- End IO methods. ------------------------------------- //-----------------------------------------------------------------------------
diff --git a/chrome/browser/net/predictor.h b/chrome/browser/net/predictor.h index 8d082def..713b433 100644 --- a/chrome/browser/net/predictor.h +++ b/chrome/browser/net/predictor.h
@@ -412,8 +412,6 @@ // Applies the HSTS redirect for |url|, if any. GURL GetHSTSRedirectOnIOThread(const GURL& url); - void LogStartupMetrics(); - // ------------- End IO thread methods. std::unique_ptr<InitialObserver> initial_observer_;
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc index 526d062..fbd9002 100644 --- a/chrome/browser/password_manager/password_manager_browsertest.cc +++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -650,12 +650,16 @@ // Verify that if XHR navigation occurs and the form is properly filled out, // we try and save the password even though onsubmit hasn't been called. - FillElementWithValue("username_field", "USER"); - FillElementWithValue("password_field", "1234"); NavigationObserver observer(WebContents()); - ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), "send_xhr()")); + std::unique_ptr<BubbleObserver> prompt_observer( + new BubbleObserver(WebContents())); + std::string fill_and_navigate = + "document.getElementById('username_field').value = 'temp';" + "document.getElementById('password_field').value = 'random';" + "send_xhr()"; + ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_navigate)); observer.Wait(); - EXPECT_TRUE(BubbleObserver(WebContents()).IsSavePromptShownAutomatically()); + EXPECT_TRUE(prompt_observer->IsSavePromptShownAutomatically()); } IN_PROC_BROWSER_TEST_P(PasswordManagerBrowserTestWithViewsFeature, @@ -666,13 +670,17 @@ // we try and save the password even though onsubmit hasn't been called. // Specifically verify that the password form saving new passwords is treated // the same as a login form. - FillElementWithValue("signup_username_field", "USER"); - FillElementWithValue("signup_password_field", "1234"); - FillElementWithValue("confirmation_password_field", "1234"); NavigationObserver observer(WebContents()); - ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), "send_xhr()")); + std::unique_ptr<BubbleObserver> prompt_observer( + new BubbleObserver(WebContents())); + std::string fill_and_navigate = + "document.getElementById('signup_username_field').value = 'temp';" + "document.getElementById('signup_password_field').value = 'random';" + "document.getElementById('confirmation_password_field').value = 'random';" + "send_xhr()"; + ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_navigate)); observer.Wait(); - EXPECT_TRUE(BubbleObserver(WebContents()).IsSavePromptShownAutomatically()); + EXPECT_TRUE(prompt_observer->IsSavePromptShownAutomatically()); } IN_PROC_BROWSER_TEST_P(PasswordManagerBrowserTestWithViewsFeature, @@ -815,13 +823,16 @@ // Verify that if Fetch navigation occurs and the form is properly filled out, // we try and save the password even though onsubmit hasn't been called. - FillElementWithValue("username_field", "USER"); - FillElementWithValue("password_field", "1234"); - NavigationObserver observer(WebContents()); - ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), "send_fetch()")); + std::unique_ptr<BubbleObserver> prompt_observer( + new BubbleObserver(WebContents())); + std::string fill_and_navigate = + "document.getElementById('username_field').value = 'temp';" + "document.getElementById('password_field').value = 'random';" + "send_fetch()"; + ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_navigate)); observer.Wait(); - EXPECT_TRUE(BubbleObserver(WebContents()).IsSavePromptShownAutomatically()); + EXPECT_TRUE(prompt_observer->IsSavePromptShownAutomatically()); } IN_PROC_BROWSER_TEST_P(PasswordManagerBrowserTestWithViewsFeature, @@ -832,13 +843,17 @@ // we try and save the password even though onsubmit hasn't been called. // Specifically verify that the password form saving new passwords is treated // the same as a login form. - FillElementWithValue("signup_username_field", "USER"); - FillElementWithValue("signup_password_field", "1234"); - FillElementWithValue("confirmation_password_field", "1234"); NavigationObserver observer(WebContents()); - ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), "send_fetch()")); + std::unique_ptr<BubbleObserver> prompt_observer( + new BubbleObserver(WebContents())); + std::string fill_and_navigate = + "document.getElementById('signup_username_field').value = 'temp';" + "document.getElementById('signup_password_field').value = 'random';" + "document.getElementById('confirmation_password_field').value = 'random';" + "send_fetch()"; + ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_navigate)); observer.Wait(); - EXPECT_TRUE(BubbleObserver(WebContents()).IsSavePromptShownAutomatically()); + EXPECT_TRUE(prompt_observer->IsSavePromptShownAutomatically()); } IN_PROC_BROWSER_TEST_P(PasswordManagerBrowserTestWithViewsFeature, @@ -1747,9 +1762,10 @@ IN_PROC_BROWSER_TEST_P(PasswordManagerBrowserTestWithViewsFeature, AutofillSuggestionsForPasswordFormWithoutUsernameField) { std::string submit = + "document.getElementById('password').value = 'mypassword';" "document.getElementById('submit-button').click();"; VerifyPasswordIsSavedAndFilled("/password/form_with_only_password_field.html", - std::string(), "password", submit); + submit, "password", "mypassword"); } // Test that if a form gets autofilled, then it gets autofilled on re-creation @@ -2158,9 +2174,11 @@ IN_PROC_BROWSER_TEST_P(PasswordManagerBrowserTestWithViewsFeature, AutofillSuggestionsForLoginSignupForm) { std::string submit = + "document.getElementById('username').value = 'myusername';" + "document.getElementById('password').value = 'mypassword';" "document.getElementById('submit').click();"; - VerifyPasswordIsSavedAndFilled("/password/login_signup_form.html", "username", - "password", submit); + VerifyPasswordIsSavedAndFilled("/password/login_signup_form.html", + submit, "password", "mypassword"); } // Check that we can fill in cases where <base href> is set and the action of @@ -2168,9 +2186,11 @@ IN_PROC_BROWSER_TEST_P(PasswordManagerBrowserTestWithViewsFeature, BaseTagWithNoActionTest) { std::string submit = + "document.getElementById('username_field').value = 'myusername';" + "document.getElementById('password_field').value = 'mypassword';" "document.getElementById('submit_button').click();"; VerifyPasswordIsSavedAndFilled("/password/password_xhr_submit.html", - "username_field", "password_field", submit); + submit, "password_field", "mypassword"); } // Check that a username and password are filled into forms in iframes @@ -2394,9 +2414,14 @@ IN_PROC_BROWSER_TEST_P(PasswordManagerBrowserTestWithViewsFeature, NoFormElementTest) { + std::string submit = + "document.getElementById('username_field').value = 'myusername';" + "document.getElementById('password_field').value = 'mypassword';" + "send_xhr();"; VerifyPasswordIsSavedAndFilled("/password/no_form_element.html", - "username_field", "password_field", - "send_xhr();"); + submit, + "password_field", + "mypassword"); } // The password manager driver will kill processes when they try to access @@ -3238,10 +3263,12 @@ IN_PROC_BROWSER_TEST_P(PasswordManagerBrowserTestWithViewsFeature, AutofillSuggestionsForPasswordFormWithAutocompleteOff) { std::string submit = + "document.getElementById('username').value = 'temp';" + "document.getElementById('password').value = 'mypassword';" "document.getElementById('submit').click();"; VerifyPasswordIsSavedAndFilled( - "/password/password_autocomplete_off_test.html", "username", "password", - submit); + "/password/password_autocomplete_off_test.html", submit, "password", + "mypassword"); } IN_PROC_BROWSER_TEST_P(
diff --git a/chrome/browser/password_manager/password_manager_test_base.cc b/chrome/browser/password_manager/password_manager_test_base.cc index 2b38019a..f7ffcad 100644 --- a/chrome/browser/password_manager/password_manager_test_base.cc +++ b/chrome/browser/password_manager/password_manager_test_base.cc
@@ -37,8 +37,6 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h" -#include "ui/events/keycodes/dom_us_layout_data.h" -#include "ui/events/keycodes/keyboard_code_conversion.h" namespace { @@ -490,10 +488,9 @@ void PasswordManagerBrowserTestBase::VerifyPasswordIsSavedAndFilled( const std::string& filename, - const std::string& username_id, - const std::string& password_id, - const std::string& submission_script) { - EXPECT_FALSE(password_id.empty()); + const std::string& submission_script, + const std::string& expected_element, + const std::string& expected_value) { password_manager::TestPasswordStore* password_store = static_cast<password_manager::TestPasswordStore*>( PasswordStoreFactory::GetForProfile( @@ -503,11 +500,6 @@ NavigateToFile(filename); NavigationObserver observer(WebContents()); - const char kUsername[] = "U"; - const char kPassword[] = "P"; - if (!username_id.empty()) - FillElementWithValue(username_id, kUsername); - FillElementWithValue(password_id, kPassword); ASSERT_TRUE(content::ExecuteScript(RenderFrameHost(), submission_script)); observer.Wait(); WaitForPasswordStore(); @@ -527,34 +519,7 @@ WebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(1, 1)); // Wait until that interaction causes the password value to be revealed. - if (!username_id.empty()) - WaitForElementValue(username_id, kUsername); - WaitForElementValue(password_id, kPassword); -} - -void PasswordManagerBrowserTestBase::FillElementWithValue( - const std::string& element_id, - const std::string& value) { - ASSERT_TRUE(content::ExecuteScript( - RenderFrameHost(), - base::StringPrintf("document.getElementById('%s').focus();", - element_id.c_str()))); - for (size_t i = 0; i < value.length(); ++i) { - ui::DomKey dom_key = ui::DomKey::FromCharacter(value[i]); - base::char16 character = value[i]; - const ui::PrintableCodeEntry* code_entry = std::find_if( - std::begin(ui::kPrintableCodeMap), std::end(ui::kPrintableCodeMap), - [character](const ui::PrintableCodeEntry& entry) { - return entry.character[0] == character || - entry.character[1] == character; - }); - ASSERT_TRUE(code_entry != std::end(ui::kPrintableCodeMap)); - bool shift = code_entry->character[1] == character; - ui::DomCode dom_code = code_entry->dom_code; - content::SimulateKeyPress(WebContents(), dom_key, dom_code, - ui::DomCodeToUsLayoutKeyboardCode(dom_code), - false, shift, false, false); - } + WaitForElementValue(expected_element, expected_value); } void PasswordManagerBrowserTestBase::WaitForElementValue(
diff --git a/chrome/browser/password_manager/password_manager_test_base.h b/chrome/browser/password_manager/password_manager_test_base.h index ea1701c..99deff3 100644 --- a/chrome/browser/password_manager/password_manager_test_base.h +++ b/chrome/browser/password_manager/password_manager_test_base.h
@@ -59,12 +59,11 @@ DISALLOW_COPY_AND_ASSIGN(NavigationObserver); }; -// Checks the save password prompt for a specified WebContents and allows -// accepting saving passwords through it. +// Observes the save password prompt for a specified WebContents, keeps track of +// whether or not it is currently shown, and allows accepting saving passwords +// through it. class BubbleObserver { public: - // The constructor doesn't start tracking |web_contents|. To check the status - // of the prompt one can even construct a temporary BubbleObserver. explicit BubbleObserver(content::WebContents* web_contents); // Checks if the save prompt is being currently available due to either manual @@ -147,19 +146,13 @@ // return immediately. void NavigateToFile(const std::string& path); - // Navigates to |filename|, fills |username_id| and |password_id| if nonempty - // and runs |submission_script| to submit. The credential is then saved. - // Navigates back to |filename| and then verifies that the same elements are - // filled. + // Navigates to |filename| and runs |submission_script| to submit. Navigates + // back to |filename| and then verifies that |expected_element| has + // |expected_value|. void VerifyPasswordIsSavedAndFilled(const std::string& filename, - const std::string& username_id, - const std::string& password_id, - const std::string& submission_script); - - // Focuses an input element with id |element_id| in the main frame and - // emulates typing |value| into it. - void FillElementWithValue(const std::string& element_id, - const std::string& value); + const std::string& submission_script, + const std::string& expected_element, + const std::string& expected_value); // Waits until the "value" attribute of the HTML element with |element_id| is // equal to |expected_value|. If the current value is not as expected, this
diff --git a/content/app/BUILD.gn b/content/app/BUILD.gn index 518bcc9..70d55be 100644 --- a/content/app/BUILD.gn +++ b/content/app/BUILD.gn
@@ -71,10 +71,10 @@ content_app_deps += [ "//content/ppapi_plugin:ppapi_plugin_sources" ] } - # Compile content_main_runner_impl.[h, cc] in a separate target to exempt from - # GN header checking without exempting any other source file. These files - # includes headers of all process types and varies significantly per platform - # in between browser and child. Otherwise it would require many "nogncheck" + # Compile content_main_runner_impl.cc in a separate target to exempt from GN + # header checking without exempting any other source file. This file includes + # headers of all process types and varies significantly per platform in + # between browser and child. Otherwise it would require many "nogncheck" # annotations that would both be useless and add noise. # # This will generate :content_main_runner_both, :content_main_runner_browser, @@ -85,7 +85,6 @@ sources = [ "content_main_runner_impl.cc", - "content_main_runner_impl.h", ] configs += extra_configs
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc index cb79126..4863bbf 100644 --- a/content/app/content_main_runner_impl.cc +++ b/content/app/content_main_runner_impl.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 "content/app/content_main_runner_impl.h" +#include "content/public/app/content_main_runner.h" #include <stddef.h> #include <stdlib.h> @@ -34,16 +34,17 @@ #include "base/process/memory.h" #include "base/process/process.h" #include "base/process/process_handle.h" -#include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/trace_event/trace_event.h" +#include "build/build_config.h" #include "components/tracing/common/trace_startup.h" #include "content/app/mojo/mojo_init.h" -#include "content/browser/browser_process_sub_thread.h" #include "content/common/url_schemes.h" +#include "content/public/app/content_main.h" #include "content/public/app/content_main_delegate.h" +#include "content/public/common/content_client.h" #include "content/public/common/content_constants.h" #include "content/public/common/content_descriptor_keys.h" #include "content/public/common/content_features.h" @@ -70,8 +71,10 @@ #include <cstring> #include "base/trace_event/trace_event_etw_export_win.h" +#include "sandbox/win/src/sandbox_types.h" #include "ui/display/win/dpi.h" #elif defined(OS_MACOSX) +#include "base/mac/scoped_nsautorelease_pool.h" #include "base/power_monitor/power_monitor_device_source.h" #include "content/browser/mach_broker_mac.h" #endif // OS_WIN @@ -288,7 +291,7 @@ switches::kVModule, }; cmd_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(), - kForwardSwitches, base::size(kForwardSwitches)); + kForwardSwitches, arraysize(kForwardSwitches)); GetContentClient()->browser()->AppendExtraCommandLineSwitches(cmd_line, -1); @@ -561,7 +564,7 @@ if (sandbox_type == service_manager::SANDBOX_TYPE_PROFILING) sandbox::SetUseLocaltimeOverride(false); - for (size_t i = 0; i < base::size(kMainFunctions); ++i) { + for (size_t i = 0; i < arraysize(kMainFunctions); ++i) { if (process_type == kMainFunctions[i].name) return kMainFunctions[i].function(main_params); } @@ -594,39 +597,17 @@ #endif // !CHROME_MULTIPLE_DLL_BROWSER && !CHROME_MULTIPLE_DLL_CHILD } -#if !defined(CHROME_MULTIPLE_DLL_CHILD) -// Run the main function for browser process. -// Returns the exit code for this process. -int RunBrowserProcessMain( - const MainFunctionParams& main_function_params, - ContentMainDelegate* delegate, - std::unique_ptr<BrowserProcessSubThread> service_manager_thread) { - if (delegate) { - int exit_code = delegate->RunProcess("", main_function_params); -#if defined(OS_ANDROID) - // In Android's browser process, the negative exit code doesn't mean the - // default behavior should be used as the UI message loop is managed by - // the Java and the browser process's default behavior is always - // overridden. - return exit_code; -#endif - if (exit_code >= 0) - return exit_code; - } - // GetServiceManagerTaskRunnerForEmbedderProcess() needs to be invoked before - // Run() for the browser process. - DCHECK(service_manager_thread); - return BrowserMain(main_function_params, std::move(service_manager_thread)); -} -#endif // !defined(CHROME_MULTIPLE_DLL_CHILD) - // Run the FooMain() for a given process type. +// If |process_type| is empty, runs BrowserMain(). // Returns the exit code for this process. -int RunOtherNamedProcessTypeMain(const std::string& process_type, - const MainFunctionParams& main_function_params, - ContentMainDelegate* delegate) { -#if !defined(CHROME_MULTIPLE_DLL_BROWSER) +int RunNamedProcessTypeMain(const std::string& process_type, + const MainFunctionParams& main_function_params, + ContentMainDelegate* delegate) { static const MainFunction kMainFunctions[] = { +#if !defined(CHROME_MULTIPLE_DLL_CHILD) + {"", BrowserMain}, +#endif +#if !defined(CHROME_MULTIPLE_DLL_BROWSER) #if BUILDFLAG(ENABLE_PLUGINS) {switches::kPpapiPluginProcess, PpapiPluginMain}, {switches::kPpapiBrokerProcess, PpapiBrokerMain}, @@ -634,20 +615,30 @@ {switches::kUtilityProcess, UtilityMain}, {switches::kRendererProcess, RendererMain}, {switches::kGpuProcess, GpuMain}, +#endif // !CHROME_MULTIPLE_DLL_BROWSER }; - for (size_t i = 0; i < base::size(kMainFunctions); ++i) { + RegisterMainThreadFactories(); + + for (size_t i = 0; i < arraysize(kMainFunctions); ++i) { if (process_type == kMainFunctions[i].name) { if (delegate) { int exit_code = delegate->RunProcess(process_type, main_function_params); +#if defined(OS_ANDROID) + // In Android's browser process, the negative exit code doesn't mean the + // default behavior should be used as the UI message loop is managed by + // the Java and the browser process's default behavior is always + // overridden. + if (process_type.empty()) + return exit_code; +#endif if (exit_code >= 0) return exit_code; } return kMainFunctions[i].function(main_function_params); } } -#endif // !CHROME_MULTIPLE_DLL_BROWSER #if BUILDFLAG(USE_ZYGOTE_HANDLE) // Zygote startup is special -- see RunZygote comments above @@ -664,342 +655,351 @@ return 1; } -// static -ContentMainRunnerImpl* ContentMainRunnerImpl::Create() { - return new ContentMainRunnerImpl(); -} - -ContentMainRunnerImpl::ContentMainRunnerImpl() { +class ContentMainRunnerImpl : public ContentMainRunner { + public: + ContentMainRunnerImpl() { #if defined(OS_WIN) - memset(&sandbox_info_, 0, sizeof(sandbox_info_)); + memset(&sandbox_info_, 0, sizeof(sandbox_info_)); #endif -} + } -ContentMainRunnerImpl::~ContentMainRunnerImpl() { - if (is_initialized_ && !is_shutdown_) - Shutdown(); -} + ~ContentMainRunnerImpl() override { + if (is_initialized_ && !is_shutdown_) + Shutdown(); + } -int ContentMainRunnerImpl::TerminateForFatalInitializationError() { - if (delegate_) - return delegate_->TerminateForFatalInitializationError(); + int TerminateForFatalInitializationError() { + if (delegate_) + return delegate_->TerminateForFatalInitializationError(); - CHECK(false); - return 0; -} + CHECK(false); + return 0; + } -int ContentMainRunnerImpl::Initialize(const ContentMainParams& params) { - ui_task_ = params.ui_task; - created_main_parts_closure_ = params.created_main_parts_closure; + int Initialize(const ContentMainParams& params) override { + ui_task_ = params.ui_task; + created_main_parts_closure_ = params.created_main_parts_closure; #if defined(OS_WIN) - sandbox_info_ = *params.sandbox_info; + sandbox_info_ = *params.sandbox_info; #else // !OS_WIN #if defined(OS_MACOSX) - autorelease_pool_ = params.autorelease_pool; + autorelease_pool_ = params.autorelease_pool; #endif // defined(OS_MACOSX) #if defined(OS_ANDROID) - // See note at the initialization of ExitManager, below; basically, - // only Android builds have the ctor/dtor handlers set up to use - // TRACE_EVENT right away. - TRACE_EVENT0("startup,benchmark,rail", "ContentMainRunnerImpl::Initialize"); + // See note at the initialization of ExitManager, below; basically, + // only Android builds have the ctor/dtor handlers set up to use + // TRACE_EVENT right away. + TRACE_EVENT0("startup,benchmark,rail", "ContentMainRunnerImpl::Initialize"); #endif // OS_ANDROID - base::GlobalDescriptors* g_fds = base::GlobalDescriptors::GetInstance(); - ALLOW_UNUSED_LOCAL(g_fds); + base::GlobalDescriptors* g_fds = base::GlobalDescriptors::GetInstance(); + ALLOW_UNUSED_LOCAL(g_fds); // On Android, the ipc_fd is passed through the Java service. #if !defined(OS_ANDROID) - g_fds->Set(kMojoIPCChannel, - kMojoIPCChannel + base::GlobalDescriptors::kBaseDescriptor); + g_fds->Set(kMojoIPCChannel, + kMojoIPCChannel + base::GlobalDescriptors::kBaseDescriptor); - g_fds->Set(kFieldTrialDescriptor, - kFieldTrialDescriptor + base::GlobalDescriptors::kBaseDescriptor); + g_fds->Set( + kFieldTrialDescriptor, + kFieldTrialDescriptor + base::GlobalDescriptors::kBaseDescriptor); #endif // !OS_ANDROID #if defined(OS_LINUX) || defined(OS_OPENBSD) - g_fds->Set(kCrashDumpSignal, - kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor); + g_fds->Set(kCrashDumpSignal, + kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor); #endif // OS_LINUX || OS_OPENBSD #endif // !OS_WIN - is_initialized_ = true; - delegate_ = params.delegate; + is_initialized_ = true; + delegate_ = params.delegate; // The exit manager is in charge of calling the dtors of singleton objects. // On Android, AtExitManager is set up when library is loaded. // A consequence of this is that you can't use the ctor/dtor-based // TRACE_EVENT methods on Linux or iOS builds till after we set this up. #if !defined(OS_ANDROID) - if (!ui_task_) { - // When running browser tests, don't create a second AtExitManager as that - // interfers with shutdown when objects created before ContentMain is - // called are destructed when it returns. - exit_manager_.reset(new base::AtExitManager); - } + if (!ui_task_) { + // When running browser tests, don't create a second AtExitManager as that + // interfers with shutdown when objects created before ContentMain is + // called are destructed when it returns. + exit_manager_.reset(new base::AtExitManager); + } #endif // !OS_ANDROID - int exit_code = 0; - if (delegate_ && delegate_->BasicStartupComplete(&exit_code)) - return exit_code; - completed_basic_startup_ = true; + int exit_code = 0; + if (delegate_ && delegate_->BasicStartupComplete(&exit_code)) + return exit_code; + completed_basic_startup_ = true; - // We will need to use data from resources.pak in later cl, so load the file - // now. - if (IsRootProcess()) { - ui::DataPack* data_pack = delegate_->LoadServiceManifestDataPack(); - // TODO(ranj): Read manifest from this data pack. - ignore_result(data_pack); - } + // We will need to use data from resources.pak in later cl, so load the file + // now. + if (IsRootProcess()) { + ui::DataPack* data_pack = delegate_->LoadServiceManifestDataPack(); + // TODO(ranj): Read manifest from this data pack. + ignore_result(data_pack); + } - const base::CommandLine& command_line = - *base::CommandLine::ForCurrentProcess(); - std::string process_type = - command_line.GetSwitchValueASCII(switches::kProcessType); - -#if defined(OS_WIN) - if (command_line.HasSwitch(switches::kDeviceScaleFactor)) { - std::string scale_factor_string = - command_line.GetSwitchValueASCII(switches::kDeviceScaleFactor); - double scale_factor = 0; - if (base::StringToDouble(scale_factor_string, &scale_factor)) - display::win::SetDefaultDeviceScaleFactor(scale_factor); - } -#endif - - if (!GetContentClient()) - SetContentClient(&empty_content_client_); - ContentClientInitializer::Set(process_type, delegate_); - -#if !defined(OS_ANDROID) - // Enable startup tracing asap to avoid early TRACE_EVENT calls being - // ignored. For Android, startup tracing is enabled in an even earlier place - // content/app/android/library_loader_hooks.cc. - // - // Startup tracing flags are not (and should not) passed to Zygote - // processes. We will enable tracing when forked, if needed. - if (process_type != switches::kZygoteProcess) - tracing::EnableStartupTracingIfNeeded(); -#endif // !OS_ANDROID - -#if defined(OS_WIN) - // Enable exporting of events to ETW if requested on the command line. - if (command_line.HasSwitch(switches::kTraceExportEventsToETW)) - base::trace_event::TraceEventETWExport::EnableETWExport(); -#endif // OS_WIN - -#if !defined(OS_ANDROID) - // Android tracing started at the beginning of the method. - // Other OSes have to wait till we get here in order for all the memory - // management setup to be completed. - TRACE_EVENT0("startup,benchmark,rail", "ContentMainRunnerImpl::Initialize"); -#endif // !OS_ANDROID - -#if defined(OS_MACOSX) - // We need to allocate the IO Ports before the Sandbox is initialized or - // the first instance of PowerMonitor is created. - // It's important not to allocate the ports for processes which don't - // register with the power monitor - see https://crbug.com/88867. - if (process_type.empty() || - (delegate_ && - delegate_->ProcessRegistersWithSystemProcess(process_type))) { - base::PowerMonitorDeviceSource::AllocateSystemIOPorts(); - } - - if (!process_type.empty() && - (!delegate_ || delegate_->ShouldSendMachPort(process_type))) { - MachBroker::ChildSendTaskPortToParent(); - } -#endif - - // If we are on a platform where the default allocator is overridden (shim - // layer on windows, tcmalloc on Linux Desktop) smoke-tests that the - // overriding logic is working correctly. If not causes a hard crash, as its - // unexpected absence has security implications. - CHECK(base::allocator::IsAllocatorInitialized()); - -#if defined(OS_POSIX) || defined(OS_FUCHSIA) - if (!process_type.empty()) { - // When you hit Ctrl-C in a terminal running the browser - // process, a SIGINT is delivered to the entire process group. - // When debugging the browser process via gdb, gdb catches the - // SIGINT for the browser process (and dumps you back to the gdb - // console) but doesn't for the child processes, killing them. - // The fix is to have child processes ignore SIGINT; they'll die - // on their own when the browser process goes away. - // - // Note that we *can't* rely on BeingDebugged to catch this case because - // we are the child process, which is not being debugged. - // TODO(evanm): move this to some shared subprocess-init function. - if (!base::debug::BeingDebugged()) - signal(SIGINT, SIG_IGN); - } -#endif - - RegisterPathProvider(); - RegisterContentSchemes(true); - -#if defined(OS_ANDROID) && (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE) - int icudata_fd = g_fds->MaybeGet(kAndroidICUDataDescriptor); - if (icudata_fd != -1) { - auto icudata_region = g_fds->GetRegion(kAndroidICUDataDescriptor); - if (!base::i18n::InitializeICUWithFileDescriptor(icudata_fd, - icudata_region)) - return TerminateForFatalInitializationError(); - } else { - if (!base::i18n::InitializeICU()) - return TerminateForFatalInitializationError(); - } -#else - if (!base::i18n::InitializeICU()) - return TerminateForFatalInitializationError(); -#endif // OS_ANDROID && (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE) - - InitializeV8IfNeeded(command_line, process_type); - - blink::TrialTokenValidator::SetOriginTrialPolicyGetter( - base::BindRepeating([]() -> blink::OriginTrialPolicy* { - if (auto* client = GetContentClient()) - return client->GetOriginTrialPolicy(); - return nullptr; - })); - -#if !defined(OFFICIAL_BUILD) -#if defined(OS_WIN) - bool should_enable_stack_dump = !process_type.empty(); -#else - bool should_enable_stack_dump = true; -#endif - // Print stack traces to stderr when crashes occur. This opens up security - // holes so it should never be enabled for official builds. This needs to - // happen before crash reporting is initialized (which for chrome happens in - // the call to PreSandboxStartup() on the delegate below), because otherwise - // this would interfere with signal handlers used by crash reporting. - if (should_enable_stack_dump && - !command_line.HasSwitch( - service_manager::switches::kDisableInProcessStackTraces)) { - base::debug::EnableInProcessStackDumping(); - } -#endif // !defined(OFFICIAL_BUILD) - - if (delegate_) - delegate_->PreSandboxStartup(); - -#if defined(OS_WIN) - if (!InitializeSandbox( - service_manager::SandboxTypeFromCommandLine(command_line), - params.sandbox_info)) - return TerminateForFatalInitializationError(); -#elif defined(OS_MACOSX) - // Do not initialize the sandbox at this point if the V2 - // sandbox is enabled for the process type. - bool v2_enabled = base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableV2Sandbox); - - if (process_type == switches::kRendererProcess || - process_type == switches::kPpapiPluginProcess || v2_enabled || - (delegate_ && delegate_->DelaySandboxInitialization(process_type))) { - // On OS X the renderer sandbox needs to be initialized later in the - // startup sequence in RendererMainPlatformDelegate::EnableSandbox(). - } else { - if (!InitializeSandbox()) - return TerminateForFatalInitializationError(); - } -#endif - - if (delegate_) - delegate_->SandboxInitialized(process_type); - -#if BUILDFLAG(USE_ZYGOTE_HANDLE) - if (process_type.empty()) { - // The sandbox host needs to be initialized before forking a thread to - // start the ServiceManager, and after setting up the sandbox and invoking - // SandboxInitialized(). - InitializeZygoteSandboxForBrowserProcess( - *base::CommandLine::ForCurrentProcess()); - } -#endif // BUILDFLAG(USE_ZYGOTE_HANDLE) - - // Return -1 to indicate no early termination. - return -1; -} - -int ContentMainRunnerImpl::Run() { - DCHECK(is_initialized_); - DCHECK(!is_shutdown_); - const base::CommandLine& command_line = - *base::CommandLine::ForCurrentProcess(); - std::string process_type = - command_line.GetSwitchValueASCII(switches::kProcessType); - - // Run this logic on all child processes. Zygotes will run this at a later - // point in time when the command line has been updated. - std::unique_ptr<base::FieldTrialList> field_trial_list; - if (!process_type.empty() && process_type != switches::kZygoteProcess) - InitializeFieldTrialAndFeatureList(&field_trial_list); - - MainFunctionParams main_params(command_line); - main_params.ui_task = ui_task_; - main_params.created_main_parts_closure = created_main_parts_closure_; -#if defined(OS_WIN) - main_params.sandbox_info = &sandbox_info_; -#elif defined(OS_MACOSX) - main_params.autorelease_pool = autorelease_pool_; -#endif - - RegisterMainThreadFactories(); - -#if !defined(CHROME_MULTIPLE_DLL_CHILD) - // The thread used to start the ServiceManager is handed-off to - // BrowserMain() which may elect to promote it (e.g. to BrowserThread::IO). - if (process_type.empty()) { - return RunBrowserProcessMain(main_params, delegate_, - std::move(service_manager_thread_)); - } -#endif - - return RunOtherNamedProcessTypeMain(process_type, main_params, delegate_); -} - -void ContentMainRunnerImpl::Shutdown() { - DCHECK(is_initialized_); - DCHECK(!is_shutdown_); - - if (completed_basic_startup_ && delegate_) { const base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); std::string process_type = command_line.GetSwitchValueASCII(switches::kProcessType); - delegate_->ProcessExiting(process_type); +#if defined(OS_WIN) + if (command_line.HasSwitch(switches::kDeviceScaleFactor)) { + std::string scale_factor_string = + command_line.GetSwitchValueASCII(switches::kDeviceScaleFactor); + double scale_factor = 0; + if (base::StringToDouble(scale_factor_string, &scale_factor)) + display::win::SetDefaultDeviceScaleFactor(scale_factor); + } +#endif + + if (!GetContentClient()) + SetContentClient(&empty_content_client_); + ContentClientInitializer::Set(process_type, delegate_); + +#if !defined(OS_ANDROID) + // Enable startup tracing asap to avoid early TRACE_EVENT calls being + // ignored. For Android, startup tracing is enabled in an even earlier place + // content/app/android/library_loader_hooks.cc. + // + // Startup tracing flags are not (and should not) passed to Zygote + // processes. We will enable tracing when forked, if needed. + if (process_type != switches::kZygoteProcess) + tracing::EnableStartupTracingIfNeeded(); +#endif // !OS_ANDROID + +#if defined(OS_WIN) + // Enable exporting of events to ETW if requested on the command line. + if (command_line.HasSwitch(switches::kTraceExportEventsToETW)) + base::trace_event::TraceEventETWExport::EnableETWExport(); +#endif // OS_WIN + +#if !defined(OS_ANDROID) + // Android tracing started at the beginning of the method. + // Other OSes have to wait till we get here in order for all the memory + // management setup to be completed. + TRACE_EVENT0("startup,benchmark,rail", "ContentMainRunnerImpl::Initialize"); +#endif // !OS_ANDROID + +#if defined(OS_MACOSX) + // We need to allocate the IO Ports before the Sandbox is initialized or + // the first instance of PowerMonitor is created. + // It's important not to allocate the ports for processes which don't + // register with the power monitor - see crbug.com/88867. + if (process_type.empty() || + (delegate_ && + delegate_->ProcessRegistersWithSystemProcess(process_type))) { + base::PowerMonitorDeviceSource::AllocateSystemIOPorts(); + } + + if (!process_type.empty() && + (!delegate_ || delegate_->ShouldSendMachPort(process_type))) { + MachBroker::ChildSendTaskPortToParent(); + } +#endif + + // If we are on a platform where the default allocator is overridden (shim + // layer on windows, tcmalloc on Linux Desktop) smoke-tests that the + // overriding logic is working correctly. If not causes a hard crash, as its + // unexpected absence has security implications. + CHECK(base::allocator::IsAllocatorInitialized()); + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) + if (!process_type.empty()) { + // When you hit Ctrl-C in a terminal running the browser + // process, a SIGINT is delivered to the entire process group. + // When debugging the browser process via gdb, gdb catches the + // SIGINT for the browser process (and dumps you back to the gdb + // console) but doesn't for the child processes, killing them. + // The fix is to have child processes ignore SIGINT; they'll die + // on their own when the browser process goes away. + // + // Note that we *can't* rely on BeingDebugged to catch this case because + // we are the child process, which is not being debugged. + // TODO(evanm): move this to some shared subprocess-init function. + if (!base::debug::BeingDebugged()) + signal(SIGINT, SIG_IGN); + } +#endif + + RegisterPathProvider(); + RegisterContentSchemes(true); + +#if defined(OS_ANDROID) && (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE) + int icudata_fd = g_fds->MaybeGet(kAndroidICUDataDescriptor); + if (icudata_fd != -1) { + auto icudata_region = g_fds->GetRegion(kAndroidICUDataDescriptor); + if (!base::i18n::InitializeICUWithFileDescriptor(icudata_fd, + icudata_region)) + return TerminateForFatalInitializationError(); + } else { + if (!base::i18n::InitializeICU()) + return TerminateForFatalInitializationError(); + } +#else + if (!base::i18n::InitializeICU()) + return TerminateForFatalInitializationError(); +#endif // OS_ANDROID && (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE) + + InitializeV8IfNeeded(command_line, process_type); + + blink::TrialTokenValidator::SetOriginTrialPolicyGetter( + base::BindRepeating([]() -> blink::OriginTrialPolicy* { + if (auto* client = GetContentClient()) + return client->GetOriginTrialPolicy(); + return nullptr; + })); + +#if !defined(OFFICIAL_BUILD) +#if defined(OS_WIN) + bool should_enable_stack_dump = !process_type.empty(); +#else + bool should_enable_stack_dump = true; +#endif + // Print stack traces to stderr when crashes occur. This opens up security + // holes so it should never be enabled for official builds. This needs to + // happen before crash reporting is initialized (which for chrome happens in + // the call to PreSandboxStartup() on the delegate below), because otherwise + // this would interfere with signal handlers used by crash reporting. + if (should_enable_stack_dump && + !command_line.HasSwitch( + service_manager::switches::kDisableInProcessStackTraces)) { + base::debug::EnableInProcessStackDumping(); + } +#endif // !defined(OFFICIAL_BUILD) + + if (delegate_) + delegate_->PreSandboxStartup(); + +#if defined(OS_WIN) + if (!InitializeSandbox( + service_manager::SandboxTypeFromCommandLine(command_line), + params.sandbox_info)) + return TerminateForFatalInitializationError(); +#elif defined(OS_MACOSX) + // Do not initialize the sandbox at this point if the V2 + // sandbox is enabled for the process type. + bool v2_enabled = base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableV2Sandbox); + + if (process_type == switches::kRendererProcess || + process_type == switches::kPpapiPluginProcess || v2_enabled || + (delegate_ && delegate_->DelaySandboxInitialization(process_type))) { + // On OS X the renderer sandbox needs to be initialized later in the + // startup sequence in RendererMainPlatformDelegate::EnableSandbox(). + } else { + if (!InitializeSandbox()) + return TerminateForFatalInitializationError(); + } +#endif + + if (delegate_) + delegate_->SandboxInitialized(process_type); + +#if BUILDFLAG(USE_ZYGOTE_HANDLE) + if (process_type.empty()) { + // The sandbox host needs to be initialized before forking a thread to + // start the ServiceManager, and after setting up the sandbox and invoking + // SandboxInitialized(). + InitializeZygoteSandboxForBrowserProcess( + *base::CommandLine::ForCurrentProcess()); + } +#endif // BUILDFLAG(USE_ZYGOTE_HANDLE) + + // Return -1 to indicate no early termination. + return -1; } + int Run() override { + DCHECK(is_initialized_); + DCHECK(!is_shutdown_); + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + std::string process_type = + command_line.GetSwitchValueASCII(switches::kProcessType); + + // Run this logic on all child processes. Zygotes will run this at a later + // point in time when the command line has been updated. + std::unique_ptr<base::FieldTrialList> field_trial_list; + if (!process_type.empty() && process_type != switches::kZygoteProcess) + InitializeFieldTrialAndFeatureList(&field_trial_list); + + MainFunctionParams main_params(command_line); + main_params.ui_task = ui_task_; + main_params.created_main_parts_closure = created_main_parts_closure_; +#if defined(OS_WIN) + main_params.sandbox_info = &sandbox_info_; +#elif defined(OS_MACOSX) + main_params.autorelease_pool = autorelease_pool_; +#endif + + return RunNamedProcessTypeMain(process_type, main_params, delegate_); + } + + void Shutdown() override { + DCHECK(is_initialized_); + DCHECK(!is_shutdown_); + + if (completed_basic_startup_ && delegate_) { + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + std::string process_type = + command_line.GetSwitchValueASCII(switches::kProcessType); + + delegate_->ProcessExiting(process_type); + } + #if defined(OS_WIN) #ifdef _CRTDBG_MAP_ALLOC - _CrtDumpMemoryLeaks(); + _CrtDumpMemoryLeaks(); #endif // _CRTDBG_MAP_ALLOC #endif // OS_WIN - exit_manager_.reset(nullptr); + exit_manager_.reset(nullptr); - delegate_ = nullptr; - is_shutdown_ = true; -} + delegate_ = nullptr; + is_shutdown_ = true; + } -#if !defined(CHROME_MULTIPLE_DLL_CHILD) -scoped_refptr<base::SingleThreadTaskRunner> -ContentMainRunnerImpl::GetServiceManagerTaskRunnerForEmbedderProcess() { - service_manager_thread_ = BrowserProcessSubThread::CreateIOThread(); - return service_manager_thread_->task_runner(); -} -#endif // !defined(CHROME_MULTIPLE_DLL_CHILD) + private: + // True if the runner has been initialized. + bool is_initialized_ = false; + + // True if the runner has been shut down. + bool is_shutdown_ = false; + + // True if basic startup was completed. + bool completed_basic_startup_ = false; + + // Used if the embedder doesn't set one. + ContentClient empty_content_client_; + + // The delegate will outlive this object. + ContentMainDelegate* delegate_ = nullptr; + + std::unique_ptr<base::AtExitManager> exit_manager_; +#if defined(OS_WIN) + sandbox::SandboxInterfaceInfo sandbox_info_; +#elif defined(OS_MACOSX) + base::mac::ScopedNSAutoreleasePool* autorelease_pool_ = nullptr; +#endif + + base::Closure* ui_task_ = nullptr; + + CreatedMainPartsClosure* created_main_parts_closure_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(ContentMainRunnerImpl); +}; // static ContentMainRunner* ContentMainRunner::Create() { - return ContentMainRunnerImpl::Create(); + return new ContentMainRunnerImpl(); } } // namespace content
diff --git a/content/app/content_main_runner_impl.h b/content/app/content_main_runner_impl.h deleted file mode 100644 index 7fab6f7..0000000 --- a/content/app/content_main_runner_impl.h +++ /dev/null
@@ -1,89 +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 CONTENT_APP_CONTENT_MAIN_RUNNER_IMPL_H_ -#define CONTENT_APP_CONTENT_MAIN_RUNNER_IMPL_H_ - -#include <memory> - -#include "base/callback_forward.h" -#include "base/memory/scoped_refptr.h" -#include "build/build_config.h" -#include "content/public/app/content_main.h" -#include "content/public/app/content_main_runner.h" -#include "content/public/common/content_client.h" - -#if defined(OS_WIN) -#include "sandbox/win/src/sandbox_types.h" -#elif defined(OS_MACOSX) -#include "base/mac/scoped_nsautorelease_pool.h" -#endif // OS_WIN - -namespace base { -class AtExitManager; -class SingleThreadTaskRunner; -} // namespace base - -namespace content { -class BrowserProcessSubThread; -class ContentMainDelegate; -struct ContentMainParams; - -class ContentMainRunnerImpl : public ContentMainRunner { - public: - static ContentMainRunnerImpl* Create(); - - ContentMainRunnerImpl(); - ~ContentMainRunnerImpl() override; - - int TerminateForFatalInitializationError(); - - // ContentMainRunner: - int Initialize(const ContentMainParams& params) override; - int Run() override; - void Shutdown() override; - -#if !defined(CHROME_MULTIPLE_DLL_CHILD) - // Creates a thread and returns the SingleThreadTaskRunner on which - // ServiceManager should run. - scoped_refptr<base::SingleThreadTaskRunner> - GetServiceManagerTaskRunnerForEmbedderProcess(); -#endif // !defined(CHROME_MULTIPLE_DLL_CHILD) - - private: - // True if the runner has been initialized. - bool is_initialized_ = false; - - // True if the runner has been shut down. - bool is_shutdown_ = false; - - // True if basic startup was completed. - bool completed_basic_startup_ = false; - - // Used if the embedder doesn't set one. - ContentClient empty_content_client_; - - // The delegate will outlive this object. - ContentMainDelegate* delegate_ = nullptr; - - std::unique_ptr<base::AtExitManager> exit_manager_; - -#if defined(OS_WIN) - sandbox::SandboxInterfaceInfo sandbox_info_; -#elif defined(OS_MACOSX) - base::mac::ScopedNSAutoreleasePool* autorelease_pool_ = nullptr; -#endif - - std::unique_ptr<BrowserProcessSubThread> service_manager_thread_; - - base::Closure* ui_task_ = nullptr; - - CreatedMainPartsClosure* created_main_parts_closure_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(ContentMainRunnerImpl); -}; - -} // namespace content - -#endif // CONTENT_APP_CONTENT_MAIN_RUNNER_IMPL_H_
diff --git a/content/app/content_service_manager_main_delegate.cc b/content/app/content_service_manager_main_delegate.cc index 119f39f..62dceb5 100644 --- a/content/app/content_service_manager_main_delegate.cc +++ b/content/app/content_service_manager_main_delegate.cc
@@ -5,8 +5,8 @@ #include "content/app/content_service_manager_main_delegate.h" #include "base/command_line.h" -#include "content/app/content_main_runner_impl.h" #include "content/public/app/content_main_delegate.h" +#include "content/public/app/content_main_runner.h" #include "content/public/common/content_switches.h" #include "content/public/common/service_names.mojom.h" #include "services/service_manager/runner/common/client_util.h" @@ -16,7 +16,7 @@ ContentServiceManagerMainDelegate::ContentServiceManagerMainDelegate( const ContentMainParams& params) : content_main_params_(params), - content_main_runner_(ContentMainRunnerImpl::Create()) {} + content_main_runner_(ContentMainRunner::Create()) {} ContentServiceManagerMainDelegate::~ContentServiceManagerMainDelegate() = default; @@ -124,11 +124,4 @@ return nullptr; } -#if !defined(CHROME_MULTIPLE_DLL_CHILD) -scoped_refptr<base::SingleThreadTaskRunner> ContentServiceManagerMainDelegate:: - GetServiceManagerTaskRunnerForEmbedderProcess() { - return content_main_runner_->GetServiceManagerTaskRunnerForEmbedderProcess(); -} -#endif // !defined(CHROME_MULTIPLE_DLL_CHILD) - } // namespace content
diff --git a/content/app/content_service_manager_main_delegate.h b/content/app/content_service_manager_main_delegate.h index a6ab54a..4393a8f 100644 --- a/content/app/content_service_manager_main_delegate.h +++ b/content/app/content_service_manager_main_delegate.h
@@ -8,15 +8,13 @@ #include <memory> #include "base/macros.h" -#include "base/memory/scoped_refptr.h" -#include "base/single_thread_task_runner.h" #include "build/build_config.h" #include "content/public/app/content_main.h" #include "services/service_manager/embedder/main_delegate.h" namespace content { -class ContentMainRunnerImpl; +class ContentMainRunner; class ContentServiceManagerMainDelegate : public service_manager::MainDelegate { public: @@ -25,10 +23,6 @@ // service_manager::MainDelegate: int Initialize(const InitializeParams& params) override; -#if !defined(CHROME_MULTIPLE_DLL_CHILD) - scoped_refptr<base::SingleThreadTaskRunner> - GetServiceManagerTaskRunnerForEmbedderProcess() override; -#endif // !defined(CHROME_MULTIPLE_DLL_CHILD) bool IsEmbedderSubprocess() override; int RunEmbedderProcess() override; void ShutDownEmbedderProcess() override; @@ -48,7 +42,7 @@ private: ContentMainParams content_main_params_; - std::unique_ptr<ContentMainRunnerImpl> content_main_runner_; + std::unique_ptr<ContentMainRunner> content_main_runner_; #if defined(OS_ANDROID) bool initialized_ = false;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index ae3f5bc..2d20fa3 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -71,6 +71,7 @@ "//content/browser/background_fetch:background_fetch_proto", "//content/browser/background_sync:background_sync_proto", "//content/browser/cache_storage:cache_storage_proto", + "//content/browser/cookie_store:cookie_store_proto", "//content/browser/devtools:devtools_resources", "//content/browser/devtools:protocol_sources", "//content/browser/dom_storage:local_storage_proto", @@ -500,7 +501,6 @@ "browser_main_loop.cc", "browser_main_loop.h", "browser_main_runner_impl.cc", - "browser_main_runner_impl.h", "browser_plugin/browser_plugin_embedder.cc", "browser_plugin/browser_plugin_embedder.h", "browser_plugin/browser_plugin_guest.cc", @@ -576,6 +576,14 @@ # needed on all platforms. "compositor/surface_utils.cc", "compositor/surface_utils.h", + "cookie_store/cookie_change_subscription.cc", + "cookie_store/cookie_change_subscription.h", + "cookie_store/cookie_store_context.cc", + "cookie_store/cookie_store_context.h", + "cookie_store/cookie_store_host.cc", + "cookie_store/cookie_store_host.h", + "cookie_store/cookie_store_manager.cc", + "cookie_store/cookie_store_manager.h", "dedicated_worker/dedicated_worker_host.cc", "dedicated_worker/dedicated_worker_host.h", "devtools/browser_devtools_agent_host.cc", @@ -1060,6 +1068,10 @@ "media/audible_metrics.h", "media/audio_input_stream_broker.cc", "media/audio_input_stream_broker.h", + "media/audio_loopback_stream_broker.cc", + "media/audio_loopback_stream_broker.h", + "media/audio_muting_session.cc", + "media/audio_muting_session.h", "media/audio_output_stream_broker.cc", "media/audio_output_stream_broker.h", "media/audio_stream_broker.cc",
diff --git a/content/browser/DEPS b/content/browser/DEPS index 4630296..98d3fd6 100644 --- a/content/browser/DEPS +++ b/content/browser/DEPS
@@ -127,6 +127,7 @@ "+third_party/blink/public/platform/modules/bluetooth/web_bluetooth.mojom.h", "+third_party/blink/public/platform/modules/broadcastchannel/broadcast_channel.mojom.h", "+third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom.h", + "+third_party/blink/public/platform/modules/cookie_store/cookie_store.mojom.h", "+third_party/blink/public/platform/modules/geolocation/geolocation_service.mojom.h", "+third_party/blink/public/platform/modules/installedapp/installed_app_provider.mojom.h", "+third_party/blink/public/platform/modules/installedapp/related_application.mojom.h",
diff --git a/content/browser/browser_main.cc b/content/browser/browser_main.cc index f06e59b..d706269 100644 --- a/content/browser/browser_main.cc +++ b/content/browser/browser_main.cc
@@ -7,9 +7,8 @@ #include <memory> #include "base/trace_event/trace_event.h" -#include "content/browser/browser_main_runner_impl.h" -#include "content/browser/browser_process_sub_thread.h" #include "content/common/content_constants_internal.h" +#include "content/public/browser/browser_main_runner.h" namespace content { @@ -31,20 +30,16 @@ } // namespace // Main routine for running as the Browser process. -int BrowserMain( - const MainFunctionParams& parameters, - std::unique_ptr<BrowserProcessSubThread> service_manager_thread) { +int BrowserMain(const MainFunctionParams& parameters) { ScopedBrowserMainEvent scoped_browser_main_event; base::trace_event::TraceLog::GetInstance()->set_process_name("Browser"); base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex( kTraceEventBrowserProcessSortIndex); - std::unique_ptr<BrowserMainRunnerImpl> main_runner( - BrowserMainRunnerImpl::Create()); + std::unique_ptr<BrowserMainRunner> main_runner(BrowserMainRunner::Create()); - int exit_code = - main_runner->Initialize(parameters, std::move(service_manager_thread)); + int exit_code = main_runner->Initialize(parameters); if (exit_code >= 0) return exit_code;
diff --git a/content/browser/browser_main.h b/content/browser/browser_main.h index 02f3af60..8fab146 100644 --- a/content/browser/browser_main.h +++ b/content/browser/browser_main.h
@@ -5,18 +5,13 @@ #ifndef CONTENT_BROWSER_BROWSER_MAIN_H_ #define CONTENT_BROWSER_BROWSER_MAIN_H_ -#include <memory> - #include "content/common/content_export.h" namespace content { -class BrowserProcessSubThread; struct MainFunctionParams; -CONTENT_EXPORT int BrowserMain( - const content::MainFunctionParams& parameters, - std::unique_ptr<BrowserProcessSubThread> service_manager_thread); +CONTENT_EXPORT int BrowserMain(const content::MainFunctionParams& parameters); } // namespace content
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 61b2e9b..efa1f5b1 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -56,6 +56,7 @@ #include "components/viz/service/display_embedder/compositing_mode_reporter_impl.h" #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" +#include "content/browser/browser_process_sub_thread.h" #include "content/browser/browser_thread_impl.h" #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/compositor/gpu_process_transport_factory.h" @@ -524,13 +525,9 @@ g_current_browser_main_loop = nullptr; } -void BrowserMainLoop::Init( - std::unique_ptr<BrowserProcessSubThread> service_manager_thread) { +void BrowserMainLoop::Init() { TRACE_EVENT0("startup", "BrowserMainLoop::Init"); - // This is always invoked before |io_thread_| is initialized (i.e. never - // resets it). - io_thread_ = std::move(service_manager_thread); parts_.reset( GetContentClient()->browser()->CreateBrowserMainParts(parameters_)); } @@ -661,6 +658,11 @@ void BrowserMainLoop::PostMainMessageLoopStart() { { + TRACE_EVENT0("startup", + "BrowserMainLoop::Subsystem:CreateBrowserThread::IO"); + InitializeIOThread(); + } + { TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:SystemMonitor"); system_monitor_.reset(new base::SystemMonitor); } @@ -925,14 +927,12 @@ *task_scheduler_init_params.get()); } - // The |io_thread| can have optionally been injected into Init(), but if not, - // create it here. Thre thread is only tagged as BrowserThread::IO here in - // order to prevent any code from statically posting to it before + // The thread used for BrowserThread::IO is created in + // |PostMainMessageLoopStart()|, but it's only tagged as BrowserThread::IO + // here in order to prevent any code from statically posting to it before // CreateThreads() (as such maintaining the invariant that PreCreateThreads() // et al. "happen-before" BrowserThread::IO is "brought up"). - if (!io_thread_) { - io_thread_ = BrowserProcessSubThread::CreateIOThread(); - } + DCHECK(io_thread_); io_thread_->RegisterAsBrowserThread(); created_threads_ = true; @@ -1136,6 +1136,10 @@ return audio_service_runner_.get(); } +void BrowserMainLoop::InitializeIOThreadForTesting() { + InitializeIOThread(); +} + #if !defined(OS_ANDROID) viz::FrameSinkManagerImpl* BrowserMainLoop::GetFrameSinkManager() const { return frame_sink_manager_impl_.get(); @@ -1489,6 +1493,21 @@ #endif } +void BrowserMainLoop::InitializeIOThread() { + base::Thread::Options options; + options.message_loop_type = base::MessageLoop::TYPE_IO; +#if defined(OS_ANDROID) || defined(OS_CHROMEOS) + // Up the priority of the |io_thread_| as some of its IPCs relate to + // display tasks. + options.priority = base::ThreadPriority::DISPLAY; +#endif + + io_thread_ = std::make_unique<BrowserProcessSubThread>(BrowserThread::IO); + + if (!io_thread_->StartWithOptions(options)) + LOG(FATAL) << "Failed to start BrowserThread::IO"; +} + void BrowserMainLoop::InitializeMojo() { if (!parsed_command_line_.HasSwitch(switches::kSingleProcess)) { // Disallow mojo sync calls in the browser process. Note that we allow sync
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h index bed92782..b25ed2a 100644 --- a/content/browser/browser_main_loop.h +++ b/content/browser/browser_main_loop.h
@@ -13,7 +13,6 @@ #include "base/memory/ref_counted.h" #include "base/timer/timer.h" #include "build/build_config.h" -#include "content/browser/browser_process_sub_thread.h" #include "content/public/browser/browser_main_runner.h" #include "media/media_buildflags.h" #include "mojo/public/cpp/bindings/binding_set.h" @@ -96,6 +95,7 @@ namespace content { class BrowserMainParts; class BrowserOnlineStateObserver; +class BrowserProcessSubThread; class BrowserThreadImpl; class LoaderDelegateImpl; class MediaStreamManager; @@ -129,10 +129,7 @@ explicit BrowserMainLoop(const MainFunctionParams& parameters); virtual ~BrowserMainLoop(); - // |service_manager_thread| is optional. If set, it will be registered as - // BrowserThread::IO in CreateThreads() instead of creating a brand new - // thread. - void Init(std::unique_ptr<BrowserProcessSubThread> service_manager_thread); + void Init(); // Return value is exit status. Anything other than RESULT_CODE_NORMAL_EXIT // is considered an error. @@ -160,6 +157,8 @@ // through stopping threads to PostDestroyThreads. void ShutdownThreadsAndCleanUp(); + void InitializeIOThreadForTesting(); + int GetResultCode() const { return result_code_; } media::AudioManager* audio_manager() const { return audio_manager_.get(); } @@ -253,6 +252,10 @@ void MainMessageLoopRun(); + // Initializes |io_thread_|. It will not be promoted to BrowserThread::IO + // until CreateThreads(). + void InitializeIOThread(); + void InitializeMojo(); void InitStartupTracingForDuration(); void EndStartupTracing();
diff --git a/content/browser/browser_main_loop_unittest.cc b/content/browser/browser_main_loop_unittest.cc index 24e38ba8..728331b 100644 --- a/content/browser/browser_main_loop_unittest.cc +++ b/content/browser/browser_main_loop_unittest.cc
@@ -29,7 +29,7 @@ *scoped_command_line.GetProcessCommandLine()); BrowserMainLoop browser_main_loop(main_function_params); browser_main_loop.MainMessageLoopStart(); - browser_main_loop.Init(nullptr); + browser_main_loop.InitializeIOThreadForTesting(); browser_main_loop.CreateThreads(); EXPECT_GE(base::TaskScheduler::GetInstance() ->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
diff --git a/content/browser/browser_main_runner_impl.cc b/content/browser/browser_main_runner_impl.cc index 6381234..8e5ef3c 100644 --- a/content/browser/browser_main_runner_impl.cc +++ b/content/browser/browser_main_runner_impl.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 "content/browser/browser_main_runner_impl.h" +#include "content/public/browser/browser_main_runner.h" #include "base/base_switches.h" #include "base/command_line.h" @@ -10,7 +10,7 @@ #include "base/debug/leak_annotations.h" #include "base/lazy_instance.h" #include "base/logging.h" -#include "base/message_loop/message_loop.h" +#include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "base/run_loop.h" #include "base/sampling_heap_profiler/sampling_heap_profiler.h" @@ -23,7 +23,6 @@ #include "components/tracing/common/trace_startup_config.h" #include "components/tracing/common/tracing_switches.h" #include "content/browser/browser_main_loop.h" -#include "content/browser/browser_process_sub_thread.h" #include "content/browser/browser_shutdown_profile_dumper.h" #include "content/browser/notification_service_impl.h" #include "content/common/content_switches_internal.h" @@ -43,208 +42,217 @@ #endif namespace content { + namespace { base::LazyInstance<base::AtomicFlag>::Leaky g_exited_main_message_loop; } // namespace -// static -BrowserMainRunnerImpl* BrowserMainRunnerImpl::Create() { - return new BrowserMainRunnerImpl(); -} +class BrowserMainRunnerImpl : public BrowserMainRunner { + public: + BrowserMainRunnerImpl() + : initialization_started_(false), is_shutdown_(false) {} -BrowserMainRunnerImpl::BrowserMainRunnerImpl() - : initialization_started_(false), is_shutdown_(false) {} + ~BrowserMainRunnerImpl() override { + if (initialization_started_ && !is_shutdown_) + Shutdown(); + } -BrowserMainRunnerImpl::~BrowserMainRunnerImpl() { - if (initialization_started_ && !is_shutdown_) - Shutdown(); -} + int Initialize(const MainFunctionParams& parameters) override { + SCOPED_UMA_HISTOGRAM_LONG_TIMER( + "Startup.BrowserMainRunnerImplInitializeLongTime"); + TRACE_EVENT0("startup", "BrowserMainRunnerImpl::Initialize"); -int BrowserMainRunnerImpl::Initialize(const MainFunctionParams& parameters) { - return Initialize(parameters, nullptr); -} + // On Android we normally initialize the browser in a series of UI thread + // tasks. While this is happening a second request can come from the OS or + // another application to start the browser. If this happens then we must + // not run these parts of initialization twice. + if (!initialization_started_) { + initialization_started_ = true; -int BrowserMainRunnerImpl::Initialize( - const MainFunctionParams& parameters, - std::unique_ptr<BrowserProcessSubThread> service_manager_thread) { - SCOPED_UMA_HISTOGRAM_LONG_TIMER( - "Startup.BrowserMainRunnerImplInitializeLongTime"); - TRACE_EVENT0("startup", "BrowserMainRunnerImpl::Initialize"); + const base::TimeTicks start_time_step1 = base::TimeTicks::Now(); - // On Android we normally initialize the browser in a series of UI thread - // tasks. While this is happening a second request can come from the OS or - // another application to start the browser. If this happens then we must - // not run these parts of initialization twice. - if (!initialization_started_) { - initialization_started_ = true; + base::SamplingHeapProfiler::InitTLSSlot(); + if (parameters.command_line.HasSwitch(switches::kSamplingHeapProfiler)) { + base::SamplingHeapProfiler* profiler = + base::SamplingHeapProfiler::GetInstance(); + unsigned sampling_interval = 0; + bool parsed = + base::StringToUint(parameters.command_line.GetSwitchValueASCII( + switches::kSamplingHeapProfiler), + &sampling_interval); + if (parsed && sampling_interval > 0) + profiler->SetSamplingInterval(sampling_interval * 1024); + profiler->Start(); + } - const base::TimeTicks start_time_step1 = base::TimeTicks::Now(); + SkGraphics::Init(); - base::SamplingHeapProfiler::InitTLSSlot(); - if (parameters.command_line.HasSwitch(switches::kSamplingHeapProfiler)) { - base::SamplingHeapProfiler* profiler = - base::SamplingHeapProfiler::GetInstance(); - unsigned sampling_interval = 0; - bool parsed = - base::StringToUint(parameters.command_line.GetSwitchValueASCII( - switches::kSamplingHeapProfiler), - &sampling_interval); - if (parsed && sampling_interval > 0) - profiler->SetSamplingInterval(sampling_interval * 1024); - profiler->Start(); - } + if (parameters.command_line.HasSwitch(switches::kWaitForDebugger)) + base::debug::WaitForDebugger(60, true); - SkGraphics::Init(); + if (parameters.command_line.HasSwitch(switches::kBrowserStartupDialog)) + WaitForDebugger("Browser"); - if (parameters.command_line.HasSwitch(switches::kWaitForDebugger)) - base::debug::WaitForDebugger(60, true); - - if (parameters.command_line.HasSwitch(switches::kBrowserStartupDialog)) - WaitForDebugger("Browser"); - - notification_service_.reset(new NotificationServiceImpl); + notification_service_.reset(new NotificationServiceImpl); #if defined(OS_WIN) - // Ole must be initialized before starting message pump, so that TSF - // (Text Services Framework) module can interact with the message pump - // on Windows 8 Metro mode. - ole_initializer_.reset(new ui::ScopedOleInitializer); - // Enable DirectWrite font rendering if needed. - gfx::win::MaybeInitializeDirectWrite(); + // Ole must be initialized before starting message pump, so that TSF + // (Text Services Framework) module can interact with the message pump + // on Windows 8 Metro mode. + ole_initializer_.reset(new ui::ScopedOleInitializer); + // Enable DirectWrite font rendering if needed. + gfx::win::MaybeInitializeDirectWrite(); #endif // OS_WIN - main_loop_.reset(new BrowserMainLoop(parameters)); + main_loop_.reset(new BrowserMainLoop(parameters)); - main_loop_->Init(std::move(service_manager_thread)); + main_loop_->Init(); - if (parameters.created_main_parts_closure) { - parameters.created_main_parts_closure->Run(main_loop_->parts()); - delete parameters.created_main_parts_closure; + if (parameters.created_main_parts_closure) { + parameters.created_main_parts_closure->Run(main_loop_->parts()); + delete parameters.created_main_parts_closure; + } + + const int early_init_error_code = main_loop_->EarlyInitialization(); + if (early_init_error_code > 0) + return early_init_error_code; + + // Must happen before we try to use a message loop or display any UI. + if (!main_loop_->InitializeToolkit()) + return 1; + + main_loop_->PreMainMessageLoopStart(); + main_loop_->MainMessageLoopStart(); + main_loop_->PostMainMessageLoopStart(); + + // WARNING: If we get a WM_ENDSESSION, objects created on the stack here + // are NOT deleted. If you need something to run during WM_ENDSESSION add + // it to browser_shutdown::Shutdown or BrowserProcess::EndSession. + + ui::InitializeInputMethod(); + UMA_HISTOGRAM_TIMES("Startup.BrowserMainRunnerImplInitializeStep1Time", + base::TimeTicks::Now() - start_time_step1); } + const base::TimeTicks start_time_step2 = base::TimeTicks::Now(); + main_loop_->CreateStartupTasks(); + int result_code = main_loop_->GetResultCode(); + if (result_code > 0) + return result_code; - const int early_init_error_code = main_loop_->EarlyInitialization(); - if (early_init_error_code > 0) - return early_init_error_code; + UMA_HISTOGRAM_TIMES("Startup.BrowserMainRunnerImplInitializeStep2Time", + base::TimeTicks::Now() - start_time_step2); - // Must happen before we try to use a message loop or display any UI. - if (!main_loop_->InitializeToolkit()) - return 1; - - main_loop_->PreMainMessageLoopStart(); - main_loop_->MainMessageLoopStart(); - main_loop_->PostMainMessageLoopStart(); - - // WARNING: If we get a WM_ENDSESSION, objects created on the stack here - // are NOT deleted. If you need something to run during WM_ENDSESSION add it - // to browser_shutdown::Shutdown or BrowserProcess::EndSession. - - ui::InitializeInputMethod(); - UMA_HISTOGRAM_TIMES("Startup.BrowserMainRunnerImplInitializeStep1Time", - base::TimeTicks::Now() - start_time_step1); + // Return -1 to indicate no early termination. + return -1; } - const base::TimeTicks start_time_step2 = base::TimeTicks::Now(); - main_loop_->CreateStartupTasks(); - int result_code = main_loop_->GetResultCode(); - if (result_code > 0) - return result_code; - - UMA_HISTOGRAM_TIMES("Startup.BrowserMainRunnerImplInitializeStep2Time", - base::TimeTicks::Now() - start_time_step2); - - // Return -1 to indicate no early termination. - return -1; -} #if defined(OS_ANDROID) -void BrowserMainRunnerImpl::SynchronouslyFlushStartupTasks() { - main_loop_->SynchronouslyFlushStartupTasks(); -} + void SynchronouslyFlushStartupTasks() override { + main_loop_->SynchronouslyFlushStartupTasks(); + } #endif -int BrowserMainRunnerImpl::Run() { - DCHECK(initialization_started_); - DCHECK(!is_shutdown_); - main_loop_->RunMainMessageLoopParts(); - return main_loop_->GetResultCode(); -} + int Run() override { + DCHECK(initialization_started_); + DCHECK(!is_shutdown_); + main_loop_->RunMainMessageLoopParts(); + return main_loop_->GetResultCode(); + } -void BrowserMainRunnerImpl::Shutdown() { - DCHECK(initialization_started_); - DCHECK(!is_shutdown_); + void Shutdown() override { + DCHECK(initialization_started_); + DCHECK(!is_shutdown_); #ifdef LEAK_SANITIZER - // Invoke leak detection now, to avoid dealing with shutdown-only leaks. - // Normally this will have already happened in - // BroserProcessImpl::ReleaseModule(), so this call has no effect. This is - // only for processes which do not instantiate a BrowserProcess. - // If leaks are found, the process will exit here. - __lsan_do_leak_check(); + // Invoke leak detection now, to avoid dealing with shutdown-only leaks. + // Normally this will have already happened in + // BroserProcessImpl::ReleaseModule(), so this call has no effect. This is + // only for processes which do not instantiate a BrowserProcess. + // If leaks are found, the process will exit here. + __lsan_do_leak_check(); #endif - main_loop_->PreShutdown(); + main_loop_->PreShutdown(); - // If startup tracing has not been finished yet, replace it's dumper - // with special version, which would save trace file on exit (i.e. - // startup tracing becomes a version of shutdown tracing). - // There are two cases: - // 1. Startup duration is not reached. - // 2. Or startup duration is not specified for --trace-config-file flag. - std::unique_ptr<BrowserShutdownProfileDumper> startup_profiler; - if (tracing::TraceStartupConfig::GetInstance() - ->IsTracingStartupForDuration()) { - main_loop_->StopStartupTracingTimer(); - if (main_loop_->startup_trace_file() != - base::FilePath().AppendASCII("none")) { - startup_profiler.reset( - new BrowserShutdownProfileDumper(main_loop_->startup_trace_file())); + // If startup tracing has not been finished yet, replace it's dumper + // with special version, which would save trace file on exit (i.e. + // startup tracing becomes a version of shutdown tracing). + // There are two cases: + // 1. Startup duration is not reached. + // 2. Or startup duration is not specified for --trace-config-file flag. + std::unique_ptr<BrowserShutdownProfileDumper> startup_profiler; + if (tracing::TraceStartupConfig::GetInstance() + ->IsTracingStartupForDuration()) { + main_loop_->StopStartupTracingTimer(); + if (main_loop_->startup_trace_file() != + base::FilePath().AppendASCII("none")) { + startup_profiler.reset( + new BrowserShutdownProfileDumper(main_loop_->startup_trace_file())); + } + } else if (tracing::TraceStartupConfig::GetInstance()->IsEnabled()) { + base::FilePath result_file = main_loop_->GetStartupTraceFileName(); + startup_profiler.reset(new BrowserShutdownProfileDumper(result_file)); } - } else if (tracing::TraceStartupConfig::GetInstance()->IsEnabled()) { - base::FilePath result_file = main_loop_->GetStartupTraceFileName(); - startup_profiler.reset(new BrowserShutdownProfileDumper(result_file)); - } - // The shutdown tracing got enabled in AttemptUserExit earlier, but someone - // needs to write the result to disc. For that a dumper needs to get created - // which will dump the traces to disc when it gets destroyed. - const base::CommandLine& command_line = - *base::CommandLine::ForCurrentProcess(); - std::unique_ptr<BrowserShutdownProfileDumper> shutdown_profiler; - if (command_line.HasSwitch(switches::kTraceShutdown)) { - shutdown_profiler.reset(new BrowserShutdownProfileDumper( - BrowserShutdownProfileDumper::GetShutdownProfileFileName())); - } + // The shutdown tracing got enabled in AttemptUserExit earlier, but someone + // needs to write the result to disc. For that a dumper needs to get created + // which will dump the traces to disc when it gets destroyed. + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + std::unique_ptr<BrowserShutdownProfileDumper> shutdown_profiler; + if (command_line.HasSwitch(switches::kTraceShutdown)) { + shutdown_profiler.reset(new BrowserShutdownProfileDumper( + BrowserShutdownProfileDumper::GetShutdownProfileFileName())); + } - { - // The trace event has to stay between profiler creation and destruction. - TRACE_EVENT0("shutdown", "BrowserMainRunner"); - g_exited_main_message_loop.Get().Set(); + { + // The trace event has to stay between profiler creation and destruction. + TRACE_EVENT0("shutdown", "BrowserMainRunner"); + g_exited_main_message_loop.Get().Set(); - main_loop_->ShutdownThreadsAndCleanUp(); + main_loop_->ShutdownThreadsAndCleanUp(); - ui::ShutdownInputMethod(); + ui::ShutdownInputMethod(); #if defined(OS_WIN) - ole_initializer_.reset(NULL); + ole_initializer_.reset(NULL); #endif #if defined(OS_ANDROID) - // Forcefully terminates the RunLoop inside MessagePumpForUI, ensuring - // proper shutdown for content_browsertests. Shutdown() is not used by - // the actual browser. - if (base::RunLoop::IsRunningOnCurrentThread()) - base::RunLoop::QuitCurrentDeprecated(); + // Forcefully terminates the RunLoop inside MessagePumpForUI, ensuring + // proper shutdown for content_browsertests. Shutdown() is not used by + // the actual browser. + if (base::RunLoop::IsRunningOnCurrentThread()) + base::RunLoop::QuitCurrentDeprecated(); #endif - main_loop_.reset(nullptr); + main_loop_.reset(nullptr); - notification_service_.reset(nullptr); + notification_service_.reset(nullptr); - is_shutdown_ = true; + is_shutdown_ = true; + } } -} + + protected: + // True if we have started to initialize the runner. + bool initialization_started_; + + // True if the runner has been shut down. + bool is_shutdown_; + + std::unique_ptr<NotificationServiceImpl> notification_service_; + std::unique_ptr<BrowserMainLoop> main_loop_; +#if defined(OS_WIN) + std::unique_ptr<ui::ScopedOleInitializer> ole_initializer_; +#endif + + private: + DISALLOW_COPY_AND_ASSIGN(BrowserMainRunnerImpl); +}; // static BrowserMainRunner* BrowserMainRunner::Create() { - return BrowserMainRunnerImpl::Create(); + return new BrowserMainRunnerImpl(); } // static
diff --git a/content/browser/browser_main_runner_impl.h b/content/browser/browser_main_runner_impl.h deleted file mode 100644 index adb084f..0000000 --- a/content/browser/browser_main_runner_impl.h +++ /dev/null
@@ -1,65 +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 CONTENT_BROWSER_BROWSER_MAIN_RUNNER_IMPL_H_ -#define CONTENT_BROWSER_BROWSER_MAIN_RUNNER_IMPL_H_ - -#include <memory> - -#include "base/macros.h" -#include "build/build_config.h" -#include "content/public/browser/browser_main_runner.h" - -#if defined(OS_WIN) -namespace ui { -class ScopedOleInitializer; -} -#endif - -namespace content { - -class BrowserProcessSubThread; -class BrowserMainLoop; -class NotificationServiceImpl; - -class BrowserMainRunnerImpl : public BrowserMainRunner { - public: - static BrowserMainRunnerImpl* Create(); - - BrowserMainRunnerImpl(); - ~BrowserMainRunnerImpl() override; - - // BrowserMainRunner: - int Initialize(const MainFunctionParams& parameters) override; -#if defined(OS_ANDROID) - void SynchronouslyFlushStartupTasks() override; -#endif - int Run() override; - void Shutdown() override; - - // Initialize all necessary browser state with a |service_manager_thread| - // on which ServiceManager is currently running. - int Initialize( - const MainFunctionParams& parameters, - std::unique_ptr<BrowserProcessSubThread> service_manager_thread); - - private: - // True if we have started to initialize the runner. - bool initialization_started_; - - // True if the runner has been shut down. - bool is_shutdown_; - - std::unique_ptr<NotificationServiceImpl> notification_service_; - std::unique_ptr<BrowserMainLoop> main_loop_; -#if defined(OS_WIN) - std::unique_ptr<ui::ScopedOleInitializer> ole_initializer_; -#endif - - DISALLOW_COPY_AND_ASSIGN(BrowserMainRunnerImpl); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_BROWSER_MAIN_RUNNER_IMPL_H_
diff --git a/content/browser/browser_process_sub_thread.cc b/content/browser/browser_process_sub_thread.cc index edc608a..0902fb6 100644 --- a/content/browser/browser_process_sub_thread.cc +++ b/content/browser/browser_process_sub_thread.cc
@@ -70,24 +70,6 @@ is_blocking_allowed_for_testing_ = true; } -// static -std::unique_ptr<BrowserProcessSubThread> -BrowserProcessSubThread::CreateIOThread() { - TRACE_EVENT0("startup", "BrowserProcessSubThread::CreateIOThread"); - base::Thread::Options options; - options.message_loop_type = base::MessageLoop::TYPE_IO; -#if defined(OS_ANDROID) || defined(OS_CHROMEOS) - // Up the priority of the |io_thread_| as some of its IPCs relate to - // display tasks. - options.priority = base::ThreadPriority::DISPLAY; -#endif - std::unique_ptr<BrowserProcessSubThread> io_thread( - new BrowserProcessSubThread(BrowserThread::IO)); - if (!io_thread->StartWithOptions(options)) - LOG(FATAL) << "Failed to start BrowserThread:IO"; - return io_thread; -} - void BrowserProcessSubThread::Init() { DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_);
diff --git a/content/browser/browser_process_sub_thread.h b/content/browser/browser_process_sub_thread.h index edc2238..f4b8799 100644 --- a/content/browser/browser_process_sub_thread.h +++ b/content/browser/browser_process_sub_thread.h
@@ -53,10 +53,6 @@ // starting this BrowserProcessSubThread. void AllowBlockingForTesting(); - // Creates and starts the IO thread. It should not be promoted to - // BrowserThread::IO until BrowserMainLoop::CreateThreads(). - static std::unique_ptr<BrowserProcessSubThread> CreateIOThread(); - protected: void Init() override; void Run(base::RunLoop* run_loop) override;
diff --git a/content/browser/cookie_store/BUILD.gn b/content/browser/cookie_store/BUILD.gn new file mode 100644 index 0000000..d5dbdd7 --- /dev/null +++ b/content/browser/cookie_store/BUILD.gn
@@ -0,0 +1,11 @@ +# 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. + +import("//third_party/protobuf/proto_library.gni") + +proto_library("cookie_store_proto") { + sources = [ + "cookie_change_subscriptions.proto", + ] +}
diff --git a/content/browser/cookie_store/OWNERS b/content/browser/cookie_store/OWNERS new file mode 100644 index 0000000..b23c10fd --- /dev/null +++ b/content/browser/cookie_store/OWNERS
@@ -0,0 +1,8 @@ +# Primary +pwnall@chromium.org + +# Secondary +jsbell@chromium.org + +# TEAM: storage-dev@chromium.org +# COMPONENT: Blink>Storage>CookiesAPI
diff --git a/content/browser/cookie_store/cookie_change_subscription.cc b/content/browser/cookie_store/cookie_change_subscription.cc new file mode 100644 index 0000000..78c4101 --- /dev/null +++ b/content/browser/cookie_store/cookie_change_subscription.cc
@@ -0,0 +1,182 @@ +// 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 "content/browser/cookie_store/cookie_change_subscription.h" + +#include <utility> + +#include "content/browser/cookie_store/cookie_change_subscriptions.pb.h" + +namespace content { + +namespace { + +#define STATIC_ASSERT_ENUM(a, b) \ + static_assert(static_cast<int>(a) == static_cast<int>(b), \ + "mismatching enums: " #a) + +STATIC_ASSERT_ENUM(network::mojom::CookieMatchType::EQUALS, + proto::CookieMatchType::EQUALS); +STATIC_ASSERT_ENUM(network::mojom::CookieMatchType::STARTS_WITH, + proto::CookieMatchType::STARTS_WITH); + +proto::CookieMatchType CookieMatchTypeToProto( + network::mojom::CookieMatchType match_type) { + switch (match_type) { + case network::mojom::CookieMatchType::EQUALS: + return proto::CookieMatchType::EQUALS; + case ::network::mojom::CookieMatchType::STARTS_WITH: + return proto::CookieMatchType::STARTS_WITH; + } + NOTREACHED(); + return proto::CookieMatchType::EQUALS; +} + +network::mojom::CookieMatchType CookieMatchTypeFromProto( + proto::CookieMatchType match_type_proto) { + switch (match_type_proto) { + case proto::CookieMatchType::EQUALS: + return network::mojom::CookieMatchType::EQUALS; + case proto::CookieMatchType::STARTS_WITH: + return ::network::mojom::CookieMatchType::STARTS_WITH; + } + NOTREACHED(); + return network::mojom::CookieMatchType::EQUALS; +} + +} // namespace + +// static +base::Optional<std::vector<CookieChangeSubscription>> +CookieChangeSubscription::DeserializeVector( + const std::string& proto_string, + int64_t service_worker_registration_id) { + proto::CookieChangeSubscriptionsProto subscriptions_proto; + if (!subscriptions_proto.ParseFromString(proto_string)) + return base::nullopt; + + std::vector<CookieChangeSubscription> subscriptions; + int subscription_count = subscriptions_proto.subscriptions_size(); + subscriptions.reserve(subscription_count); + for (int i = 0; i < subscription_count; ++i) { + base::Optional<CookieChangeSubscription> subscription_opt = + CookieChangeSubscription::Create(subscriptions_proto.subscriptions(i), + service_worker_registration_id); + if (!subscription_opt.has_value()) + continue; + subscriptions.emplace_back(std::move(subscription_opt).value()); + } + + return base::make_optional( + std::vector<CookieChangeSubscription>(std::move(subscriptions))); +} + +// static +std::vector<CookieChangeSubscription> CookieChangeSubscription::FromMojoVector( + std::vector<blink::mojom::CookieChangeSubscriptionPtr> mojo_subscriptions, + int64_t service_worker_registration_id) { + std::vector<CookieChangeSubscription> subscriptions; + subscriptions.reserve(mojo_subscriptions.size()); + for (const auto& mojo_subscription : mojo_subscriptions) { + subscriptions.emplace_back( + std::move(mojo_subscription->url), std::move(mojo_subscription->name), + mojo_subscription->match_type, service_worker_registration_id); + } + return subscriptions; +} + +// static +std::string CookieChangeSubscription::SerializeVector( + const std::vector<CookieChangeSubscription>& subscriptions) { + proto::CookieChangeSubscriptionsProto subscriptions_proto; + for (const auto& subscription : subscriptions) + subscription.Serialize(subscriptions_proto.add_subscriptions()); + return subscriptions_proto.SerializeAsString(); +} + +// static +std::vector<blink::mojom::CookieChangeSubscriptionPtr> +CookieChangeSubscription::ToMojoVector( + const std::vector<CookieChangeSubscription>& subscriptions) { + std::vector<blink::mojom::CookieChangeSubscriptionPtr> mojo_subscriptions; + mojo_subscriptions.reserve(subscriptions.size()); + for (const auto& subscription : subscriptions) { + auto mojo_subscription = blink::mojom::CookieChangeSubscription::New(); + subscription.Serialize(mojo_subscription.get()); + mojo_subscriptions.emplace_back(std::move(mojo_subscription)); + } + return mojo_subscriptions; +} + +// static +base::Optional<CookieChangeSubscription> CookieChangeSubscription::Create( + proto::CookieChangeSubscriptionProto proto, + int64_t service_worker_registration_id) { + if (!proto.has_url()) + return base::nullopt; + GURL url = GURL(proto.url()); + if (!url.is_valid()) + return base::nullopt; + + std::string name = proto.has_name() ? proto.name() : ""; + ::network::mojom::CookieMatchType match_type = + proto.has_match_type() ? CookieMatchTypeFromProto(proto.match_type()) + : ::network::mojom::CookieMatchType::EQUALS; + + return CookieChangeSubscription(std::move(url), std::move(name), match_type, + service_worker_registration_id); +} + +CookieChangeSubscription::CookieChangeSubscription(CookieChangeSubscription&&) = + default; + +CookieChangeSubscription::~CookieChangeSubscription() = default; + +CookieChangeSubscription::CookieChangeSubscription( + GURL url, + std::string name, + ::network::mojom::CookieMatchType match_type, + int64_t service_worker_registration_id) + : url_(std::move(url)), + name_(std::move(name)), + match_type_(match_type), + service_worker_registration_id_(service_worker_registration_id) {} + +void CookieChangeSubscription::Serialize( + proto::CookieChangeSubscriptionProto* proto) const { + proto->set_match_type(CookieMatchTypeToProto(match_type_)); + proto->set_name(name_); + proto->set_url(url_.spec()); +} + +void CookieChangeSubscription::Serialize( + blink::mojom::CookieChangeSubscription* mojo_subscription) const { + mojo_subscription->url = url_; + mojo_subscription->name = name_; + mojo_subscription->match_type = match_type_; +} + +bool CookieChangeSubscription::ShouldObserveChangeTo( + const net::CanonicalCookie& cookie) const { + switch (match_type_) { + case ::network::mojom::CookieMatchType::EQUALS: + if (cookie.Name() != name_) + return false; + break; + case ::network::mojom::CookieMatchType::STARTS_WITH: + if (!base::StartsWith(cookie.Name(), name_, base::CompareCase::SENSITIVE)) + return false; + break; + } + + net::CookieOptions net_options; + net_options.set_same_site_cookie_mode( + net::CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX); + if (!cookie.IncludeForRequestURL(url_, net_options)) + return false; + + return true; +} + +} // namespace content
diff --git a/content/browser/cookie_store/cookie_change_subscription.h b/content/browser/cookie_store/cookie_change_subscription.h new file mode 100644 index 0000000..c2c4839 --- /dev/null +++ b/content/browser/cookie_store/cookie_change_subscription.h
@@ -0,0 +1,114 @@ +// 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 CONTENT_BROWSER_COOKIE_STORE_COOKIE_CHANGE_SUBSCRIPTION_H_ +#define CONTENT_BROWSER_COOKIE_STORE_COOKIE_CHANGE_SUBSCRIPTION_H_ + +#include <memory> +#include <string> + +#include "base/containers/linked_list.h" +#include "base/macros.h" +#include "base/optional.h" +#include "third_party/blink/public/mojom/cookie_store/cookie_store.mojom.h" +#include "url/gurl.h" + +namespace content { + +namespace proto { + +class CookieChangeSubscriptionProto; + +} // namespace proto + +// Represents a single subscription to the list of cookies sent to a URL. +// +// The included linked list node and service worker registration ID are used by +// CookieStoreManager. +class CookieChangeSubscription + : public base::LinkNode<CookieChangeSubscription> { + public: + // Used to read a service worker's subscriptions from the persistent store. + static base::Optional<std::vector<CookieChangeSubscription>> + DeserializeVector(const std::string& proto_string, + int64_t service_worker_registration_id); + + // Converts subscriptions from a Mojo API call. + static std::vector<CookieChangeSubscription> FromMojoVector( + std::vector<blink::mojom::CookieChangeSubscriptionPtr> mojo_subscriptions, + int64_t service_worker_registration_id); + + // Used to write a service worker's subscriptions to the service worker store. + // + // Returns the empty string in case of a serialization error. + static std::string SerializeVector( + const std::vector<CookieChangeSubscription>&); + + // Converts a service worker's subscriptions to a Mojo API call result. + static std::vector<blink::mojom::CookieChangeSubscriptionPtr> ToMojoVector( + const std::vector<CookieChangeSubscription>&); + + // Public for testing. + // + // Production code should use the vector-based factory methods above. + static base::Optional<CookieChangeSubscription> Create( + proto::CookieChangeSubscriptionProto proto, + int64_t service_worker_registration_id); + + // Public for testing. + // + // Production code should use the vector-based factory methods above. + CookieChangeSubscription(GURL url, + std::string name, + ::network::mojom::CookieMatchType match_type, + int64_t service_worker_registration_id); + + // LinkNode supports move-construction, but not move assignment. + CookieChangeSubscription(CookieChangeSubscription&&); + CookieChangeSubscription& operator=(CookieChangeSubscription&&) = delete; + + ~CookieChangeSubscription(); + + // The URL whose cookie list is watched for changes. + const GURL& url() const { return url_; } + + // Operator for name-based matching. + // + // This is used to implement both equality and prefix-based name matching. + // Supporting the latter helps avoid wasting battery by waking up service + // workers unnecessarily. + ::network::mojom::CookieMatchType match_type() const { return match_type_; } + + // Operand for the name-based matching operator above. + // + // For EQUAL matching, the cookie name must precisely match name(). For + // STARTS_WITH matching, the cookie name must be prefixed by name(). + const std::string& name() const { return name_; } + + // The service worker registration that this subscription belongs to. + int64_t service_worker_registration_id() const { + return service_worker_registration_id_; + } + + // Writes the subscription to the given protobuf. + void Serialize(proto::CookieChangeSubscriptionProto* proto) const; + // Writes the subscription to the given Mojo object. + void Serialize( + blink::mojom::CookieChangeSubscription* mojo_subscription) const; + + // True if the subscription covers a change to the given cookie. + bool ShouldObserveChangeTo(const net::CanonicalCookie& cookie) const; + + private: + const GURL url_; + const std::string name_; + const ::network::mojom::CookieMatchType match_type_; + const int64_t service_worker_registration_id_; + + DISALLOW_COPY_AND_ASSIGN(CookieChangeSubscription); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_COOKIE_STORE_COOKIE_CHANGE_SUBSCRIPTION_H_
diff --git a/content/browser/cookie_store/cookie_change_subscriptions.proto b/content/browser/cookie_store/cookie_change_subscriptions.proto new file mode 100644 index 0000000..4ee027f --- /dev/null +++ b/content/browser/cookie_store/cookie_change_subscriptions.proto
@@ -0,0 +1,27 @@ +// 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. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package content.proto; + +// Proto equivalent of network::mojom::CookieMatchType. Values must match. +enum CookieMatchType { + EQUALS = 0; + STARTS_WITH = 1; +} + +// A single cookie change subscription. +message CookieChangeSubscriptionProto { + required string url = 1; + optional string name = 2; + optional CookieMatchType match_type = 3; +} + +// All cookie change subscriptions belonging to a service worker registration. +message CookieChangeSubscriptionsProto { + repeated CookieChangeSubscriptionProto subscriptions = 1; +}
diff --git a/content/browser/cookie_store/cookie_store_context.cc b/content/browser/cookie_store/cookie_store_context.cc new file mode 100644 index 0000000..eeea0d0 --- /dev/null +++ b/content/browser/cookie_store/cookie_store_context.cc
@@ -0,0 +1,117 @@ +// 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 "content/browser/cookie_store/cookie_store_context.h" + +#include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/storage_partition.h" + +namespace content { + +CookieStoreContext::CookieStoreContext() + : base::RefCountedDeleteOnSequence<CookieStoreContext>( + BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)) {} + +CookieStoreContext::~CookieStoreContext() { + // The destructor must be called on the IO thread, because it runs + // cookie_store_manager_'s destructor, and the latter is only accessed on the + // IO thread. + DCHECK_CURRENTLY_ON(BrowserThread::IO); +} + +void CookieStoreContext::Initialize( + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context, + base::OnceCallback<void(bool)> callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +#if DCHECK_IS_ON() + DCHECK(!initialize_called_) << __func__ << " called twice"; + initialize_called_ = true; +#endif // DCHECK_IS_ON() + + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::BindOnce( + &CookieStoreContext::InitializeOnIOThread, this, + std::move(service_worker_context), + base::BindOnce( + [](scoped_refptr<base::SequencedTaskRunner> task_runner, + base::OnceCallback<void(bool)> callback, bool result) { + task_runner->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), result)); + }, + base::SequencedTaskRunnerHandle::Get(), std::move(callback)))); +} + +void CookieStoreContext::ListenToCookieChanges( + ::network::mojom::NetworkContext* network_context, + base::OnceCallback<void(bool)> callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +#if DCHECK_IS_ON() + DCHECK(initialize_called_) << __func__ << " called before Initialize()"; +#endif // DCHECK_IS_ON() + + ::network::mojom::CookieManagerPtrInfo cookie_manager_ptr_info; + network_context->GetCookieManager( + mojo::MakeRequest(&cookie_manager_ptr_info)); + + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::BindOnce( + &CookieStoreContext::ListenToCookieChangesOnIOThread, this, + std::move(cookie_manager_ptr_info), + base::BindOnce( + [](scoped_refptr<base::SequencedTaskRunner> task_runner, + base::OnceCallback<void(bool)> callback, bool result) { + task_runner->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), result)); + }, + base::SequencedTaskRunnerHandle::Get(), std::move(callback)))); +} + +void CookieStoreContext::CreateService(blink::mojom::CookieStoreRequest request, + const url::Origin& origin) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +#if DCHECK_IS_ON() + DCHECK(initialize_called_) << __func__ << " called before Initialize()"; +#endif // DCHECK_IS_ON() + + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::BindOnce(&CookieStoreContext::CreateServiceOnIOThread, this, + std::move(request), origin)); +} + +void CookieStoreContext::InitializeOnIOThread( + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context, + base::OnceCallback<void(bool)> callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(!cookie_store_manager_) << __func__ << " called more than once"; + + cookie_store_manager_ = + std::make_unique<CookieStoreManager>(std::move(service_worker_context)); + cookie_store_manager_->LoadAllSubscriptions(std::move(callback)); +} + +void CookieStoreContext::ListenToCookieChangesOnIOThread( + ::network::mojom::CookieManagerPtrInfo cookie_manager_ptr_info, + base::OnceCallback<void(bool)> callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(cookie_store_manager_); + + cookie_store_manager_->ListenToCookieChanges( + ::network::mojom::CookieManagerPtr(std::move(cookie_manager_ptr_info)), + std::move(callback)); +} + +void CookieStoreContext::CreateServiceOnIOThread( + blink::mojom::CookieStoreRequest request, + const url::Origin& origin) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(cookie_store_manager_); + + cookie_store_manager_->CreateService(std::move(request), origin); +} + +} // namespace content
diff --git a/content/browser/cookie_store/cookie_store_context.h b/content/browser/cookie_store/cookie_store_context.h new file mode 100644 index 0000000..0317b9f0 --- /dev/null +++ b/content/browser/cookie_store/cookie_store_context.h
@@ -0,0 +1,98 @@ +// 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 CONTENT_BROWSER_COOKIE_STORE_COOKIE_STORE_CONTEXT_H_ +#define CONTENT_BROWSER_COOKIE_STORE_COOKIE_STORE_CONTEXT_H_ + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ref_counted_delete_on_sequence.h" +#include "base/memory/scoped_refptr.h" +#include "content/browser/cookie_store/cookie_store_manager.h" +#include "content/common/content_export.h" +#include "services/network/public/mojom/network_service.mojom.h" +#include "third_party/blink/public/mojom/cookie_store/cookie_store.mojom.h" +#include "url/origin.h" + +namespace content { + +class CookieStoreManager; +class ServiceWorkerContextWrapper; + +// UI thread handle to a CookieStoreManager. +// +// This class is RefCountedDeleteOnSequence because it has members that must be +// accessed on the IO thread, and therefore must be destroyed on the IO thread. +// Conceptually, CookieStoreContext instances are owned by StoragePartitionImpl. +class CONTENT_EXPORT CookieStoreContext + : public base::RefCountedDeleteOnSequence<CookieStoreContext> { + public: + REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE(); + + // Creates an empty CookieStoreContext shell. + // + // Newly created instances must be initialized via Initialize() before any + // other methods are used. + CookieStoreContext(); + + // Creates the underlying CookieStoreManager. + // + // This must be called before any other CookieStoreContext method. + // + // The newly created CookieStoreManager starts loading any persisted cookie + // change subscriptions from ServiceWorkerStorage. When the loading completes, + // the given callback is called with a boolean indicating whether the loading + // succeeded. + // + // It is safe to call all the other methods during the loading operation. This + // includes creating and using CookieStore mojo services. The + // CookieStoreManager has well-defined semantics if loading from + // ServiceWorkerStorage fails, so the caller does not need to handle loading + // errors. + void Initialize( + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context, + base::OnceCallback<void(bool)> callback); + + // Starts listening to cookie changes from a network service instance. + // + // The callback is called with the (success / failure) result of subscribing. + void ListenToCookieChanges(::network::mojom::NetworkContext* network_context, + base::OnceCallback<void(bool)> callback); + + // Routes a mojo request to the CookieStoreManager on the IO thread. + void CreateService(blink::mojom::CookieStoreRequest request, + const url::Origin& origin); + + private: + friend class base::RefCountedDeleteOnSequence<CookieStoreContext>; + friend class base::DeleteHelper<CookieStoreContext>; + ~CookieStoreContext(); + + void InitializeOnIOThread( + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context, + base::OnceCallback<void(bool)> callback); + + void ListenToCookieChangesOnIOThread( + ::network::mojom::CookieManagerPtrInfo cookie_manager_ptr_info, + base::OnceCallback<void(bool)> callback); + + void CreateServiceOnIOThread(blink::mojom::CookieStoreRequest request, + const url::Origin& origin); + + // Only accessed on the IO thread. + std::unique_ptr<CookieStoreManager> cookie_store_manager_; + +#if DCHECK_IS_ON() + // Only accesssed on the UI thread. + bool initialize_called_ = false; +#endif // DCHECK_IS_ON() + + SEQUENCE_CHECKER(sequence_checker_); + + DISALLOW_COPY_AND_ASSIGN(CookieStoreContext); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_COOKIE_STORE_COOKIE_STORE_CONTEXT_H_
diff --git a/content/browser/cookie_store/cookie_store_host.cc b/content/browser/cookie_store/cookie_store_host.cc new file mode 100644 index 0000000..69e85466 --- /dev/null +++ b/content/browser/cookie_store/cookie_store_host.cc
@@ -0,0 +1,38 @@ +// 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 "content/browser/cookie_store/cookie_store_host.h" + +#include <utility> + +#include "content/browser/cookie_store/cookie_store_manager.h" +#include "url/origin.h" + +namespace content { + +CookieStoreHost::CookieStoreHost(CookieStoreManager* manager, + const url::Origin& origin) + : manager_(manager), origin_(origin.GetURL()) {} + +CookieStoreHost::~CookieStoreHost() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} + +void CookieStoreHost::AppendSubscriptions( + int64_t service_worker_registration_id, + std::vector<blink::mojom::CookieChangeSubscriptionPtr> subscriptions, + AppendSubscriptionsCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + manager_->AppendSubscriptions(service_worker_registration_id, origin_, + std::move(subscriptions), std::move(callback)); +} + +void CookieStoreHost::GetSubscriptions(int64_t service_worker_registration_id, + GetSubscriptionsCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + manager_->GetSubscriptions(service_worker_registration_id, origin_, + std::move(callback)); +} + +} // namespace content
diff --git a/content/browser/cookie_store/cookie_store_host.h b/content/browser/cookie_store/cookie_store_host.h new file mode 100644 index 0000000..e4e04f6 --- /dev/null +++ b/content/browser/cookie_store/cookie_store_host.h
@@ -0,0 +1,65 @@ +// 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 CONTENT_BROWSER_COOKIE_STORE_COOKIE_STORE_HOST_H_ +#define CONTENT_BROWSER_COOKIE_STORE_COOKIE_STORE_HOST_H_ + +#include <vector> + +#include "base/macros.h" +#include "base/sequence_checker.h" +#include "third_party/blink/public/mojom/cookie_store/cookie_store.mojom.h" +#include "url/gurl.h" + +namespace url { + +class Origin; + +} // namespace url + +namespace content { + +class CookieStoreManager; + +// Stores the state associated with each CookieStore mojo connection. +// +// The bulk of the CookieStore implementation is in the CookieStoreManager +// class. Each StoragePartition has a single associated CookieStoreManager +// instance. By contrast, each CookieStore mojo connection has an associated +// CoookieStoreHost instance, which stores the per-connection state. +// +// Instances of this class must be accessed exclusively on the IO thread, +// because they call into CookieStoreManager directly. +class CookieStoreHost : public blink::mojom::CookieStore { + public: + CookieStoreHost(CookieStoreManager* manager, const url::Origin& origin); + ~CookieStoreHost() override; + + // content::mojom::CookieStore + void AppendSubscriptions( + int64_t service_worker_registration_id, + std::vector<blink::mojom::CookieChangeSubscriptionPtr>, + AppendSubscriptionsCallback callback) override; + void GetSubscriptions(int64_t service_worker_registration_id, + GetSubscriptionsCallback callback) override; + + private: + // The raw pointer is safe because CookieStoreManager owns this instance via a + // mojo::BindingSet. + CookieStoreManager* const manager_; + + const GURL origin_; + + // Instances of this class are currently bound to the IO thread, because they + // call ServiceWorkerContextWrapper methods that are restricted to the IO + // thread. However, the class implementation itself is thread-friendly, so it + // only checks that methods are called on the same sequence. + SEQUENCE_CHECKER(sequence_checker_); + + DISALLOW_COPY_AND_ASSIGN(CookieStoreHost); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_COOKIE_STORE_COOKIE_STORE_HOST_H_
diff --git a/content/browser/cookie_store/cookie_store_manager.cc b/content/browser/cookie_store/cookie_store_manager.cc new file mode 100644 index 0000000..b1153cf --- /dev/null +++ b/content/browser/cookie_store/cookie_store_manager.cc
@@ -0,0 +1,505 @@ +// 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 "content/browser/cookie_store/cookie_store_manager.h" + +#include <utility> + +#include "base/optional.h" +#include "content/browser/cookie_store/cookie_change_subscriptions.pb.h" +#include "content/browser/service_worker/embedded_worker_status.h" +#include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/browser/service_worker/service_worker_metrics.h" +#include "content/browser/service_worker/service_worker_registration.h" +#include "content/browser/service_worker/service_worker_version.h" +#include "content/common/service_worker/service_worker_status_code.h" +#include "content/public/browser/browser_context.h" +#include "net/base/registry_controlled_domains/registry_controlled_domain.h" +#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h" +#include "url/gurl.h" + +namespace content { + +namespace { + +// ServiceWorkerStorage user data key for cookie change subscriptions. +const char kSubscriptionsUserKey[] = "cookie_store_subscriptions"; + +// Handles the result of ServiceWorkerContextWrapper::StoreRegistrationUserData. +void HandleStoreRegistrationUserDataStatus(ServiceWorkerStatusCode status) { + // The current implementation does not have a good way to handle errors in + // StoreRegistrationUserData. Cookie change subscriptions have been added to + // the registration during the install event, so it's too late to surface the + // error to the renderer. The registration has already been persisted, and the + // Service Worker is likely active by now. + DLOG_IF(ERROR, status != SERVICE_WORKER_OK) + << "StoreRegistrationUserData failed"; +} + +} // namespace + +CookieStoreManager::CookieStoreManager( + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context) + : service_worker_context_(std::move(service_worker_context)), + cookie_change_listener_binding_(this), + registration_user_data_key_(kSubscriptionsUserKey), + weak_factory_(this) { + service_worker_context_->AddObserver(this); +} + +CookieStoreManager::~CookieStoreManager() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + service_worker_context_->RemoveObserver(this); +} + +void CookieStoreManager::CreateService(blink::mojom::CookieStoreRequest request, + const url::Origin& origin) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + bindings_.AddBinding(std::make_unique<CookieStoreHost>(this, origin), + std::move(request)); +} + +void CookieStoreManager::LoadAllSubscriptions( + base::OnceCallback<void(bool)> callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + DCHECK(!done_loading_subscriptions_) << __func__ << " already called"; + + service_worker_context_->GetUserDataForAllRegistrations( + registration_user_data_key_, + base::BindOnce(&CookieStoreManager::ProcessOnDiskSubscriptions, + weak_factory_.GetWeakPtr(), std::move(callback))); +} + +void CookieStoreManager::ListenToCookieChanges( + ::network::mojom::CookieManagerPtr cookie_manager, + base::OnceCallback<void(bool)> callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + DCHECK(!cookie_manager_) << __func__ << " already called"; + cookie_manager_ = std::move(cookie_manager); + + DCHECK(!cookie_change_listener_binding_.is_bound()); + ::network::mojom::CookieChangeListenerPtr cookie_change_listener; + cookie_change_listener_binding_.Bind( + mojo::MakeRequest(&cookie_change_listener)); + + // TODO(pwnall): Switch to an API with subscription confirmation. + cookie_manager_->AddGlobalChangeListener(std::move(cookie_change_listener)); + std::move(callback).Run(true); +} + +void CookieStoreManager::ProcessOnDiskSubscriptions( + base::OnceCallback<void(bool)> load_callback, + const std::vector<std::pair<int64_t, std::string>>& user_data, + ServiceWorkerStatusCode status) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + DCHECK(!done_loading_subscriptions_) << __func__ << " already called"; + done_loading_subscriptions_ = true; + + if (status != SERVICE_WORKER_OK) { + DidLoadAllSubscriptions(false, std::move(load_callback)); + return; + } + + DCHECK(subscriptions_by_registration_.empty()); + subscriptions_by_registration_.reserve(user_data.size()); + bool load_success = true; + for (const auto& pair : user_data) { + int64_t service_worker_registration_id = pair.first; + const std::string& proto_string = pair.second; + + base::Optional<std::vector<CookieChangeSubscription>> subscriptions_opt = + CookieChangeSubscription::DeserializeVector( + proto_string, service_worker_registration_id); + if (!subscriptions_opt.has_value()) { + load_success = false; + continue; + } + + ActivateSubscriptions(&subscriptions_opt.value()); + DCHECK( + !subscriptions_by_registration_.count(service_worker_registration_id)); + subscriptions_by_registration_.emplace( + std::move(service_worker_registration_id), + std::move(subscriptions_opt).value()); + } + + DidLoadAllSubscriptions(load_success, std::move(load_callback)); +} + +void CookieStoreManager::DidLoadAllSubscriptions( + bool succeeded, + base::OnceCallback<void(bool)> load_callback) { + DCHECK(done_loading_subscriptions_); + succeeded_loading_subscriptions_ = succeeded; + + for (auto& callback : subscriptions_loaded_callbacks_) + std::move(callback).Run(); + subscriptions_loaded_callbacks_.clear(); + + std::move(load_callback).Run(succeeded); +} + +void CookieStoreManager::AppendSubscriptions( + int64_t service_worker_registration_id, + const GURL& origin, + std::vector<blink::mojom::CookieChangeSubscriptionPtr> mojo_subscriptions, + blink::mojom::CookieStore::AppendSubscriptionsCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!done_loading_subscriptions_) { + subscriptions_loaded_callbacks_.emplace_back(base::BindOnce( + &CookieStoreManager::AppendSubscriptions, weak_factory_.GetWeakPtr(), + service_worker_registration_id, origin, std::move(mojo_subscriptions), + std::move(callback))); + return; + } + + if (!succeeded_loading_subscriptions_) { + std::move(callback).Run(false); + return; + } + + // GetLiveRegistration() is sufficient here (as opposed to a flavor of + // FindRegistration()) because AppendSubscriptions is only called from the + // implementation of the Cookie Store API, which is exposed to + // ServiceWorkerGlobalScope. ServiceWorkerGlobalScope references the + // service worker's registration via a ServiceWorkerRegistration JavaScript + // object, so the registration is guaranteed to be live while the service + // worker is executing. + // + // It is possible for the service worker to get killed while this API call is + // in progress, for example, if the service worker code exceeds an event + // handling time limit. In that case, the return value will not be observed, + // so a false negative is acceptable. + ServiceWorkerRegistration* service_worker_registration = + service_worker_context_->GetLiveRegistration( + service_worker_registration_id); + if (!service_worker_registration) { + // This error case is a good fit for mojo::ReportBadMessage(), because the + // renderer has passed an invalid registration ID. However, the code here + // might run without a mojo call context, if the original call was delayed + // while loading on-disk subscription data. + // + // While it would be possible to have two code paths for the two situations, + // the extra complexity doesn't seem warranted for the limited debuggig + // benefits provided by mojo::ReportBadMessage. + std::move(callback).Run(false); + return; + } + + // TODO(crbug.com/843079): This check incorrectly allows an active service + // worker version to call the API, if another version + // is installing at the same time. + if (!service_worker_registration->installing_version()) { + // A service worker's cookie change subscriptions can only be modified while + // the service worker's install event is handled. + std::move(callback).Run(false); + return; + } + + if (mojo_subscriptions.empty()) { + // Empty subscriptions are special-cased so we never have to serialize an + // empty array of subscriptions. This is advantageous because the protobuf + // serialization of an empty array is the empty string, which is also used + // by the convenience protobuf serialization API to signal serialization + // failure. So, supporting serializing an empty array would mean we can't + // use the convenience serialization API. + std::move(callback).Run(true); + return; + } + + std::vector<CookieChangeSubscription> new_subscriptions = + CookieChangeSubscription::FromMojoVector( + std::move(mojo_subscriptions), service_worker_registration->id()); + DCHECK(!new_subscriptions.empty()); + + auto old_subscriptions_it = + subscriptions_by_registration_.find(service_worker_registration_id); + if (old_subscriptions_it == subscriptions_by_registration_.end()) { + subscriptions_by_registration_.emplace(service_worker_registration_id, + std::move(new_subscriptions)); + std::move(callback).Run(true); + return; + } + + std::vector<CookieChangeSubscription>& old_subscriptions = + old_subscriptions_it->second; + old_subscriptions.reserve(old_subscriptions.size() + + new_subscriptions.size()); + for (auto& new_subscription : new_subscriptions) + old_subscriptions.emplace_back(std::move(new_subscription)); + + std::move(callback).Run(true); +} + +void CookieStoreManager::GetSubscriptions( + int64_t service_worker_registration_id, + const GURL& origin, + blink::mojom::CookieStore::GetSubscriptionsCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!done_loading_subscriptions_) { + subscriptions_loaded_callbacks_.emplace_back(base::BindOnce( + &CookieStoreManager::GetSubscriptions, weak_factory_.GetWeakPtr(), + service_worker_registration_id, origin, std::move(callback))); + return; + } + + if (!succeeded_loading_subscriptions_) { + std::move(callback).Run( + std::vector<blink::mojom::CookieChangeSubscriptionPtr>(), false); + return; + } + + auto it = subscriptions_by_registration_.find(service_worker_registration_id); + if (it == subscriptions_by_registration_.end()) { + std::move(callback).Run( + std::vector<blink::mojom::CookieChangeSubscriptionPtr>(), true); + return; + } + + std::move(callback).Run(CookieChangeSubscription::ToMojoVector(it->second), + true); +} + +void CookieStoreManager::OnNewLiveRegistration( + int64_t service_worker_registration_id, + const GURL& pattern) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} + +void CookieStoreManager::OnRegistrationStored( + int64_t service_worker_registration_id, + const GURL& pattern) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Waiting for the on-disk subscriptions to be loaded ensures that the + // registration's subscriptions aren't activated twice. Without waiting, + // there's a risk that LoadAllSubscriptions() sees the result of the + // StoreRegistrationUserData() call below. + if (!done_loading_subscriptions_) { + subscriptions_loaded_callbacks_.emplace_back(base::BindOnce( + &CookieStoreManager::OnRegistrationStored, weak_factory_.GetWeakPtr(), + service_worker_registration_id, pattern)); + return; + } + + auto it = subscriptions_by_registration_.find(service_worker_registration_id); + if (it == subscriptions_by_registration_.end()) + return; + + ActivateSubscriptions(&it->second); + + std::string subscriptions_data = + CookieChangeSubscription::SerializeVector(it->second); + DCHECK(!subscriptions_data.empty()) + << "Failed to create cookie change subscriptions protobuf"; + + service_worker_context_->StoreRegistrationUserData( + service_worker_registration_id, pattern.GetOrigin(), + std::vector<std::pair<std::string, std::string>>( + {{registration_user_data_key_, subscriptions_data}}), + base::BindOnce(&HandleStoreRegistrationUserDataStatus)); +} + +void CookieStoreManager::OnRegistrationDeleted( + int64_t service_worker_registration_id, + const GURL& pattern) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Waiting for the on-disk subscriptions to be loaded ensures that the + // registration's subscriptions are removed. Without waiting, there's a risk + // that a registration's subscriptions will finish loading (and thus remain + // active) right after this function runs. + if (!done_loading_subscriptions_) { + subscriptions_loaded_callbacks_.emplace_back(base::BindOnce( + &CookieStoreManager::OnRegistrationDeleted, weak_factory_.GetWeakPtr(), + service_worker_registration_id, pattern)); + return; + } + + auto it = subscriptions_by_registration_.find(service_worker_registration_id); + if (it == subscriptions_by_registration_.end()) + return; + + DeactivateSubscriptions(&it->second); + subscriptions_by_registration_.erase(it); +} + +void CookieStoreManager::ActivateSubscriptions( + std::vector<CookieChangeSubscription>* subscriptions) { + if (subscriptions->empty()) + return; + + // Service workers can only observe changes to cookies for URLs under their + // scope. This means all the URLs that the worker is observing must map to the + // same domain key (eTLD+1). + // + // TODO(pwnall): This is the same as implementation as + // net::CookieMonsterChangeDispatcher::DomainKey. Extract that + // implementation into net/cookies.cookie_util.h and call it. + std::string url_key = net::registry_controlled_domains::GetDomainAndRegistry( + + (*subscriptions)[0].url(), + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); + base::LinkedList<CookieChangeSubscription>& url_key_subscriptions_list = + subscriptions_by_url_key_[url_key]; + + for (auto& subscription : *subscriptions) { + DCHECK(!subscription.next() && !subscription.previous()) + << "Subscription passed to " << __func__ << " already activated"; + DCHECK_EQ(url_key, + net::registry_controlled_domains::GetDomainAndRegistry( + subscription.url(), + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) + << __func__ << " subscriptions belong to different registrations"; + url_key_subscriptions_list.Append(&subscription); + } +} + +void CookieStoreManager::DeactivateSubscriptions( + std::vector<CookieChangeSubscription>* subscriptions) { + if (subscriptions->empty()) + return; + + // Service workers can only observe changes to cookies for URLs under their + // scope. This means all the URLs that the worker is observing must map to the + // same domain key (eTLD+1). + // + // TODO(pwnall): This has the same implementation as + // net::CookieMonsterChangeDispatcher::DomainKey. Extract that + // implementation into net/cookies.cookie_util.h and call it. + std::string url_key = net::registry_controlled_domains::GetDomainAndRegistry( + (*subscriptions)[0].url(), + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); + for (auto& subscription : *subscriptions) { + DCHECK(subscription.next() && subscription.previous()) + << "Subscription passed to " << __func__ << " not previously activated"; + DCHECK_EQ(url_key, + net::registry_controlled_domains::GetDomainAndRegistry( + subscription.url(), + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) + << __func__ << " subscriptions belong to different registrations"; + subscription.RemoveFromList(); + } + auto it = subscriptions_by_url_key_.find(url_key); + DCHECK(it != subscriptions_by_url_key_.end()); + if (it->second.empty()) + subscriptions_by_url_key_.erase(it); +} + +void CookieStoreManager::OnStorageWiped() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Waiting for the on-disk subscriptions to be loaded ensures that all + // subscriptions are removed. Without waiting, there's a risk that some + // subscriptions will finish loading (and thus remain active) after this + // function runs. + if (!done_loading_subscriptions_) { + subscriptions_loaded_callbacks_.emplace_back(base::BindOnce( + &CookieStoreManager::OnStorageWiped, weak_factory_.GetWeakPtr())); + return; + } + + subscriptions_by_url_key_.clear(); + subscriptions_by_registration_.clear(); +} + +void CookieStoreManager::OnCookieChange( + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause) { + // Waiting for on-disk subscriptions to be loaded ensures that changes are + // delivered to all service workers that subscribed to them in previous + // browser sessions. Without waiting, workers might miss cookie changes. + if (!done_loading_subscriptions_) { + subscriptions_loaded_callbacks_.emplace_back( + base::BindOnce(&CookieStoreManager::OnCookieChange, + weak_factory_.GetWeakPtr(), cookie, cause)); + return; + } + + // Compute the list of service workers interested in this change. A worker + // might have multiple subscriptions that cover this change, but should still + // receive a single change event. + // TODO(pwnall): This has same as implementation as + // net::CookieMonsterChangeDispatcher::DomainKey. Extract that + // implementation into net/cookies.cookie_util.h and call it. + std::string url_key = net::registry_controlled_domains::GetDomainAndRegistry( + cookie.Domain(), + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); + auto it = subscriptions_by_url_key_.find(url_key); + if (it == subscriptions_by_url_key_.end()) + return; + std::set<int64_t> interested_registration_ids; + const base::LinkedList<CookieChangeSubscription>& subscriptions = it->second; + for (const base::LinkNode<CookieChangeSubscription>* node = + subscriptions.head(); + node != subscriptions.end(); node = node->next()) { + const CookieChangeSubscription* subscription = node->value(); + if (subscription->ShouldObserveChangeTo(cookie)) { + interested_registration_ids.insert( + subscription->service_worker_registration_id()); + } + } + + // Dispatch the change to interested workers. + for (int64_t registration_id : interested_registration_ids) { + service_worker_context_->FindReadyRegistrationForIdOnly( + registration_id, + base::BindOnce( + [](base::WeakPtr<CookieStoreManager> manager, + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause, + ServiceWorkerStatusCode find_status, + scoped_refptr<ServiceWorkerRegistration> registration) { + if (find_status != SERVICE_WORKER_OK) + return; + + DCHECK(registration); + if (!manager) + return; + manager->DispatchChangeEvent(std::move(registration), cookie, + cause); + }, + weak_factory_.GetWeakPtr(), cookie, cause)); + } +} + +void CookieStoreManager::DispatchChangeEvent( + scoped_refptr<ServiceWorkerRegistration> registration, + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause) { + scoped_refptr<ServiceWorkerVersion> active_version = + registration->active_version(); + if (active_version->running_status() != EmbeddedWorkerStatus::RUNNING) { + active_version->RunAfterStartWorker( + ServiceWorkerMetrics::EventType::COOKIE_CHANGE, + base::BindOnce(&CookieStoreManager::DidStartWorkerForChangeEvent, + weak_factory_.GetWeakPtr(), std::move(registration), + cookie, cause)); + return; + } + + int request_id = active_version->StartRequest( + ServiceWorkerMetrics::EventType::COOKIE_CHANGE, base::DoNothing()); + + active_version->event_dispatcher()->DispatchCookieChangeEvent( + cookie, cause, active_version->CreateSimpleEventCallback(request_id)); +} + +void CookieStoreManager::DidStartWorkerForChangeEvent( + scoped_refptr<ServiceWorkerRegistration> registration, + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause, + ServiceWorkerStatusCode start_worker_status) { + if (start_worker_status != SERVICE_WORKER_OK) + return; + DispatchChangeEvent(std::move(registration), cookie, cause); +} + +} // namespace content
diff --git a/content/browser/cookie_store/cookie_store_manager.h b/content/browser/cookie_store/cookie_store_manager.h new file mode 100644 index 0000000..2eac6ccc --- /dev/null +++ b/content/browser/cookie_store/cookie_store_manager.h
@@ -0,0 +1,228 @@ +// 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 CONTENT_BROWSER_COOKIE_STORE_COOKIE_STORE_MANAGER_H_ +#define CONTENT_BROWSER_COOKIE_STORE_COOKIE_STORE_MANAGER_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/containers/linked_list.h" +#include "base/macros.h" +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "base/sequence_checker.h" +#include "content/browser/cookie_store/cookie_change_subscription.h" +#include "content/browser/cookie_store/cookie_store_host.h" +#include "content/browser/service_worker/service_worker_context_core_observer.h" +#include "mojo/public/cpp/bindings/strong_binding_set.h" +#include "services/network/public/mojom/network_service.mojom.h" +#include "third_party/blink/public/mojom/cookie_store/cookie_store.mojom.h" +#include "url/origin.h" + +class GURL; + +namespace content { + +class ServiceWorkerContextWrapper; +class ServiceWorkerRegistration; + +// Manages cookie change subscriptions for a StoragePartition's service workers. +// +// Subscriptions are stored along with their associated service worker +// registrations in ServiceWorkerStorage, as user data. When a service worker is +// unregistered, its cookie change subscriptions are removed. The storage method +// (user data) is an implementation detail. Callers should not rely on it, as +// the storage method may change in the future. +// +// Instances of this class must be accessed exclusively on the IO thread, +// because they call into ServiceWorkerContextWrapper methods that are +// restricted to the IO thread. +class CookieStoreManager : public ServiceWorkerContextCoreObserver, + public ::network::mojom::CookieChangeListener { + public: + // Creates a CookieStoreManager with an empty in-memory subscription database. + // + // The in-memory subscription database must be populated with data from disk, + // by calling ReadAllSubscriptions(). + CookieStoreManager( + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context); + + ~CookieStoreManager() override; + + // Creates a mojo connection to a service worker. + // + // This is called when service workers use the Cookie Store API to subscribe + // to cookie changes or obtain the list of cookie changes. + void CreateService(blink::mojom::CookieStoreRequest request, + const url::Origin& origin); + + // Starts loading the on-disk subscription data. + // + // Returns after scheduling the work. The callback is called with a boolean + // that indicates if the load operation succeeded. + // + // It is safe to call all the other CookieStoreManager methods during the + // loading operation. The CookieStoreManager has well-defined semantics if + // loading fails, so it is not necessary to handle loading errors. + void LoadAllSubscriptions(base::OnceCallback<void(bool)> callback); + + // Processes cookie changes from a network service instance. + void ListenToCookieChanges(::network::mojom::CookieManagerPtr cookie_manager, + base::OnceCallback<void(bool)> callback); + + // content::mojom::CookieStore implementation + void AppendSubscriptions( + int64_t service_worker_registration_id, + const GURL& origin, + std::vector<blink::mojom::CookieChangeSubscriptionPtr> mojo_subscriptions, + blink::mojom::CookieStore::AppendSubscriptionsCallback callback); + void GetSubscriptions( + int64_t service_worker_registration_id, + const GURL& origin, + blink::mojom::CookieStore::GetSubscriptionsCallback callback); + + // ServiceWorkerContextCoreObserver + void OnRegistrationStored(int64_t service_worker_registration_id, + const GURL& pattern) override; + void OnRegistrationDeleted(int64_t service_worker_registration_id, + const GURL& pattern) override; + void OnNewLiveRegistration(int64_t service_worker_registration_id, + const GURL& pattern) override; + void OnStorageWiped() override; + + // ::network::mojom::CookieChangeListener + void OnCookieChange(const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause) override; + + private: + // Updates internal state with the result of loading disk subscription data. + // + // Called exactly once. + void ProcessOnDiskSubscriptions( + base::OnceCallback<void(bool)> load_callback, + const std::vector<std::pair<int64_t, std::string>>& user_data, + ServiceWorkerStatusCode status); + + // Runs all the callbacks waiting for on-disk subscription data. + // + // Called exactly once, after on-disk subcriptions have been loaded. + void DidLoadAllSubscriptions(bool succeeded, + base::OnceCallback<void(bool)> load_callback); + + // Starts sending cookie change events to a service worker. + // + // All subscriptions must belong to the same service worker registration. This + // method is not idempotent. + void ActivateSubscriptions( + std::vector<CookieChangeSubscription>* subscriptions); + + // Stops sending cookie change events to a service worker. + // + // All subscriptions must belong to the same service worker registration. This + // method is not idempotent. + void DeactivateSubscriptions( + std::vector<CookieChangeSubscription>* subscriptions); + + // Sends a cookie change to interested service workers. + // + // Must only be called after the on-disk subscription data is successfully + // loaded. + void DispatchCookieChange(const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause); + + // Sends a cookie change event to one service worker. + void DispatchChangeEvent( + scoped_refptr<ServiceWorkerRegistration> registration, + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause); + + // Called after a service worker was started so it can get a cookie change. + void DidStartWorkerForChangeEvent( + scoped_refptr<ServiceWorkerRegistration> registration, + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause, + ServiceWorkerStatusCode start_worker_status); + + // Used to efficiently implement OnRegistrationDeleted(). + // + // When a service worker registration is removed from the system, the + // CookieStoreManager needs to remove all the cookie change subscriptions + // associated with the registration. Looking up the registration ID in the + // |subscriptions_by_registration_| map is done in O(1) time, and then each + // subscription is removed from a LinkedList in |subscription_by_url_key_| in + // O(1) time. + std::unordered_map<int64_t, std::vector<CookieChangeSubscription>> + subscriptions_by_registration_; + + // Used to efficiently implement DispatchCookieChange(). + // + // When a cookie change notification comes from the network service, the + // CookieStoreManager needs to dispatch events to the workers with relevant + // subscriptions. |subscriptions_by_url_key_| indexes change subscriptions + // according to the eTLD+1 of the subscription's scope URL, so each cookie + // change only needs to be checked against the subscriptions of the service + // workers in the same eTLD+1. The reduction in work is signficant, given that + // checking whether a subscription matches a cookie isn't very cheap. + // + // The current implementation's performance profile could have been achieved + // with a map from eTLD+1 to registration IDs, which would not have required + // linked lists. However, the current approach is more amenable to future + // optimizations, such as partitioning by (eTLD+1, cookie name). + std::map<std::string, base::LinkedList<CookieChangeSubscription>> + subscriptions_by_url_key_; + + // Used to look up and modify service worker registration data. + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_; + + // Tracks the open mojo pipes created by CreateService(). + // + // Each pipe is associated with the CookieStoreHost instance that it is + // connected to. When the pipe is closed, the StrongBindingSet automatically + // deletes the CookieStoreHost. + mojo::StrongBindingSet<blink::mojom::CookieStore> bindings_; + + // Used to receive cookie changes from the network service. + ::network::mojom::CookieManagerPtr cookie_manager_; + mojo::Binding<::network::mojom::CookieChangeListener> + cookie_change_listener_binding_; + + // The service worker registration user data key for subscription data. + // + // All the subscriptions associated with a registration are stored in a single + // user data entry whose key is |registration_user_data_key_|, and whose value + // is a serialized CookieChangeSubscriptionsProto. + const std::string registration_user_data_key_; + + // Called after all subscriptions have been loaded. + // + // Callbacks can assume that |done_loading_subscriptions_| is true + // and |succeeded_loading_subscriptions_| is set. If the latter is true, + // |subscriptions_by_registration_| and |subscriptions_by_url_key_| will also + // be populated. + std::vector<base::OnceClosure> subscriptions_loaded_callbacks_; + + // Set to true once all subscriptions have been loaded. + bool done_loading_subscriptions_ = false; + + // Only defined when |done_loading_subscriptions_| is true. + bool succeeded_loading_subscriptions_ = false; + + // Instances of this class are currently bound to the IO thread, because they + // call ServiceWorkerContextWrapper methods that are restricted to the IO + // thread. However, the class implementation itself is thread-friendly, so it + // only checks that methods are called on the same sequence. + SEQUENCE_CHECKER(sequence_checker_); + + // Supports having the manager destroyed while waiting for disk I/O. + base::WeakPtrFactory<CookieStoreManager> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(CookieStoreManager); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_COOKIE_STORE_COOKIE_STORE_MANAGER_H_
diff --git a/content/browser/cookie_store/cookie_store_manager_unittest.cc b/content/browser/cookie_store/cookie_store_manager_unittest.cc new file mode 100644 index 0000000..d548c209 --- /dev/null +++ b/content/browser/cookie_store/cookie_store_manager_unittest.cc
@@ -0,0 +1,784 @@ +// 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 <memory> + +#include "base/bind.h" +#include "base/files/scoped_temp_dir.h" +#include "base/macros.h" +#include "base/memory/scoped_refptr.h" +#include "content/browser/cookie_store/cookie_store_context.h" +#include "content/browser/cookie_store/cookie_store_manager.h" +#include "content/browser/service_worker/embedded_worker_test_helper.h" +#include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/browser/storage_partition_impl.h" +#include "content/common/service_worker/service_worker_event_dispatcher.mojom.h" +#include "content/public/test/test_browser_context.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "mojo/edk/embedder/embedder.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h" +#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h" +#include "url/gurl.h" +#include "url/origin.h" + +namespace content { + +namespace { + +// Synchronous proxies to a wrapped CookieStore service's methods. +class CookieStoreSync { + public: + using Subscriptions = std::vector<blink::mojom::CookieChangeSubscriptionPtr>; + + // The caller must ensure that the CookieStore service outlives this. + explicit CookieStoreSync(blink::mojom::CookieStore* cookie_store_service) + : cookie_store_service_(cookie_store_service) {} + ~CookieStoreSync() = default; + + bool AppendSubscriptions(int64_t service_worker_registration_id, + Subscriptions subscriptions) { + bool success; + base::RunLoop run_loop; + cookie_store_service_->AppendSubscriptions( + service_worker_registration_id, std::move(subscriptions), + base::BindOnce( + [](base::RunLoop* run_loop, bool* success, bool service_success) { + *success = service_success; + run_loop->Quit(); + }, + &run_loop, &success)); + run_loop.Run(); + return success; + } + + Subscriptions GetSubscriptions(int64_t service_worker_registration_id) { + Subscriptions result; + base::RunLoop run_loop; + cookie_store_service_->GetSubscriptions( + service_worker_registration_id, + base::BindOnce( + [](base::RunLoop* run_loop, Subscriptions* result, + Subscriptions service_result, bool success) { + *result = std::move(service_result); + run_loop->Quit(); + EXPECT_TRUE(success) << "GetSubscriptions failed"; + }, + &run_loop, &result)); + run_loop.Run(); + return result; + } + + private: + blink::mojom::CookieStore* cookie_store_service_; + + DISALLOW_COPY_AND_ASSIGN(CookieStoreSync); +}; + +const char kExampleScope[] = "https://example.com/a"; +const char kExampleWorkerScript[] = "https://example.com/a/script.js"; +const char kGoogleScope[] = "https://google.com/a"; +const char kGoogleWorkerScript[] = "https://google.com/a/script.js"; + +// Mocks a service worker that uses the cookieStore API. +class CookieStoreWorkerTestHelper : public EmbeddedWorkerTestHelper { + public: + using EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper; + + // Sets the cookie change subscriptions requested in the next install event. + void SetOnInstallSubscriptions( + std::vector<CookieStoreSync::Subscriptions> subscription_batches, + blink::mojom::CookieStore* cookie_store_service) { + install_subscription_batches_ = std::move(subscription_batches); + cookie_store_service_ = cookie_store_service; + } + + // Spins inside a run loop until a service worker activate event is received. + void WaitForActivateEvent() { + base::RunLoop run_loop; + quit_on_activate_ = &run_loop; + run_loop.Run(); + } + + // The data in the CookieChangeEvents received by the worker. + std::vector< + std::pair<net::CanonicalCookie, ::network::mojom::CookieChangeCause>>& + changes() { + return changes_; + } + + protected: + // Collects the worker's registration ID for OnInstallEvent(). + void OnStartWorker( + int embedded_worker_id, + int64_t service_worker_version_id, + const GURL& scope, + const GURL& script_url, + bool pause_after_download, + mojom::ServiceWorkerEventDispatcherRequest dispatcher_request, + mojom::ControllerServiceWorkerRequest controller_request, + mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, + mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, + blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info) + override { + ServiceWorkerVersion* service_worker_version = + context()->GetLiveVersion(service_worker_version_id); + DCHECK(service_worker_version); + service_worker_registration_id_ = service_worker_version->registration_id(); + + EmbeddedWorkerTestHelper::OnStartWorker( + embedded_worker_id, service_worker_version_id, scope, script_url, + pause_after_download, std::move(dispatcher_request), + std::move(controller_request), std::move(instance_host), + std::move(provider_info), std::move(installed_scripts_info)); + } + + // Cookie change subscriptions can only be created in this event handler. + void OnInstallEvent( + mojom::ServiceWorkerEventDispatcher::DispatchInstallEventCallback + callback) override { + for (auto& subscriptions : install_subscription_batches_) { + cookie_store_service_->AppendSubscriptions( + service_worker_registration_id_, std::move(subscriptions), + base::BindOnce([](bool success) { + CHECK(success) << "AppendSubscriptions failed"; + })); + } + install_subscription_batches_.clear(); + + EmbeddedWorkerTestHelper::OnInstallEvent(std::move(callback)); + } + + // Used to implement WaitForActivateEvent(). + void OnActivateEvent( + mojom::ServiceWorkerEventDispatcher::DispatchActivateEventCallback + callback) override { + if (quit_on_activate_) { + quit_on_activate_->Quit(); + quit_on_activate_ = nullptr; + } + + EmbeddedWorkerTestHelper::OnActivateEvent(std::move(callback)); + } + + void OnCookieChangeEvent( + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause, + mojom::ServiceWorkerEventDispatcher::DispatchCookieChangeEventCallback + callback) override { + changes_.emplace_back(cookie, cause); + std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED, + base::Time::Now()); + } + + private: + // Used to add cookie change subscriptions during OnInstallEvent(). + blink::mojom::CookieStore* cookie_store_service_ = nullptr; + std::vector<CookieStoreSync::Subscriptions> install_subscription_batches_; + int64_t service_worker_registration_id_; + + // Set by WaitForActivateEvent(), used in OnActivateEvent(). + base::RunLoop* quit_on_activate_ = nullptr; + + // Collects the changes reported to OnCookieChangeEvent(). + std::vector< + std::pair<net::CanonicalCookie, ::network::mojom::CookieChangeCause>> + changes_; +}; + +} // namespace + +// This class cannot be in an anonymous namespace because it needs to be a +// friend of StoragePartitionImpl, to access its constructor. +class CookieStoreManagerTest + : public testing::Test, + public testing::WithParamInterface<bool /* reset_context */> { + public: + CookieStoreManagerTest() + : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} + + void SetUp() override { + // Use an on-disk service worker storage to test saving and loading. + ASSERT_TRUE(user_data_directory_.CreateUniqueTempDir()); + + ResetServiceWorkerContext(); + } + + void TearDown() override { + thread_bundle_.RunUntilIdle(); + + // Smart pointers are reset manually in destruction order because this is + // called by ResetServiceWorkerContext(). + example_service_.reset(); + google_service_.reset(); + example_service_ptr_.reset(); + google_service_ptr_.reset(); + cookie_manager_.reset(); + cookie_store_context_ = nullptr; + storage_partition_impl_.reset(); + worker_test_helper_.reset(); + } + + void ResetServiceWorkerContext() { + if (cookie_store_context_) + TearDown(); + + worker_test_helper_ = std::make_unique<CookieStoreWorkerTestHelper>( + user_data_directory_.GetPath()); + cookie_store_context_ = base::MakeRefCounted<CookieStoreContext>(); + cookie_store_context_->Initialize(worker_test_helper_->context_wrapper(), + base::BindOnce([](bool success) { + CHECK(success) << "Initialize failed"; + })); + storage_partition_impl_ = base::WrapUnique( + new StoragePartitionImpl(worker_test_helper_->browser_context(), + user_data_directory_.GetPath(), nullptr)); + storage_partition_impl_->SetURLRequestContext( + worker_test_helper_->browser_context() + ->CreateRequestContextForStoragePartition( + user_data_directory_.GetPath(), false, nullptr, + URLRequestInterceptorScopedVector())); + ::network::mojom::NetworkContext* network_context = + storage_partition_impl_->GetNetworkContext(); + cookie_store_context_->ListenToCookieChanges( + network_context, base::BindOnce([](bool success) { + CHECK(success) << "ListenToCookieChanges failed"; + })); + network_context->GetCookieManager(mojo::MakeRequest(&cookie_manager_)); + + cookie_store_context_->CreateService( + mojo::MakeRequest(&example_service_ptr_), + url::Origin::Create(GURL(kExampleScope))); + example_service_ = + std::make_unique<CookieStoreSync>(example_service_ptr_.get()); + + cookie_store_context_->CreateService( + mojo::MakeRequest(&google_service_ptr_), + url::Origin::Create(GURL(kGoogleScope))); + google_service_ = + std::make_unique<CookieStoreSync>(google_service_ptr_.get()); + } + + int64_t RegisterServiceWorker(const char* scope, const char* script_url) { + bool success = false; + int64_t registration_id; + blink::mojom::ServiceWorkerRegistrationOptions options; + options.scope = GURL(scope); + base::RunLoop run_loop; + worker_test_helper_->context()->RegisterServiceWorker( + GURL(script_url), options, + base::BindOnce( + [](base::RunLoop* run_loop, bool* success, int64_t* registration_id, + ServiceWorkerStatusCode status, + const std::string& status_message, + int64_t service_worker_registration_id) { + *success = (status == SERVICE_WORKER_OK); + *registration_id = service_worker_registration_id; + EXPECT_EQ(SERVICE_WORKER_OK, status) + << ServiceWorkerStatusToString(status); + run_loop->Quit(); + }, + &run_loop, &success, ®istration_id)); + run_loop.Run(); + if (!success) + return kInvalidRegistrationId; + + worker_test_helper_->WaitForActivateEvent(); + return registration_id; + } + + // Simplified helper for SetCanonicalCookie. + // + // Creates a CanonicalCookie that is not secure, not http-only, + // and not restricted to first parties. Returns false if creation fails. + bool SetSessionCookie(const char* name, + const char* value, + const char* domain, + const char* path) { + net::CanonicalCookie cookie( + name, value, domain, path, base::Time(), base::Time(), base::Time(), + /* secure = */ false, + /* httponly = */ false, net::CookieSameSite::NO_RESTRICTION, + net::COOKIE_PRIORITY_DEFAULT); + base::RunLoop run_loop; + bool success = false; + cookie_manager_->SetCanonicalCookie( + cookie, /* secure_source = */ true, /* can_modify_httponly = */ true, + base::BindOnce( + [](base::RunLoop* run_loop, bool* success, bool service_success) { + *success = success; + run_loop->Quit(); + }, + &run_loop, &success)); + run_loop.Run(); + return success; + } + + bool reset_context_during_test() const { return GetParam(); } + + static constexpr const int64_t kInvalidRegistrationId = -1; + + protected: + TestBrowserThreadBundle thread_bundle_; + base::ScopedTempDir user_data_directory_; + std::unique_ptr<CookieStoreWorkerTestHelper> worker_test_helper_; + std::unique_ptr<StoragePartitionImpl> storage_partition_impl_; + scoped_refptr<CookieStoreContext> cookie_store_context_; + ::network::mojom::CookieManagerPtr cookie_manager_; + + blink::mojom::CookieStorePtr example_service_ptr_, google_service_ptr_; + std::unique_ptr<CookieStoreSync> example_service_, google_service_; +}; + +const int64_t CookieStoreManagerTest::kInvalidRegistrationId; + +namespace { + +// Useful for sorting a vector of cookie change subscriptions. +bool CookieChangeSubscriptionLessThan( + const blink::mojom::CookieChangeSubscriptionPtr& lhs, + const blink::mojom::CookieChangeSubscriptionPtr& rhs) { + return std::tie(lhs->name, lhs->match_type, lhs->url) < + std::tie(rhs->name, rhs->match_type, rhs->url); +} + +TEST_P(CookieStoreManagerTest, NoSubscriptions) { + worker_test_helper_->SetOnInstallSubscriptions( + std::vector<CookieStoreSync::Subscriptions>(), + example_service_ptr_.get()); + int64_t registration_id = + RegisterServiceWorker(kExampleScope, kExampleWorkerScript); + ASSERT_NE(registration_id, kInvalidRegistrationId); + + if (reset_context_during_test()) + ResetServiceWorkerContext(); + + std::vector<blink::mojom::CookieChangeSubscriptionPtr> all_subscriptions = + example_service_->GetSubscriptions(registration_id); + EXPECT_EQ(0u, all_subscriptions.size()); +} + +TEST_P(CookieStoreManagerTest, EmptySubscriptions) { + std::vector<CookieStoreSync::Subscriptions> batches; + batches.emplace_back(); + worker_test_helper_->SetOnInstallSubscriptions(std::move(batches), + example_service_ptr_.get()); + int64_t registration_id = + RegisterServiceWorker(kExampleScope, kExampleWorkerScript); + ASSERT_NE(registration_id, kInvalidRegistrationId); + + if (reset_context_during_test()) + ResetServiceWorkerContext(); + + std::vector<blink::mojom::CookieChangeSubscriptionPtr> all_subscriptions = + example_service_->GetSubscriptions(registration_id); + EXPECT_EQ(0u, all_subscriptions.size()); +} + +TEST_P(CookieStoreManagerTest, OneSubscription) { + std::vector<CookieStoreSync::Subscriptions> batches; + batches.emplace_back(); + + CookieStoreSync::Subscriptions& subscriptions = batches.back(); + subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New()); + subscriptions.back()->name = "cookie_name_prefix"; + subscriptions.back()->match_type = + ::network::mojom::CookieMatchType::STARTS_WITH; + subscriptions.back()->url = GURL(kExampleScope); + + worker_test_helper_->SetOnInstallSubscriptions(std::move(batches), + example_service_ptr_.get()); + int64_t registration_id = + RegisterServiceWorker(kExampleScope, kExampleWorkerScript); + ASSERT_NE(registration_id, kInvalidRegistrationId); + + if (reset_context_during_test()) + ResetServiceWorkerContext(); + + std::vector<blink::mojom::CookieChangeSubscriptionPtr> all_subscriptions = + example_service_->GetSubscriptions(registration_id); + EXPECT_EQ(1u, all_subscriptions.size()); + EXPECT_EQ("cookie_name_prefix", all_subscriptions[0]->name); + EXPECT_EQ(::network::mojom::CookieMatchType::STARTS_WITH, + all_subscriptions[0]->match_type); + EXPECT_EQ(GURL(kExampleScope), all_subscriptions[0]->url); +} + +TEST_P(CookieStoreManagerTest, AppendSubscriptionsAfterEmptyInstall) { + worker_test_helper_->SetOnInstallSubscriptions( + std::vector<CookieStoreSync::Subscriptions>(), + example_service_ptr_.get()); + int64_t registration_id = + RegisterServiceWorker(kExampleScope, kExampleWorkerScript); + ASSERT_NE(registration_id, kInvalidRegistrationId); + + CookieStoreSync::Subscriptions subscriptions; + subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New()); + subscriptions.back()->name = "cookie_name_prefix"; + subscriptions.back()->match_type = + ::network::mojom::CookieMatchType::STARTS_WITH; + subscriptions.back()->url = GURL(kExampleScope); + + EXPECT_FALSE(example_service_->AppendSubscriptions(registration_id, + std::move(subscriptions))); + + if (reset_context_during_test()) + ResetServiceWorkerContext(); + + std::vector<blink::mojom::CookieChangeSubscriptionPtr> all_subscriptions = + example_service_->GetSubscriptions(registration_id); + EXPECT_EQ(0u, all_subscriptions.size()); +} + +TEST_P(CookieStoreManagerTest, AppendSubscriptionsAfterInstall) { + { + std::vector<CookieStoreSync::Subscriptions> batches; + batches.emplace_back(); + + CookieStoreSync::Subscriptions& subscriptions = batches.back(); + subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New()); + subscriptions.back()->name = "cookie_name_prefix"; + subscriptions.back()->match_type = + ::network::mojom::CookieMatchType::STARTS_WITH; + subscriptions.back()->url = GURL(kExampleScope); + + worker_test_helper_->SetOnInstallSubscriptions(std::move(batches), + example_service_ptr_.get()); + } + int64_t registration_id = + RegisterServiceWorker(kExampleScope, kExampleWorkerScript); + ASSERT_NE(registration_id, kInvalidRegistrationId); + + { + CookieStoreSync::Subscriptions subscriptions; + subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New()); + subscriptions.back()->name = "cookie_name"; + subscriptions.back()->match_type = + ::network::mojom::CookieMatchType::EQUALS; + subscriptions.back()->url = GURL(kExampleScope); + + EXPECT_FALSE(example_service_->AppendSubscriptions( + registration_id, std::move(subscriptions))); + } + + if (reset_context_during_test()) + ResetServiceWorkerContext(); + + std::vector<blink::mojom::CookieChangeSubscriptionPtr> all_subscriptions = + example_service_->GetSubscriptions(registration_id); + EXPECT_EQ(1u, all_subscriptions.size()); + EXPECT_EQ("cookie_name_prefix", all_subscriptions[0]->name); + EXPECT_EQ(::network::mojom::CookieMatchType::STARTS_WITH, + all_subscriptions[0]->match_type); + EXPECT_EQ(GURL(kExampleScope), all_subscriptions[0]->url); +} + +TEST_P(CookieStoreManagerTest, AppendSubscriptionsInvalidRegistrationId) { + worker_test_helper_->SetOnInstallSubscriptions( + std::vector<CookieStoreSync::Subscriptions>(), + example_service_ptr_.get()); + int64_t registration_id = + RegisterServiceWorker(kExampleScope, kExampleWorkerScript); + ASSERT_NE(registration_id, kInvalidRegistrationId); + + if (reset_context_during_test()) + ResetServiceWorkerContext(); + + CookieStoreSync::Subscriptions subscriptions; + subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New()); + subscriptions.back()->name = "cookie_name_prefix"; + subscriptions.back()->match_type = + ::network::mojom::CookieMatchType::STARTS_WITH; + subscriptions.back()->url = GURL(kExampleScope); + + EXPECT_FALSE(example_service_->AppendSubscriptions(registration_id + 100, + std::move(subscriptions))); + + std::vector<blink::mojom::CookieChangeSubscriptionPtr> all_subscriptions = + example_service_->GetSubscriptions(registration_id); + EXPECT_EQ(0u, all_subscriptions.size()); +} + +TEST_P(CookieStoreManagerTest, MultiWorkerSubscriptions) { + { + std::vector<CookieStoreSync::Subscriptions> batches; + batches.emplace_back(); + + CookieStoreSync::Subscriptions& subscriptions = batches.back(); + subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New()); + subscriptions.back()->name = "cookie_name_prefix"; + subscriptions.back()->match_type = + ::network::mojom::CookieMatchType::STARTS_WITH; + subscriptions.back()->url = GURL(kExampleScope); + + worker_test_helper_->SetOnInstallSubscriptions(std::move(batches), + example_service_ptr_.get()); + } + int64_t example_registration_id = + RegisterServiceWorker(kExampleScope, kExampleWorkerScript); + ASSERT_NE(example_registration_id, kInvalidRegistrationId); + + { + std::vector<CookieStoreSync::Subscriptions> batches; + batches.emplace_back(); + + CookieStoreSync::Subscriptions& subscriptions = batches.back(); + subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New()); + subscriptions.back()->name = "cookie_name"; + subscriptions.back()->match_type = + ::network::mojom::CookieMatchType::EQUALS; + subscriptions.back()->url = GURL(kGoogleScope); + + worker_test_helper_->SetOnInstallSubscriptions(std::move(batches), + google_service_ptr_.get()); + } + int64_t google_registration_id = + RegisterServiceWorker(kGoogleScope, kGoogleWorkerScript); + ASSERT_NE(google_registration_id, kInvalidRegistrationId); + EXPECT_NE(example_registration_id, google_registration_id); + + if (reset_context_during_test()) + ResetServiceWorkerContext(); + + std::vector<blink::mojom::CookieChangeSubscriptionPtr> example_subscriptions = + example_service_->GetSubscriptions(example_registration_id); + EXPECT_EQ(1u, example_subscriptions.size()); + EXPECT_EQ("cookie_name_prefix", example_subscriptions[0]->name); + EXPECT_EQ(::network::mojom::CookieMatchType::STARTS_WITH, + example_subscriptions[0]->match_type); + EXPECT_EQ(GURL(kExampleScope), example_subscriptions[0]->url); + + std::vector<blink::mojom::CookieChangeSubscriptionPtr> google_subscriptions = + google_service_->GetSubscriptions(google_registration_id); + EXPECT_EQ(1u, google_subscriptions.size()); + EXPECT_EQ("cookie_name", google_subscriptions[0]->name); + EXPECT_EQ(::network::mojom::CookieMatchType::EQUALS, + google_subscriptions[0]->match_type); + EXPECT_EQ(GURL(kGoogleScope), google_subscriptions[0]->url); +} + +TEST_P(CookieStoreManagerTest, MultipleSubscriptions) { + std::vector<CookieStoreSync::Subscriptions> batches; + + { + batches.emplace_back(); + CookieStoreSync::Subscriptions& subscriptions = batches.back(); + + subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New()); + subscriptions.back()->name = "name1"; + subscriptions.back()->match_type = + ::network::mojom::CookieMatchType::STARTS_WITH; + subscriptions.back()->url = GURL("https://example.com/a/1"); + subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New()); + subscriptions.back()->name = "name2"; + subscriptions.back()->match_type = + ::network::mojom::CookieMatchType::EQUALS; + subscriptions.back()->url = GURL("https://example.com/a/2"); + } + + batches.emplace_back(); + + { + batches.emplace_back(); + CookieStoreSync::Subscriptions& subscriptions = batches.back(); + + subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New()); + subscriptions.back()->name = "name3"; + subscriptions.back()->match_type = + ::network::mojom::CookieMatchType::STARTS_WITH; + subscriptions.back()->url = GURL("https://example.com/a/3"); + } + + worker_test_helper_->SetOnInstallSubscriptions(std::move(batches), + example_service_ptr_.get()); + int64_t registration_id = + RegisterServiceWorker(kExampleScope, kExampleWorkerScript); + ASSERT_NE(registration_id, kInvalidRegistrationId); + + if (reset_context_during_test()) + ResetServiceWorkerContext(); + + std::vector<blink::mojom::CookieChangeSubscriptionPtr> all_subscriptions = + example_service_->GetSubscriptions(registration_id); + + std::sort(all_subscriptions.begin(), all_subscriptions.end(), + CookieChangeSubscriptionLessThan); + + EXPECT_EQ(3u, all_subscriptions.size()); + EXPECT_EQ("name1", all_subscriptions[0]->name); + EXPECT_EQ(::network::mojom::CookieMatchType::STARTS_WITH, + all_subscriptions[0]->match_type); + EXPECT_EQ(GURL("https://example.com/a/1"), all_subscriptions[0]->url); + EXPECT_EQ("name2", all_subscriptions[1]->name); + EXPECT_EQ(::network::mojom::CookieMatchType::EQUALS, + all_subscriptions[1]->match_type); + EXPECT_EQ(GURL("https://example.com/a/2"), all_subscriptions[1]->url); + EXPECT_EQ("name3", all_subscriptions[2]->name); + EXPECT_EQ(::network::mojom::CookieMatchType::STARTS_WITH, + all_subscriptions[2]->match_type); + EXPECT_EQ(GURL("https://example.com/a/3"), all_subscriptions[2]->url); +} + +TEST_P(CookieStoreManagerTest, OneCookieChange) { + std::vector<CookieStoreSync::Subscriptions> batches; + batches.emplace_back(); + + CookieStoreSync::Subscriptions& subscriptions = batches.back(); + subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New()); + subscriptions.back()->name = ""; + subscriptions.back()->match_type = + ::network::mojom::CookieMatchType::STARTS_WITH; + subscriptions.back()->url = GURL(kExampleScope); + + worker_test_helper_->SetOnInstallSubscriptions(std::move(batches), + example_service_ptr_.get()); + int64_t registration_id = + RegisterServiceWorker(kExampleScope, kExampleWorkerScript); + ASSERT_NE(registration_id, kInvalidRegistrationId); + + std::vector<blink::mojom::CookieChangeSubscriptionPtr> all_subscriptions = + example_service_->GetSubscriptions(registration_id); + ASSERT_EQ(1u, all_subscriptions.size()); + + if (reset_context_during_test()) + ResetServiceWorkerContext(); + + ASSERT_TRUE( + SetSessionCookie("cookie-name", "cookie-value", "example.com", "/")); + thread_bundle_.RunUntilIdle(); + + ASSERT_EQ(1u, worker_test_helper_->changes().size()); + EXPECT_EQ("cookie-name", worker_test_helper_->changes()[0].first.Name()); + EXPECT_EQ("cookie-value", worker_test_helper_->changes()[0].first.Value()); + EXPECT_EQ("example.com", worker_test_helper_->changes()[0].first.Domain()); + EXPECT_EQ("/", worker_test_helper_->changes()[0].first.Path()); + EXPECT_EQ(::network::mojom::CookieChangeCause::INSERTED, + worker_test_helper_->changes()[0].second); +} + +TEST_P(CookieStoreManagerTest, CookieChangeNameStartsWith) { + std::vector<CookieStoreSync::Subscriptions> batches; + batches.emplace_back(); + + CookieStoreSync::Subscriptions& subscriptions = batches.back(); + subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New()); + subscriptions.back()->name = "cookie-name-2"; + subscriptions.back()->match_type = + ::network::mojom::CookieMatchType::STARTS_WITH; + subscriptions.back()->url = GURL(kExampleScope); + + worker_test_helper_->SetOnInstallSubscriptions(std::move(batches), + example_service_ptr_.get()); + int64_t registration_id = + RegisterServiceWorker(kExampleScope, kExampleWorkerScript); + ASSERT_NE(registration_id, kInvalidRegistrationId); + + std::vector<blink::mojom::CookieChangeSubscriptionPtr> all_subscriptions = + example_service_->GetSubscriptions(registration_id); + ASSERT_EQ(1u, all_subscriptions.size()); + + if (reset_context_during_test()) + ResetServiceWorkerContext(); + + ASSERT_TRUE( + SetSessionCookie("cookie-name-1", "cookie-value-1", "example.com", "/")); + thread_bundle_.RunUntilIdle(); + EXPECT_EQ(0u, worker_test_helper_->changes().size()); + + worker_test_helper_->changes().clear(); + ASSERT_TRUE( + SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/")); + thread_bundle_.RunUntilIdle(); + + ASSERT_EQ(1u, worker_test_helper_->changes().size()); + EXPECT_EQ("cookie-name-2", worker_test_helper_->changes()[0].first.Name()); + EXPECT_EQ("cookie-value-2", worker_test_helper_->changes()[0].first.Value()); + EXPECT_EQ("example.com", worker_test_helper_->changes()[0].first.Domain()); + EXPECT_EQ("/", worker_test_helper_->changes()[0].first.Path()); + EXPECT_EQ(::network::mojom::CookieChangeCause::INSERTED, + worker_test_helper_->changes()[0].second); + + worker_test_helper_->changes().clear(); + ASSERT_TRUE(SetSessionCookie("cookie-name-22", "cookie-value-22", + "example.com", "/")); + thread_bundle_.RunUntilIdle(); + + ASSERT_EQ(1u, worker_test_helper_->changes().size()); + EXPECT_EQ("cookie-name-22", worker_test_helper_->changes()[0].first.Name()); + EXPECT_EQ("cookie-value-22", worker_test_helper_->changes()[0].first.Value()); + EXPECT_EQ("example.com", worker_test_helper_->changes()[0].first.Domain()); + EXPECT_EQ("/", worker_test_helper_->changes()[0].first.Path()); + EXPECT_EQ(::network::mojom::CookieChangeCause::INSERTED, + worker_test_helper_->changes()[0].second); +} + +TEST_P(CookieStoreManagerTest, CookieChangeUrl) { + std::vector<CookieStoreSync::Subscriptions> batches; + batches.emplace_back(); + + CookieStoreSync::Subscriptions& subscriptions = batches.back(); + subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New()); + subscriptions.back()->name = ""; + subscriptions.back()->match_type = + ::network::mojom::CookieMatchType::STARTS_WITH; + subscriptions.back()->url = GURL(kExampleScope); + + worker_test_helper_->SetOnInstallSubscriptions(std::move(batches), + example_service_ptr_.get()); + int64_t registration_id = + RegisterServiceWorker(kExampleScope, kExampleWorkerScript); + ASSERT_NE(registration_id, kInvalidRegistrationId); + + std::vector<blink::mojom::CookieChangeSubscriptionPtr> all_subscriptions = + example_service_->GetSubscriptions(registration_id); + ASSERT_EQ(1u, all_subscriptions.size()); + + if (reset_context_during_test()) + ResetServiceWorkerContext(); + + ASSERT_TRUE( + SetSessionCookie("cookie-name-1", "cookie-value-1", "google.com", "/")); + thread_bundle_.RunUntilIdle(); + ASSERT_EQ(0u, worker_test_helper_->changes().size()); + + worker_test_helper_->changes().clear(); + ASSERT_TRUE(SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", + "/a/subpath")); + thread_bundle_.RunUntilIdle(); + EXPECT_EQ(0u, worker_test_helper_->changes().size()); + + worker_test_helper_->changes().clear(); + ASSERT_TRUE( + SetSessionCookie("cookie-name-3", "cookie-value-3", "example.com", "/")); + thread_bundle_.RunUntilIdle(); + + ASSERT_EQ(1u, worker_test_helper_->changes().size()); + EXPECT_EQ("cookie-name-3", worker_test_helper_->changes()[0].first.Name()); + EXPECT_EQ("cookie-value-3", worker_test_helper_->changes()[0].first.Value()); + EXPECT_EQ("example.com", worker_test_helper_->changes()[0].first.Domain()); + EXPECT_EQ("/", worker_test_helper_->changes()[0].first.Path()); + EXPECT_EQ(::network::mojom::CookieChangeCause::INSERTED, + worker_test_helper_->changes()[0].second); + + worker_test_helper_->changes().clear(); + ASSERT_TRUE( + SetSessionCookie("cookie-name-4", "cookie-value-4", "example.com", "/a")); + thread_bundle_.RunUntilIdle(); + + ASSERT_EQ(1u, worker_test_helper_->changes().size()); + EXPECT_EQ("cookie-name-4", worker_test_helper_->changes()[0].first.Name()); + EXPECT_EQ("cookie-value-4", worker_test_helper_->changes()[0].first.Value()); + EXPECT_EQ("example.com", worker_test_helper_->changes()[0].first.Domain()); + EXPECT_EQ("/a", worker_test_helper_->changes()[0].first.Path()); + EXPECT_EQ(::network::mojom::CookieChangeCause::INSERTED, + worker_test_helper_->changes()[0].second); +} + +INSTANTIATE_TEST_CASE_P(CookieStoreManagerTest, + CookieStoreManagerTest, + testing::Bool() /* reset_storage_during_test */); + +} // namespace + +} // namespace content
diff --git a/content/browser/media/audio_input_stream_broker_unittest.cc b/content/browser/media/audio_input_stream_broker_unittest.cc index 956f5f04..f0e1ce4 100644 --- a/content/browser/media/audio_input_stream_broker_unittest.cc +++ b/content/browser/media/audio_input_stream_broker_unittest.cc
@@ -68,6 +68,7 @@ mojo::Binding<mojom::RendererAudioInputStreamFactoryClient> binding_; media::mojom::AudioInputStreamPtr input_stream_; media::mojom::AudioInputStreamClientRequest client_request_; + DISALLOW_COPY_AND_ASSIGN(MockRendererAudioInputStreamFactoryClient); }; class MockStreamFactory : public audio::FakeStreamFactory { @@ -128,6 +129,7 @@ } StreamRequestData* stream_request_data_; + DISALLOW_COPY_AND_ASSIGN(MockStreamFactory); }; struct TestEnvironment {
diff --git a/content/browser/media/audio_loopback_stream_broker.cc b/content/browser/media/audio_loopback_stream_broker.cc new file mode 100644 index 0000000..6d1b8af --- /dev/null +++ b/content/browser/media/audio_loopback_stream_broker.cc
@@ -0,0 +1,163 @@ +// 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 "content/browser/media/audio_loopback_stream_broker.h" + +#include <utility> + +#include "base/unguessable_token.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_process_host.h" + +namespace content { + +AudioStreamBrokerFactory::LoopbackSource::LoopbackSource() = default; + +AudioStreamBrokerFactory::LoopbackSource::LoopbackSource( + WebContents* source_contents) + : WebContentsObserver(source_contents) { + DCHECK(source_contents); +} + +AudioStreamBrokerFactory::LoopbackSource::~LoopbackSource() = default; + +base::UnguessableToken AudioStreamBrokerFactory::LoopbackSource::GetGroupID() { + if (WebContentsImpl* source_contents = + static_cast<WebContentsImpl*>(web_contents())) { + return source_contents->GetAudioStreamFactory()->group_id(); + } + return base::UnguessableToken(); +} + +void AudioStreamBrokerFactory::LoopbackSource::OnStartCapturing() { + if (WebContentsImpl* source_contents = + static_cast<WebContentsImpl*>(web_contents())) { + source_contents->IncrementCapturerCount(gfx::Size()); + } +} + +void AudioStreamBrokerFactory::LoopbackSource::OnStopCapturing() { + if (WebContentsImpl* source_contents = + static_cast<WebContentsImpl*>(web_contents())) { + source_contents->DecrementCapturerCount(); + } +} + +void AudioStreamBrokerFactory::LoopbackSource::WebContentsDestroyed() { + if (on_gone_closure_) + std::move(on_gone_closure_).Run(); +} + +AudioLoopbackStreamBroker::AudioLoopbackStreamBroker( + int render_process_id, + int render_frame_id, + std::unique_ptr<AudioStreamBrokerFactory::LoopbackSource> source, + const media::AudioParameters& params, + uint32_t shared_memory_count, + bool mute_source, + AudioStreamBroker::DeleterCallback deleter, + mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) + : AudioStreamBroker(render_process_id, render_frame_id), + source_(std::move(source)), + params_(params), + shared_memory_count_(shared_memory_count), + deleter_(std::move(deleter)), + renderer_factory_client_(std::move(renderer_factory_client)), + observer_binding_(this), + weak_ptr_factory_(this) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK(source_); + DCHECK(source_->GetGroupID()); + DCHECK(renderer_factory_client_); + DCHECK(deleter_); + + // Unretained is safe because |this| owns |source_|. + source_->set_on_gone_closure(base::BindOnce( + &AudioLoopbackStreamBroker::Cleanup, base::Unretained(this))); + + if (mute_source) { + muter_.emplace(source_->GetGroupID()); + } + + // Unretained is safe because |this| owns |renderer_factory_client_|. + renderer_factory_client_.set_connection_error_handler(base::BindOnce( + &AudioLoopbackStreamBroker::Cleanup, base::Unretained(this))); + + // Notify the source that we are capturing from it, to prevent its + // backgrounding. + source_->OnStartCapturing(); + + // Notify RenderProcessHost about the input stream, so that the destination + // renderer does not get background. + if (auto* process_host = RenderProcessHost::FromID(render_process_id)) + process_host->OnMediaStreamAdded(); +} + +AudioLoopbackStreamBroker::~AudioLoopbackStreamBroker() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + source_->OnStopCapturing(); + + if (auto* process_host = RenderProcessHost::FromID(render_process_id())) + process_host->OnMediaStreamRemoved(); +} + +void AudioLoopbackStreamBroker::CreateStream( + audio::mojom::StreamFactory* factory) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK(!observer_binding_.is_bound()); + DCHECK(!client_request_); + DCHECK(source_->GetGroupID()); + + if (muter_) // Mute the source. + muter_->Connect(factory); + + media::mojom::AudioInputStreamClientPtr client; + client_request_ = mojo::MakeRequest(&client); + + media::mojom::AudioInputStreamPtr stream; + media::mojom::AudioInputStreamRequest stream_request = + mojo::MakeRequest(&stream); + + media::mojom::AudioInputStreamObserverPtr observer_ptr; + observer_binding_.Bind(mojo::MakeRequest(&observer_ptr)); + + // Unretained is safe because |this| owns |observer_binding_|. + observer_binding_.set_connection_error_handler(base::BindOnce( + &AudioLoopbackStreamBroker::Cleanup, base::Unretained(this))); + + factory->CreateLoopbackStream( + std::move(stream_request), std::move(client), std::move(observer_ptr), + params_, shared_memory_count_, source_->GetGroupID(), + base::BindOnce(&AudioLoopbackStreamBroker::StreamCreated, + weak_ptr_factory_.GetWeakPtr(), std::move(stream))); +} + +void AudioLoopbackStreamBroker::DidStartRecording() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); +} + +void AudioLoopbackStreamBroker::StreamCreated( + media::mojom::AudioInputStreamPtr stream, + media::mojom::AudioDataPipePtr data_pipe) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + if (!data_pipe) { + Cleanup(); + return; + } + + DCHECK(renderer_factory_client_); + renderer_factory_client_->StreamCreated( + std::move(stream), std::move(client_request_), std::move(data_pipe), + false /* |initially_muted|: Loopback streams are never muted. */); +} + +void AudioLoopbackStreamBroker::Cleanup() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + std::move(deleter_).Run(this); +} + +} // namespace content
diff --git a/content/browser/media/audio_loopback_stream_broker.h b/content/browser/media/audio_loopback_stream_broker.h new file mode 100644 index 0000000..71778564 --- /dev/null +++ b/content/browser/media/audio_loopback_stream_broker.h
@@ -0,0 +1,74 @@ +// 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 CONTENT_BROWSER_MEDIA_AUDIO_LOOPBACK_STREAM_BROKER_H_ +#define CONTENT_BROWSER_MEDIA_AUDIO_LOOPBACK_STREAM_BROKER_H_ + +#include <string> + +#include "base/memory/weak_ptr.h" +#include "base/optional.h" +#include "base/sequence_checker.h" +#include "content/browser/media/audio_muting_session.h" +#include "content/browser/media/audio_stream_broker.h" +#include "content/common/content_export.h" +#include "content/common/media/renderer_audio_input_stream_factory.mojom.h" +#include "media/base/audio_parameters.h" +#include "media/mojo/interfaces/audio_input_stream.mojom.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "services/audio/public/mojom/stream_factory.mojom.h" + +namespace content { + +// AudioLoopbackStreamBroker is used to broker a connection between a client +// (typically renderer) and the audio service. It is operated on the UI thread. +class CONTENT_EXPORT AudioLoopbackStreamBroker final + : public AudioStreamBroker, + public media::mojom::AudioInputStreamObserver { + public: + AudioLoopbackStreamBroker( + int render_process_id, + int render_frame_id, + std::unique_ptr<AudioStreamBrokerFactory::LoopbackSource> source, + const media::AudioParameters& params, + uint32_t shared_memory_count, + bool mute_source, + AudioStreamBroker::DeleterCallback deleter, + mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client); + + ~AudioLoopbackStreamBroker() final; + + // Creates the stream. + void CreateStream(audio::mojom::StreamFactory* factory) final; + + // media::AudioInputStreamObserver implementation. + void DidStartRecording() final; + + private: + void StreamCreated(media::mojom::AudioInputStreamPtr stream, + media::mojom::AudioDataPipePtr data_pipe); + void Cleanup(); + + const std::unique_ptr<AudioStreamBrokerFactory::LoopbackSource> source_; + const media::AudioParameters params_; + const uint32_t shared_memory_count_; + + DeleterCallback deleter_; + + // Constructed only if the loopback source playback should be muted while the + // loopback stream is running. + base::Optional<AudioMutingSession> muter_; + + mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client_; + mojo::Binding<AudioInputStreamObserver> observer_binding_; + media::mojom::AudioInputStreamClientRequest client_request_; + + base::WeakPtrFactory<AudioLoopbackStreamBroker> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(AudioLoopbackStreamBroker); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_AUDIO_LOOPBACK_STREAM_BROKER_H_
diff --git a/content/browser/media/audio_loopback_stream_broker_unittest.cc b/content/browser/media/audio_loopback_stream_broker_unittest.cc new file mode 100644 index 0000000..0507f990 --- /dev/null +++ b/content/browser/media/audio_loopback_stream_broker_unittest.cc
@@ -0,0 +1,370 @@ +// 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 "content/browser/media/audio_loopback_stream_broker.h" + +#include <memory> +#include <utility> + +#include "base/sync_socket.h" +#include "base/test/mock_callback.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "media/mojo/interfaces/audio_input_stream.mojom.h" +#include "mojo/public/cpp/system/platform_handle.h" +#include "services/audio/public/cpp/fake_stream_factory.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::_; +using ::testing::Test; +using ::testing::Mock; +using ::testing::NiceMock; +using ::testing::StrictMock; +using ::testing::InSequence; + +namespace content { + +namespace { + +const int kRenderProcessId = 123; +const int kRenderFrameId = 234; +const uint32_t kShMemCount = 10; + +media::AudioParameters TestParams() { + return media::AudioParameters::UnavailableDeviceParams(); +} + +class MockSource : public AudioStreamBrokerFactory::LoopbackSource { + public: + explicit MockSource(const base::UnguessableToken& group_id) + : group_id_(group_id) {} + ~MockSource() override {} + + // AudioStreamBrokerFactory::LoopbackSource mocking. + base::UnguessableToken GetGroupID() override { return group_id_; } + MOCK_METHOD0(OnStartCapturing, void(void)); + MOCK_METHOD0(OnStopCapturing, void(void)); + + private: + base::UnguessableToken group_id_; + DISALLOW_COPY_AND_ASSIGN(MockSource); +}; + +using MockDeleterCallback = StrictMock< + base::MockCallback<base::OnceCallback<void(AudioStreamBroker*)>>>; + +class MockRendererAudioInputStreamFactoryClient + : public mojom::RendererAudioInputStreamFactoryClient { + public: + MockRendererAudioInputStreamFactoryClient() : binding_(this) {} + ~MockRendererAudioInputStreamFactoryClient() override {} + + mojom::RendererAudioInputStreamFactoryClientPtr MakePtr() { + mojom::RendererAudioInputStreamFactoryClientPtr ret; + binding_.Bind(mojo::MakeRequest(&ret)); + return ret; + } + + MOCK_METHOD0(OnStreamCreated, void()); + + void StreamCreated(media::mojom::AudioInputStreamPtr input_stream, + media::mojom::AudioInputStreamClientRequest client_request, + media::mojom::AudioDataPipePtr data_pipe, + bool initially_muted) override { + input_stream_ = std::move(input_stream); + client_request_ = std::move(client_request); + OnStreamCreated(); + } + + void CloseBinding() { binding_.Close(); } + + private: + mojo::Binding<mojom::RendererAudioInputStreamFactoryClient> binding_; + media::mojom::AudioInputStreamPtr input_stream_; + media::mojom::AudioInputStreamClientRequest client_request_; +}; + +class MockStreamFactory : public audio::FakeStreamFactory { + public: + MockStreamFactory() {} + ~MockStreamFactory() final {} + + // State of an expected stream creation. |device_id| and |params| are set + // ahead of time and verified during request. The other fields are filled in + // when the request is received. + struct StreamRequestData { + StreamRequestData(const base::UnguessableToken& group_id, + const media::AudioParameters& params) + : params(params), group_id(group_id) {} + + bool requested = false; + media::mojom::AudioInputStreamRequest stream_request; + media::mojom::AudioInputStreamClientPtr client; + media::mojom::AudioInputStreamObserverPtr observer; + const media::AudioParameters params; + uint32_t shared_memory_count; + base::UnguessableToken group_id; + mojo::ScopedSharedBufferHandle key_press_count_buffer; + CreateLoopbackStreamCallback created_callback; + audio::mojom::LocalMuterAssociatedRequest muter_request; + }; + + void ExpectStreamCreation(StreamRequestData* ex) { + stream_request_data_ = ex; + } + + MOCK_METHOD1(IsMuting, void(const base::UnguessableToken&)); + + private: + void CreateLoopbackStream( + media::mojom::AudioInputStreamRequest stream_request, + media::mojom::AudioInputStreamClientPtr client, + media::mojom::AudioInputStreamObserverPtr observer, + const media::AudioParameters& params, + uint32_t shared_memory_count, + const base::UnguessableToken& group_id, + CreateLoopbackStreamCallback created_callback) final { + // No way to cleanly exit the test here in case of failure, so use CHECK. + CHECK(stream_request_data_); + EXPECT_EQ(stream_request_data_->group_id, group_id); + EXPECT_TRUE(stream_request_data_->params.Equals(params)); + stream_request_data_->requested = true; + stream_request_data_->stream_request = std::move(stream_request); + stream_request_data_->client = std::move(client); + stream_request_data_->observer = std::move(observer); + stream_request_data_->shared_memory_count = shared_memory_count; + stream_request_data_->created_callback = std::move(created_callback); + } + + void BindMuter(audio::mojom::LocalMuterAssociatedRequest request, + const base::UnguessableToken& group_id) final { + stream_request_data_->muter_request = std::move(request); + IsMuting(group_id); + } + + StreamRequestData* stream_request_data_; + + DISALLOW_COPY_AND_ASSIGN(MockStreamFactory); +}; + +const bool kMuteSource = true; + +struct TestEnvironment { + TestEnvironment(const base::UnguessableToken& group_id, bool mute_source) { + // Muting should not start until CreateStream() is called. + EXPECT_CALL(stream_factory, IsMuting(_)).Times(0); + auto mock_source = std::make_unique<NiceMock<MockSource>>(group_id); + source = mock_source.get(); + broker = std::make_unique<AudioLoopbackStreamBroker>( + kRenderProcessId, kRenderFrameId, std::move(mock_source), TestParams(), + kShMemCount, mute_source, deleter.Get(), + renderer_factory_client.MakePtr()); + } + + void RunUntilIdle() { thread_bundle.RunUntilIdle(); } + + TestBrowserThreadBundle thread_bundle; + MockDeleterCallback deleter; + MockSource* source; + StrictMock<MockRendererAudioInputStreamFactoryClient> renderer_factory_client; + std::unique_ptr<AudioLoopbackStreamBroker> broker; + MockStreamFactory stream_factory; + audio::mojom::StreamFactoryPtr factory_ptr = stream_factory.MakePtr(); +}; + +} // namespace + +TEST(AudioLoopbackStreamBrokerTest, StoresProcessAndFrameId) { + InSequence seq; + TestBrowserThreadBundle thread_bundle; + MockDeleterCallback deleter; + StrictMock<MockRendererAudioInputStreamFactoryClient> renderer_factory_client; + auto source = std::make_unique<StrictMock<MockSource>>( + base::UnguessableToken::Create()); + MockSource* mock_source = source.get(); + + EXPECT_CALL(*mock_source, OnStartCapturing()); + + AudioLoopbackStreamBroker broker(kRenderProcessId, kRenderFrameId, + std::move(source), TestParams(), kShMemCount, + !kMuteSource, deleter.Get(), + renderer_factory_client.MakePtr()); + + EXPECT_EQ(kRenderProcessId, broker.render_process_id()); + EXPECT_EQ(kRenderFrameId, broker.render_frame_id()); + + EXPECT_CALL(*mock_source, OnStopCapturing()); +} + +TEST(AudioLoopbackStreamBrokerTest, StreamCreationSuccess_Propagates) { + TestEnvironment env(base::UnguessableToken::Create(), !kMuteSource); + MockStreamFactory::StreamRequestData stream_request_data( + env.source->GetGroupID(), TestParams()); + env.stream_factory.ExpectStreamCreation(&stream_request_data); + + EXPECT_CALL(env.stream_factory, IsMuting(_)).Times(0); + + env.broker->CreateStream(env.factory_ptr.get()); + env.RunUntilIdle(); + + EXPECT_TRUE(stream_request_data.requested); + + // Set up test IPC primitives. + const size_t shmem_size = 456; + base::SyncSocket socket1, socket2; + base::SyncSocket::CreatePair(&socket1, &socket2); + std::move(stream_request_data.created_callback) + .Run({base::in_place, mojo::SharedBufferHandle::Create(shmem_size), + mojo::WrapPlatformFile(socket1.Release())}); + + EXPECT_CALL(env.renderer_factory_client, OnStreamCreated()); + + env.RunUntilIdle(); + + Mock::VerifyAndClear(&env.renderer_factory_client); + env.broker.reset(); +} + +TEST(AudioLoopbackStreamBrokerTest, MutedStreamCreation_Mutes) { + TestEnvironment env(base::UnguessableToken::Create(), kMuteSource); + MockStreamFactory::StreamRequestData stream_request_data( + env.source->GetGroupID(), TestParams()); + env.stream_factory.ExpectStreamCreation(&stream_request_data); + + EXPECT_CALL(env.stream_factory, IsMuting(env.source->GetGroupID())); + + env.broker->CreateStream(env.factory_ptr.get()); + env.RunUntilIdle(); + + EXPECT_TRUE(stream_request_data.requested); + + // Set up test IPC primitives. + const size_t shmem_size = 456; + base::SyncSocket socket1, socket2; + base::SyncSocket::CreatePair(&socket1, &socket2); + std::move(stream_request_data.created_callback) + .Run({base::in_place, mojo::SharedBufferHandle::Create(shmem_size), + mojo::WrapPlatformFile(socket1.Release())}); + + EXPECT_CALL(env.renderer_factory_client, OnStreamCreated()); + + env.RunUntilIdle(); + + Mock::VerifyAndClear(&env.renderer_factory_client); + env.broker.reset(); +} + +TEST(AudioLoopbackStreamBrokerTest, SourceGone_CallsDeleter) { + TestEnvironment env(base::UnguessableToken::Create(), kMuteSource); + MockStreamFactory::StreamRequestData stream_request_data( + env.source->GetGroupID(), TestParams()); + env.stream_factory.ExpectStreamCreation(&stream_request_data); + + EXPECT_CALL(env.stream_factory, IsMuting(env.source->GetGroupID())); + + env.broker->CreateStream(env.factory_ptr.get()); + env.RunUntilIdle(); + + EXPECT_TRUE(stream_request_data.requested); + + // Set up test IPC primitives. + const size_t shmem_size = 456; + base::SyncSocket socket1, socket2; + base::SyncSocket::CreatePair(&socket1, &socket2); + std::move(stream_request_data.created_callback) + .Run({base::in_place, mojo::SharedBufferHandle::Create(shmem_size), + mojo::WrapPlatformFile(socket1.Release())}); + + EXPECT_CALL(env.renderer_factory_client, OnStreamCreated()); + + env.RunUntilIdle(); + + Mock::VerifyAndClear(&env.renderer_factory_client); + + EXPECT_CALL(env.deleter, Run(env.broker.release())) + .WillOnce(testing::DeleteArg<0>()); + + env.source->WebContentsDestroyed(); + + env.RunUntilIdle(); +} + +TEST(AudioLoopbackStreamBrokerTest, StreamCreationFailure_CallsDeleter) { + TestEnvironment env(base::UnguessableToken::Create(), !kMuteSource); + MockStreamFactory::StreamRequestData stream_request_data( + env.source->GetGroupID(), TestParams()); + env.stream_factory.ExpectStreamCreation(&stream_request_data); + + EXPECT_CALL(env.stream_factory, IsMuting(_)).Times(0); + + env.broker->CreateStream(env.factory_ptr.get()); + env.RunUntilIdle(); + + EXPECT_TRUE(stream_request_data.requested); + EXPECT_CALL(env.deleter, Run(env.broker.release())) + .WillOnce(testing::DeleteArg<0>()); + + std::move(stream_request_data.created_callback).Run(nullptr); + + env.RunUntilIdle(); +} + +TEST(AudioLoopbackStreamBrokerTest, + RendererFactoryClientDisconnect_CallsDeleter) { + TestEnvironment env(base::UnguessableToken::Create(), !kMuteSource); + MockStreamFactory::StreamRequestData stream_request_data( + env.source->GetGroupID(), TestParams()); + env.stream_factory.ExpectStreamCreation(&stream_request_data); + + EXPECT_CALL(env.stream_factory, IsMuting(_)).Times(0); + + env.broker->CreateStream(env.factory_ptr.get()); + env.RunUntilIdle(); + EXPECT_TRUE(stream_request_data.requested); + + EXPECT_CALL(env.deleter, Run(env.broker.release())) + .WillOnce(testing::DeleteArg<0>()); + env.renderer_factory_client.CloseBinding(); + env.RunUntilIdle(); + Mock::VerifyAndClear(&env.deleter); + + env.stream_factory.CloseBinding(); + env.RunUntilIdle(); +} + +TEST(AudioLoopbackStreamBrokerTest, ObserverDisconnect_CallsDeleter) { + TestEnvironment env(base::UnguessableToken::Create(), !kMuteSource); + MockStreamFactory::StreamRequestData stream_request_data( + env.source->GetGroupID(), TestParams()); + env.stream_factory.ExpectStreamCreation(&stream_request_data); + + EXPECT_CALL(env.stream_factory, IsMuting(_)).Times(0); + + env.broker->CreateStream(env.factory_ptr.get()); + env.RunUntilIdle(); + EXPECT_TRUE(stream_request_data.requested); + + EXPECT_CALL(env.deleter, Run(env.broker.release())) + .WillOnce(testing::DeleteArg<0>()); + stream_request_data.observer.reset(); + env.RunUntilIdle(); + Mock::VerifyAndClear(&env.deleter); + + env.stream_factory.CloseBinding(); + env.RunUntilIdle(); +} + +TEST(AudioLoopbackStreamBrokerTest, + FactoryDisconnectDuringConstruction_CallsDeleter) { + TestEnvironment env(base::UnguessableToken::Create(), !kMuteSource); + env.broker->CreateStream(env.factory_ptr.get()); + env.stream_factory.CloseBinding(); + + EXPECT_CALL(env.deleter, Run(env.broker.release())) + .WillOnce(testing::DeleteArg<0>()); + + env.RunUntilIdle(); +} + +} // namespace content
diff --git a/content/browser/media/audio_muting_session.cc b/content/browser/media/audio_muting_session.cc new file mode 100644 index 0000000..6e8c13d3 --- /dev/null +++ b/content/browser/media/audio_muting_session.cc
@@ -0,0 +1,22 @@ +// 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 "content/browser/media/audio_muting_session.h" + +namespace content { + +AudioMutingSession::AudioMutingSession(const base::UnguessableToken& group_id) + : group_id_(group_id) {} + +AudioMutingSession::~AudioMutingSession(){}; + +void AudioMutingSession::Connect(audio::mojom::StreamFactory* factory) { + if (muter_) + muter_.reset(); + + DCHECK(factory); + factory->BindMuter(mojo::MakeRequest(&muter_), group_id_); +} + +} // namespace content
diff --git a/content/browser/media/audio_muting_session.h b/content/browser/media/audio_muting_session.h new file mode 100644 index 0000000..a13c13c --- /dev/null +++ b/content/browser/media/audio_muting_session.h
@@ -0,0 +1,32 @@ +// 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 CONTENT_BROWSER_MEDIA_AUDIO_MUTING_SESSION_H_ +#define CONTENT_BROWSER_MEDIA_AUDIO_MUTING_SESSION_H_ + +#include <utility> + +#include "base/unguessable_token.h" +#include "content/common/content_export.h" +#include "services/audio/public/mojom/stream_factory.mojom.h" + +namespace content { + +class CONTENT_EXPORT AudioMutingSession { + public: + explicit AudioMutingSession(const base::UnguessableToken& group_id); + ~AudioMutingSession(); + + void Connect(audio::mojom::StreamFactory* factory); + + private: + const base::UnguessableToken group_id_; + audio::mojom::LocalMuterAssociatedPtr muter_; + + DISALLOW_COPY_AND_ASSIGN(AudioMutingSession); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_AUDIO_MUTING_SESSION_H_
diff --git a/content/browser/media/audio_output_stream_broker_unittest.cc b/content/browser/media/audio_output_stream_broker_unittest.cc index 2a634904..1c9213a 100644 --- a/content/browser/media/audio_output_stream_broker_unittest.cc +++ b/content/browser/media/audio_output_stream_broker_unittest.cc
@@ -74,6 +74,7 @@ private: mojo::Binding<media::mojom::AudioOutputStreamProviderClient> binding_; + DISALLOW_COPY_AND_ASSIGN(MockAudioOutputStreamProviderClient); }; class MockStreamFactory : public audio::FakeStreamFactory { @@ -128,6 +129,7 @@ } StreamRequestData* stream_request_data_; + DISALLOW_COPY_AND_ASSIGN(MockStreamFactory); }; // This struct collects test state we need without doing anything fancy.
diff --git a/content/browser/media/audio_stream_broker.cc b/content/browser/media/audio_stream_broker.cc index abe535a..6ff668c 100644 --- a/content/browser/media/audio_stream_broker.cc +++ b/content/browser/media/audio_stream_broker.cc
@@ -7,6 +7,7 @@ #include <utility> #include "content/browser/media/audio_input_stream_broker.h" +#include "content/browser/media/audio_loopback_stream_broker.h" #include "content/browser/media/audio_output_stream_broker.h" namespace content { @@ -34,6 +35,22 @@ std::move(renderer_factory_client)); } + std::unique_ptr<AudioStreamBroker> CreateAudioLoopbackStreamBroker( + int render_process_id, + int render_frame_id, + std::unique_ptr<LoopbackSource> source, + const media::AudioParameters& params, + uint32_t shared_memory_count, + bool mute_source, + AudioStreamBroker::DeleterCallback deleter, + mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) + final { + return std::make_unique<AudioLoopbackStreamBroker>( + render_process_id, render_frame_id, std::move(source), params, + shared_memory_count, mute_source, std::move(deleter), + std::move(renderer_factory_client)); + } + std::unique_ptr<AudioStreamBroker> CreateAudioOutputStreamBroker( int render_process_id, int render_frame_id,
diff --git a/content/browser/media/audio_stream_broker.h b/content/browser/media/audio_stream_broker.h index 29e3079..40af0ea 100644 --- a/content/browser/media/audio_stream_broker.h +++ b/content/browser/media/audio_stream_broker.h
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "content/common/content_export.h" #include "content/common/media/renderer_audio_input_stream_factory.mojom.h" +#include "content/public/browser/web_contents_observer.h" #include "media/mojo/interfaces/audio_input_stream.mojom.h" #include "media/mojo/interfaces/audio_output_stream.mojom.h" @@ -30,6 +31,7 @@ } namespace content { +class WebContents; // An AudioStreamBroker is used to broker a connection between a client // (typically renderer) and the audio service. It also sets up all objects @@ -57,6 +59,38 @@ // Used for dependency injection into ForwardingAudioStreamFactory. class CONTENT_EXPORT AudioStreamBrokerFactory { public: + class CONTENT_EXPORT LoopbackSource : public WebContentsObserver { + public: + explicit LoopbackSource(WebContents* source_contents); + ~LoopbackSource() override; + + // Virtual for mocking in tests. + // Will return an empty token if the source is not present. + + virtual base::UnguessableToken GetGroupID(); + + // Signals the source WebContents that capturing started. + virtual void OnStartCapturing(); + + // Signals the source WebContents that capturing stopped. + virtual void OnStopCapturing(); + + // Sets the closure to run when the source WebContents is gone. + void set_on_gone_closure(base::OnceClosure on_gone_closure) { + on_gone_closure_ = std::move(on_gone_closure); + } + + // WebContentsObserver implementation. + void WebContentsDestroyed() override; + + protected: + LoopbackSource(); + + private: + base::OnceClosure on_gone_closure_; + DISALLOW_COPY_AND_ASSIGN(LoopbackSource); + }; + static std::unique_ptr<AudioStreamBrokerFactory> CreateImpl(); AudioStreamBrokerFactory(); @@ -73,6 +107,17 @@ mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) = 0; + virtual std::unique_ptr<AudioStreamBroker> CreateAudioLoopbackStreamBroker( + int render_process_id, + int render_frame_id, + std::unique_ptr<LoopbackSource> source, + const media::AudioParameters& params, + uint32_t shared_memory_count, + bool mute_source, + AudioStreamBroker::DeleterCallback deleter, + mojom::RendererAudioInputStreamFactoryClientPtr + renderer_factory_client) = 0; + virtual std::unique_ptr<AudioStreamBroker> CreateAudioOutputStreamBroker( int render_process_id, int render_frame_id,
diff --git a/content/browser/media/forwarding_audio_stream_factory.cc b/content/browser/media/forwarding_audio_stream_factory.cc index ad71db9..63c426ab 100644 --- a/content/browser/media/forwarding_audio_stream_factory.cc +++ b/content/browser/media/forwarding_audio_stream_factory.cc
@@ -79,6 +79,7 @@ const int process_id = frame->GetProcess()->GetID(); const int frame_id = frame->GetRoutingID(); + outputs_ .insert(broker_factory_->CreateAudioOutputStreamBroker( process_id, frame_id, ++stream_id_counter_, device_id, params, @@ -90,18 +91,55 @@ ->CreateStream(GetFactory()); } +void ForwardingAudioStreamFactory::CreateLoopbackStream( + RenderFrameHost* frame, + WebContents* source_contents, + const media::AudioParameters& params, + uint32_t shared_memory_count, + bool mute_source, + mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + const int process_id = frame->GetProcess()->GetID(); + const int frame_id = frame->GetRoutingID(); + inputs_ + .insert(broker_factory_->CreateAudioLoopbackStreamBroker( + process_id, frame_id, + std::make_unique<AudioStreamBrokerFactory::LoopbackSource>( + source_contents), + params, shared_memory_count, mute_source, + base::BindOnce(&ForwardingAudioStreamFactory::RemoveInput, + base::Unretained(this)), + std::move(renderer_factory_client))) + .first->get() + ->CreateStream(GetFactory()); +} + +void ForwardingAudioStreamFactory::SetMuted(bool muted) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_NE(muted, IsMuted()); + + if (!muted) { + muter_.reset(); + return; + } + + muter_.emplace(group_id_); + if (remote_factory_) + muter_->Connect(remote_factory_.get()); +} + +bool ForwardingAudioStreamFactory::IsMuted() const { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + return !!muter_; +} + void ForwardingAudioStreamFactory::FrameDeleted( RenderFrameHost* render_frame_host) { DCHECK_CURRENTLY_ON(BrowserThread::UI); CleanupStreamsBelongingTo(render_frame_host); } -void ForwardingAudioStreamFactory::WebContentsDestroyed() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(outputs_.empty()); - DCHECK(inputs_.empty()); -} - void ForwardingAudioStreamFactory::CleanupStreamsBelongingTo( RenderFrameHost* render_frame_host) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -145,6 +183,10 @@ remote_factory_.set_connection_error_handler( base::BindOnce(&ForwardingAudioStreamFactory::ResetRemoteFactoryPtr, base::Unretained(this))); + + // Restore the muting session on reconnect. + if (muter_) + muter_->Connect(remote_factory_.get()); } return remote_factory_.get(); @@ -161,6 +203,8 @@ remote_factory_.reset(); // The stream brokers will call a callback to be deleted soon, give them a // chance to signal an error to the client first. + inputs_.clear(); + outputs_.clear(); } } // namespace content
diff --git a/content/browser/media/forwarding_audio_stream_factory.h b/content/browser/media/forwarding_audio_stream_factory.h index 535a604e..12667079 100644 --- a/content/browser/media/forwarding_audio_stream_factory.h +++ b/content/browser/media/forwarding_audio_stream_factory.h
@@ -11,7 +11,9 @@ #include "base/containers/flat_set.h" #include "base/containers/unique_ptr_adapters.h" #include "base/macros.h" +#include "base/optional.h" #include "base/unguessable_token.h" +#include "content/browser/media/audio_muting_session.h" #include "content/browser/media/audio_stream_broker.h" #include "content/common/content_export.h" #include "content/common/media/renderer_audio_input_stream_factory.mojom.h" @@ -30,6 +32,7 @@ class AudioStreamBroker; class RenderFrameHost; +class WebContents; // This class handles stream creation operations for a WebContents. // This class is operated on the UI thread. @@ -50,7 +53,6 @@ const base::UnguessableToken& group_id() { return group_id_; } - // TODO(https://crbug.com/803102): Add loopback and muting streams. // TODO(https://crbug.com/787806): Automatically restore streams on audio // service restart. void CreateInputStream( @@ -67,10 +69,23 @@ const media::AudioParameters& params, media::mojom::AudioOutputStreamProviderClientPtr client); + void CreateLoopbackStream( + RenderFrameHost* frame, + WebContents* source_contents, + const media::AudioParameters& params, + uint32_t shared_memory_count, + bool mute_source, + mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client); + + // Sets the muting state for all output streams created through this factory. + void SetMuted(bool muted); + + // Returns the current muting state. + bool IsMuted() const; + // WebContentsObserver implementation. We observe these events so that we can // clean up streams belonging to a frame when that frame is destroyed. void FrameDeleted(RenderFrameHost* render_frame_host) final; - void WebContentsDestroyed() final; // E.g. to override binder. service_manager::Connector* get_connector_for_testing() { @@ -111,6 +126,9 @@ // remove it. int stream_id_counter_ = 0; + // Instantiated when |outputs_| should be muted, empty otherwise. + base::Optional<AudioMutingSession> muter_; + StreamBrokerSet inputs_; StreamBrokerSet outputs_;
diff --git a/content/browser/media/forwarding_audio_stream_factory_unittest.cc b/content/browser/media/forwarding_audio_stream_factory_unittest.cc index b96e500..d3c1e688 100644 --- a/content/browser/media/forwarding_audio_stream_factory_unittest.cc +++ b/content/browser/media/forwarding_audio_stream_factory_unittest.cc
@@ -14,11 +14,14 @@ #include "base/unguessable_token.h" #include "content/common/media/renderer_audio_input_stream_factory.mojom.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/web_contents.h" #include "content/public/test/test_renderer_host.h" #include "media/base/audio_parameters.h" #include "media/mojo/interfaces/audio_output_stream.mojom.h" +#include "mojo/public/cpp/bindings/associated_binding.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/interface_request.h" +#include "services/audio/public/cpp/fake_stream_factory.h" #include "services/audio/public/mojom/constants.mojom.h" #include "services/audio/public/mojom/stream_factory.mojom.h" #include "services/service_manager/public/cpp/connector.h" @@ -35,6 +38,30 @@ namespace { +class MockStreamFactory : public audio::FakeStreamFactory, + public audio::mojom::LocalMuter { + public: + MockStreamFactory() : muter_binding_(this) {} + ~MockStreamFactory() final {} + + bool IsConnected() { + return binding_ && !binding_.handle().QuerySignalsState().peer_closed(); + } + bool IsMuterConnected() { return muter_binding_.is_bound(); } + + private: + void BindMuter(audio::mojom::LocalMuterAssociatedRequest request, + const base::UnguessableToken& group_id) final { + muter_binding_.Bind(std::move(request)); + muter_binding_.set_connection_error_handler(base::BindOnce( + &MockStreamFactory::MuterUnbound, base::Unretained(this))); + } + void MuterUnbound() { muter_binding_.Close(); } + + mojo::AssociatedBinding<audio::mojom::LocalMuter> muter_binding_; + DISALLOW_COPY_AND_ASSIGN(MockStreamFactory); +}; + class MockBroker : public AudioStreamBroker { public: explicit MockBroker(RenderFrameHost* rfh) @@ -52,6 +79,7 @@ private: base::WeakPtrFactory<MockBroker> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(MockBroker); }; class MockBrokerFactory : public AudioStreamBrokerFactory { @@ -72,6 +100,10 @@ prepared_output_stream_brokers_.push(std::move(broker)); } + void ExpectLoopbackStreamBrokerCreation(std::unique_ptr<MockBroker> broker) { + prepared_loopback_stream_brokers_.push(std::move(broker)); + } + std::unique_ptr<AudioStreamBroker> CreateAudioInputStreamBroker( int render_process_id, int render_frame_id, @@ -111,9 +143,31 @@ return std::move(prepared_broker); } + std::unique_ptr<AudioStreamBroker> CreateAudioLoopbackStreamBroker( + int render_process_id, + int render_frame_id, + std::unique_ptr<LoopbackSource> source, + const media::AudioParameters& params, + uint32_t shared_memory_count, + bool mute_source, + AudioStreamBroker::DeleterCallback deleter, + mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) + final { + std::unique_ptr<MockBroker> prepared_broker = + std::move(prepared_loopback_stream_brokers_.front()); + prepared_loopback_stream_brokers_.pop(); + CHECK_NE(nullptr, prepared_broker.get()); + EXPECT_EQ(render_process_id, prepared_broker->render_process_id()); + EXPECT_EQ(render_frame_id, prepared_broker->render_frame_id()); + prepared_broker->deleter = std::move(deleter); + return std::move(prepared_broker); + } + private: + base::queue<std::unique_ptr<MockBroker>> prepared_loopback_stream_brokers_; base::queue<std::unique_ptr<MockBroker>> prepared_input_stream_brokers_; base::queue<std::unique_ptr<MockBroker>> prepared_output_stream_brokers_; + DISALLOW_COPY_AND_ASSIGN(MockBrokerFactory); }; class ForwardingAudioStreamFactoryTest : public RenderViewHostTestHarness { @@ -125,9 +179,8 @@ connector_test_api.OverrideBinderForTesting( service_manager::Identity(audio::mojom::kServiceName), audio::mojom::StreamFactory::Name_, - base::BindRepeating( - &ForwardingAudioStreamFactoryTest::SetPendingFactoryRequest, - base::Unretained(this))); + base::BindRepeating(&ForwardingAudioStreamFactoryTest::BindFactory, + base::Unretained(this))); } ~ForwardingAudioStreamFactoryTest() override {} @@ -139,8 +192,17 @@ RenderFrameHostTester::For(main_rfh())->AppendChild("other_rfh"); } - void SetPendingFactoryRequest(mojo::ScopedMessagePipeHandle factory_request) { - pending_factory_request_ = std::move(factory_request); + void BindFactory(mojo::ScopedMessagePipeHandle factory_request) { + stream_factory_.binding_.Bind( + audio::mojom::StreamFactoryRequest(std::move(factory_request))); + } + + base::WeakPtr<MockBroker> ExpectLoopbackBrokerConstruction( + RenderFrameHost* rfh) { + auto broker = std::make_unique<StrictMock<MockBroker>>(rfh); + auto weak_broker = broker->GetWeakPtr(); + broker_factory_->ExpectLoopbackStreamBrokerCreation(std::move(broker)); + return weak_broker; } base::WeakPtr<MockBroker> ExpectInputBrokerConstruction( @@ -166,9 +228,9 @@ static const media::AudioParameters kParams; static const uint32_t kSharedMemoryCount; static const bool kEnableAgc; + MockStreamFactory stream_factory_; service_manager::mojom::ConnectorRequest connector_request_; std::unique_ptr<service_manager::Connector> connector_; - mojo::ScopedMessagePipeHandle pending_factory_request_; RenderFrameHost* other_rfh_; std::unique_ptr<MockBrokerFactory> broker_factory_; }; @@ -181,6 +243,7 @@ media::AudioParameters::UnavailableDeviceParams(); const uint32_t ForwardingAudioStreamFactoryTest::kSharedMemoryCount = 10; const bool ForwardingAudioStreamFactoryTest::kEnableAgc = false; +const bool kMuteSource = true; } // namespace @@ -198,6 +261,23 @@ } TEST_F(ForwardingAudioStreamFactoryTest, + CreateLoopbackStream_CreatesLoopbackStream) { + std::unique_ptr<WebContents> source_contents = CreateTestWebContents(); + mojom::RendererAudioInputStreamFactoryClientPtr client; + base::WeakPtr<MockBroker> broker = + ExpectLoopbackBrokerConstruction(main_rfh()); + + ForwardingAudioStreamFactory factory(web_contents(), std::move(connector_), + std::move(broker_factory_)); + + EXPECT_CALL(*broker, CreateStream(NotNull())); + mojo::MakeRequest(&client); + factory.CreateLoopbackStream(main_rfh(), source_contents.get(), kParams, + kSharedMemoryCount, kMuteSource, + std::move(client)); +} + +TEST_F(ForwardingAudioStreamFactoryTest, CreateOutputStream_CreatesOutputStream) { media::mojom::AudioOutputStreamProviderClientPtr client; base::WeakPtr<MockBroker> broker = ExpectOutputBrokerConstruction(main_rfh()); @@ -246,6 +326,41 @@ } TEST_F(ForwardingAudioStreamFactoryTest, + LoopbackBrokerDeleterCalled_DestroysInputStream) { + std::unique_ptr<WebContents> source_contents = CreateTestWebContents(); + mojom::RendererAudioInputStreamFactoryClientPtr client; + base::WeakPtr<MockBroker> main_rfh_broker = + ExpectLoopbackBrokerConstruction(main_rfh()); + base::WeakPtr<MockBroker> other_rfh_broker = + ExpectLoopbackBrokerConstruction(other_rfh()); + + ForwardingAudioStreamFactory factory(web_contents(), std::move(connector_), + std::move(broker_factory_)); + + { + EXPECT_CALL(*main_rfh_broker, CreateStream(NotNull())); + mojo::MakeRequest(&client); + factory.CreateLoopbackStream(main_rfh(), source_contents.get(), kParams, + kSharedMemoryCount, kMuteSource, + std::move(client)); + testing::Mock::VerifyAndClear(&*main_rfh_broker); + } + { + EXPECT_CALL(*other_rfh_broker, CreateStream(NotNull())); + mojo::MakeRequest(&client); + factory.CreateLoopbackStream(other_rfh(), source_contents.get(), kParams, + kSharedMemoryCount, kMuteSource, + std::move(client)); + testing::Mock::VerifyAndClear(&*other_rfh_broker); + } + + std::move(other_rfh_broker->deleter).Run(&*other_rfh_broker); + EXPECT_FALSE(other_rfh_broker) + << "Loopback broker should be destructed when deleter is called."; + EXPECT_TRUE(main_rfh_broker); +} + +TEST_F(ForwardingAudioStreamFactoryTest, OutputBrokerDeleterCalled_DestroysOutputStream) { media::mojom::AudioOutputStreamProviderClientPtr client; base::WeakPtr<MockBroker> main_rfh_broker = @@ -278,12 +393,19 @@ } TEST_F(ForwardingAudioStreamFactoryTest, DestroyFrame_DestroysRelatedStreams) { + std::unique_ptr<WebContents> source_contents = CreateTestWebContents(); + mojom::RendererAudioInputStreamFactoryClientPtr input_client; base::WeakPtr<MockBroker> main_rfh_input_broker = ExpectInputBrokerConstruction(main_rfh()); base::WeakPtr<MockBroker> other_rfh_input_broker = ExpectInputBrokerConstruction(other_rfh()); + base::WeakPtr<MockBroker> main_rfh_loopback_broker = + ExpectLoopbackBrokerConstruction(main_rfh()); + base::WeakPtr<MockBroker> other_rfh_loopback_broker = + ExpectLoopbackBrokerConstruction(other_rfh()); + media::mojom::AudioOutputStreamProviderClientPtr output_client; base::WeakPtr<MockBroker> main_rfh_output_broker = ExpectOutputBrokerConstruction(main_rfh()); @@ -311,6 +433,23 @@ } { + EXPECT_CALL(*main_rfh_loopback_broker, CreateStream(NotNull())); + mojo::MakeRequest(&input_client); + factory.CreateLoopbackStream(main_rfh(), source_contents.get(), kParams, + kSharedMemoryCount, kMuteSource, + std::move(input_client)); + testing::Mock::VerifyAndClear(&*main_rfh_loopback_broker); + } + { + EXPECT_CALL(*other_rfh_loopback_broker, CreateStream(NotNull())); + mojo::MakeRequest(&input_client); + factory.CreateLoopbackStream(other_rfh(), source_contents.get(), kParams, + kSharedMemoryCount, kMuteSource, + std::move(input_client)); + testing::Mock::VerifyAndClear(&*other_rfh_loopback_broker); + } + + { EXPECT_CALL(*main_rfh_output_broker, CreateStream(NotNull())); mojo::MakeRequest(&output_client); factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, @@ -330,6 +469,10 @@ EXPECT_FALSE(other_rfh_input_broker) << "Input broker should be destructed when owning frame is destructed."; EXPECT_TRUE(main_rfh_input_broker); + EXPECT_FALSE(other_rfh_loopback_broker) << "Loopback broker should be " + "destructed when owning frame is " + "destructed."; + EXPECT_TRUE(main_rfh_loopback_broker); EXPECT_FALSE(other_rfh_output_broker) << "Output broker should be destructed when owning frame is destructed."; EXPECT_TRUE(main_rfh_output_broker); @@ -416,23 +559,153 @@ } base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(pending_factory_request_->QuerySignalsState().peer_closed()); + EXPECT_TRUE(stream_factory_.IsConnected()); std::move(other_rfh_input_broker->deleter).Run(&*other_rfh_input_broker); base::RunLoop().RunUntilIdle(); // Connection should still be open, since there are still streams left. - EXPECT_FALSE(pending_factory_request_->QuerySignalsState().peer_closed()); + EXPECT_TRUE(stream_factory_.IsConnected()); std::move(main_rfh_input_broker->deleter).Run(&*main_rfh_input_broker); base::RunLoop().RunUntilIdle(); // Connection should still be open, since there are still streams left. - EXPECT_FALSE(pending_factory_request_->QuerySignalsState().peer_closed()); + EXPECT_TRUE(stream_factory_.IsConnected()); std::move(other_rfh_output_broker->deleter).Run(&*other_rfh_output_broker); base::RunLoop().RunUntilIdle(); // Connection should still be open, since there's still a stream left. - EXPECT_FALSE(pending_factory_request_->QuerySignalsState().peer_closed()); + EXPECT_TRUE(stream_factory_.IsConnected()); std::move(main_rfh_output_broker->deleter).Run(&*main_rfh_output_broker); base::RunLoop().RunUntilIdle(); // Now there are no streams left, connection should be broken. - EXPECT_TRUE(pending_factory_request_->QuerySignalsState().peer_closed()); + EXPECT_FALSE(stream_factory_.IsConnected()); +} + +TEST_F(ForwardingAudioStreamFactoryTest, + MuteNoOutputStreams_DoesNotConnectMuter) { + ForwardingAudioStreamFactory factory(web_contents(), std::move(connector_), + std::move(broker_factory_)); + EXPECT_FALSE(factory.IsMuted()); + + factory.SetMuted(true); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(factory.IsMuted()); + EXPECT_FALSE(stream_factory_.IsConnected()); + EXPECT_FALSE(stream_factory_.IsMuterConnected()); + + factory.SetMuted(false); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(factory.IsMuted()); + EXPECT_FALSE(stream_factory_.IsConnected()); + EXPECT_FALSE(stream_factory_.IsMuterConnected()); +} + +TEST_F(ForwardingAudioStreamFactoryTest, MuteWithOutputStream_ConnectsMuter) { + media::mojom::AudioOutputStreamProviderClientPtr client; + base::WeakPtr<MockBroker> broker = ExpectOutputBrokerConstruction(main_rfh()); + ForwardingAudioStreamFactory factory(web_contents(), std::move(connector_), + std::move(broker_factory_)); + + EXPECT_CALL(*broker, CreateStream(NotNull())); + mojo::MakeRequest(&client); + factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, + std::move(client)); + base::RunLoop().RunUntilIdle(); + testing::Mock::VerifyAndClear(&*broker); + + EXPECT_TRUE(stream_factory_.IsConnected()); + EXPECT_FALSE(factory.IsMuted()); + + factory.SetMuted(true); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(factory.IsMuted()); + EXPECT_TRUE(stream_factory_.IsConnected()); + EXPECT_TRUE(stream_factory_.IsMuterConnected()); + + factory.SetMuted(false); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(factory.IsMuted()); + EXPECT_TRUE(stream_factory_.IsConnected()); + EXPECT_FALSE(stream_factory_.IsMuterConnected()); +} + +TEST_F(ForwardingAudioStreamFactoryTest, + WhenMuting_ConnectedWhenOutputStreamExists) { + media::mojom::AudioOutputStreamProviderClientPtr client; + base::WeakPtr<MockBroker> broker = ExpectOutputBrokerConstruction(main_rfh()); + ForwardingAudioStreamFactory factory(web_contents(), std::move(connector_), + std::move(broker_factory_)); + + EXPECT_FALSE(stream_factory_.IsConnected()); + EXPECT_FALSE(factory.IsMuted()); + + factory.SetMuted(true); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(factory.IsMuted()); + EXPECT_FALSE(stream_factory_.IsConnected()); + EXPECT_FALSE(stream_factory_.IsMuterConnected()); + + EXPECT_CALL(*broker, CreateStream(NotNull())); + mojo::MakeRequest(&client); + factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, + std::move(client)); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(factory.IsMuted()); + EXPECT_TRUE(stream_factory_.IsConnected()); + EXPECT_TRUE(stream_factory_.IsMuterConnected()); + testing::Mock::VerifyAndClear(&*broker); + + std::move(broker->deleter).Run(&*broker); + EXPECT_FALSE(broker); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(factory.IsMuted()); + EXPECT_FALSE(stream_factory_.IsConnected()); + EXPECT_FALSE(stream_factory_.IsMuterConnected()); +} + +TEST_F(ForwardingAudioStreamFactoryTest, + WhenMuting_AddRemoveSecondStream_DoesNotChangeMuting) { + media::mojom::AudioOutputStreamProviderClientPtr client; + base::WeakPtr<MockBroker> broker = ExpectOutputBrokerConstruction(main_rfh()); + base::WeakPtr<MockBroker> another_broker = + ExpectOutputBrokerConstruction(main_rfh()); + ForwardingAudioStreamFactory factory(web_contents(), std::move(connector_), + std::move(broker_factory_)); + + { + EXPECT_CALL(*broker, CreateStream(NotNull())); + mojo::MakeRequest(&client); + factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, + std::move(client)); + base::RunLoop().RunUntilIdle(); + testing::Mock::VerifyAndClear(&*broker); + } + EXPECT_TRUE(stream_factory_.IsConnected()); + EXPECT_FALSE(factory.IsMuted()); + + factory.SetMuted(true); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(factory.IsMuted()); + EXPECT_TRUE(stream_factory_.IsConnected()); + EXPECT_TRUE(stream_factory_.IsMuterConnected()); + + { + EXPECT_CALL(*another_broker, CreateStream(NotNull())); + mojo::MakeRequest(&client); + factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, + std::move(client)); + base::RunLoop().RunUntilIdle(); + testing::Mock::VerifyAndClear(&*another_broker); + } + + EXPECT_TRUE(factory.IsMuted()); + EXPECT_TRUE(stream_factory_.IsConnected()); + EXPECT_TRUE(stream_factory_.IsMuterConnected()); + + std::move(another_broker->deleter).Run(&*another_broker); + EXPECT_FALSE(another_broker); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(factory.IsMuted()); + EXPECT_TRUE(stream_factory_.IsConnected()); + EXPECT_TRUE(stream_factory_.IsMuterConnected()); } } // namespace content
diff --git a/content/browser/renderer_interface_binders.cc b/content/browser/renderer_interface_binders.cc index 74a060e..e306536 100644 --- a/content/browser/renderer_interface_binders.cc +++ b/content/browser/renderer_interface_binders.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "content/browser/background_fetch/background_fetch_service_impl.h" +#include "content/browser/cookie_store/cookie_store_context.h" #include "content/browser/locks/lock_manager.h" #include "content/browser/notifications/platform_notification_context_impl.h" #include "content/browser/payments/payment_manager.h" @@ -31,6 +32,7 @@ #include "services/shape_detection/public/mojom/constants.mojom.h" #include "services/shape_detection/public/mojom/facedetection_provider.mojom.h" #include "services/shape_detection/public/mojom/textdetection.mojom.h" +#include "third_party/blink/public/mojom/cookie_store/cookie_store.mojom.h" #include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom.h" #include "third_party/blink/public/platform/modules/notifications/notification_service.mojom.h" #include "url/origin.h" @@ -180,6 +182,13 @@ base::BindRepeating(GetRestrictedCookieManagerForWorker)); parameterized_binder_registry_.AddInterface( base::BindRepeating(&QuotaDispatcherHost::CreateForWorker)); + parameterized_binder_registry_.AddInterface(base::BindRepeating( + [](blink::mojom::CookieStoreRequest request, RenderProcessHost* host, + const url::Origin& origin) { + static_cast<StoragePartitionImpl*>(host->GetStoragePartition()) + ->GetCookieStoreContext() + ->CreateService(std::move(request), origin); + })); } RendererInterfaceBinders& GetRendererInterfaceBinders() {
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc index 4ff9fda..3b456e68 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.cc +++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -239,6 +239,15 @@ std::move(callback)); } + void DispatchCookieChangeEvent( + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause, + DispatchCookieChangeEventCallback callback) override { + if (!helper_) + return; + helper_->OnCookieChangeEventStub(cookie, cause, std::move(callback)); + } + void DispatchFetchEvent( mojom::DispatchFetchEventParamsPtr params, mojom::ServiceWorkerFetchResponseCallbackPtr response_callback, @@ -611,6 +620,15 @@ base::Time::Now()); } +void EmbeddedWorkerTestHelper::OnCookieChangeEvent( + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause, + mojom::ServiceWorkerEventDispatcher::DispatchCookieChangeEventCallback + callback) { + std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED, + base::Time::Now()); +} + void EmbeddedWorkerTestHelper::OnExtendableMessageEvent( mojom::ExtendableMessageEventPtr event, mojom::ServiceWorkerEventDispatcher::DispatchExtendableMessageEventCallback @@ -911,6 +929,17 @@ std::move(callback))); } +void EmbeddedWorkerTestHelper::OnCookieChangeEventStub( + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause, + mojom::ServiceWorkerEventDispatcher::DispatchCookieChangeEventCallback + callback) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(&EmbeddedWorkerTestHelper::OnCookieChangeEvent, + AsWeakPtr(), cookie, cause, std::move(callback))); +} + void EmbeddedWorkerTestHelper::OnExtendableMessageEventStub( mojom::ExtendableMessageEventPtr event, mojom::ServiceWorkerEventDispatcher::DispatchExtendableMessageEventCallback
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h index 4501893..609a991 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.h +++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -25,7 +25,9 @@ #include "ipc/ipc_listener.h" #include "ipc/ipc_test_sink.h" #include "mojo/public/cpp/bindings/binding.h" +#include "net/cookies/cookie_change_dispatcher.h" #include "net/http/http_response_info.h" +#include "services/network/public/mojom/cookie_manager.mojom.h" #include "third_party/blink/public/mojom/service_worker/service_worker.mojom.h" #include "third_party/blink/public/mojom/service_worker/service_worker_installed_scripts_manager.mojom.h" #include "url/gurl.h" @@ -218,6 +220,11 @@ const std::vector<BackgroundFetchSettledFetch>& fetches, mojom::ServiceWorkerEventDispatcher:: DispatchBackgroundFetchedEventCallback callback); + virtual void OnCookieChangeEvent( + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause, + mojom::ServiceWorkerEventDispatcher::DispatchCookieChangeEventCallback + callback); virtual void OnExtendableMessageEvent( mojom::ExtendableMessageEventPtr event, mojom::ServiceWorkerEventDispatcher:: @@ -319,6 +326,11 @@ const std::vector<BackgroundFetchSettledFetch>& fetches, mojom::ServiceWorkerEventDispatcher:: DispatchBackgroundFetchedEventCallback callback); + void OnCookieChangeEventStub( + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause, + mojom::ServiceWorkerEventDispatcher::DispatchCookieChangeEventCallback + callback); void OnExtendableMessageEventStub( mojom::ExtendableMessageEventPtr event, mojom::ServiceWorkerEventDispatcher::
diff --git a/content/browser/service_worker/service_worker_metrics.cc b/content/browser/service_worker/service_worker_metrics.cc index 463d9e7..f5fc5073 100644 --- a/content/browser/service_worker/service_worker_metrics.cc +++ b/content/browser/service_worker/service_worker_metrics.cc
@@ -94,6 +94,8 @@ return "_CAN_MAKE_PAYMENT"; case ServiceWorkerMetrics::EventType::ABORT_PAYMENT: return "_ABORT_PAYMENT"; + case ServiceWorkerMetrics::EventType::COOKIE_CHANGE: + return "_COOKIE_CHANGE"; case ServiceWorkerMetrics::EventType::NUM_TYPES: NOTREACHED() << static_cast<int>(event_type); } @@ -339,8 +341,10 @@ return "Navigation Hint"; case EventType::CAN_MAKE_PAYMENT: return "Can Make Payment"; - case ServiceWorkerMetrics::EventType::ABORT_PAYMENT: + case EventType::ABORT_PAYMENT: return "Abort Payment"; + case EventType::COOKIE_CHANGE: + return "Cookie Change"; case EventType::NUM_TYPES: break; } @@ -717,6 +721,9 @@ case EventType::ABORT_PAYMENT: UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.AbortPaymentEvent.Time", time); break; + case EventType::COOKIE_CHANGE: + UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.CookieChangeEvent.Time", time); + break; case EventType::NAVIGATION_HINT: // The navigation hint should not be sent as an event.
diff --git a/content/browser/service_worker/service_worker_metrics.h b/content/browser/service_worker/service_worker_metrics.h index e0a5ce15..5c3c512 100644 --- a/content/browser/service_worker/service_worker_metrics.h +++ b/content/browser/service_worker/service_worker_metrics.h
@@ -128,6 +128,7 @@ NAVIGATION_HINT = 27, CAN_MAKE_PAYMENT = 28, ABORT_PAYMENT = 29, + COOKIE_CHANGE = 30, // Add new events to record here. NUM_TYPES };
diff --git a/content/browser/service_worker/service_worker_new_script_loader.cc b/content/browser/service_worker/service_worker_new_script_loader.cc index 5a64bf4f..52b788a5 100644 --- a/content/browser/service_worker/service_worker_new_script_loader.cc +++ b/content/browser/service_worker/service_worker_new_script_loader.cc
@@ -35,8 +35,8 @@ const network::ResourceRequest& original_request, network::mojom::URLLoaderClientPtr client, scoped_refptr<ServiceWorkerVersion> version, - scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter, - network::mojom::URLLoaderFactoryPtr non_network_loader_factory, + scoped_refptr<network::SharedURLLoaderFactory> network_factory, + network::mojom::URLLoaderFactoryPtr non_network_factory, const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) : request_url_(original_request.url), resource_type_(static_cast<ResourceType>(original_request.resource_type)), @@ -46,7 +46,8 @@ network_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL, base::SequencedTaskRunnerHandle::Get()), - non_network_loader_factory_(std::move(non_network_loader_factory)), + network_factory_(std::move(network_factory)), + non_network_factory_(std::move(non_network_factory)), client_(std::move(client)), weak_factory_(this) { // ServiceWorkerNewScriptLoader is used for fetching the service worker main @@ -113,13 +114,13 @@ network::mojom::URLLoaderClientPtr network_client; network_client_binding_.Bind(mojo::MakeRequest(&network_client)); - if (non_network_loader_factory_) { - non_network_loader_factory_->CreateLoaderAndStart( + if (non_network_factory_) { + non_network_factory_->CreateLoaderAndStart( mojo::MakeRequest(&network_loader_), routing_id, request_id, options, *resource_request_.get(), std::move(network_client), traffic_annotation); } else { - loader_factory_getter->GetNetworkFactory()->CreateLoaderAndStart( + network_factory_->CreateLoaderAndStart( mojo::MakeRequest(&network_loader_), routing_id, request_id, options, *resource_request_.get(), std::move(network_client), traffic_annotation);
diff --git a/content/browser/service_worker/service_worker_new_script_loader.h b/content/browser/service_worker/service_worker_new_script_loader.h index b14c8d92..328091cb 100644 --- a/content/browser/service_worker/service_worker_new_script_loader.h +++ b/content/browser/service_worker/service_worker_new_script_loader.h
@@ -19,7 +19,6 @@ class ServiceWorkerCacheWriter; class ServiceWorkerVersion; -class URLLoaderFactoryGetter; struct HttpResponseInfoIOBuffer; // S13nServiceWorker: @@ -45,7 +44,7 @@ // worker. If the script is identical, the load succeeds but no script is // written, and ServiceWorkerVersion is told to terminate startup. // -// NOTE: To load a script, this class uses |non_network_loader_factory| when the +// NOTE: To load a script, this class uses |non_network_factory| when the // URL has a non-http(s) scheme, e.g., a chrome-extension:// URL. Regardless, // that is still called a "network" request in comments and naming. "network" is // meant to distinguish from the load this URLLoader does for its client: @@ -55,10 +54,9 @@ : public network::mojom::URLLoader, public network::mojom::URLLoaderClient { public: - // |loader_factory_getter| is used to get the network factory when the script - // URL has an http(s) scheme. + // |network_factory| is used when the script URL has an http(s) scheme. // - // |non_network_loader_factory| is non-null when the script URL has a + // |non_network_factory| is non-null when the script URL has a // non-http(s) scheme (e.g., a chrome-extension:// URL). It is used in that // case since the network factory can't be used. ServiceWorkerNewScriptLoader( @@ -68,8 +66,8 @@ const network::ResourceRequest& original_request, network::mojom::URLLoaderClientPtr client, scoped_refptr<ServiceWorkerVersion> version, - scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter, - network::mojom::URLLoaderFactoryPtr non_network_loader_factory, + scoped_refptr<network::SharedURLLoaderFactory> network_factory, + network::mojom::URLLoaderFactoryPtr non_network_factory, const net::MutableNetworkTrafficAnnotationTag& traffic_annotation); ~ServiceWorkerNewScriptLoader() override; @@ -154,10 +152,11 @@ mojo::ScopedDataPipeConsumerHandle network_consumer_; mojo::SimpleWatcher network_watcher_; bool network_load_completed_ = false; - // |non_network_loader_factory_| is non-null when the script URL is + scoped_refptr<network::SharedURLLoaderFactory> network_factory_; + // |non_network_factory_| is non-null when the script URL is // non-http(s). It is used to make the "network" request because the usual // network factory can't be used in that case. See class comments. - network::mojom::URLLoaderFactoryPtr non_network_loader_factory_; + network::mojom::URLLoaderFactoryPtr non_network_factory_; // Used for responding with the fetched script to this loader's client. network::mojom::URLLoaderClientPtr client_;
diff --git a/content/browser/service_worker/service_worker_new_script_loader_unittest.cc b/content/browser/service_worker/service_worker_new_script_loader_unittest.cc index 52007754..fe1216a7 100644 --- a/content/browser/service_worker/service_worker_new_script_loader_unittest.cc +++ b/content/browser/service_worker/service_worker_new_script_loader_unittest.cc
@@ -227,7 +227,7 @@ client_ = std::make_unique<network::TestURLLoaderClient>(); loader_ = std::make_unique<ServiceWorkerNewScriptLoader>( routing_id, request_id, options, request, client_->CreateInterfacePtr(), - version_, helper_->url_loader_factory_getter(), + version_, helper_->url_loader_factory_getter()->GetNetworkFactory(), nullptr /* non_network_loader_factory */, net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS)); }
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc index 2a22bfc..955c9043 100644 --- a/content/browser/service_worker/service_worker_provider_host.cc +++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -688,7 +688,8 @@ if (ServiceWorkerUtils::IsServicificationEnabled()) { mojo::MakeStrongAssociatedBinding( std::make_unique<ServiceWorkerScriptLoaderFactory>( - context_, AsWeakPtr(), context_->loader_factory_getter(), + context_, AsWeakPtr(), + context_->loader_factory_getter()->GetNetworkFactory(), std::move(non_network_loader_factory)), mojo::MakeRequest(&script_loader_factory_ptr_info)); provider_info->script_loader_factory_ptr_info =
diff --git a/content/browser/service_worker/service_worker_script_loader_factory.cc b/content/browser/service_worker/service_worker_script_loader_factory.cc index 6d779103..5a282d4 100644 --- a/content/browser/service_worker/service_worker_script_loader_factory.cc +++ b/content/browser/service_worker/service_worker_script_loader_factory.cc
@@ -10,22 +10,22 @@ #include "content/browser/service_worker/service_worker_new_script_loader.h" #include "content/browser/service_worker/service_worker_provider_host.h" #include "content/browser/service_worker/service_worker_version.h" -#include "content/browser/url_loader_factory_getter.h" #include "content/common/service_worker/service_worker_utils.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "services/network/public/cpp/resource_response.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" namespace content { ServiceWorkerScriptLoaderFactory::ServiceWorkerScriptLoaderFactory( base::WeakPtr<ServiceWorkerContextCore> context, base::WeakPtr<ServiceWorkerProviderHost> provider_host, - scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter, - network::mojom::URLLoaderFactoryPtr non_network_loader_factory) + scoped_refptr<network::SharedURLLoaderFactory> network_factory, + network::mojom::URLLoaderFactoryPtr non_network_factory) : context_(context), provider_host_(provider_host), - loader_factory_getter_(loader_factory_getter), - non_network_loader_factory_(std::move(non_network_loader_factory)) { + network_factory_(std::move(network_factory)), + non_network_factory_(std::move(non_network_factory)) { DCHECK(provider_host_->IsProviderForServiceWorker()); } @@ -40,20 +40,19 @@ network::mojom::URLLoaderClientPtr client, const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) { DCHECK(ServiceWorkerUtils::IsServicificationEnabled()); - DCHECK(loader_factory_getter_); + DCHECK(network_factory_); if (!ShouldHandleScriptRequest(resource_request)) { // If the request should not be handled (e.g., a fetch() request), just do a // passthrough load. This needs a relaying as we use different associated // message pipes. // TODO(kinuko): Record the reason like what we do with netlog in // ServiceWorkerContextRequestHandler. - if (!resource_request.url.SchemeIsHTTPOrHTTPS() && - non_network_loader_factory_) { - non_network_loader_factory_->CreateLoaderAndStart( + if (!resource_request.url.SchemeIsHTTPOrHTTPS() && non_network_factory_) { + non_network_factory_->CreateLoaderAndStart( std::move(request), routing_id, request_id, options, resource_request, std::move(client), traffic_annotation); } else { - loader_factory_getter_->GetNetworkFactory()->CreateLoaderAndStart( + network_factory_->CreateLoaderAndStart( std::move(request), routing_id, request_id, options, resource_request, std::move(client), traffic_annotation); } @@ -81,17 +80,14 @@ } // The common case: load the script and install it. - network::mojom::URLLoaderFactoryPtr cloned_non_network_loader_factory; - if (!resource_request.url.SchemeIsHTTPOrHTTPS() && - non_network_loader_factory_) { - non_network_loader_factory_->Clone( - mojo::MakeRequest(&cloned_non_network_loader_factory)); - } + network::mojom::URLLoaderFactoryPtr cloned_non_network_factory; + if (!resource_request.url.SchemeIsHTTPOrHTTPS() && non_network_factory_) + non_network_factory_->Clone(mojo::MakeRequest(&cloned_non_network_factory)); mojo::MakeStrongBinding( std::make_unique<ServiceWorkerNewScriptLoader>( routing_id, request_id, options, resource_request, std::move(client), - provider_host_->running_hosted_version(), loader_factory_getter_, - std::move(cloned_non_network_loader_factory), traffic_annotation), + provider_host_->running_hosted_version(), network_factory_, + std::move(cloned_non_network_factory), traffic_annotation), std::move(request)); }
diff --git a/content/browser/service_worker/service_worker_script_loader_factory.h b/content/browser/service_worker/service_worker_script_loader_factory.h index b2f09ca8..069eb76 100644 --- a/content/browser/service_worker/service_worker_script_loader_factory.h +++ b/content/browser/service_worker/service_worker_script_loader_factory.h
@@ -8,11 +8,14 @@ #include "base/macros.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" +namespace network { +class SharedURLLoaderFactory; +} // namespace network + namespace content { class ServiceWorkerContextCore; class ServiceWorkerProviderHost; -class URLLoaderFactoryGetter; // S13nServiceWorker: // Created per one running service worker for loading its scripts. This is kept @@ -29,10 +32,10 @@ class ServiceWorkerScriptLoaderFactory : public network::mojom::URLLoaderFactory { public: - // |loader_factory_getter| is used to get the network factory for - // loading the script. + // |network_factory| is used to load scripts when the service worker main + // script has an http(s) scheme. // - // |non_network_loader_factory| is non-null when the service worker main + // |non_network_factory| is non-null when the service worker main // script URL has a non-http(s) scheme (e.g., a chrome-extension:// URL). // It will be used to load the main script and any non-http(s) imported // script. @@ -48,8 +51,8 @@ ServiceWorkerScriptLoaderFactory( base::WeakPtr<ServiceWorkerContextCore> context, base::WeakPtr<ServiceWorkerProviderHost> provider_host, - scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter, - network::mojom::URLLoaderFactoryPtr non_network_loader_factory); + scoped_refptr<network::SharedURLLoaderFactory> network_factory, + network::mojom::URLLoaderFactoryPtr non_network_factory); ~ServiceWorkerScriptLoaderFactory() override; // network::mojom::URLLoaderFactory: @@ -69,8 +72,8 @@ base::WeakPtr<ServiceWorkerContextCore> context_; base::WeakPtr<ServiceWorkerProviderHost> provider_host_; - scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter_; - network::mojom::URLLoaderFactoryPtr non_network_loader_factory_; + scoped_refptr<network::SharedURLLoaderFactory> network_factory_; + network::mojom::URLLoaderFactoryPtr non_network_factory_; DISALLOW_COPY_AND_ASSIGN(ServiceWorkerScriptLoaderFactory); };
diff --git a/content/browser/shared_worker/shared_worker_script_loader.cc b/content/browser/shared_worker/shared_worker_script_loader.cc index ff39e06..c964947 100644 --- a/content/browser/shared_worker/shared_worker_script_loader.cc +++ b/content/browser/shared_worker/shared_worker_script_loader.cc
@@ -6,10 +6,10 @@ #include "content/browser/loader/navigation_loader_interceptor.h" #include "content/browser/service_worker/service_worker_provider_host.h" -#include "content/browser/url_loader_factory_getter.h" #include "content/common/service_worker/service_worker_utils.h" #include "content/public/browser/resource_context.h" #include "net/url_request/redirect_util.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" namespace content { @@ -21,7 +21,7 @@ network::mojom::URLLoaderClientPtr client, base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host, ResourceContext* resource_context, - scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter, + scoped_refptr<network::SharedURLLoaderFactory> network_factory, const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) : routing_id_(routing_id), request_id_(request_id), @@ -30,7 +30,7 @@ client_(std::move(client)), service_worker_provider_host_(service_worker_provider_host), resource_context_(resource_context), - loader_factory_getter_(std::move(loader_factory_getter)), + network_factory_(std::move(network_factory)), traffic_annotation_(traffic_annotation), url_loader_client_binding_(this), weak_factory_(this) { @@ -84,7 +84,7 @@ void SharedWorkerScriptLoader::LoadFromNetwork() { network::mojom::URLLoaderClientPtr client; url_loader_client_binding_.Bind(mojo::MakeRequest(&client)); - url_loader_factory_ = loader_factory_getter_->GetNetworkFactory(); + url_loader_factory_ = network_factory_; url_loader_factory_->CreateLoaderAndStart( mojo::MakeRequest(&url_loader_), routing_id_, request_id_, options_, resource_request_, std::move(client), traffic_annotation_);
diff --git a/content/browser/shared_worker/shared_worker_script_loader.h b/content/browser/shared_worker/shared_worker_script_loader.h index f1d55c74..38a29cd8 100644 --- a/content/browser/shared_worker/shared_worker_script_loader.h +++ b/content/browser/shared_worker/shared_worker_script_loader.h
@@ -12,11 +12,14 @@ #include "services/network/public/cpp/resource_request.h" #include "services/network/public/mojom/url_loader.mojom.h" +namespace network { +class SharedURLLoaderFactory; +} // namespace network + namespace content { class NavigationLoaderInterceptor; class ResourceContext; class ServiceWorkerProviderHost; -class URLLoaderFactoryGetter; // The URLLoader for loading a shared worker script. Only used for the main // script request. @@ -40,7 +43,7 @@ network::mojom::URLLoaderClientPtr client, base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host, ResourceContext* resource_context, - scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter, + scoped_refptr<network::SharedURLLoaderFactory> network_factory, const net::MutableNetworkTrafficAnnotationTag& traffic_annotation); ~SharedWorkerScriptLoader() override; @@ -86,7 +89,7 @@ network::mojom::URLLoaderClientPtr client_; base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host_; ResourceContext* resource_context_; - scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter_; + scoped_refptr<network::SharedURLLoaderFactory> network_factory_; net::MutableNetworkTrafficAnnotationTag traffic_annotation_; base::Optional<net::RedirectInfo> redirect_info_;
diff --git a/content/browser/shared_worker/shared_worker_script_loader_factory.cc b/content/browser/shared_worker/shared_worker_script_loader_factory.cc index f819351..6329bcd 100644 --- a/content/browser/shared_worker/shared_worker_script_loader_factory.cc +++ b/content/browser/shared_worker/shared_worker_script_loader_factory.cc
@@ -10,10 +10,10 @@ #include "content/browser/service_worker/service_worker_provider_host.h" #include "content/browser/service_worker/service_worker_version.h" #include "content/browser/shared_worker/shared_worker_script_loader.h" -#include "content/browser/url_loader_factory_getter.h" #include "content/common/service_worker/service_worker_utils.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "services/network/public/cpp/resource_response.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" #include "third_party/blink/public/mojom/service_worker/service_worker_provider_type.mojom.h" namespace content { @@ -22,10 +22,10 @@ ServiceWorkerContextWrapper* context, base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host, ResourceContext* resource_context, - scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter) + scoped_refptr<network::SharedURLLoaderFactory> network_factory) : service_worker_provider_host_(service_worker_provider_host), resource_context_(resource_context), - loader_factory_getter_(loader_factory_getter) { + network_factory_(std::move(network_factory)) { DCHECK(ServiceWorkerUtils::IsServicificationEnabled()); DCHECK_EQ(service_worker_provider_host_->provider_type(), blink::mojom::ServiceWorkerProviderType::kForSharedWorker); @@ -54,8 +54,8 @@ mojo::MakeStrongBinding( std::make_unique<SharedWorkerScriptLoader>( routing_id, request_id, options, resource_request, std::move(client), - service_worker_provider_host_, resource_context_, - loader_factory_getter_, traffic_annotation), + service_worker_provider_host_, resource_context_, network_factory_, + traffic_annotation), std::move(request)); }
diff --git a/content/browser/shared_worker/shared_worker_script_loader_factory.h b/content/browser/shared_worker/shared_worker_script_loader_factory.h index 7e0e4c5c..9353548 100644 --- a/content/browser/shared_worker/shared_worker_script_loader_factory.h +++ b/content/browser/shared_worker/shared_worker_script_loader_factory.h
@@ -8,11 +8,14 @@ #include "base/macros.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" +namespace network { +class SharedURLLoaderFactory; +} // namespace network + namespace content { class ServiceWorkerContextWrapper; class ServiceWorkerProviderHost; -class URLLoaderFactoryGetter; class ResourceContext; // S13nServiceWorker: @@ -32,7 +35,7 @@ ServiceWorkerContextWrapper* context, base::WeakPtr<ServiceWorkerProviderHost> provider_host, ResourceContext* resource_context, - scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter); + scoped_refptr<network::SharedURLLoaderFactory> network_factory); ~SharedWorkerScriptLoaderFactory() override; // network::mojom::URLLoaderFactory: @@ -49,7 +52,7 @@ private: base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host_; ResourceContext* resource_context_ = nullptr; - scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter_; + scoped_refptr<network::SharedURLLoaderFactory> network_factory_; DISALLOW_COPY_AND_ASSIGN(SharedWorkerScriptLoaderFactory); };
diff --git a/content/browser/shared_worker/shared_worker_service_impl.cc b/content/browser/shared_worker/shared_worker_service_impl.cc index 597e99215..5b5d3a79 100644 --- a/content/browser/shared_worker/shared_worker_service_impl.cc +++ b/content/browser/shared_worker/shared_worker_service_impl.cc
@@ -57,7 +57,7 @@ mojo::MakeStrongAssociatedBinding( std::make_unique<SharedWorkerScriptLoaderFactory>( context.get(), host->AsWeakPtr(), context->resource_context(), - std::move(loader_factory_getter)), + loader_factory_getter->GetNetworkFactory()), mojo::MakeRequest(&script_loader_factory)); BrowserThread::PostTask(
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index 735251f5..bd24432 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc
@@ -24,6 +24,7 @@ #include "content/browser/browser_main_loop.h" #include "content/browser/browsing_data/storage_partition_http_cache_data_remover.h" #include "content/browser/child_process_security_policy_impl.h" +#include "content/browser/cookie_store/cookie_store_context.h" #include "content/browser/fileapi/browser_file_system_helper.h" #include "content/browser/gpu/shader_cache_factory.h" #include "content/browser/loader/prefetch_url_loader_service.h" @@ -667,6 +668,14 @@ base::MakeRefCounted<PrefetchURLLoaderService>( partition->url_loader_factory_getter_); + partition->cookie_store_context_ = base::MakeRefCounted<CookieStoreContext>(); + // Unit tests use the Initialize() callback to crash early if restoring the + // CookieManagerStore's state from ServiceWorkerStorage fails. Production and + // browser tests rely on CookieStoreManager's well-defined behavior when + // restoring the state fails. + partition->cookie_store_context_->Initialize( + partition->service_worker_context_, base::DoNothing()); + return partition; } @@ -827,6 +836,10 @@ return prefetch_url_loader_service_.get(); } +CookieStoreContext* StoragePartitionImpl::GetCookieStoreContext() { + return cookie_store_context_.get(); +} + void StoragePartitionImpl::OpenLocalStorage( const url::Origin& origin, mojom::LevelDBWrapperRequest request) {
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h index 07992017..102e3ff 100644 --- a/content/browser/storage_partition_impl.h +++ b/content/browser/storage_partition_impl.h
@@ -46,6 +46,7 @@ namespace content { class BackgroundFetchContext; +class CookieStoreContext; class BlobRegistryWrapper; class BlobURLLoaderFactory; class PrefetchURLLoaderService; @@ -142,6 +143,7 @@ BlobURLLoaderFactory* GetBlobURLLoaderFactory(); BlobRegistryWrapper* GetBlobRegistry(); PrefetchURLLoaderService* GetPrefetchURLLoaderService(); + CookieStoreContext* GetCookieStoreContext(); // mojom::StoragePartitionService interface. void OpenLocalStorage(const url::Origin& origin, @@ -187,6 +189,7 @@ friend class BackgroundSyncManagerTest; friend class BackgroundSyncServiceImplTest; + friend class CookieStoreManagerTest; friend class PaymentAppContentUnitTestBase; friend class StoragePartitionImplMap; friend class URLLoaderFactoryForBrowserProcess; @@ -309,6 +312,7 @@ scoped_refptr<BlobURLLoaderFactory> blob_url_loader_factory_; scoped_refptr<BlobRegistryWrapper> blob_registry_; scoped_refptr<PrefetchURLLoaderService> prefetch_url_loader_service_; + scoped_refptr<CookieStoreContext> cookie_store_context_; // BindingSet for StoragePartitionService, using the process id as the // binding context type. The process id can subsequently be used during
diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc index 2f5875b..3be6979 100644 --- a/content/browser/storage_partition_impl_map.cc +++ b/content/browser/storage_partition_impl_map.cc
@@ -25,6 +25,7 @@ #include "content/browser/appcache/chrome_appcache_service.h" #include "content/browser/background_fetch/background_fetch_context.h" #include "content/browser/blob_storage/chrome_blob_storage_context.h" +#include "content/browser/cookie_store/cookie_store_context.h" #include "content/browser/devtools/devtools_url_request_interceptor.h" #include "content/browser/fileapi/browser_file_system_helper.h" #include "content/browser/loader/prefetch_url_loader_service.h" @@ -435,10 +436,12 @@ browser_context_->CreateMediaRequestContext() : browser_context_->CreateMediaRequestContextForStoragePartition( partition->GetPath(), in_memory)); + partition->GetCookieStoreContext()->ListenToCookieChanges( + partition->GetNetworkContext(), base::DoNothing()); if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) { // This needs to happen after SetURLRequestContext() since we need this - // code path only for non-NetworkService case where NetworkContext needs to + // code path only for non-NetworkService cases where NetworkContext needs to // be initialized using |url_request_context_|, which is initialized by // SetURLRequestContext(). DCHECK(partition->url_loader_factory_getter());
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index e167401..04fce8c 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -329,6 +329,7 @@ "//components/viz/service", "//content:resources", "//content/app/resources", + "//content/common/service_worker:service_worker_types_proto", "//content/public/common:interfaces", "//content/public/common:service_names", "//content/public/common:zygote_buildflags",
diff --git a/content/common/service_worker/BUILD.gn b/content/common/service_worker/BUILD.gn new file mode 100644 index 0000000..65c27c1 --- /dev/null +++ b/content/common/service_worker/BUILD.gn
@@ -0,0 +1,11 @@ +# 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. + +import("//third_party/protobuf/proto_library.gni") + +proto_library("service_worker_types_proto") { + sources = [ + "service_worker_types.proto", + ] +}
diff --git a/content/common/service_worker/service_worker_event_dispatcher.mojom b/content/common/service_worker/service_worker_event_dispatcher.mojom index 03204167..dc52bf4 100644 --- a/content/common/service_worker/service_worker_event_dispatcher.mojom +++ b/content/common/service_worker/service_worker_event_dispatcher.mojom
@@ -8,6 +8,7 @@ import "content/common/service_worker/service_worker_fetch_response_callback.mojom"; import "mojo/public/mojom/base/string16.mojom"; import "mojo/public/mojom/base/time.mojom"; +import "services/network/public/mojom/cookie_manager.mojom"; import "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom"; import "third_party/blink/public/platform/modules/payments/payment_app.mojom"; import "third_party/blink/public/mojom/message_port/message_port.mojom"; @@ -109,6 +110,16 @@ => (blink.mojom.ServiceWorkerEventStatus status, mojo_base.mojom.Time dispatch_event_time); + // Dispatches the cookie change events in the Async Cookie API specification. + // https://github.com/WICG/cookie-store/ + // The callback is called once the event handler has run and the waitUntil() + // promise has settled. + DispatchCookieChangeEvent( + network.mojom.CanonicalCookie cookie, + network.mojom.CookieChangeCause cause) + => (blink.mojom.ServiceWorkerEventStatus status, + mojo_base.mojom.Time dispatch_event_time); + // The Dispatch*FetchEvent() callback is called once the event finishes, // which means the event handler ran and all outstanding respondWith() and // waitUntil() promises have settled. |response_callback| is called once the
diff --git a/content/common/service_worker/service_worker_types.cc b/content/common/service_worker/service_worker_types.cc index 4f93a652e..687235e 100644 --- a/content/common/service_worker/service_worker_types.cc +++ b/content/common/service_worker/service_worker_types.cc
@@ -4,6 +4,7 @@ #include "content/common/service_worker/service_worker_types.h" +#include "content/common/service_worker/service_worker_types.pb.h" #include "net/base/load_flags.h" #include "storage/common/blob_storage/blob_handle.h" @@ -55,6 +56,28 @@ ServiceWorkerFetchRequest::~ServiceWorkerFetchRequest() {} +std::string ServiceWorkerFetchRequest::Serialize() { + proto::internal::ServiceWorkerFetchRequest request_proto; + + request_proto.set_url(url.spec()); + request_proto.set_method(method); + request_proto.mutable_headers()->insert(headers.begin(), headers.end()); + request_proto.mutable_referrer()->set_url(referrer.url.spec()); + request_proto.mutable_referrer()->set_policy(referrer.policy); + request_proto.set_is_reload(is_reload); + request_proto.set_mode(static_cast<int>(mode)); + request_proto.set_is_main_resource_load(is_main_resource_load); + request_proto.set_request_context_type(request_context_type); + request_proto.set_credentials_mode(static_cast<int>(credentials_mode)); + request_proto.set_cache_mode(static_cast<int>(cache_mode)); + request_proto.set_redirect_mode(static_cast<int>(redirect_mode)); + request_proto.set_integrity(integrity); + request_proto.set_keepalive(keepalive); + request_proto.set_client_id(client_id); + + return request_proto.SerializeAsString(); +} + size_t ServiceWorkerFetchRequest::EstimatedStructSize() { size_t size = sizeof(ServiceWorkerFetchRequest); size += url.spec().size(); @@ -69,6 +92,40 @@ } // static +ServiceWorkerFetchRequest ServiceWorkerFetchRequest::ParseFromString( + const std::string& serialized) { + proto::internal::ServiceWorkerFetchRequest request_proto; + if (!request_proto.ParseFromString(serialized)) { + return ServiceWorkerFetchRequest(); + } + + ServiceWorkerFetchRequest request( + GURL(request_proto.url()), request_proto.method(), + ServiceWorkerHeaderMap(request_proto.headers().begin(), + request_proto.headers().end()), + Referrer(GURL(request_proto.referrer().url()), + static_cast<blink::WebReferrerPolicy>( + request_proto.referrer().policy())), + request_proto.is_reload()); + request.mode = + static_cast<network::mojom::FetchRequestMode>(request_proto.mode()); + request.is_main_resource_load = request_proto.is_main_resource_load(); + request.request_context_type = + static_cast<RequestContextType>(request_proto.request_context_type()); + request.credentials_mode = static_cast<network::mojom::FetchCredentialsMode>( + request_proto.credentials_mode()); + request.cache_mode = + static_cast<blink::mojom::FetchCacheMode>(request_proto.cache_mode()); + request.redirect_mode = static_cast<network::mojom::FetchRedirectMode>( + request_proto.redirect_mode()); + request.integrity = request_proto.integrity(); + request.keepalive = request_proto.keepalive(); + request.client_id = request_proto.client_id(); + + return request; +} + +// static blink::mojom::FetchCacheMode ServiceWorkerFetchRequest::GetCacheModeFromLoadFlags(int load_flags) { if (load_flags & net::LOAD_DISABLE_CACHE)
diff --git a/content/common/service_worker/service_worker_types.h b/content/common/service_worker/service_worker_types.h index bf4983a..d84d525 100644 --- a/content/common/service_worker/service_worker_types.h +++ b/content/common/service_worker/service_worker_types.h
@@ -90,10 +90,14 @@ ServiceWorkerFetchRequest& operator=(const ServiceWorkerFetchRequest& other); ~ServiceWorkerFetchRequest(); size_t EstimatedStructSize(); + std::string Serialize(); static blink::mojom::FetchCacheMode GetCacheModeFromLoadFlags(int load_flags); + static ServiceWorkerFetchRequest ParseFromString( + const std::string& serialized); - // Be sure to update EstimatedStructSize() when adding members. + // Be sure to update EstimatedStructSize(), Serialize(), and ParseFromString() + // when adding members. network::mojom::FetchRequestMode mode = network::mojom::FetchRequestMode::kNoCORS; bool is_main_resource_load = false;
diff --git a/content/common/service_worker/service_worker_types.proto b/content/common/service_worker/service_worker_types.proto new file mode 100644 index 0000000..f4470b52 --- /dev/null +++ b/content/common/service_worker/service_worker_types.proto
@@ -0,0 +1,41 @@ +// 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. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package content.proto.internal; + +// Serializable version of ServiceWorkerFetchRequest. +// +// Next Tag: 15 +message ServiceWorkerFetchRequest { + // Serializable version of the Referrer struct defined in + // https://cs.chromium.org/chromium/src/content/public/common/referrer.h + // + // Next Tag: 3 + message Referrer { + optional string url = 1; + optional int32 policy = 2; // blink::WebReferrerPolicy. + } + + // Constructor params. + optional string url = 1; + optional string method = 2; + map<string, string> headers = 3; + optional Referrer referrer = 4; + optional bool is_reload = 5; + + // Other params. + optional int32 mode = 6; // network::mojom::FetchRequestMode. + optional bool is_main_resource_load = 7; + optional int32 request_context_type = 8; // content::RequestContextType. + optional int32 credentials_mode = 9; // network::mojom::FetchCredentialsMode. + optional int32 cache_mode = 10; // blink::mojom::FetchCacheMode. + optional int32 redirect_mode = 11; // network::mojom::FetchRedirectMode. + optional string integrity = 12; + optional bool keepalive = 13; + optional string client_id = 14; +} \ No newline at end of file
diff --git a/content/common/service_worker/service_worker_types_unittest.cc b/content/common/service_worker/service_worker_types_unittest.cc index 546f56b..17a0818 100644 --- a/content/common/service_worker/service_worker_types_unittest.cc +++ b/content/common/service_worker/service_worker_types_unittest.cc
@@ -87,6 +87,29 @@ EXPECT_EQ(input.side_data_blob, output.side_data_blob); } +TEST(ServiceWorkerRequestTest, SerialiazeDeserializeRoundTrip) { + ServiceWorkerFetchRequest request( + GURL("foo.com"), "GET", {{"User-Agent", "Chrome"}}, + Referrer( + GURL("bar.com"), + blink::WebReferrerPolicy::kWebReferrerPolicyNoReferrerWhenDowngrade), + true); + request.mode = network::mojom::FetchRequestMode::kSameOrigin; + request.is_main_resource_load = true; + request.request_context_type = + RequestContextType::REQUEST_CONTEXT_TYPE_IFRAME; + request.credentials_mode = network::mojom::FetchCredentialsMode::kSameOrigin; + request.cache_mode = blink::mojom::FetchCacheMode::kForceCache; + request.redirect_mode = network::mojom::FetchRedirectMode::kManual; + request.integrity = "integrity"; + request.keepalive = true; + request.client_id = "42"; + + EXPECT_EQ(request.Serialize(), + ServiceWorkerFetchRequest::ParseFromString(request.Serialize()) + .Serialize()); +} + } // namespace } // namespace content
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json index 9642ff3..b8b3c922e 100644 --- a/content/public/app/mojo/content_browser_manifest.json +++ b/content/public/app/mojo/content_browser_manifest.json
@@ -228,6 +228,7 @@ "blink::mojom::BackgroundFetchService", "blink::mojom::BudgetService", "blink::mojom::CacheStorage", + "blink::mojom::CookieStore", "blink::mojom::LockManager", "blink::mojom::NotificationService", "blink::mojom::PermissionService",
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc index aae1e6c..68df932 100644 --- a/content/public/test/browser_test_base.cc +++ b/content/public/test/browser_test_base.cc
@@ -23,7 +23,6 @@ #include "base/test/test_timeouts.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" -#include "content/browser/browser_process_sub_thread.h" #include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/tracing/tracing_controller_impl.h" #include "content/public/app/content_main.h" @@ -122,8 +121,7 @@ } // namespace -extern int BrowserMain(const MainFunctionParams&, - std::unique_ptr<BrowserProcessSubThread> io_thread); +extern int BrowserMain(const MainFunctionParams&); BrowserTestBase::BrowserTestBase() : field_trial_list_(std::make_unique<base::FieldTrialList>(nullptr)), @@ -315,7 +313,7 @@ params.ui_task = ui_task.release(); params.created_main_parts_closure = created_main_parts_closure.release(); // TODO(phajdan.jr): Check return code, http://crbug.com/374738 . - BrowserMain(params, nullptr); + BrowserMain(params); #else GetContentMainParams()->ui_task = ui_task.release(); GetContentMainParams()->created_main_parts_closure =
diff --git a/content/renderer/media/stream/webmediaplayer_ms.cc b/content/renderer/media/stream/webmediaplayer_ms.cc index 125c03f..f2a1233 100644 --- a/content/renderer/media/stream/webmediaplayer_ms.cc +++ b/content/renderer/media/stream/webmediaplayer_ms.cc
@@ -42,12 +42,19 @@ #include "third_party/blink/public/web/web_local_frame.h" namespace { + enum class RendererReloadAction { KEEP_RENDERER, REMOVE_RENDERER, NEW_RENDERER }; +bool IsPlayableTrack(const blink::WebMediaStreamTrack& track) { + return !track.IsNull() && !track.Source().IsNull() && + track.Source().GetReadyState() != + blink::WebMediaStreamSource::kReadyStateEnded; +} + } // namespace namespace content { @@ -417,6 +424,16 @@ Reload(); } +void WebMediaPlayerMS::ActiveStateChanged(bool is_active) { + if (!is_active) { + // This makes the media element elegible to be garbage collected. Otherwise, + // the element will be considered active and will never be garbage + // collected. + SetNetworkState(kNetworkStateIdle); + } + // The case when the stream becomes active is handled by TrackAdded(). +} + void WebMediaPlayerMS::Reload() { DCHECK(thread_checker_.CalledOnValidThread()); if (web_stream_.IsNull()) @@ -438,7 +455,8 @@ if (video_frame_provider_) renderer_action = RendererReloadAction::REMOVE_RENDERER; current_video_track_id_ = blink::WebString(); - } else if (video_tracks[0].Id() != current_video_track_id_) { + } else if (video_tracks[0].Id() != current_video_track_id_ && + IsPlayableTrack(video_tracks[0])) { renderer_action = RendererReloadAction::NEW_RENDERER; current_video_track_id_ = video_tracks[0].Id(); } @@ -448,6 +466,7 @@ if (video_frame_provider_) video_frame_provider_->Stop(); + SetNetworkState(kNetworkStateLoading); video_frame_provider_ = renderer_factory_->GetVideoRenderer( web_stream_, media::BindToCurrentLoop( @@ -487,7 +506,8 @@ if (audio_renderer_) renderer_action = RendererReloadAction::REMOVE_RENDERER; current_audio_track_id_ = blink::WebString(); - } else if (audio_tracks[0].Id() != current_video_track_id_) { + } else if (audio_tracks[0].Id() != current_audio_track_id_ && + IsPlayableTrack(audio_tracks[0])) { renderer_action = RendererReloadAction::NEW_RENDERER; current_audio_track_id_ = audio_tracks[0].Id(); } @@ -497,8 +517,14 @@ if (audio_renderer_) audio_renderer_->Stop(); + SetNetworkState(WebMediaPlayer::kNetworkStateLoading); audio_renderer_ = renderer_factory_->GetAudioRenderer( web_stream_, frame->GetRoutingID(), initial_audio_output_device_id_); + + // |audio_renderer_| can be null in tests. + if (!audio_renderer_) + break; + audio_renderer_->SetVolume(volume_); audio_renderer_->Start(); audio_renderer_->Play();
diff --git a/content/renderer/media/stream/webmediaplayer_ms.h b/content/renderer/media/stream/webmediaplayer_ms.h index d43fdad..cf07496 100644 --- a/content/renderer/media/stream/webmediaplayer_ms.h +++ b/content/renderer/media/stream/webmediaplayer_ms.h
@@ -195,6 +195,7 @@ // blink::WebMediaStreamObserver implementation void TrackAdded(const blink::WebMediaStreamTrack& track) override; void TrackRemoved(const blink::WebMediaStreamTrack& track) override; + void ActiveStateChanged(bool is_active) override; private: friend class WebMediaPlayerMSTest;
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc index f2c3024a..3db7956 100644 --- a/content/renderer/service_worker/service_worker_context_client.cc +++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -490,6 +490,8 @@ notification_close_event_callbacks; std::map<int, DispatchPushEventCallback> push_event_callbacks; std::map<int, DispatchFetchEventCallback> fetch_event_callbacks; + std::map<int, DispatchCookieChangeEventCallback> + cookie_change_event_callbacks; std::map<int, DispatchExtendableMessageEventCallback> message_event_callbacks; // Maps for response callbacks. @@ -970,6 +972,15 @@ base::Time::FromDoubleT(event_dispatch_time)); } +void ServiceWorkerContextClient::DidHandleCookieChangeEvent( + int request_id, + blink::mojom::ServiceWorkerEventStatus status, + double event_dispatch_time) { + RunEventCallback(&context_->cookie_change_event_callbacks, + context_->timeout_timer.get(), request_id, status, + base::Time::FromDoubleT(event_dispatch_time)); +} + void ServiceWorkerContextClient::DidHandleExtendableMessageEvent( int request_id, blink::mojom::ServiceWorkerEventStatus status, @@ -1606,6 +1617,27 @@ proxy_->DispatchPushEvent(request_id, data); } +void ServiceWorkerContextClient::DispatchCookieChangeEvent( + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause, + DispatchCookieChangeEventCallback callback) { + TRACE_EVENT0("ServiceWorker", + "ServiceWorkerContextClient::DispatchCookieChangeEvent"); + + int request_id = context_->timeout_timer->StartEvent( + CreateAbortCallback(&context_->cookie_change_event_callbacks)); + context_->cookie_change_event_callbacks.emplace(request_id, + std::move(callback)); + + // TODO(pwnall): Map |cause| to a blink enum. Currently, a cookie overwrite + // shows up as delete + insert. + bool is_cookie_delete = + cause != ::network::mojom::CookieChangeCause::INSERTED; + proxy_->DispatchCookieChangeEvent( + request_id, blink::WebString::FromUTF8(cookie.Name()), + blink::WebString::FromUTF8(cookie.Value()), is_cookie_delete); +} + void ServiceWorkerContextClient::Ping(PingCallback callback) { std::move(callback).Run(); }
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h index 3b02aa2..8151a71 100644 --- a/content/renderer/service_worker/service_worker_context_client.h +++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -163,6 +163,9 @@ int request_id, blink::mojom::ServiceWorkerEventStatus status, double dispatch_event_time) override; + void DidHandleCookieChangeEvent(int request_id, + blink::mojom::ServiceWorkerEventStatus status, + double dispatch_event_time) override; void DidHandleExtendableMessageEvent( int request_id, blink::mojom::ServiceWorkerEventStatus status, @@ -335,6 +338,10 @@ payments::mojom::PaymentRequestEventDataPtr event_data, payments::mojom::PaymentHandlerResponseCallbackPtr response_callback, DispatchPaymentRequestEventCallback callback) override; + void DispatchCookieChangeEvent( + const net::CanonicalCookie& cookie, + ::network::mojom::CookieChangeCause cause, + DispatchCookieChangeEventCallback callback) override; void Ping(PingCallback callback) override; void SetIdleTimerDelayToZero() override;
diff --git a/content/renderer/service_worker/service_worker_context_client_unittest.cc b/content/renderer/service_worker/service_worker_context_client_unittest.cc index 856d20e..d0c04b3 100644 --- a/content/renderer/service_worker/service_worker_context_client_unittest.cc +++ b/content/renderer/service_worker/service_worker_context_client_unittest.cc
@@ -104,6 +104,12 @@ override { NOTREACHED(); } + void DispatchCookieChangeEvent(int event_id, + const blink::WebString& name, + const blink::WebString& value, + bool is_deleted) override { + NOTREACHED(); + } void DispatchExtendableMessageEvent( int event_id, blink::TransferableMessage message,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 92dda1c..d7cb4ae6 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1264,6 +1264,7 @@ "../browser/compositor/gpu_vsync_begin_frame_source_unittest.cc", "../browser/compositor/reflector_impl_unittest.cc", "../browser/compositor/software_browser_compositor_output_surface_unittest.cc", + "../browser/cookie_store/cookie_store_manager_unittest.cc", "../browser/devtools/devtools_http_handler_unittest.cc", "../browser/devtools/devtools_manager_unittest.cc", "../browser/devtools/devtools_video_consumer_unittest.cc", @@ -1363,6 +1364,7 @@ "../browser/manifest/manifest_icon_selector_unittest.cc", "../browser/media/audible_metrics_unittest.cc", "../browser/media/audio_input_stream_broker_unittest.cc", + "../browser/media/audio_loopback_stream_broker_unittest.cc", "../browser/media/audio_output_stream_broker_unittest.cc", "../browser/media/audio_stream_monitor_unittest.cc", "../browser/media/capture/audio_mirroring_manager_unittest.cc",
diff --git a/docs/code_reviews.md b/docs/code_reviews.md index 08af713..05b4cf0 100644 --- a/docs/code_reviews.md +++ b/docs/code_reviews.md
@@ -33,7 +33,7 @@ request more time, or suggest another reviewer. * Use the status field in Gerrit settings to indicate if you're away and when - * you'll be back. + you'll be back. * Don't generally discourage people from sending you code reviews. This includes using a blanket "slow" in your status field.
diff --git a/gpu/command_buffer/build_raster_cmd_buffer.py b/gpu/command_buffer/build_raster_cmd_buffer.py index 2a688a3..d19b7432 100755 --- a/gpu/command_buffer/build_raster_cmd_buffer.py +++ b/gpu/command_buffer/build_raster_cmd_buffer.py
@@ -313,6 +313,20 @@ 'OrderingBarrierCHROMIUM': { 'type': 'NoCommand', }, + 'TraceBeginCHROMIUM': { + 'type': 'Custom', + 'impl_func': False, + 'client_test': False, + 'cmd_args': 'GLuint category_bucket_id, GLuint name_bucket_id', + 'extension': 'CHROMIUM_trace_marker', + }, + 'TraceEndCHROMIUM': { + 'impl_func': False, + 'client_test': False, + 'decoder_func': 'DoTraceEndCHROMIUM', + 'unit_test': False, + 'extension': 'CHROMIUM_trace_marker', + }, 'InsertFenceSyncCHROMIUM': { 'type': 'Custom', 'internal': True,
diff --git a/gpu/command_buffer/client/raster_cmd_helper_autogen.h b/gpu/command_buffer/client/raster_cmd_helper_autogen.h index c252dac6..4d6d255d 100644 --- a/gpu/command_buffer/client/raster_cmd_helper_autogen.h +++ b/gpu/command_buffer/client/raster_cmd_helper_autogen.h
@@ -294,4 +294,20 @@ } } +void TraceBeginCHROMIUM(GLuint category_bucket_id, GLuint name_bucket_id) { + raster::cmds::TraceBeginCHROMIUM* c = + GetCmdSpace<raster::cmds::TraceBeginCHROMIUM>(); + if (c) { + c->Init(category_bucket_id, name_bucket_id); + } +} + +void TraceEndCHROMIUM() { + raster::cmds::TraceEndCHROMIUM* c = + GetCmdSpace<raster::cmds::TraceEndCHROMIUM>(); + if (c) { + c->Init(); + } +} + #endif // GPU_COMMAND_BUFFER_CLIENT_RASTER_CMD_HELPER_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/raster_implementation.cc b/gpu/command_buffer/client/raster_implementation.cc index c18bda98..5fb833f2 100644 --- a/gpu/command_buffer/client/raster_implementation.cc +++ b/gpu/command_buffer/client/raster_implementation.cc
@@ -1231,6 +1231,32 @@ NOTREACHED(); } +void RasterImplementation::TraceBeginCHROMIUM(const char* category_name, + const char* trace_name) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM(" + << category_name << ", " << trace_name << ")"); + SetBucketAsCString(kResultBucketId, category_name); + SetBucketAsCString(kResultBucketId + 1, trace_name); + helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1); + helper_->SetBucketSize(kResultBucketId, 0); + helper_->SetBucketSize(kResultBucketId + 1, 0); + current_trace_stack_++; +} + +void RasterImplementation::TraceEndCHROMIUM() { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" + << ")"); + if (current_trace_stack_ == 0) { + SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM", + "missing begin trace"); + return; + } + helper_->TraceEndCHROMIUM(); + current_trace_stack_--; +} + RasterImplementation::RasterProperties::RasterProperties( SkColor background_color, bool can_use_lcd_text,
diff --git a/gpu/command_buffer/client/raster_implementation_autogen.h b/gpu/command_buffer/client/raster_implementation_autogen.h index 9b064384..aee0e055 100644 --- a/gpu/command_buffer/client/raster_implementation_autogen.h +++ b/gpu/command_buffer/client/raster_implementation_autogen.h
@@ -103,4 +103,9 @@ GLsizei width, GLsizei height) override; +void TraceBeginCHROMIUM(const char* category_name, + const char* trace_name) override; + +void TraceEndCHROMIUM() override; + #endif // GPU_COMMAND_BUFFER_CLIENT_RASTER_IMPLEMENTATION_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/raster_implementation_gles.cc b/gpu/command_buffer/client/raster_implementation_gles.cc index 8630cf5..0a32278 100644 --- a/gpu/command_buffer/client/raster_implementation_gles.cc +++ b/gpu/command_buffer/client/raster_implementation_gles.cc
@@ -352,5 +352,14 @@ gl_->ActiveTexture(GL_TEXTURE0); } +void RasterImplementationGLES::TraceBeginCHROMIUM(const char* category_name, + const char* trace_name) { + gl_->TraceBeginCHROMIUM(category_name, trace_name); +} + +void RasterImplementationGLES::TraceEndCHROMIUM() { + gl_->TraceEndCHROMIUM(); +} + } // namespace raster } // namespace gpu
diff --git a/gpu/command_buffer/client/raster_implementation_gles.h b/gpu/command_buffer/client/raster_implementation_gles.h index a665567f..a5a7172f 100644 --- a/gpu/command_buffer/client/raster_implementation_gles.h +++ b/gpu/command_buffer/client/raster_implementation_gles.h
@@ -128,6 +128,10 @@ void BeginGpuRaster() override; void EndGpuRaster() override; + void TraceBeginCHROMIUM(const char* category_name, + const char* trace_name) override; + void TraceEndCHROMIUM() override; + private: struct Texture { Texture(GLuint id,
diff --git a/gpu/command_buffer/client/raster_interface_autogen.h b/gpu/command_buffer/client/raster_interface_autogen.h index abdfc4e..39fb283a 100644 --- a/gpu/command_buffer/client/raster_interface_autogen.h +++ b/gpu/command_buffer/client/raster_interface_autogen.h
@@ -71,4 +71,7 @@ GLint y, GLsizei width, GLsizei height) = 0; +virtual void TraceBeginCHROMIUM(const char* category_name, + const char* trace_name) = 0; +virtual void TraceEndCHROMIUM() = 0; #endif // GPU_COMMAND_BUFFER_CLIENT_RASTER_INTERFACE_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/raster_cmd_format_autogen.h b/gpu/command_buffer/common/raster_cmd_format_autogen.h index faad7ed..51c39d02 100644 --- a/gpu/command_buffer/common/raster_cmd_format_autogen.h +++ b/gpu/command_buffer/common/raster_cmd_format_autogen.h
@@ -1397,4 +1397,68 @@ static_assert(offsetof(CopySubTexture, height) == 32, "offset of CopySubTexture height should be 32"); +struct TraceBeginCHROMIUM { + typedef TraceBeginCHROMIUM ValueType; + static const CommandId kCmdId = kTraceBeginCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _category_bucket_id, GLuint _name_bucket_id) { + SetHeader(); + category_bucket_id = _category_bucket_id; + name_bucket_id = _name_bucket_id; + } + + void* Set(void* cmd, GLuint _category_bucket_id, GLuint _name_bucket_id) { + static_cast<ValueType*>(cmd)->Init(_category_bucket_id, _name_bucket_id); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t category_bucket_id; + uint32_t name_bucket_id; +}; + +static_assert(sizeof(TraceBeginCHROMIUM) == 12, + "size of TraceBeginCHROMIUM should be 12"); +static_assert(offsetof(TraceBeginCHROMIUM, header) == 0, + "offset of TraceBeginCHROMIUM header should be 0"); +static_assert(offsetof(TraceBeginCHROMIUM, category_bucket_id) == 4, + "offset of TraceBeginCHROMIUM category_bucket_id should be 4"); +static_assert(offsetof(TraceBeginCHROMIUM, name_bucket_id) == 8, + "offset of TraceBeginCHROMIUM name_bucket_id should be 8"); + +struct TraceEndCHROMIUM { + typedef TraceEndCHROMIUM ValueType; + static const CommandId kCmdId = kTraceEndCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init() { SetHeader(); } + + void* Set(void* cmd) { + static_cast<ValueType*>(cmd)->Init(); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; +}; + +static_assert(sizeof(TraceEndCHROMIUM) == 4, + "size of TraceEndCHROMIUM should be 4"); +static_assert(offsetof(TraceEndCHROMIUM, header) == 0, + "offset of TraceEndCHROMIUM header should be 0"); + #endif // GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_FORMAT_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/raster_cmd_format_test_autogen.h b/gpu/command_buffer/common/raster_cmd_format_test_autogen.h index 84bd76f..774ad6ca 100644 --- a/gpu/command_buffer/common/raster_cmd_format_test_autogen.h +++ b/gpu/command_buffer/common/raster_cmd_format_test_autogen.h
@@ -481,4 +481,25 @@ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); } +TEST_F(RasterFormatTest, TraceBeginCHROMIUM) { + cmds::TraceBeginCHROMIUM& cmd = *GetBufferAs<cmds::TraceBeginCHROMIUM>(); + void* next_cmd = + cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12)); + EXPECT_EQ(static_cast<uint32_t>(cmds::TraceBeginCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.category_bucket_id); + EXPECT_EQ(static_cast<GLuint>(12), cmd.name_bucket_id); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(RasterFormatTest, TraceEndCHROMIUM) { + cmds::TraceEndCHROMIUM& cmd = *GetBufferAs<cmds::TraceEndCHROMIUM>(); + void* next_cmd = cmd.Set(&cmd); + EXPECT_EQ(static_cast<uint32_t>(cmds::TraceEndCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + #endif // GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_FORMAT_TEST_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/raster_cmd_ids_autogen.h b/gpu/command_buffer/common/raster_cmd_ids_autogen.h index e64146a2..bfa96d3 100644 --- a/gpu/command_buffer/common/raster_cmd_ids_autogen.h +++ b/gpu/command_buffer/common/raster_cmd_ids_autogen.h
@@ -40,7 +40,9 @@ OP(BindTexImage2DCHROMIUM) /* 281 */ \ OP(ReleaseTexImage2DCHROMIUM) /* 282 */ \ OP(TexStorage2D) /* 283 */ \ - OP(CopySubTexture) /* 284 */ + OP(CopySubTexture) /* 284 */ \ + OP(TraceBeginCHROMIUM) /* 285 */ \ + OP(TraceEndCHROMIUM) /* 286 */ enum CommandId { kOneBeforeStartPoint =
diff --git a/gpu/command_buffer/raster_cmd_buffer_functions.txt b/gpu/command_buffer/raster_cmd_buffer_functions.txt index f616108..69b2ab0 100644 --- a/gpu/command_buffer/raster_cmd_buffer_functions.txt +++ b/gpu/command_buffer/raster_cmd_buffer_functions.txt
@@ -52,3 +52,5 @@ GL_APICALL void GL_APIENTRY glReleaseTexImage2DCHROMIUM (GLuint texture_id, GLint image_id); GL_APICALL void GL_APIENTRY glTexStorage2D (GLuint texture_id, GLsizei levels, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glCopySubTexture (GLuint source_id, GLuint dest_id, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glTraceBeginCHROMIUM (const char* category_name, const char* trace_name); +GL_APICALL void GL_APIENTRY glTraceEndCHROMIUM (void);
diff --git a/gpu/command_buffer/service/decoder_context.h b/gpu/command_buffer/service/decoder_context.h index 2c2ab08..9aa5c53 100644 --- a/gpu/command_buffer/service/decoder_context.h +++ b/gpu/command_buffer/service/decoder_context.h
@@ -35,6 +35,7 @@ class ErrorState; class FeatureInfo; class GpuFenceManager; +class Outputter; class Texture; struct ContextState; struct DisallowedFeatures; @@ -218,6 +219,11 @@ // // Set to true to LOG every command. virtual void SetLogCommands(bool log_commands) = 0; + + // + // Methods required by GpuTracer + // + virtual gles2::Outputter* outputter() const = 0; }; } // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 00a82d0..f1245433 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -560,6 +560,10 @@ log_commands_ = log_commands; } +Outputter* GLES2Decoder::outputter() const { + return outputter_; +} + // This class implements GLES2Decoder so we don't have to expose all the GLES2 // cmd stuff to outside this class. class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h index 56e53edd..fd5dacc 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -130,7 +130,7 @@ // Set to true to LOG every command. void SetLogCommands(bool log_commands) override; - Outputter* outputter() const { return outputter_; } + Outputter* outputter() const override; // Set the surface associated with the default FBO. virtual void SetSurface(const scoped_refptr<gl::GLSurface>& surface) = 0;
diff --git a/gpu/command_buffer/service/gpu_tracer.cc b/gpu/command_buffer/service/gpu_tracer.cc index 748dcc7..a0461746 100644 --- a/gpu/command_buffer/service/gpu_tracer.cc +++ b/gpu/command_buffer/service/gpu_tracer.cc
@@ -17,6 +17,7 @@ #include "base/trace_event/trace_event.h" #include "gpu/command_buffer/common/gles2_cmd_utils.h" #include "gpu/command_buffer/service/context_group.h" +#include "gpu/command_buffer/service/decoder_context.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_version_info.h" @@ -171,7 +172,7 @@ } } -GPUTracer::GPUTracer(GLES2Decoder* decoder) +GPUTracer::GPUTracer(DecoderContext* decoder) : gpu_trace_srv_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( TRACE_DISABLED_BY_DEFAULT("gpu.service"))), gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( @@ -297,7 +298,7 @@ void GPUTracer::ProcessTraces() { if (!gpu_timing_client_->IsAvailable()) { - while (!finished_traces_.empty()) { + while (!finished_traces_.empty()) { finished_traces_.front()->Destroy(false); finished_traces_.pop_front(); }
diff --git a/gpu/command_buffer/service/gpu_tracer.h b/gpu/command_buffer/service/gpu_tracer.h index 79de329..a78ed87 100644 --- a/gpu/command_buffer/service/gpu_tracer.h +++ b/gpu/command_buffer/service/gpu_tracer.h
@@ -16,15 +16,17 @@ #include "base/containers/stack.h" #include "base/macros.h" #include "base/threading/thread.h" -#include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/gpu_gles2_export.h" namespace gl { class GPUTimingClient; class GPUTimer; -} +} // namespace gl namespace gpu { + +class DecoderContext; + namespace gles2 { class Outputter; @@ -36,7 +38,7 @@ kTraceCHROMIUM, kTraceDecoder, - kTraceDisjoint, // Used internally. + kTraceDisjoint, // Used internally. NUM_TRACER_SOURCES }; @@ -55,7 +57,7 @@ // Traces GPU Commands. class GPU_GLES2_EXPORT GPUTracer { public: - explicit GPUTracer(GLES2Decoder* decoder); + explicit GPUTracer(DecoderContext* decoder); virtual ~GPUTracer(); void Destroy(bool have_context); @@ -95,7 +97,7 @@ Outputter* outputter_ = nullptr; std::vector<TraceMarker> markers_[NUM_TRACER_SOURCES]; base::circular_deque<scoped_refptr<GPUTrace>> finished_traces_; - GLES2Decoder* decoder_; + DecoderContext* decoder_; int64_t disjoint_time_ = 0; bool gpu_executing_ = false; bool began_device_traces_ = false;
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc index 6de44a8..c6b6456 100644 --- a/gpu/command_buffer/service/raster_decoder.cc +++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -45,6 +45,7 @@ #include "gpu/command_buffer/service/gl_utils.h" #include "gpu/command_buffer/service/gles2_cmd_copy_tex_image.h" #include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h" +#include "gpu/command_buffer/service/gpu_tracer.h" #include "gpu/command_buffer/service/image_factory.h" #include "gpu/command_buffer/service/image_manager.h" #include "gpu/command_buffer/service/indexed_buffer_binding_host.h" @@ -543,6 +544,7 @@ void DoGetIntegerv(GLenum pname, GLint* params, GLsizei params_size); void DoTexParameteri(GLuint texture_id, GLenum pname, GLint param); void DoBindTexImage2DCHROMIUM(GLuint texture_id, GLint image_id); + void DoTraceEndCHROMIUM(); void DoProduceTextureDirect(GLuint texture, const volatile GLbyte* key); void DoReleaseTexImage2DCHROMIUM(GLuint texture_id, GLint image_id); void TexStorage2DImage(TextureRef* texture_ref, @@ -724,8 +726,6 @@ DecoderTextureState texture_state_; DecoderFramebufferState framebuffer_state_; - bool gpu_debug_commands_; - // An optional behaviour to lose the context and group when OOM. bool lose_context_when_out_of_memory_ = false; @@ -735,6 +735,12 @@ std::unique_ptr<CopyTexImageResourceManager> copy_tex_image_blit_; std::unique_ptr<CopyTextureCHROMIUMResourceManager> copy_texture_chromium_; + std::unique_ptr<GPUTracer> gpu_tracer_; + const unsigned char* gpu_decoder_category_; + static constexpr int gpu_trace_level_ = 2; + bool gpu_trace_commands_ = false; + bool gpu_debug_commands_ = false; + // Raster helpers. ServiceFontManager font_manager_; sk_sp<GrContext> gr_context_; @@ -770,11 +776,9 @@ group); } -RasterDecoder::RasterDecoder(CommandBufferServiceBase* command_buffer_service) - : CommonDecoder(command_buffer_service), - initialized_(false), - debug_(false), - log_commands_(false) {} +RasterDecoder::RasterDecoder(CommandBufferServiceBase* command_buffer_service, + gles2::Outputter* outputter) + : CommonDecoder(command_buffer_service), outputter_(outputter) {} RasterDecoder::~RasterDecoder() {} @@ -804,6 +808,10 @@ log_commands_ = log_commands; } +gles2::Outputter* RasterDecoder::outputter() const { + return outputter_; +} + base::StringPiece RasterDecoder::GetLogPrefix() { return GetLogger()->GetLogPrefix(); } @@ -813,7 +821,7 @@ CommandBufferServiceBase* command_buffer_service, Outputter* outputter, ContextGroup* group) - : RasterDecoder(command_buffer_service), + : RasterDecoder(command_buffer_service, outputter), client_(client), logger_(&debug_marker_manager_, client), group_(group), @@ -823,6 +831,8 @@ texture_state_(group_->feature_info()->workarounds()), service_logging_( group_->gpu_preferences().enable_gpu_service_logging_gpu), + gpu_decoder_category_(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( + TRACE_DISABLED_BY_DEFAULT("gpu_decoder"))), font_manager_(this), weak_ptr_factory_(this) {} @@ -859,6 +869,9 @@ surface_ = surface; context_ = context; + // Create GPU Tracer for timing values. + gpu_tracer_.reset(new GPUTracer(this)); + // Save the loseContextWhenOutOfMemory context creation attribute. lose_context_when_out_of_memory_ = attrib_helper.lose_context_when_out_of_memory; @@ -1258,10 +1271,11 @@ } bool RasterDecoderImpl::HasMoreIdleWork() const { - return false; + return gpu_tracer_->HasTracesToProcess(); } void RasterDecoderImpl::PerformIdleWork() { + gpu_tracer_->ProcessTraces(); } bool RasterDecoderImpl::HasPollingWork() const { @@ -1368,10 +1382,14 @@ } void RasterDecoderImpl::BeginDecoding() { - gpu_debug_commands_ = log_commands() || debug(); + gpu_tracer_->BeginDecoding(); + gpu_trace_commands_ = gpu_tracer_->IsTracing() && *gpu_decoder_category_; + gpu_debug_commands_ = log_commands() || debug() || gpu_trace_commands_; } -void RasterDecoderImpl::EndDecoding() {} +void RasterDecoderImpl::EndDecoding() { + gpu_tracer_->EndDecoding(); +} const char* RasterDecoderImpl::GetCommandName(unsigned int command_id) const { if (command_id >= kFirstRasterCommand && command_id < kNumCommands) { @@ -1431,9 +1449,22 @@ unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count); if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) || (info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) { + bool doing_gpu_trace = false; + if (DebugImpl && gpu_trace_commands_) { + if (CMD_FLAG_GET_TRACE_LEVEL(info.cmd_flags) <= gpu_trace_level_) { + doing_gpu_trace = true; + gpu_tracer_->Begin(TRACE_DISABLED_BY_DEFAULT("gpu_decoder"), + GetCommandName(command), kTraceDecoder); + } + } + uint32_t immediate_data_size = (arg_count - info_arg_count) * sizeof(CommandBufferEntry); // NOLINT result = (this->*info.cmd_handler)(immediate_data_size, cmd_data); + + if (DebugImpl && doing_gpu_trace) + gpu_tracer_->End(kTraceDecoder); + if (DebugImpl && debug() && !WasContextLost()) { GLenum error; while ((error = api()->glGetErrorFn()) != GL_NO_ERROR) { @@ -2143,6 +2174,43 @@ nullptr, Texture::UNBOUND); } +error::Error RasterDecoderImpl::HandleTraceBeginCHROMIUM( + uint32_t immediate_data_size, + const volatile void* cmd_data) { + const volatile gles2::cmds::TraceBeginCHROMIUM& c = + *static_cast<const volatile gles2::cmds::TraceBeginCHROMIUM*>(cmd_data); + Bucket* category_bucket = GetBucket(c.category_bucket_id); + Bucket* name_bucket = GetBucket(c.name_bucket_id); + if (!category_bucket || category_bucket->size() == 0 || !name_bucket || + name_bucket->size() == 0) { + return error::kInvalidArguments; + } + + std::string category_name; + std::string trace_name; + if (!category_bucket->GetAsString(&category_name) || + !name_bucket->GetAsString(&trace_name)) { + return error::kInvalidArguments; + } + + debug_marker_manager_.PushGroup(trace_name); + if (!gpu_tracer_->Begin(category_name, trace_name, kTraceCHROMIUM)) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glTraceBeginCHROMIUM", + "unable to create begin trace"); + return error::kNoError; + } + return error::kNoError; +} + +void RasterDecoderImpl::DoTraceEndCHROMIUM() { + debug_marker_manager_.PopGroup(); + if (!gpu_tracer_->End(kTraceCHROMIUM)) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glTraceEndCHROMIUM", + "no trace begin found"); + return; + } +} + void RasterDecoderImpl::DoProduceTextureDirect(GLuint client_id, const volatile GLbyte* key) { TRACE_EVENT2("gpu", "RasterDecoderImpl::DoProduceTextureDirect", "context",
diff --git a/gpu/command_buffer/service/raster_decoder.h b/gpu/command_buffer/service/raster_decoder.h index c2ce9cc5c..99eafe44 100644 --- a/gpu/command_buffer/service/raster_decoder.h +++ b/gpu/command_buffer/service/raster_decoder.h
@@ -68,6 +68,7 @@ // Set to true to LOG every command. void SetLogCommands(bool log_commands) override; + gles2::Outputter* outputter() const override; bool log_commands() const { return log_commands_; } virtual void SetCopyTextureResourceManagerForTest( @@ -77,12 +78,14 @@ virtual ServiceTransferCache* GetTransferCacheForTest() = 0; protected: - RasterDecoder(CommandBufferServiceBase* command_buffer_service); + RasterDecoder(CommandBufferServiceBase* command_buffer_service, + gles2::Outputter* outputter); private: - bool initialized_; - bool debug_; - bool log_commands_; + bool initialized_ = false; + bool debug_ = false; + bool log_commands_ = false; + gles2::Outputter* outputter_ = nullptr; DISALLOW_COPY_AND_ASSIGN(RasterDecoder); };
diff --git a/gpu/command_buffer/service/raster_decoder_autogen.h b/gpu/command_buffer/service/raster_decoder_autogen.h index c090ea26..df594cf88 100644 --- a/gpu/command_buffer/service/raster_decoder_autogen.h +++ b/gpu/command_buffer/service/raster_decoder_autogen.h
@@ -477,4 +477,11 @@ return error::kNoError; } +error::Error RasterDecoderImpl::HandleTraceEndCHROMIUM( + uint32_t immediate_data_size, + const volatile void* cmd_data) { + DoTraceEndCHROMIUM(); + return error::kNoError; +} + #endif // GPU_COMMAND_BUFFER_SERVICE_RASTER_DECODER_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/raster_decoder_mock.cc b/gpu/command_buffer/service/raster_decoder_mock.cc index ccef0fb..85a53cbc 100644 --- a/gpu/command_buffer/service/raster_decoder_mock.cc +++ b/gpu/command_buffer/service/raster_decoder_mock.cc
@@ -11,7 +11,8 @@ MockRasterDecoder::MockRasterDecoder( CommandBufferServiceBase* command_buffer_service) - : RasterDecoder(command_buffer_service), weak_ptr_factory_(this) { + : RasterDecoder(command_buffer_service, /*outputter=*/nullptr), + weak_ptr_factory_(this) { ON_CALL(*this, MakeCurrent()).WillByDefault(testing::Return(true)); }
diff --git a/ios/chrome/browser/ui/infobars/confirm_infobar_view.mm b/ios/chrome/browser/ui/infobars/confirm_infobar_view.mm index f9b5a03..2ab869f0 100644 --- a/ios/chrome/browser/ui/infobars/confirm_infobar_view.mm +++ b/ios/chrome/browser/ui/infobars/confirm_infobar_view.mm
@@ -966,7 +966,8 @@ if (IsRefreshInfobarEnabled()) { button.uppercaseTitle = NO; button.layer.cornerRadius = kButtonCornerRadius; - button.titleLabel.font = InfoBarButtonLabelFont(); + [button setTitleFont:InfoBarButtonLabelFont() + forState:UIControlStateNormal]; } button.inkColor = [[palette tint300] colorWithAlphaComponent:0.5f]; [button setBackgroundColor:[palette tint500] forState:UIControlStateNormal];
diff --git a/media/audio/mac/core_audio_util_mac.cc b/media/audio/mac/core_audio_util_mac.cc index 249ea67..3c050b4b 100644 --- a/media/audio/mac/core_audio_util_mac.cc +++ b/media/audio/mac/core_audio_util_mac.cc
@@ -10,7 +10,6 @@ #include "base/single_thread_task_runner.h" #include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" -#include "media/audio/audio_manager.h" namespace media { namespace core_audio_mac { @@ -25,7 +24,6 @@ base::Optional<std::string> GetDeviceStringProperty( AudioObjectID device_id, AudioObjectPropertySelector property_selector) { - DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); CFStringRef property_value = nullptr; UInt32 size = sizeof(property_value); AudioObjectPropertyAddress property_address = { @@ -55,7 +53,6 @@ AudioObjectID device_id, AudioObjectPropertySelector property_selector, AudioObjectPropertyScope property_scope) { - DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); AudioObjectPropertyAddress property_address = { property_selector, property_scope, kAudioObjectPropertyElementMaster}; UInt32 property_value; @@ -72,7 +69,6 @@ uint32_t GetDevicePropertySize(AudioObjectID device_id, AudioObjectPropertySelector property_selector, AudioObjectPropertyScope property_scope) { - DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); AudioObjectPropertyAddress property_address = { property_selector, property_scope, kAudioObjectPropertyElementMaster}; UInt32 size = 0; @@ -91,7 +87,6 @@ std::vector<AudioObjectID> GetAudioDeviceIDs( AudioObjectID audio_object_id, AudioObjectPropertySelector property_selector) { - DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); AudioObjectPropertyAddress property_address = { property_selector, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster};
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn index acdf83e..be5925b2 100644 --- a/media/capture/BUILD.gn +++ b/media/capture/BUILD.gn
@@ -223,6 +223,8 @@ if (is_chromeos) { sources += [ + "video/chromeos/camera_3a_controller.cc", + "video/chromeos/camera_3a_controller.h", "video/chromeos/camera_buffer_factory.cc", "video/chromeos/camera_buffer_factory.h", "video/chromeos/camera_device_context.cc", @@ -342,6 +344,7 @@ if (is_chromeos) { sources += [ + "video/chromeos/camera_3a_controller_unittest.cc", "video/chromeos/camera_device_delegate_unittest.cc", "video/chromeos/camera_hal_delegate_unittest.cc", "video/chromeos/camera_hal_dispatcher_impl_unittest.cc",
diff --git a/media/capture/video/chromeos/camera_3a_controller.cc b/media/capture/video/chromeos/camera_3a_controller.cc new file mode 100644 index 0000000..0ff045e --- /dev/null +++ b/media/capture/video/chromeos/camera_3a_controller.cc
@@ -0,0 +1,327 @@ +// 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 "media/capture/video/chromeos/camera_3a_controller.h" + +#include "media/capture/video/chromeos/camera_metadata_utils.h" + +namespace media { + +namespace { + +template <typename EntryType> +bool Get3AEntry(const cros::mojom::CameraMetadataPtr& metadata, + cros::mojom::CameraMetadataTag control, + EntryType* result) { + const auto* entry = GetMetadataEntry(metadata, control); + if (entry) { + *result = static_cast<EntryType>((*entry)->data[0]); + return true; + } else { + return false; + } +} + +} // namespace + +Camera3AController::Camera3AController( + const cros::mojom::CameraMetadataPtr& static_metadata, + CaptureMetadataDispatcher* capture_metadata_dispatcher, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : capture_metadata_dispatcher_(capture_metadata_dispatcher), + task_runner_(std::move(task_runner)), + af_mode_(cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF), + af_state_(cros::mojom::AndroidControlAfState:: + ANDROID_CONTROL_AF_STATE_INACTIVE), + af_mode_set_(false), + ae_mode_(cros::mojom::AndroidControlAeMode::ANDROID_CONTROL_AE_MODE_ON), + ae_state_(cros::mojom::AndroidControlAeState:: + ANDROID_CONTROL_AE_STATE_INACTIVE), + ae_mode_set_(false), + awb_mode_( + cros::mojom::AndroidControlAwbMode::ANDROID_CONTROL_AWB_MODE_AUTO), + awb_state_(cros::mojom::AndroidControlAwbState:: + ANDROID_CONTROL_AWB_STATE_INACTIVE), + awb_mode_set_(false), + weak_ptr_factory_(this) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + capture_metadata_dispatcher_->AddResultMetadataObserver(this); + + auto* af_modes = GetMetadataEntry( + static_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES); + if (af_modes) { + for (const auto& m : (*af_modes)->data) { + available_af_modes_.insert( + static_cast<cros::mojom::AndroidControlAfMode>(m)); + } + } + auto* ae_modes = GetMetadataEntry( + static_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_AVAILABLE_MODES); + if (ae_modes) { + for (const auto& m : (*ae_modes)->data) { + available_ae_modes_.insert( + static_cast<cros::mojom::AndroidControlAeMode>(m)); + } + } + auto* awb_modes = GetMetadataEntry( + static_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_AVAILABLE_MODES); + if (awb_modes) { + for (const auto& m : (*awb_modes)->data) { + available_awb_modes_.insert( + static_cast<cros::mojom::AndroidControlAwbMode>(m)); + } + } + + // Enable AF if supported. MODE_AUTO is always supported on auto-focus camera + // modules; fixed focus camera modules always has MODE_OFF. + if (available_af_modes_.count( + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_AUTO)) { + af_mode_ = cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_AUTO; + } + // AE should always be MODE_ON unless we enable manual sensor control. Since + // we don't have flash on any of our devices we don't care about the + // flash-related AE modes. + // + // AWB should always be MODE_AUTO unless we enable manual sensor control. + Set3AMode(cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, + base::checked_cast<uint8_t>(af_mode_)); + Set3AMode(cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_MODE, + base::checked_cast<uint8_t>(ae_mode_)); + Set3AMode(cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_MODE, + base::checked_cast<uint8_t>(awb_mode_)); +} + +Camera3AController::~Camera3AController() { + DCHECK(task_runner_->BelongsToCurrentThread()); + + capture_metadata_dispatcher_->RemoveResultMetadataObserver(this); +} + +void Camera3AController::Stabilize3AForStillCapture( + base::OnceClosure on_3a_stabilized_callback) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + if (on_3a_stabilized_callback_ || on_3a_mode_set_callback_) { + // Already stabilizing 3A. + return; + } + + if (Is3AStabilized()) { + std::move(on_3a_stabilized_callback).Run(); + return; + } + + // Wait until all the 3A modes are set in the HAL; otherwise the AF trigger + // and AE precapture trigger may be invalidated during mode transition. + if (!af_mode_set_ || !ae_mode_set_ || !awb_mode_set_) { + on_3a_mode_set_callback_ = + base::BindOnce(&Camera3AController::Stabilize3AForStillCapture, + GetWeakPtr(), base::Passed(&on_3a_stabilized_callback)); + return; + } + + on_3a_stabilized_callback_ = std::move(on_3a_stabilized_callback); + + if (af_mode_ != + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF) { + DVLOG(1) << "Start AF trigger to lock focus"; + std::vector<uint8_t> af_trigger = { + base::checked_cast<uint8_t>(cros::mojom::AndroidControlAfTrigger:: + ANDROID_CONTROL_AF_TRIGGER_START)}; + capture_metadata_dispatcher_->SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, std::move(af_trigger)); + } + + if (ae_mode_ != + cros::mojom::AndroidControlAeMode::ANDROID_CONTROL_AE_MODE_OFF) { + DVLOG(1) << "Start AE precapture trigger to converge exposure"; + std::vector<uint8_t> ae_precapture_trigger = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAePrecaptureTrigger:: + ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START)}; + capture_metadata_dispatcher_->SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, std::move(ae_precapture_trigger)); + } +} + +void Camera3AController::OnResultMetadataAvailable( + const cros::mojom::CameraMetadataPtr& result_metadata) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + if (af_mode_set_ && ae_mode_set_ && awb_mode_set_ && + !on_3a_stabilized_callback_) { + // Process the result metadata only when we need to check if 3A modes are + // synchronized, or when there's a pending 3A stabilization request. + return; + } + + cros::mojom::AndroidControlAfMode af_mode; + if (Get3AEntry(result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, + &af_mode)) { + af_mode_set_ = (af_mode == af_mode_); + } else { + DVLOG(2) << "AF mode is not available in the metadata"; + } + if (!Get3AEntry(result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_STATE, + &af_state_)) { + DVLOG(2) << "AF state is not available in the metadata"; + } + + cros::mojom::AndroidControlAeMode ae_mode; + if (Get3AEntry(result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_MODE, + &ae_mode)) { + ae_mode_set_ = (ae_mode == ae_mode_); + } else { + DVLOG(2) << "AE mode is not available in the metadata"; + } + if (!Get3AEntry(result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_STATE, + &ae_state_)) { + DVLOG(2) << "AE state is not available in the metadata"; + } + + cros::mojom::AndroidControlAwbMode awb_mode; + if (Get3AEntry(result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_MODE, + &awb_mode)) { + awb_mode_set_ = (awb_mode == awb_mode_); + } else { + DVLOG(2) << "AWB mode is not available in the metadata"; + } + if (!Get3AEntry(result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_STATE, + &awb_state_)) { + DVLOG(2) << "AWB state is not available in the metadata"; + } + + DVLOG(2) << "AF mode: " << af_mode_; + DVLOG(2) << "AF state: " << af_state_; + DVLOG(2) << "AE mode: " << ae_mode_; + DVLOG(2) << "AE state: " << ae_state_; + DVLOG(2) << "AWB mode: " << awb_mode_; + DVLOG(2) << "AWB state: " << awb_state_; + + if (on_3a_mode_set_callback_ && af_mode_set_ && ae_mode_set_ && + awb_mode_set_) { + task_runner_->PostTask(FROM_HERE, std::move(on_3a_mode_set_callback_)); + } + + if (on_3a_stabilized_callback_ && Is3AStabilized()) { + std::move(on_3a_stabilized_callback_).Run(); + } +} + +void Camera3AController::SetAutoFocusModeForStillCapture() { + DCHECK(task_runner_->BelongsToCurrentThread()); + + std::vector<uint8_t> af_trigger = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAfTrigger::ANDROID_CONTROL_AF_TRIGGER_CANCEL)}; + capture_metadata_dispatcher_->SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, std::move(af_trigger)); + + if (available_af_modes_.count( + cros::mojom::AndroidControlAfMode:: + ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE)) { + af_mode_ = cros::mojom::AndroidControlAfMode:: + ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE; + } + std::vector<uint8_t> af_mode = {base::checked_cast<uint8_t>(af_mode_)}; + Set3AMode(cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, + base::checked_cast<uint8_t>(af_mode_)); + DVLOG(1) << "Setting AF mode to: " << af_mode_; +} + +void Camera3AController::SetAutoFocusModeForVideoRecording() { + DCHECK(task_runner_->BelongsToCurrentThread()); + + std::vector<uint8_t> af_trigger = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAfTrigger::ANDROID_CONTROL_AF_TRIGGER_CANCEL)}; + capture_metadata_dispatcher_->SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, std::move(af_trigger)); + + if (available_af_modes_.count(cros::mojom::AndroidControlAfMode:: + ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO)) { + af_mode_ = cros::mojom::AndroidControlAfMode:: + ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO; + } + Set3AMode(cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, + base::checked_cast<uint8_t>(af_mode_)); + DVLOG(1) << "Setting AF mode to: " << af_mode_; +} + +base::WeakPtr<Camera3AController> Camera3AController::GetWeakPtr() { + DCHECK(task_runner_->BelongsToCurrentThread()); + + return weak_ptr_factory_.GetWeakPtr(); +} + +void Camera3AController::Set3AMode(cros::mojom::CameraMetadataTag tag, + uint8_t target_mode) { + DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(tag == cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE || + tag == cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_MODE || + tag == cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_MODE); + + std::vector<uint8_t> mode = {base::checked_cast<uint8_t>(target_mode)}; + capture_metadata_dispatcher_->SetCaptureMetadata( + tag, cros::mojom::EntryType::TYPE_BYTE, 1, std::move(mode)); + + switch (tag) { + case cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE: + af_mode_set_ = false; + break; + case cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_MODE: + ae_mode_set_ = false; + break; + case cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_MODE: + awb_mode_set_ = false; + break; + default: + NOTREACHED() << "Invalid 3A mode: " << tag; + } +} + +bool Camera3AController::Is3AStabilized() { + DCHECK(task_runner_->BelongsToCurrentThread()); + + if (af_mode_ != + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF) { + if (af_state_ != cros::mojom::AndroidControlAfState:: + ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED && + af_state_ != cros::mojom::AndroidControlAfState:: + ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) { + return false; + } + } + if (ae_mode_ != + cros::mojom::AndroidControlAeMode::ANDROID_CONTROL_AE_MODE_OFF) { + if (ae_state_ != cros::mojom::AndroidControlAeState:: + ANDROID_CONTROL_AE_STATE_CONVERGED && + ae_state_ != cros::mojom::AndroidControlAeState:: + ANDROID_CONTROL_AE_STATE_FLASH_REQUIRED) { + return false; + } + } + if (awb_mode_ == + cros::mojom::AndroidControlAwbMode::ANDROID_CONTROL_AWB_MODE_AUTO) { + if (awb_state_ != cros::mojom::AndroidControlAwbState:: + ANDROID_CONTROL_AWB_STATE_CONVERGED) { + return false; + } + } + DVLOG(1) << "3A stabilized"; + return true; +} + +} // namespace media
diff --git a/media/capture/video/chromeos/camera_3a_controller.h b/media/capture/video/chromeos/camera_3a_controller.h new file mode 100644 index 0000000..c96b550a --- /dev/null +++ b/media/capture/video/chromeos/camera_3a_controller.h
@@ -0,0 +1,83 @@ +// 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 MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_3A_CONTROLLER_H_ +#define MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_3A_CONTROLLER_H_ + +#include <unordered_set> + +#include "media/base/media_export.h" +#include "media/capture/video/chromeos/mojo/camera3.mojom.h" +#include "media/capture/video/chromeos/stream_buffer_manager.h" + +namespace media { + +// A class to control the auto-exposure, auto-focus, and auto-white-balancing +// operations and modes of the camera. For the detailed state transitions for +// auto-exposure, auto-focus, and auto-white-balancing, see +// https://source.android.com/devices/camera/camera3_3Amodes +class CAPTURE_EXPORT Camera3AController + : public CaptureMetadataDispatcher::ResultMetadataObserver { + public: + Camera3AController(const cros::mojom::CameraMetadataPtr& static_metadata, + CaptureMetadataDispatcher* capture_metadata_dispatcher, + scoped_refptr<base::SingleThreadTaskRunner> task_runner); + ~Camera3AController() final; + + // Trigger the camera to start exposure, focus, and white-balance metering and + // lock them for still capture. + void Stabilize3AForStillCapture(base::OnceClosure on_3a_stabilized_callback); + + // CaptureMetadataDispatcher::ResultMetadataObserver implementation. + void OnResultMetadataAvailable( + const cros::mojom::CameraMetadataPtr& result_metadata) final; + + // Enable the auto-focus mode suitable for still capture. + void SetAutoFocusModeForStillCapture(); + + // Enable the auto-focus mode suitable for video recording. + void SetAutoFocusModeForVideoRecording(); + + base::WeakPtr<Camera3AController> GetWeakPtr(); + + private: + void Set3AMode(cros::mojom::CameraMetadataTag tag, uint8_t target_mode); + bool Is3AStabilized(); + + CaptureMetadataDispatcher* capture_metadata_dispatcher_; + const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + std::unordered_set<cros::mojom::AndroidControlAfMode> available_af_modes_; + cros::mojom::AndroidControlAfMode af_mode_; + cros::mojom::AndroidControlAfState af_state_; + // |af_mode_set_| is set to true when the AF mode is synchronized between the + // HAL and the Camera3AController. + bool af_mode_set_; + + std::unordered_set<cros::mojom::AndroidControlAeMode> available_ae_modes_; + cros::mojom::AndroidControlAeMode ae_mode_; + cros::mojom::AndroidControlAeState ae_state_; + // |ae_mode_set_| is set to true when the AE mode is synchronized between the + // HAL and the Camera3AController. + bool ae_mode_set_; + + std::unordered_set<cros::mojom::AndroidControlAwbMode> available_awb_modes_; + cros::mojom::AndroidControlAwbMode awb_mode_; + cros::mojom::AndroidControlAwbState awb_state_; + // |awb_mode_set_| is set to true when the AWB mode is synchronized between + // the HAL and the Camera3AController. + bool awb_mode_set_; + + base::OnceClosure on_3a_mode_set_callback_; + + base::OnceClosure on_3a_stabilized_callback_; + + base::WeakPtrFactory<Camera3AController> weak_ptr_factory_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(Camera3AController); +}; + +} // namespace media + +#endif // MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_3A_CONTROLLER_H_
diff --git a/media/capture/video/chromeos/camera_3a_controller_unittest.cc b/media/capture/video/chromeos/camera_3a_controller_unittest.cc new file mode 100644 index 0000000..070e0fe1 --- /dev/null +++ b/media/capture/video/chromeos/camera_3a_controller_unittest.cc
@@ -0,0 +1,502 @@ +// 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 "media/capture/video/chromeos/camera_3a_controller.h" + +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread.h" +#include "media/capture/video/chromeos/camera_metadata_utils.h" +#include "media/capture/video/chromeos/stream_buffer_manager.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; + +namespace media { + +namespace { + +class MockCaptureMetadataDispatcher : public CaptureMetadataDispatcher { + public: + MockCaptureMetadataDispatcher() {} + ~MockCaptureMetadataDispatcher() override {} + MOCK_METHOD1( + AddResultMetadataObserver, + void(CaptureMetadataDispatcher::ResultMetadataObserver* observer)); + MOCK_METHOD1( + RemoveResultMetadataObserver, + void(CaptureMetadataDispatcher::ResultMetadataObserver* observer)); + MOCK_METHOD4(SetCaptureMetadata, + void(cros::mojom::CameraMetadataTag tag, + cros::mojom::EntryType type, + size_t count, + std::vector<uint8_t> value)); +}; + +} // namespace + +class Camera3AControllerTest : public ::testing::Test { + public: + Camera3AControllerTest() : thread_("Camera3AControllerThread") {} + + void SetUp() override { + thread_.Start(); + mock_capture_metadata_dispatcher_ = + std::make_unique<MockCaptureMetadataDispatcher>(); + } + + void TearDown() override { + thread_.task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&Camera3AControllerTest::Clear3AControllerOnThread, + base::Unretained(this))); + thread_.Stop(); + mock_capture_metadata_dispatcher_.reset(); + } + + void RunOnThreadSync(const base::Location& location, + base::OnceClosure closure) { + base::WaitableEvent done(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + thread_.task_runner()->PostTask( + location, + base::BindOnce(&Camera3AControllerTest::RunOnThread, + base::Unretained(this), base::ConstRef(location), + base::Passed(&closure), base::Unretained(&done))); + done.Wait(); + } + + void Reset3AController( + const cros::mojom::CameraMetadataPtr& static_metadata) { + RunOnThreadSync( + FROM_HERE, + base::BindOnce(&Camera3AControllerTest::Reset3AControllerOnThread, + base::Unretained(this), + base::ConstRef(static_metadata))); + } + + template <typename Value> + void Set3AMode(cros::mojom::CameraMetadataPtr* metadata, + cros::mojom::CameraMetadataTag control, + Value value, + bool append = false) { + auto* e = GetMetadataEntry(*metadata, control); + if (e) { + if (append) { + (*e)->count++; + (*e)->data.push_back(base::checked_cast<uint8_t>(value)); + } else { + (*e)->count = 1; + (*e)->data = {base::checked_cast<uint8_t>(value)}; + } + } else { + cros::mojom::CameraMetadataEntryPtr entry = + cros::mojom::CameraMetadataEntry::New(); + entry->index = (*metadata)->entries.value().size(); + entry->tag = control; + entry->type = cros::mojom::EntryType::TYPE_BYTE; + entry->count = 1; + entry->data = {base::checked_cast<uint8_t>(value)}; + + (*metadata)->entries.value().push_back(std::move(entry)); + (*metadata)->entry_count++; + (*metadata)->entry_capacity++; + } + SortCameraMetadata(metadata); + } + + cros::mojom::CameraMetadataPtr CreateDefaultFakeStaticMetadata() { + auto metadata = cros::mojom::CameraMetadata::New(); + metadata->entries = std::vector<cros::mojom::CameraMetadataEntryPtr>(); + metadata->entry_count = 0; + metadata->entry_capacity = 0; + + // Set the available AF modes. + Set3AMode( + &metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF); + Set3AMode( + &metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_AUTO, + /* append */ true); + Set3AMode( + &metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, + cros::mojom::AndroidControlAfMode:: + ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE, + /* append */ true); + Set3AMode( + &metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, + cros::mojom::AndroidControlAfMode:: + ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO, + /* append */ true); + + // Set the available AE modes. + Set3AMode( + &metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_AVAILABLE_MODES, + cros::mojom::AndroidControlAeMode::ANDROID_CONTROL_AE_MODE_OFF); + Set3AMode( + &metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_AVAILABLE_MODES, + cros::mojom::AndroidControlAeMode::ANDROID_CONTROL_AE_MODE_ON, + /* append */ true); + + // Set the available AWB modes. + Set3AMode( + &metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_AVAILABLE_MODES, + cros::mojom::AndroidControlAwbMode::ANDROID_CONTROL_AWB_MODE_OFF); + Set3AMode( + &metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_AVAILABLE_MODES, + cros::mojom::AndroidControlAwbMode::ANDROID_CONTROL_AWB_MODE_AUTO, + /* append */ true); + + return metadata; + } + + void On3AStabilizedCallback(base::WaitableEvent* done) { done->Signal(); } + + protected: + base::Thread thread_; + std::unique_ptr<MockCaptureMetadataDispatcher> + mock_capture_metadata_dispatcher_; + std::unique_ptr<Camera3AController> camera_3a_controller_; + + private: + void RunOnThread(const base::Location& location, + base::OnceClosure closure, + base::WaitableEvent* done) { + DCHECK(thread_.task_runner()->BelongsToCurrentThread()); + + std::move(closure).Run(); + done->Signal(); + } + + void Clear3AControllerOnThread() { + DCHECK(thread_.task_runner()->BelongsToCurrentThread()); + + if (camera_3a_controller_) { + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + RemoveResultMetadataObserver(camera_3a_controller_.get())) + .Times(1); + } + camera_3a_controller_.reset(); + } + + void Reset3AControllerOnThread( + const cros::mojom::CameraMetadataPtr& static_metadata) { + DCHECK(thread_.task_runner()->BelongsToCurrentThread()); + + Clear3AControllerOnThread(); + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + AddResultMetadataObserver(_)) + .Times(1); + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, + cros::mojom::EntryType::TYPE_BYTE, 1, _)) + .Times(1); + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_MODE, + cros::mojom::EntryType::TYPE_BYTE, 1, _)) + .Times(1); + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_MODE, + cros::mojom::EntryType::TYPE_BYTE, 1, _)) + .Times(1); + camera_3a_controller_ = std::make_unique<Camera3AController>( + static_metadata, mock_capture_metadata_dispatcher_.get(), + thread_.task_runner()); + } +}; + +TEST_F(Camera3AControllerTest, Stabilize3AForStillCaptureTest) { + Reset3AController(CreateDefaultFakeStaticMetadata()); + + // Set AF mode. + std::vector<uint8_t> af_trigger_start, af_trigger_cancel, af_mode, ae_trigger; + af_trigger_start = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAfTrigger::ANDROID_CONTROL_AF_TRIGGER_START)}; + af_trigger_cancel = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAfTrigger::ANDROID_CONTROL_AF_TRIGGER_CANCEL)}; + af_mode = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAfMode:: + ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE)}; + ae_trigger = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAePrecaptureTrigger:: + ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START)}; + + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger_cancel)) + .Times(1); + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, + cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) + .Times(1); + RunOnThreadSync( + FROM_HERE, + base::BindOnce(&Camera3AController::SetAutoFocusModeForStillCapture, + base::Unretained(camera_3a_controller_.get()))); + + // |camera_3a_controller_| should wait until the AF mode is set + // before setting the AF and AE precapture triggers. + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger_start)) + .Times(0); + EXPECT_CALL( + *mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, ae_trigger)) + .Times(0); + base::WaitableEvent done(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + RunOnThreadSync( + FROM_HERE, + base::BindOnce( + &Camera3AController::Stabilize3AForStillCapture, + base::Unretained(camera_3a_controller_.get()), + base::BindOnce(&Camera3AControllerTest::On3AStabilizedCallback, + base::Unretained(this), &done))); + testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); + + // |camera_3a_controller_| should set the AF and AE precapture triggers once + // the 3A modes are set. + auto result_metadata = CreateDefaultFakeStaticMetadata(); + Set3AMode(&result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, + cros::mojom::AndroidControlAfMode:: + ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE); + Set3AMode( + &result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_STATE, + cros::mojom::AndroidControlAfState::ANDROID_CONTROL_AF_STATE_INACTIVE); + Set3AMode(&result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_MODE, + cros::mojom::AndroidControlAeMode::ANDROID_CONTROL_AE_MODE_ON); + Set3AMode( + &result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_STATE, + cros::mojom::AndroidControlAeState::ANDROID_CONTROL_AE_STATE_INACTIVE); + Set3AMode(&result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_MODE, + cros::mojom::AndroidControlAwbMode::ANDROID_CONTROL_AWB_MODE_AUTO); + Set3AMode( + &result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_STATE, + cros::mojom::AndroidControlAwbState::ANDROID_CONTROL_AWB_STATE_INACTIVE); + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger_start)) + .Times(1); + EXPECT_CALL( + *mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, ae_trigger)) + .Times(1); + RunOnThreadSync(FROM_HERE, + base::BindOnce(&Camera3AController::OnResultMetadataAvailable, + base::Unretained(camera_3a_controller_.get()), + base::ConstRef(result_metadata))); + + // |camera_3a_controller_| should call the registered callback once 3A are + // stabilized. + Set3AMode(&result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_STATE, + cros::mojom::AndroidControlAfState:: + ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED); + Set3AMode( + &result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_STATE, + cros::mojom::AndroidControlAeState::ANDROID_CONTROL_AE_STATE_CONVERGED); + Set3AMode( + &result_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_STATE, + cros::mojom::AndroidControlAwbState::ANDROID_CONTROL_AWB_STATE_CONVERGED); + RunOnThreadSync(FROM_HERE, + base::BindOnce(&Camera3AController::OnResultMetadataAvailable, + base::Unretained(camera_3a_controller_.get()), + base::ConstRef(result_metadata))); + done.Wait(); +} + +// Test that SetAutoFocusModeForStillCapture sets the right auto-focus mode on +// cameras with different capabilities. +TEST_F(Camera3AControllerTest, SetAutoFocusModeForStillCaptureTest) { + auto static_metadata = CreateDefaultFakeStaticMetadata(); + std::vector<uint8_t> af_mode; + std::vector<uint8_t> af_trigger = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAfTrigger::ANDROID_CONTROL_AF_TRIGGER_CANCEL)}; + + // For camera that supports continuous auto-focus for picture mode. + Reset3AController(static_metadata); + af_mode = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAfMode:: + ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE)}; + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger)) + .Times(1); + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, + cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) + .Times(1); + RunOnThreadSync( + FROM_HERE, + base::BindOnce(&Camera3AController::SetAutoFocusModeForStillCapture, + base::Unretained(camera_3a_controller_.get()))); + testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); + + // For camera that only supports basic auto focus. + Set3AMode(&static_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF); + Set3AMode(&static_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_AUTO, + /* append */ true); + Reset3AController(static_metadata); + af_mode.clear(); + af_mode = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_AUTO)}; + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger)) + .Times(1); + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, + cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) + .Times(1); + RunOnThreadSync( + FROM_HERE, + base::BindOnce(&Camera3AController::SetAutoFocusModeForStillCapture, + base::Unretained(camera_3a_controller_.get()))); + testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); + + // For camera that is fixed-focus. + Set3AMode(&static_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF); + Reset3AController(static_metadata); + af_mode.clear(); + af_mode = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF)}; + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger)) + .Times(1); + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, + cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) + .Times(1); + RunOnThreadSync( + FROM_HERE, + base::BindOnce(&Camera3AController::SetAutoFocusModeForStillCapture, + base::Unretained(camera_3a_controller_.get()))); + testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); +} + +// Test that SetAutoFocusModeForVideoRecording sets the right auto-focus mode on +// cameras with different capabilities. +TEST_F(Camera3AControllerTest, SetAutoFocusModeForVideoRecordingTest) { + auto static_metadata = CreateDefaultFakeStaticMetadata(); + std::vector<uint8_t> af_mode; + std::vector<uint8_t> af_trigger = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAfTrigger::ANDROID_CONTROL_AF_TRIGGER_CANCEL)}; + + // For camera that supports continuous auto-focus for picture mode. + Reset3AController(static_metadata); + af_mode = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAfMode:: + ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO)}; + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger)) + .Times(1); + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, + cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) + .Times(1); + RunOnThreadSync( + FROM_HERE, + base::BindOnce(&Camera3AController::SetAutoFocusModeForVideoRecording, + base::Unretained(camera_3a_controller_.get()))); + testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); + + // For camera that only supports basic auto focus. + Set3AMode(&static_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF); + Set3AMode(&static_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_AUTO, + /* append */ true); + Reset3AController(static_metadata); + af_mode.clear(); + af_mode = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_AUTO)}; + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger)) + .Times(1); + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, + cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) + .Times(1); + RunOnThreadSync( + FROM_HERE, + base::BindOnce(&Camera3AController::SetAutoFocusModeForVideoRecording, + base::Unretained(camera_3a_controller_.get()))); + testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); + + // For camera that is fixed-focus. + Set3AMode(&static_metadata, + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF); + Reset3AController(static_metadata); + af_mode.clear(); + af_mode = {base::checked_cast<uint8_t>( + cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF)}; + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, + cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger)) + .Times(1); + EXPECT_CALL(*mock_capture_metadata_dispatcher_, + SetCaptureMetadata( + cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, + cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) + .Times(1); + RunOnThreadSync( + FROM_HERE, + base::BindOnce(&Camera3AController::SetAutoFocusModeForVideoRecording, + base::Unretained(camera_3a_controller_.get()))); + testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); +} + +} // namespace media
diff --git a/media/capture/video/chromeos/camera_buffer_factory.cc b/media/capture/video/chromeos/camera_buffer_factory.cc index 02df0b66..7cdd186 100644 --- a/media/capture/video/chromeos/camera_buffer_factory.cc +++ b/media/capture/video/chromeos/camera_buffer_factory.cc
@@ -21,9 +21,12 @@ LOG(ERROR) << "GpuMemoryBufferManager not set"; return std::unique_ptr<gfx::GpuMemoryBuffer>(); } - return buf_manager->CreateGpuMemoryBuffer( - size, format, gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE, - gpu::kNullSurfaceHandle); + gfx::BufferUsage buffer_usage = gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE; + if (format == gfx::BufferFormat::R_8) { + buffer_usage = gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE; + } + return buf_manager->CreateGpuMemoryBuffer(size, format, buffer_usage, + gpu::kNullSurfaceHandle); } // There's no good way to resolve the HAL pixel format to the platform-specific
diff --git a/media/capture/video/chromeos/camera_device_context.h b/media/capture/video/chromeos/camera_device_context.h index aaeedc7..a114ffe 100644 --- a/media/capture/video/chromeos/camera_device_context.h +++ b/media/capture/video/chromeos/camera_device_context.h
@@ -56,7 +56,7 @@ // // ConstructDefaultRequestSettings() -> // OnConstructedDefaultRequestSettings() -> - // |stream_buffer_manager_|->StartCapture() + // |stream_buffer_manager_|->StartPreview() // // In the kCapturing state the |stream_buffer_manager_| runs the capture // loop to send capture requests and process capture results.
diff --git a/media/capture/video/chromeos/camera_device_delegate.cc b/media/capture/video/chromeos/camera_device_delegate.cc index b668249..d4bb290f 100644 --- a/media/capture/video/chromeos/camera_device_delegate.cc +++ b/media/capture/video/chromeos/camera_device_delegate.cc
@@ -10,6 +10,9 @@ #include <vector> #include "media/base/bind_to_current_loop.h" +#include "media/capture/mojom/image_capture_types.h" +#include "media/capture/video/blob_utils.h" +#include "media/capture/video/chromeos/camera_3a_controller.h" #include "media/capture/video/chromeos/camera_buffer_factory.h" #include "media/capture/video/chromeos/camera_device_context.h" #include "media/capture/video/chromeos/camera_hal_delegate.h" @@ -20,6 +23,81 @@ namespace media { +namespace { + +void GetMaxBlobStreamResolution( + const cros::mojom::CameraMetadataPtr& static_metadata, + int32_t* max_blob_width, + int32_t* max_blob_height) { + const cros::mojom::CameraMetadataEntryPtr* stream_configurations = + GetMetadataEntry(static_metadata, + cros::mojom::CameraMetadataTag:: + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS); + DCHECK(stream_configurations); + // The available stream configurations are stored as tuples of four int32s: + // (hal_pixel_format, width, height, type) x n + const size_t kStreamFormatOffset = 0; + const size_t kStreamWidthOffset = 1; + const size_t kStreamHeightOffset = 2; + const size_t kStreamTypeOffset = 3; + const size_t kStreamConfigurationSize = 4; + int32_t* iter = + reinterpret_cast<int32_t*>((*stream_configurations)->data.data()); + *max_blob_width = 0; + *max_blob_height = 0; + for (size_t i = 0; i < (*stream_configurations)->count; + i += kStreamConfigurationSize) { + auto format = + static_cast<cros::mojom::HalPixelFormat>(iter[kStreamFormatOffset]); + int32_t width = iter[kStreamWidthOffset]; + int32_t height = iter[kStreamHeightOffset]; + auto type = + static_cast<cros::mojom::Camera3StreamType>(iter[kStreamTypeOffset]); + iter += kStreamConfigurationSize; + + if (type != cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT || + format != cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_BLOB) { + continue; + } + if (width > *max_blob_width && height > *max_blob_height) { + *max_blob_width = width; + *max_blob_height = height; + } + } + DCHECK_GT(*max_blob_width, 0); + DCHECK_GT(*max_blob_height, 0); +} + +// VideoCaptureDevice::TakePhotoCallback is given by the application and is used +// to return the captured JPEG blob buffer. The second base::OnceClosure is +// created locally by the caller of TakePhoto(), and can be used to, for +// exmaple, restore some settings to the values before TakePhoto() is called to +// facilitate the switch between photo and non-photo modes. +void TakePhotoCallbackBundle(VideoCaptureDevice::TakePhotoCallback callback, + base::OnceClosure on_photo_taken_callback, + mojom::BlobPtr blob) { + std::move(callback).Run(std::move(blob)); + std::move(on_photo_taken_callback).Run(); +} + +} // namespace + +std::string StreamTypeToString(StreamType stream_type) { + switch (stream_type) { + case StreamType::kPreview: + return std::string("StreamType::kPreview"); + case StreamType::kStillCapture: + return std::string("StreamType::kStillCapture"); + default: + return std::string("Unknown StreamType value: ") + + std::to_string(static_cast<int32_t>(stream_type)); + } +} // namespace media + +std::ostream& operator<<(std::ostream& os, StreamType stream_type) { + return os << StreamTypeToString(stream_type); +} + StreamCaptureInterface::Plane::Plane() = default; StreamCaptureInterface::Plane::~Plane() = default; @@ -110,7 +188,7 @@ // The device delegate is in the process of opening the camera device. return; } - stream_buffer_manager_->StopCapture(); + stream_buffer_manager_->StopPreview(); device_ops_->Close( base::BindOnce(&CameraDeviceDelegate::OnClosed, GetWeakPtr())); } @@ -118,23 +196,57 @@ void CameraDeviceDelegate::TakePhoto( VideoCaptureDevice::TakePhotoCallback callback) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - // TODO(jcliang): Implement TakePhoto. - NOTIMPLEMENTED() << "TakePhoto is not implemented"; + + take_photo_callbacks_.push(std::move(callback)); + + if (!device_context_ || + (device_context_->GetState() != + CameraDeviceContext::State::kStreamConfigured && + device_context_->GetState() != CameraDeviceContext::State::kCapturing)) { + return; + } + + camera_3a_controller_->Stabilize3AForStillCapture( + base::BindOnce(&CameraDeviceDelegate::ConstructDefaultRequestSettings, + GetWeakPtr(), StreamType::kStillCapture)); } void CameraDeviceDelegate::GetPhotoState( VideoCaptureDevice::GetPhotoStateCallback callback) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - // TODO(jcliang): Implement GetPhotoState. - NOTIMPLEMENTED() << "GetPhotoState is not implemented"; + + auto photo_state = mojo::CreateEmptyPhotoState(); + + if (!device_context_ || + (device_context_->GetState() != + CameraDeviceContext::State::kStreamConfigured && + device_context_->GetState() != CameraDeviceContext::State::kCapturing)) { + std::move(callback).Run(std::move(photo_state)); + return; + } + + auto stream_config = + stream_buffer_manager_->GetStreamConfiguration(StreamType::kStillCapture); + if (stream_config) { + photo_state->width->current = stream_config->width; + photo_state->width->min = stream_config->width; + photo_state->width->max = stream_config->width; + photo_state->width->step = 0.0; + photo_state->height->current = stream_config->height; + photo_state->height->min = stream_config->height; + photo_state->height->max = stream_config->height; + photo_state->height->step = 0.0; + } + std::move(callback).Run(std::move(photo_state)); } void CameraDeviceDelegate::SetPhotoOptions( mojom::PhotoSettingsPtr settings, VideoCaptureDevice::SetPhotoOptionsCallback callback) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - // TODO(jcliang): Implement SetPhotoOptions. - NOTIMPLEMENTED() << "SetPhotoOptions is not implemented"; + + // Not supported at the moment. + std::move(callback).Run(true); } void CameraDeviceDelegate::SetRotation(int rotation) { @@ -158,7 +270,7 @@ } else { // The Mojo channel terminated unexpectedly. if (stream_buffer_manager_) { - stream_buffer_manager_->StopCapture(); + stream_buffer_manager_->StopPreview(); } device_context_->SetState(CameraDeviceContext::State::kStopped); device_context_->SetErrorState(FROM_HERE, "Mojo connection error"); @@ -187,6 +299,7 @@ DCHECK(ipc_task_runner_->BelongsToCurrentThread()); device_ops_.reset(); + camera_3a_controller_.reset(); stream_buffer_manager_.reset(); } @@ -206,6 +319,7 @@ device_context_->SetErrorState(FROM_HERE, "Failed to get camera info"); return; } + SortCameraMetadata(&camera_info->static_camera_characteristics); static_metadata_ = std::move(camera_info->static_camera_characteristics); const cros::mojom::CameraMetadataEntryPtr* sensor_orientation = @@ -265,7 +379,9 @@ std::move(callback_ops_request), std::make_unique<StreamCaptureInterfaceImpl>(GetWeakPtr()), device_context_, std::make_unique<CameraBufferFactory>(), - ipc_task_runner_); + base::BindRepeating(&Blobify), ipc_task_runner_); + camera_3a_controller_ = std::make_unique<Camera3AController>( + static_metadata_, stream_buffer_manager_.get(), ipc_task_runner_); device_ops_->Initialize( std::move(callback_ops_ptr), base::BindOnce(&CameraDeviceDelegate::OnInitialized, GetWeakPtr())); @@ -297,8 +413,7 @@ // Set up context for preview stream. cros::mojom::Camera3StreamPtr preview_stream = cros::mojom::Camera3Stream::New(); - preview_stream->id = static_cast<uint64_t>( - cros::mojom::Camera3RequestTemplate::CAMERA3_TEMPLATE_PREVIEW); + preview_stream->id = static_cast<uint64_t>(StreamType::kPreview); preview_stream->stream_type = cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT; preview_stream->width = @@ -311,9 +426,31 @@ preview_stream->rotation = cros::mojom::Camera3StreamRotation::CAMERA3_STREAM_ROTATION_0; + // Set up context for still capture stream. We set still capture stream to the + // JPEG stream configuration with maximum supported resolution. + // TODO(jcliang): Once we support SetPhotoOptions() the still capture stream + // should be configured dynamically per the photo options. + int32_t max_blob_width = 0, max_blob_height = 0; + GetMaxBlobStreamResolution(static_metadata_, &max_blob_width, + &max_blob_height); + + cros::mojom::Camera3StreamPtr still_capture_stream = + cros::mojom::Camera3Stream::New(); + still_capture_stream->id = static_cast<uint64_t>(StreamType::kStillCapture); + still_capture_stream->stream_type = + cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT; + still_capture_stream->width = max_blob_width; + still_capture_stream->height = max_blob_height; + still_capture_stream->format = + cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_BLOB; + still_capture_stream->data_space = 0; + still_capture_stream->rotation = + cros::mojom::Camera3StreamRotation::CAMERA3_STREAM_ROTATION_0; + cros::mojom::Camera3StreamConfigurationPtr stream_config = cros::mojom::Camera3StreamConfiguration::New(); stream_config->streams.push_back(std::move(preview_stream)); + stream_config->streams.push_back(std::move(still_capture_stream)); stream_config->operation_mode = cros::mojom::Camera3StreamConfigurationMode:: CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE; device_ops_->ConfigureStreams( @@ -337,43 +474,46 @@ std::string(strerror(result))); return; } - if (!updated_config || updated_config->streams.size() != 1) { + if (!updated_config || + updated_config->streams.size() != kMaxConfiguredStreams) { device_context_->SetErrorState( FROM_HERE, std::string("Wrong number of streams configured: ") + std::to_string(updated_config->streams.size())); return; } - // The partial result count metadata is optional; defaults to 1 in case it - // is not set in the static metadata. - uint32_t partial_result_count = 1; - const cros::mojom::CameraMetadataEntryPtr* partial_count = GetMetadataEntry( - static_metadata_, - cros::mojom::CameraMetadataTag::ANDROID_REQUEST_PARTIAL_RESULT_COUNT); - if (partial_count) { - partial_result_count = - *reinterpret_cast<int32_t*>((*partial_count)->data.data()); - } - stream_buffer_manager_->SetUpStreamAndBuffers( - chrome_capture_params_.requested_format, partial_result_count, - std::move(updated_config->streams[0])); + stream_buffer_manager_->SetUpStreamsAndBuffers( + chrome_capture_params_.requested_format, static_metadata_, + std::move(updated_config->streams)); device_context_->SetState(CameraDeviceContext::State::kStreamConfigured); - ConstructDefaultRequestSettings(); + // Kick off the preview stream. + ConstructDefaultRequestSettings(StreamType::kPreview); } -void CameraDeviceDelegate::ConstructDefaultRequestSettings() { +void CameraDeviceDelegate::ConstructDefaultRequestSettings( + StreamType stream_type) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - DCHECK_EQ(device_context_->GetState(), - CameraDeviceContext::State::kStreamConfigured); + DCHECK(device_context_->GetState() == + CameraDeviceContext::State::kStreamConfigured || + device_context_->GetState() == CameraDeviceContext::State::kCapturing); - device_ops_->ConstructDefaultRequestSettings( - cros::mojom::Camera3RequestTemplate::CAMERA3_TEMPLATE_PREVIEW, - base::BindOnce(&CameraDeviceDelegate::OnConstructedDefaultRequestSettings, - GetWeakPtr())); + if (stream_type == StreamType::kPreview) { + device_ops_->ConstructDefaultRequestSettings( + cros::mojom::Camera3RequestTemplate::CAMERA3_TEMPLATE_PREVIEW, + base::BindOnce( + &CameraDeviceDelegate::OnConstructedDefaultPreviewRequestSettings, + GetWeakPtr())); + } else { // stream_type == StreamType::kStillCapture + device_ops_->ConstructDefaultRequestSettings( + cros::mojom::Camera3RequestTemplate::CAMERA3_TEMPLATE_STILL_CAPTURE, + base::BindOnce(&CameraDeviceDelegate:: + OnConstructedDefaultStillCaptureRequestSettings, + GetWeakPtr())); + } } -void CameraDeviceDelegate::OnConstructedDefaultRequestSettings( +void CameraDeviceDelegate::OnConstructedDefaultPreviewRequestSettings( cros::mojom::CameraMetadataPtr settings) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); @@ -389,7 +529,29 @@ return; } device_context_->SetState(CameraDeviceContext::State::kCapturing); - stream_buffer_manager_->StartCapture(std::move(settings)); + camera_3a_controller_->SetAutoFocusModeForStillCapture(); + stream_buffer_manager_->StartPreview(std::move(settings)); + + if (!take_photo_callbacks_.empty()) { + camera_3a_controller_->Stabilize3AForStillCapture( + base::BindOnce(&CameraDeviceDelegate::ConstructDefaultRequestSettings, + GetWeakPtr(), StreamType::kStillCapture)); + } +} + +void CameraDeviceDelegate::OnConstructedDefaultStillCaptureRequestSettings( + cros::mojom::CameraMetadataPtr settings) { + DCHECK(ipc_task_runner_->BelongsToCurrentThread()); + + while (!take_photo_callbacks_.empty()) { + stream_buffer_manager_->TakePhoto( + std::move(settings), + base::BindOnce( + &TakePhotoCallbackBundle, std::move(take_photo_callbacks_.front()), + base::BindOnce(&Camera3AController::SetAutoFocusModeForStillCapture, + camera_3a_controller_->GetWeakPtr()))); + take_photo_callbacks_.pop(); + } } void CameraDeviceDelegate::RegisterBuffer(
diff --git a/media/capture/video/chromeos/camera_device_delegate.h b/media/capture/video/chromeos/camera_device_delegate.h index 8d268013..2b297b6 100644 --- a/media/capture/video/chromeos/camera_device_delegate.h +++ b/media/capture/video/chromeos/camera_device_delegate.h
@@ -17,10 +17,21 @@ namespace media { -class CameraHalDelegate; +class Camera3AController; class CameraDeviceContext; +class CameraHalDelegate; class StreamBufferManager; +enum class StreamType : int32_t { + kPreview = 0, + kStillCapture = 1, + kUnknown, +}; + +std::string StreamTypeToString(StreamType stream_type); + +std::ostream& operator<<(std::ostream& os, StreamType stream_type); + // The interface to register buffer with and send capture request to the // camera HAL. class CAPTURE_EXPORT StreamCaptureInterface { @@ -122,10 +133,14 @@ // settings of the stream in |stream_context_|. // OnConstructedDefaultRequestSettings sets the request settings in // |streams_context_|. If there's no error - // OnConstructedDefaultRequestSettings calls StartCapture to start the video - // capture loop. - void ConstructDefaultRequestSettings(); - void OnConstructedDefaultRequestSettings( + // OnConstructedDefaultPreviewRequestSettings calls StartPreview to start the + // video capture loop. + // OnConstructDefaultStillCaptureRequestSettings triggers + // |stream_buffer_manager_| to request a still capture. + void ConstructDefaultRequestSettings(StreamType stream_type); + void OnConstructedDefaultPreviewRequestSettings( + cros::mojom::CameraMetadataPtr settings); + void OnConstructedDefaultStillCaptureRequestSettings( cros::mojom::CameraMetadataPtr settings); // StreamCaptureInterface implementations. These methods are called by @@ -151,8 +166,12 @@ CameraDeviceContext* device_context_; + std::queue<VideoCaptureDevice::TakePhotoCallback> take_photo_callbacks_; + std::unique_ptr<StreamBufferManager> stream_buffer_manager_; + std::unique_ptr<Camera3AController> camera_3a_controller_; + // Stores the static camera characteristics of the camera device. E.g. the // supported formats and resolution, various available exposure and apeture // settings, etc.
diff --git a/media/capture/video/chromeos/camera_device_delegate_unittest.cc b/media/capture/video/chromeos/camera_device_delegate_unittest.cc index d29c322..aa0f3c91 100644 --- a/media/capture/video/chromeos/camera_device_delegate_unittest.cc +++ b/media/capture/video/chromeos/camera_device_delegate_unittest.cc
@@ -110,8 +110,11 @@ DISALLOW_COPY_AND_ASSIGN(MockCameraDevice); }; +constexpr int32_t kJpegMaxBufferSize = 1024; +constexpr size_t kDefaultWidth = 1280, kDefaultHeight = 720; const VideoCaptureDeviceDescriptor kDefaultDescriptor("Fake device", "0"); -const VideoCaptureFormat kDefaultCaptureFormat(gfx::Size(1280, 720), +const VideoCaptureFormat kDefaultCaptureFormat(gfx::Size(kDefaultWidth, + kDefaultHeight), 30.0, PIXEL_FORMAT_I420); @@ -153,16 +156,60 @@ cros::mojom::CameraInfoPtr camera_info = cros::mojom::CameraInfo::New(); cros::mojom::CameraMetadataPtr static_metadata = cros::mojom::CameraMetadata::New(); + + static_metadata->entry_count = 3; + static_metadata->entry_capacity = 3; + static_metadata->entries = + std::vector<cros::mojom::CameraMetadataEntryPtr>(); + cros::mojom::CameraMetadataEntryPtr entry = cros::mojom::CameraMetadataEntry::New(); entry->index = 0; + entry->tag = cros::mojom::CameraMetadataTag:: + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS; + entry->type = cros::mojom::EntryType::TYPE_INT32; + entry->count = 12; + std::vector<int32_t> stream_configurations(entry->count); + stream_configurations[0] = static_cast<int32_t>( + cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED); + stream_configurations[1] = kDefaultWidth; + stream_configurations[2] = kDefaultHeight; + stream_configurations[3] = static_cast<int32_t>( + cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT); + stream_configurations[4] = static_cast<int32_t>( + cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_YCbCr_420_888); + stream_configurations[5] = kDefaultWidth; + stream_configurations[6] = kDefaultHeight; + stream_configurations[7] = static_cast<int32_t>( + cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT); + stream_configurations[8] = static_cast<int32_t>( + cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_BLOB); + stream_configurations[9] = kDefaultWidth; + stream_configurations[10] = kDefaultHeight; + stream_configurations[11] = static_cast<int32_t>( + cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT); + uint8_t* as_int8 = reinterpret_cast<uint8_t*>(stream_configurations.data()); + entry->data.assign(as_int8, as_int8 + entry->count * sizeof(int32_t)); + static_metadata->entries->push_back(std::move(entry)); + + entry = cros::mojom::CameraMetadataEntry::New(); + entry->index = 1; entry->tag = cros::mojom::CameraMetadataTag::ANDROID_SENSOR_ORIENTATION; entry->type = cros::mojom::EntryType::TYPE_INT32; entry->count = 1; entry->data = std::vector<uint8_t>(4, 0); - static_metadata->entries = - std::vector<cros::mojom::CameraMetadataEntryPtr>(); static_metadata->entries->push_back(std::move(entry)); + + entry = cros::mojom::CameraMetadataEntry::New(); + entry->index = 2; + entry->tag = cros::mojom::CameraMetadataTag::ANDROID_JPEG_MAX_SIZE; + entry->type = cros::mojom::EntryType::TYPE_INT32; + entry->count = 1; + int32_t jpeg_max_size = kJpegMaxBufferSize; + as_int8 = reinterpret_cast<uint8_t*>(&jpeg_max_size); + entry->data.assign(as_int8, as_int8 + entry->count * sizeof(int32_t)); + static_metadata->entries->push_back(std::move(entry)); + switch (camera_id) { case 0: camera_info->facing = cros::mojom::CameraFacing::CAMERA_FACING_FRONT; @@ -195,23 +242,17 @@ base::OnceCallback<void(int32_t, cros::mojom::Camera3StreamConfigurationPtr)>& callback) { - ASSERT_EQ(1u, config->streams.size()); - ASSERT_EQ(static_cast<uint32_t>(kDefaultCaptureFormat.frame_size.width()), - config->streams[0]->width); - ASSERT_EQ(static_cast<uint32_t>(kDefaultCaptureFormat.frame_size.height()), - config->streams[0]->height); - ASSERT_EQ(cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_YCbCr_420_888, - config->streams[0]->format); - config->streams[0]->usage = 0; - config->streams[0]->max_buffers = 1; + ASSERT_EQ(2u, config->streams.size()); + for (size_t i = 0; i < config->streams.size(); ++i) { + config->streams[i]->usage = 0; + config->streams[i]->max_buffers = 1; + } std::move(callback).Run(0, std::move(config)); } void ConstructFakeRequestSettings( cros::mojom::Camera3RequestTemplate type, base::OnceCallback<void(cros::mojom::CameraMetadataPtr)>& callback) { - ASSERT_EQ(cros::mojom::Camera3RequestTemplate::CAMERA3_TEMPLATE_PREVIEW, - type); cros::mojom::CameraMetadataPtr fake_settings = cros::mojom::CameraMetadata::New(); fake_settings->entry_count = 1; @@ -291,10 +332,27 @@ .Times(1) .WillOnce(Invoke(&unittest_internal::MockGpuMemoryBufferManager:: CreateFakeGpuMemoryBuffer)); + EXPECT_CALL( + mock_gpu_memory_buffer_manager_, + CreateGpuMemoryBuffer(_, gfx::BufferFormat::R_8, + gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE, + gpu::kNullSurfaceHandle)) + .Times(1) + .WillOnce(Invoke(&unittest_internal::MockGpuMemoryBufferManager:: + CreateFakeGpuMemoryBuffer)); + EXPECT_CALL( + mock_gpu_memory_buffer_manager_, + CreateGpuMemoryBuffer(gfx::Size(kDefaultWidth, kDefaultHeight), + gfx::BufferFormat::YUV_420_BIPLANAR, + gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE, + gpu::kNullSurfaceHandle)) + .Times(1) + .WillOnce(Invoke(&unittest_internal::MockGpuMemoryBufferManager:: + CreateFakeGpuMemoryBuffer)); EXPECT_CALL(mock_gpu_memory_buffer_manager_, CreateGpuMemoryBuffer( - gfx::Size(1280, 720), gfx::BufferFormat::YUV_420_BIPLANAR, - gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE, + gfx::Size(kJpegMaxBufferSize, 1), gfx::BufferFormat::R_8, + gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE, gpu::kNullSurfaceHandle)) .Times(1) .WillOnce(Invoke(&unittest_internal::MockGpuMemoryBufferManager::
diff --git a/media/capture/video/chromeos/camera_hal_delegate.cc b/media/capture/video/chromeos/camera_hal_delegate.cc index 33a145f..3a33d9b 100644 --- a/media/capture/video/chromeos/camera_hal_delegate.cc +++ b/media/capture/video/chromeos/camera_hal_delegate.cc
@@ -130,21 +130,25 @@ reinterpret_cast<int64_t*>((*min_frame_durations)->data.data()); for (size_t i = 0; i < (*min_frame_durations)->count; i += kStreamDurationSize) { - int32_t format = base::checked_cast<int32_t>(iter[kStreamFormatOffset]); + auto hal_format = + static_cast<cros::mojom::HalPixelFormat>(iter[kStreamFormatOffset]); int32_t width = base::checked_cast<int32_t>(iter[kStreamWidthOffset]); int32_t height = base::checked_cast<int32_t>(iter[kStreamHeightOffset]); int64_t duration = iter[kStreamDurationOffset]; iter += kStreamDurationSize; + if (hal_format == cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_BLOB) { + // Skip BLOB formats and use it only for TakePicture() since it's + // inefficient to stream JPEG frames for CrOS camera HAL. + continue; + } + if (duration <= 0) { LOG(ERROR) << "Ignoring invalid frame duration: " << duration; continue; } float max_fps = 1.0 * 1000000000LL / duration; - DVLOG(1) << "[" << std::hex << format << " " << std::dec << width << " " - << height << " " << duration << "]"; - auto hal_format = static_cast<cros::mojom::HalPixelFormat>(format); const ChromiumPixelFormat cr_format = camera_buffer_factory_->ResolveStreamBufferFormat(hal_format); if (cr_format.video_format == PIXEL_FORMAT_UNKNOWN) { @@ -327,6 +331,7 @@ LOG(ERROR) << "Failed to get camera info. Camera id: " << camera_id; } // In case of error |camera_info| is empty. + SortCameraMetadata(&camera_info->static_camera_characteristics); camera_info_[std::to_string(camera_id)] = std::move(camera_info); if (camera_info_.size() == num_builtin_cameras_) { builtin_camera_info_updated_.Signal();
diff --git a/media/capture/video/chromeos/camera_metadata_utils.cc b/media/capture/video/chromeos/camera_metadata_utils.cc index 8f3d3a4..c168f87b 100644 --- a/media/capture/video/chromeos/camera_metadata_utils.cc +++ b/media/capture/video/chromeos/camera_metadata_utils.cc
@@ -4,22 +4,43 @@ #include "media/capture/video/chromeos/camera_metadata_utils.h" -#include <set> +#include <algorithm> +#include <unordered_set> namespace media { -const cros::mojom::CameraMetadataEntryPtr* GetMetadataEntry( +cros::mojom::CameraMetadataEntryPtr* GetMetadataEntry( const cros::mojom::CameraMetadataPtr& camera_metadata, cros::mojom::CameraMetadataTag tag) { - if (!camera_metadata->entries.has_value()) { + if (!camera_metadata || !camera_metadata->entries.has_value()) { return nullptr; } - for (const auto& entry : camera_metadata->entries.value()) { - if (entry->tag == tag) { - return &entry; - } + // We assume the metadata entries are sorted. + auto iter = std::find_if(camera_metadata->entries.value().begin(), + camera_metadata->entries.value().end(), + [tag](const cros::mojom::CameraMetadataEntryPtr& e) { + return e->tag == tag; + }); + if (iter == camera_metadata->entries.value().end()) { + return nullptr; } - return nullptr; + return &(camera_metadata->entries.value()[(*iter)->index]); +} + +void SortCameraMetadata(cros::mojom::CameraMetadataPtr* camera_metadata) { + if (!camera_metadata || !(*camera_metadata) || + !(*camera_metadata)->entries.has_value()) { + return; + } + std::sort((*camera_metadata)->entries.value().begin(), + (*camera_metadata)->entries.value().end(), + [](const cros::mojom::CameraMetadataEntryPtr& a, + const cros::mojom::CameraMetadataEntryPtr& b) { + return a->tag < b->tag; + }); + for (size_t i = 0; i < (*camera_metadata)->entries.value().size(); ++i) { + (*camera_metadata)->entries.value()[i]->index = i; + } } void MergeMetadata(cros::mojom::CameraMetadataPtr* to, @@ -34,7 +55,7 @@ return; } - std::set<cros::mojom::CameraMetadataTag> tags; + std::unordered_set<cros::mojom::CameraMetadataTag> tags; if ((*to)->entries) { for (const auto& entry : (*to)->entries.value()) { tags.insert(entry->tag);
diff --git a/media/capture/video/chromeos/camera_metadata_utils.h b/media/capture/video/chromeos/camera_metadata_utils.h index 8dbb1084..172bcd0 100644 --- a/media/capture/video/chromeos/camera_metadata_utils.h +++ b/media/capture/video/chromeos/camera_metadata_utils.h
@@ -5,16 +5,21 @@ #ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_METADATA_UTILS_H_ #define MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_METADATA_UTILS_H_ +#include "media/capture/capture_export.h" #include "media/capture/video/chromeos/mojo/camera_metadata.mojom.h" namespace media { -const cros::mojom::CameraMetadataEntryPtr* GetMetadataEntry( +CAPTURE_EXPORT cros::mojom::CameraMetadataEntryPtr* GetMetadataEntry( const cros::mojom::CameraMetadataPtr& camera_metadata, cros::mojom::CameraMetadataTag tag); -void MergeMetadata(cros::mojom::CameraMetadataPtr* to, - const cros::mojom::CameraMetadataPtr& from); +// Sort the camera metadata entries using the metadata tags. +CAPTURE_EXPORT void SortCameraMetadata( + cros::mojom::CameraMetadataPtr* camera_metadata); + +CAPTURE_EXPORT void MergeMetadata(cros::mojom::CameraMetadataPtr* to, + const cros::mojom::CameraMetadataPtr& from); } // namespace media
diff --git a/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc b/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc index 2396d59..020ca13 100644 --- a/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc +++ b/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc
@@ -51,6 +51,8 @@ uint32_t GetDrmFormat(gfx::BufferFormat gfx_format) { switch (gfx_format) { + case gfx::BufferFormat::R_8: + return DRM_FORMAT_R8; case gfx::BufferFormat::YUV_420_BIPLANAR: return DRM_FORMAT_NV12; // Add more formats when needed. @@ -186,7 +188,8 @@ gfx::BufferFormat format, gfx::BufferUsage usage, gpu::SurfaceHandle surface_handle) { - if (usage != gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE) { + if (usage != gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE && + usage != gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE) { LOG(ERROR) << "Unsupported gfx::BufferUsage" << static_cast<int>(usage); return std::unique_ptr<gfx::GpuMemoryBuffer>(); }
diff --git a/media/capture/video/chromeos/pixel_format_utils.cc b/media/capture/video/chromeos/pixel_format_utils.cc index 9e1449a..6f9d4e3 100644 --- a/media/capture/video/chromeos/pixel_format_utils.cc +++ b/media/capture/video/chromeos/pixel_format_utils.cc
@@ -31,6 +31,9 @@ // support YUV flexbile format video streams. {cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_YCbCr_420_888, {PIXEL_FORMAT_NV12, gfx::BufferFormat::YUV_420_BIPLANAR}}, + // FIXME(jcliang): MJPEG is not accurate; we should have BLOB or JPEG + {cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_BLOB, + {PIXEL_FORMAT_MJPEG, gfx::BufferFormat::R_8}}, // Add more mappings when we have more devices. }; @@ -51,6 +54,8 @@ switch (from) { case PIXEL_FORMAT_NV12: return DRM_FORMAT_NV12; + case PIXEL_FORMAT_MJPEG: + return DRM_FORMAT_R8; default: // Unsupported format. return 0;
diff --git a/media/capture/video/chromeos/stream_buffer_manager.cc b/media/capture/video/chromeos/stream_buffer_manager.cc index df8f42bd..3fc9457 100644 --- a/media/capture/video/chromeos/stream_buffer_manager.cc +++ b/media/capture/video/chromeos/stream_buffer_manager.cc
@@ -15,16 +15,40 @@ namespace media { +namespace { + +size_t GetBufferIndex(uint64_t buffer_id) { + return buffer_id & 0xFFFFFFFF; +} + +StreamType StreamIdToStreamType(uint64_t stream_id) { + switch (stream_id) { + case 0: + return StreamType::kPreview; + case 1: + return StreamType::kStillCapture; + default: + return StreamType::kUnknown; + } +} + +} // namespace + StreamBufferManager::StreamBufferManager( cros::mojom::Camera3CallbackOpsRequest callback_ops_request, std::unique_ptr<StreamCaptureInterface> capture_interface, CameraDeviceContext* device_context, std::unique_ptr<CameraBufferFactory> camera_buffer_factory, + base::RepeatingCallback<mojom::BlobPtr( + const uint8_t* buffer, + const uint32_t bytesused, + const VideoCaptureFormat& capture_format)> blobify_callback, scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner) : callback_ops_(this, std::move(callback_ops_request)), capture_interface_(std::move(capture_interface)), device_context_(device_context), camera_buffer_factory_(std::move(camera_buffer_factory)), + blobify_callback_(std::move(blobify_callback)), ipc_task_runner_(std::move(ipc_task_runner)), capturing_(false), frame_number_(0), @@ -38,107 +62,235 @@ StreamBufferManager::~StreamBufferManager() { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - if (stream_context_) { - for (const auto& buf : stream_context_->buffers) { - if (buf) { - buf->Unmap(); + for (const auto& iter : stream_context_) { + if (iter.second) { + for (const auto& buf : iter.second->buffers) { + if (buf) { + buf->Unmap(); + } } } } } -void StreamBufferManager::SetUpStreamAndBuffers( +void StreamBufferManager::SetUpStreamsAndBuffers( VideoCaptureFormat capture_format, - uint32_t partial_result_count, - cros::mojom::Camera3StreamPtr stream) { + const cros::mojom::CameraMetadataPtr& static_metadata, + std::vector<cros::mojom::Camera3StreamPtr> streams) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - DCHECK(!stream_context_); + DCHECK(!stream_context_[StreamType::kPreview]); - VLOG(2) << "Stream " << stream->id << " configured: usage=" << stream->usage - << " max_buffers=" << stream->max_buffers; - - const size_t kMaximumAllowedBuffers = 15; - if (stream->max_buffers > kMaximumAllowedBuffers) { - device_context_->SetErrorState( - FROM_HERE, std::string("Camera HAL requested ") + - std::to_string(stream->max_buffers) + - std::string(" buffers which exceeds the allowed maximum " - "number of buffers")); - return; + // The partial result count metadata is optional; defaults to 1 in case it + // is not set in the static metadata. + const cros::mojom::CameraMetadataEntryPtr* partial_count = GetMetadataEntry( + static_metadata, + cros::mojom::CameraMetadataTag::ANDROID_REQUEST_PARTIAL_RESULT_COUNT); + if (partial_count) { + partial_result_count_ = + *reinterpret_cast<int32_t*>((*partial_count)->data.data()); } - partial_result_count_ = partial_result_count; - stream_context_ = std::make_unique<StreamContext>(); - stream_context_->capture_format = capture_format; - stream_context_->stream = std::move(stream); + for (auto& stream : streams) { + DVLOG(2) << "Stream " << stream->id + << " configured: usage=" << stream->usage + << " max_buffers=" << stream->max_buffers; - const ChromiumPixelFormat stream_format = - camera_buffer_factory_->ResolveStreamBufferFormat( - stream_context_->stream->format); - stream_context_->capture_format.pixel_format = stream_format.video_format; - - // Allocate buffers. - size_t num_buffers = stream_context_->stream->max_buffers; - stream_context_->buffers.resize(num_buffers); - for (size_t j = 0; j < num_buffers; ++j) { - auto buffer = camera_buffer_factory_->CreateGpuMemoryBuffer( - gfx::Size(stream_context_->stream->width, - stream_context_->stream->height), - stream_format.gfx_format); - if (!buffer) { - device_context_->SetErrorState(FROM_HERE, - "Failed to create GpuMemoryBuffer"); + const size_t kMaximumAllowedBuffers = 15; + if (stream->max_buffers > kMaximumAllowedBuffers) { + device_context_->SetErrorState( + FROM_HERE, + std::string("Camera HAL requested ") + + std::to_string(stream->max_buffers) + + std::string(" buffers which exceeds the allowed maximum " + "number of buffers")); return; } - bool ret = buffer->Map(); - if (!ret) { - device_context_->SetErrorState(FROM_HERE, - "Failed to map GpuMemoryBuffer"); - return; + + // A better way to tell the stream type here would be to check on the usage + // flags of the stream. + StreamType stream_type; + if (stream->format == + cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_YCbCr_420_888) { + stream_type = StreamType::kPreview; + } else { // stream->format == + // cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_BLOB + stream_type = StreamType::kStillCapture; } - stream_context_->buffers[j] = std::move(buffer); - stream_context_->free_buffers.push(j); + stream_context_[stream_type] = std::make_unique<StreamContext>(); + stream_context_[stream_type]->capture_format = capture_format; + stream_context_[stream_type]->stream = std::move(stream); + + const ChromiumPixelFormat stream_format = + camera_buffer_factory_->ResolveStreamBufferFormat( + stream_context_[stream_type]->stream->format); + stream_context_[stream_type]->capture_format.pixel_format = + stream_format.video_format; + + // Allocate buffers. + size_t num_buffers = stream_context_[stream_type]->stream->max_buffers; + stream_context_[stream_type]->buffers.resize(num_buffers); + int32_t buffer_width, buffer_height; + if (stream_type == StreamType::kPreview) { + buffer_width = stream_context_[stream_type]->stream->width; + buffer_height = stream_context_[stream_type]->stream->height; + } else { // StreamType::kStillCapture + const cros::mojom::CameraMetadataEntryPtr* jpeg_max_size = + GetMetadataEntry( + static_metadata, + cros::mojom::CameraMetadataTag::ANDROID_JPEG_MAX_SIZE); + buffer_width = *reinterpret_cast<int32_t*>((*jpeg_max_size)->data.data()); + buffer_height = 1; + } + for (size_t j = 0; j < num_buffers; ++j) { + auto buffer = camera_buffer_factory_->CreateGpuMemoryBuffer( + gfx::Size(buffer_width, buffer_height), stream_format.gfx_format); + if (!buffer) { + device_context_->SetErrorState(FROM_HERE, + "Failed to create GpuMemoryBuffer"); + return; + } + bool ret = buffer->Map(); + if (!ret) { + device_context_->SetErrorState(FROM_HERE, + "Failed to map GpuMemoryBuffer"); + return; + } + stream_context_[stream_type]->buffers[j] = std::move(buffer); + stream_context_[stream_type]->free_buffers.push( + GetBufferIpcId(stream_type, j)); + } + DVLOG(2) << "Allocated " + << stream_context_[stream_type]->stream->max_buffers << " buffers"; } - VLOG(2) << "Allocated " << stream_context_->stream->max_buffers << " buffers"; } -void StreamBufferManager::StartCapture( - cros::mojom::CameraMetadataPtr settings) { +void StreamBufferManager::StartPreview( + cros::mojom::CameraMetadataPtr preview_settings) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - DCHECK(stream_context_); - DCHECK(stream_context_->request_settings.is_null()); + DCHECK(stream_context_[StreamType::kPreview]); + DCHECK(repeating_request_settings_.is_null()); capturing_ = true; - stream_context_->request_settings = std::move(settings); + repeating_request_settings_ = std::move(preview_settings); // We cannot use a loop to register all the free buffers in one shot here // because the camera HAL v3 API specifies that the client cannot call // ProcessCaptureRequest before the previous one returns. - RegisterBuffer(); + RegisterBuffer(StreamType::kPreview); } -void StreamBufferManager::StopCapture() { +void StreamBufferManager::StopPreview() { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); capturing_ = false; } -void StreamBufferManager::RegisterBuffer() { +cros::mojom::Camera3StreamPtr StreamBufferManager::GetStreamConfiguration( + StreamType stream_type) { + if (!stream_context_.count(stream_type)) { + return cros::mojom::Camera3Stream::New(); + } + return stream_context_[stream_type]->stream.Clone(); +} + +void StreamBufferManager::TakePhoto( + cros::mojom::CameraMetadataPtr settings, + VideoCaptureDevice::TakePhotoCallback callback) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - DCHECK(stream_context_); + DCHECK(stream_context_[StreamType::kStillCapture]); + + pending_still_capture_callbacks_.push(std::move(callback)); + oneshot_request_settings_.push(std::move(settings)); + RegisterBuffer(StreamType::kStillCapture); +} + +void StreamBufferManager::AddResultMetadataObserver( + ResultMetadataObserver* observer) { + DCHECK(ipc_task_runner_->BelongsToCurrentThread()); + DCHECK(!result_metadata_observers_.count(observer)); + + result_metadata_observers_.insert(observer); +} + +void StreamBufferManager::RemoveResultMetadataObserver( + ResultMetadataObserver* observer) { + DCHECK(ipc_task_runner_->BelongsToCurrentThread()); + DCHECK(result_metadata_observers_.count(observer)); + + result_metadata_observers_.erase(observer); +} + +void StreamBufferManager::SetCaptureMetadata(cros::mojom::CameraMetadataTag tag, + cros::mojom::EntryType type, + size_t count, + std::vector<uint8_t> value) { + DCHECK(ipc_task_runner_->BelongsToCurrentThread()); + + cros::mojom::CameraMetadataEntryPtr setting = + cros::mojom::CameraMetadataEntry::New(); + + setting->tag = tag; + setting->type = type; + setting->count = count; + setting->data = std::move(value); + + capture_settings_override_.push_back(std::move(setting)); +} + +// static +uint64_t StreamBufferManager::GetBufferIpcId(StreamType stream_type, + size_t index) { + uint64_t id = 0; + id |= static_cast<int64_t>(stream_type) << 32; + id |= index; + return id; +} + +void StreamBufferManager::ApplyCaptureSettings( + cros::mojom::CameraMetadataPtr* capture_settings) { + DCHECK(ipc_task_runner_->BelongsToCurrentThread()); + + if (capture_settings_override_.empty()) { + return; + } + for (auto& s : capture_settings_override_) { + auto* entry = GetMetadataEntry(*capture_settings, s->tag); + if (entry) { + DCHECK_EQ((*entry)->type, s->type); + (*entry).Swap(&s); + } else { + (*capture_settings)->entry_count += 1; + (*capture_settings)->entry_capacity += 1; + (*capture_settings)->data_count += s->data.size(); + (*capture_settings)->data_capacity += s->data.size(); + if (!(*capture_settings)->entries) { + (*capture_settings)->entries = + std::vector<cros::mojom::CameraMetadataEntryPtr>(); + } + (*capture_settings)->entries.value().push_back(std::move(s)); + } + } + capture_settings_override_.clear(); + SortCameraMetadata(capture_settings); +} + +void StreamBufferManager::RegisterBuffer(StreamType stream_type) { + DCHECK(ipc_task_runner_->BelongsToCurrentThread()); + DCHECK(stream_context_[stream_type]); if (!capturing_) { return; } - if (stream_context_->free_buffers.empty()) { + if (stream_context_[stream_type]->free_buffers.empty()) { return; } - size_t buffer_id = stream_context_->free_buffers.front(); - stream_context_->free_buffers.pop(); + size_t buffer_id = stream_context_[stream_type]->free_buffers.front(); + stream_context_[stream_type]->free_buffers.pop(); const gfx::GpuMemoryBuffer* buffer = - stream_context_->buffers[buffer_id].get(); + stream_context_[stream_type]->buffers[GetBufferIndex(buffer_id)].get(); - VideoPixelFormat buffer_format = stream_context_->capture_format.pixel_format; + VideoPixelFormat buffer_format = + stream_context_[stream_type]->capture_format.pixel_format; uint32_t drm_format = PixFormatVideoToDrm(buffer_format); if (!drm_format) { device_context_->SetErrorState( @@ -147,7 +299,7 @@ return; } cros::mojom::HalPixelFormat hal_pixel_format = - stream_context_->stream->format; + stream_context_[stream_type]->stream->format; gfx::NativePixmapHandle buffer_handle = buffer->GetHandle().native_pixmap_handle; @@ -178,15 +330,18 @@ // gralloc buffers. capture_interface_->RegisterBuffer( buffer_id, cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, drm_format, - hal_pixel_format, stream_context_->stream->width, - stream_context_->stream->height, std::move(planes), + hal_pixel_format, buffer->GetSize().width(), buffer->GetSize().height(), + std::move(planes), base::BindOnce(&StreamBufferManager::OnRegisteredBuffer, - weak_ptr_factory_.GetWeakPtr(), buffer_id)); - VLOG(2) << "Registered buffer " << buffer_id; + weak_ptr_factory_.GetWeakPtr(), stream_type, buffer_id)); + DVLOG(2) << "Registered buffer " << buffer_id; } -void StreamBufferManager::OnRegisteredBuffer(size_t buffer_id, int32_t result) { +void StreamBufferManager::OnRegisteredBuffer(StreamType stream_type, + size_t buffer_id, + int32_t result) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); + DCHECK(stream_context_[stream_type]); if (!capturing_) { return; @@ -197,32 +352,64 @@ std::string(strerror(result))); return; } - ProcessCaptureRequest(buffer_id); + stream_context_[stream_type]->registered_buffers.push(buffer_id); + ProcessCaptureRequest(); } -void StreamBufferManager::ProcessCaptureRequest(size_t buffer_id) { +void StreamBufferManager::ProcessCaptureRequest() { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - DCHECK(stream_context_); - - cros::mojom::Camera3StreamBufferPtr buffer = - cros::mojom::Camera3StreamBuffer::New(); - buffer->stream_id = static_cast<uint64_t>( - cros::mojom::Camera3RequestTemplate::CAMERA3_TEMPLATE_PREVIEW); - buffer->buffer_id = buffer_id; - buffer->status = cros::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_OK; + DCHECK(stream_context_[StreamType::kPreview]); + DCHECK(stream_context_[StreamType::kStillCapture]); cros::mojom::Camera3CaptureRequestPtr request = cros::mojom::Camera3CaptureRequest::New(); request->frame_number = frame_number_; - request->settings = stream_context_->request_settings.Clone(); - request->output_buffers.push_back(std::move(buffer)); + CaptureResult& pending_result = pending_results_[frame_number_]; + + if (!stream_context_[StreamType::kPreview]->registered_buffers.empty()) { + cros::mojom::Camera3StreamBufferPtr buffer = + cros::mojom::Camera3StreamBuffer::New(); + buffer->stream_id = static_cast<uint64_t>(StreamType::kPreview); + buffer->buffer_id = + stream_context_[StreamType::kPreview]->registered_buffers.front(); + stream_context_[StreamType::kPreview]->registered_buffers.pop(); + buffer->status = cros::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_OK; + + DVLOG(2) << "Requested capture for stream " << StreamType::kPreview + << " in frame " << frame_number_; + request->settings = repeating_request_settings_.Clone(); + request->output_buffers.push_back(std::move(buffer)); + } + + if (!stream_context_[StreamType::kStillCapture]->registered_buffers.empty()) { + DCHECK(!pending_still_capture_callbacks_.empty()); + cros::mojom::Camera3StreamBufferPtr buffer = + cros::mojom::Camera3StreamBuffer::New(); + buffer->stream_id = static_cast<uint64_t>(StreamType::kStillCapture); + buffer->buffer_id = + stream_context_[StreamType::kStillCapture]->registered_buffers.front(); + stream_context_[StreamType::kStillCapture]->registered_buffers.pop(); + buffer->status = cros::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_OK; + + DVLOG(2) << "Requested capture for stream " << StreamType::kStillCapture + << " in frame " << frame_number_; + // Use the still capture settings and override the preview ones. + request->settings = std::move(oneshot_request_settings_.front()); + oneshot_request_settings_.pop(); + pending_result.still_capture_callback = + std::move(pending_still_capture_callbacks_.front()); + pending_still_capture_callbacks_.pop(); + request->output_buffers.push_back(std::move(buffer)); + } + + pending_result.unsubmitted_buffer_count = request->output_buffers.size(); + + ApplyCaptureSettings(&request->settings); capture_interface_->ProcessCaptureRequest( std::move(request), base::BindOnce(&StreamBufferManager::OnProcessedCaptureRequest, weak_ptr_factory_.GetWeakPtr())); - VLOG(2) << "Requested capture for frame " << frame_number_ << " with buffer " - << buffer_id; frame_number_++; } @@ -238,7 +425,8 @@ std::string(strerror(result))); return; } - RegisterBuffer(); + // Keeps the preview stream going. + RegisterBuffer(StreamType::kPreview); } void StreamBufferManager::ProcessCaptureResult( @@ -251,70 +439,78 @@ uint32_t frame_number = result->frame_number; // A new partial result may be created in either ProcessCaptureResult or // Notify. - CaptureResult& partial_result = partial_results_[frame_number]; - if (partial_results_.size() > stream_context_->stream->max_buffers) { - device_context_->SetErrorState( - FROM_HERE, - "Received more capture results than the maximum number of buffers"); - return; + CaptureResult& pending_result = pending_results_[frame_number]; + + // |result->pending_result| is set to 0 if the capture result contains only + // the result buffer handles and no result metadata. + if (result->partial_result) { + uint32_t result_id = result->partial_result; + if (result_id > partial_result_count_) { + device_context_->SetErrorState( + FROM_HERE, std::string("Invalid pending_result id: ") + + std::to_string(result_id)); + return; + } + if (pending_result.partial_metadata_received.count(result_id)) { + device_context_->SetErrorState( + FROM_HERE, std::string("Received duplicated partial metadata: ") + + std::to_string(result_id)); + return; + } + DVLOG(2) << "Received partial result " << result_id << " for frame " + << frame_number; + pending_result.partial_metadata_received.insert(result_id); + MergeMetadata(&pending_result.metadata, result->result); } + if (result->output_buffers) { - if (result->output_buffers->size() != 1) { + if (result->output_buffers->size() > kMaxConfiguredStreams) { device_context_->SetErrorState( FROM_HERE, std::string("Incorrect number of output buffers received: ") + std::to_string(result->output_buffers->size())); return; } - cros::mojom::Camera3StreamBufferPtr& stream_buffer = - result->output_buffers.value()[0]; - VLOG(2) << "Received capture result for frame " << frame_number - << " stream_id: " << stream_buffer->stream_id; - // The camera HAL v3 API specifies that only one capture result can carry - // the result buffer for any given frame number. - if (!partial_result.buffer.is_null()) { - device_context_->SetErrorState( - FROM_HERE, - std::string("Received multiple result buffers for frame ") + - std::to_string(frame_number)); - return; - } else { - partial_result.buffer = std::move(stream_buffer); - // If the buffer is marked as error it is due to either a request or a - // buffer error. In either case the content of the buffer must be dropped - // and the buffer can be reused. We simply submit the buffer here and - // don't wait for any partial results. SubmitCaptureResult() will drop - // and reuse the buffer. - if (partial_result.buffer->status == - cros::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_ERROR) { - SubmitCaptureResult(frame_number); + for (auto& stream_buffer : result->output_buffers.value()) { + DVLOG(2) << "Received capture result for frame " << frame_number + << " stream_id: " << stream_buffer->stream_id; + StreamType stream_type = StreamIdToStreamType(stream_buffer->stream_id); + if (stream_type == StreamType::kUnknown) { + device_context_->SetErrorState( + FROM_HERE, + std::string("Invalid type of output buffers received: ") + + std::to_string(stream_buffer->stream_id)); return; } + + // The camera HAL v3 API specifies that only one capture result can carry + // the result buffer for any given frame number. + if (stream_context_[stream_type]->capture_results_with_buffer.count( + frame_number)) { + device_context_->SetErrorState( + FROM_HERE, + std::string("Received multiple result buffers for frame ") + + std::to_string(frame_number) + std::string(" for stream ") + + std::to_string(stream_buffer->stream_id)); + return; + } + + pending_result.buffers[stream_type] = std::move(stream_buffer); + stream_context_[stream_type]->capture_results_with_buffer[frame_number] = + &pending_result; + if (pending_result.buffers[stream_type]->status == + cros::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_ERROR) { + // If the buffer is marked as error, its content is discarded for this + // frame. Send the buffer to the free list directly through + // SubmitCaptureResult. + SubmitCaptureResult(frame_number, stream_type); + } } } - // |result->partial_result| is set to 0 if the capture result contains only - // the result buffer handles and no result metadata. - if (result->partial_result) { - uint32_t result_id = result->partial_result; - if (result_id > partial_result_count_) { - device_context_->SetErrorState( - FROM_HERE, std::string("Invalid partial_result id: ") + - std::to_string(result_id)); - return; - } - if (partial_result.partial_metadata_received.find(result_id) != - partial_result.partial_metadata_received.end()) { - device_context_->SetErrorState( - FROM_HERE, std::string("Received duplicated partial metadata: ") + - std::to_string(result_id)); - return; - } - partial_result.partial_metadata_received.insert(result_id); - MergeMetadata(&partial_result.metadata, result->result); + for (const auto& iter : stream_context_) { + SubmitCaptureResultIfComplete(frame_number, iter.first); } - - SubmitCaptureResultIfComplete(frame_number); } void StreamBufferManager::Notify(cros::mojom::Camera3NotifyMsgPtr message) { @@ -326,46 +522,49 @@ if (message->type == cros::mojom::Camera3MsgType::CAMERA3_MSG_ERROR) { uint32_t frame_number = message->message->get_error()->frame_number; uint64_t error_stream_id = message->message->get_error()->error_stream_id; + StreamType stream_type = StreamIdToStreamType(error_stream_id); + if (stream_type == StreamType::kUnknown) { + device_context_->SetErrorState( + FROM_HERE, std::string("Unknown stream in Camera3NotifyMsg: ") + + std::to_string(error_stream_id)); + return; + } cros::mojom::Camera3ErrorMsgCode error_code = message->message->get_error()->error_code; - HandleNotifyError(frame_number, error_stream_id, error_code); + HandleNotifyError(frame_number, stream_type, error_code); } else { // cros::mojom::Camera3MsgType::CAMERA3_MSG_SHUTTER uint32_t frame_number = message->message->get_shutter()->frame_number; uint64_t shutter_time = message->message->get_shutter()->timestamp; - // A new partial result may be created in either ProcessCaptureResult or - // Notify. - VLOG(2) << "Received shutter time for frame " << frame_number; + DVLOG(2) << "Received shutter time for frame " << frame_number; if (!shutter_time) { device_context_->SetErrorState( FROM_HERE, std::string("Received invalid shutter time: ") + std::to_string(shutter_time)); return; } - CaptureResult& partial_result = partial_results_[frame_number]; - if (partial_results_.size() > stream_context_->stream->max_buffers) { - device_context_->SetErrorState( - FROM_HERE, - "Received more capture results than the maximum number of buffers"); - return; - } + CaptureResult& pending_result = pending_results_[frame_number]; // Shutter timestamp is in ns. base::TimeTicks reference_time = base::TimeTicks::FromInternalValue(shutter_time / 1000); - partial_result.reference_time = reference_time; + pending_result.reference_time = reference_time; if (first_frame_shutter_time_.is_null()) { // Record the shutter time of the first frame for calculating the // timestamp. first_frame_shutter_time_ = reference_time; } - partial_result.timestamp = reference_time - first_frame_shutter_time_; - SubmitCaptureResultIfComplete(frame_number); + pending_result.timestamp = reference_time - first_frame_shutter_time_; + for (const auto& iter : stream_context_) { + SubmitCaptureResultIfComplete(frame_number, iter.first); + } } } void StreamBufferManager::HandleNotifyError( uint32_t frame_number, - uint64_t error_stream_id, + StreamType stream_type, cros::mojom::Camera3ErrorMsgCode error_code) { + DCHECK(ipc_task_runner_->BelongsToCurrentThread()); + std::string warning_msg; switch (error_code) { @@ -400,7 +599,7 @@ case cros::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_BUFFER: // An error has occurred in placing the output buffer into a stream for // a request. |frame_number| specifies the request for which the buffer - // was dropped, and |error_stream_id| specifies the stream that dropped + // was dropped, and |stream_type| specifies the stream that dropped // the buffer. // // The HAL will call ProcessCaptureResult with the buffer's state set to @@ -409,7 +608,7 @@ warning_msg = std::string( "An error occurred while filling output buffer of stream ") + - std::to_string(error_stream_id) + std::string(" in frame ") + + StreamTypeToString(stream_type) + std::string(" in frame ") + std::to_string(frame_number); break; @@ -418,55 +617,76 @@ break; } - LOG(WARNING) << warning_msg; + LOG(WARNING) << warning_msg << stream_type; device_context_->LogToClient(warning_msg); // If the buffer is already returned by the HAL, submit it and we're done. - auto partial_result = partial_results_.find(frame_number); - if (partial_result != partial_results_.end() && - !partial_result->second.buffer.is_null()) { - SubmitCaptureResult(frame_number); + if (pending_results_.count(frame_number) && + pending_results_[frame_number].buffers.count(stream_type)) { + SubmitCaptureResult(frame_number, stream_type); } } -void StreamBufferManager::SubmitCaptureResultIfComplete(uint32_t frame_number) { +void StreamBufferManager::SubmitCaptureResultIfComplete( + uint32_t frame_number, + StreamType stream_type) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - DCHECK(partial_results_.find(frame_number) != partial_results_.end()); - CaptureResult& partial_result = partial_results_[frame_number]; - if (partial_result.partial_metadata_received.size() < partial_result_count_ || - partial_result.buffer.is_null() || - partial_result.reference_time == base::TimeTicks()) { - // We can only submit the result buffer when: - // 1. All the result metadata are received, and - // 2. The result buffer is received, and - // 3. The the shutter time is received. + if (!pending_results_.count(frame_number)) { + // The capture result may be discarded in case of error. return; } - SubmitCaptureResult(frame_number); + + CaptureResult& pending_result = pending_results_[frame_number]; + if (!stream_context_[stream_type]->capture_results_with_buffer.count( + frame_number) || + pending_result.partial_metadata_received.size() < partial_result_count_ || + pending_result.reference_time == base::TimeTicks()) { + // We can only submit the result buffer of |frame_number| for |stream_type| + // when: + // 1. The result buffer for |stream_type| is received, and + // 2. All the result metadata are received, and + // 3. The shutter time is received. + return; + } + SubmitCaptureResult(frame_number, stream_type); } -void StreamBufferManager::SubmitCaptureResult(uint32_t frame_number) { +void StreamBufferManager::SubmitCaptureResult(uint32_t frame_number, + StreamType stream_type) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - DCHECK(partial_results_.find(frame_number) != partial_results_.end()); + DCHECK(pending_results_.count(frame_number)); + DCHECK(stream_context_[stream_type]->capture_results_with_buffer.count( + frame_number)); - CaptureResult& partial_result = partial_results_[frame_number]; - if (partial_results_.begin()->first != frame_number) { + CaptureResult& pending_result = + *stream_context_[stream_type]->capture_results_with_buffer[frame_number]; + if (stream_context_[stream_type] + ->capture_results_with_buffer.begin() + ->first != frame_number) { device_context_->SetErrorState( FROM_HERE, std::string("Received frame is out-of-order; expect ") + - std::to_string(partial_results_.begin()->first) + + std::to_string(pending_results_.begin()->first) + std::string(" but got ") + std::to_string(frame_number)); return; } - VLOG(2) << "Submit capture result of frame " << frame_number; - uint32_t buffer_id = partial_result.buffer->buffer_id; + DVLOG(2) << "Submit capture result of frame " << frame_number + << " for stream " << static_cast<int>(stream_type); + for (auto* iter : result_metadata_observers_) { + iter->OnResultMetadataAvailable(pending_result.metadata); + } + + DCHECK(pending_result.buffers[stream_type]); + const cros::mojom::Camera3StreamBufferPtr& stream_buffer = + pending_result.buffers[stream_type]; + uint64_t buffer_id = stream_buffer->buffer_id; // Wait on release fence before delivering the result buffer to client. - if (partial_result.buffer->release_fence.is_valid()) { + if (stream_buffer->release_fence.is_valid()) { const int kSyncWaitTimeoutMs = 1000; mojo::edk::ScopedPlatformHandle fence; MojoResult result = mojo::edk::PassWrappedPlatformHandle( - partial_result.buffer->release_fence.release().value(), &fence); + stream_buffer->release_fence.release().value(), &fence); if (result != MOJO_RESULT_OK) { device_context_->SetErrorState(FROM_HERE, "Failed to unwrap release fence fd"); @@ -479,17 +699,55 @@ } } - // Deliver the captured data to client and then re-queue the buffer. - if (partial_result.buffer->status != + // Deliver the captured data to client. + if (stream_buffer->status != cros::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_ERROR) { - gfx::GpuMemoryBuffer* buffer = stream_context_->buffers[buffer_id].get(); - device_context_->SubmitCapturedData(buffer, stream_context_->capture_format, - partial_result.reference_time, - partial_result.timestamp); + size_t buffer_index = GetBufferIndex(buffer_id); + gfx::GpuMemoryBuffer* buffer = + stream_context_[stream_type]->buffers[buffer_index].get(); + if (stream_type == StreamType::kPreview) { + device_context_->SubmitCapturedData( + buffer, stream_context_[StreamType::kPreview]->capture_format, + pending_result.reference_time, pending_result.timestamp); + ipc_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&StreamBufferManager::RegisterBuffer, + weak_ptr_factory_.GetWeakPtr(), StreamType::kPreview)); + } else { // StreamType::kStillCapture + DCHECK(pending_result.still_capture_callback); + const Camera3JpegBlob* header = reinterpret_cast<Camera3JpegBlob*>( + reinterpret_cast<uintptr_t>(buffer->memory(0)) + + buffer->GetSize().width() - sizeof(Camera3JpegBlob)); + if (header->jpeg_blob_id != kCamera3JpegBlobId) { + device_context_->SetErrorState(FROM_HERE, "Invalid JPEG blob"); + return; + } + mojom::BlobPtr blob = blobify_callback_.Run( + reinterpret_cast<uint8_t*>(buffer->memory(0)), header->jpeg_size, + stream_context_[stream_type]->capture_format); + if (blob) { + std::move(pending_result.still_capture_callback).Run(std::move(blob)); + } else { + LOG(ERROR) << "Failed to blobify the captured JPEG image"; + } + } } - stream_context_->free_buffers.push(buffer_id); - partial_results_.erase(frame_number); - RegisterBuffer(); + + stream_context_[stream_type]->free_buffers.push(buffer_id); + stream_context_[stream_type]->capture_results_with_buffer.erase(frame_number); + pending_result.unsubmitted_buffer_count--; + if (!pending_result.unsubmitted_buffer_count) { + pending_results_.erase(frame_number); + } + + if (stream_type == StreamType::kPreview) { + // Always keep the preview stream running. + RegisterBuffer(StreamType::kPreview); + } else { // stream_type == StreamType::kStillCapture + if (!pending_still_capture_callbacks_.empty()) { + RegisterBuffer(StreamType::kStillCapture); + } + } } StreamBufferManager::StreamContext::StreamContext() = default; @@ -497,7 +755,8 @@ StreamBufferManager::StreamContext::~StreamContext() = default; StreamBufferManager::CaptureResult::CaptureResult() - : metadata(cros::mojom::CameraMetadata::New()) {} + : metadata(cros::mojom::CameraMetadata::New()), + unsubmitted_buffer_count(0) {} StreamBufferManager::CaptureResult::~CaptureResult() = default;
diff --git a/media/capture/video/chromeos/stream_buffer_manager.h b/media/capture/video/chromeos/stream_buffer_manager.h index 5c544c9..75a1e58 100644 --- a/media/capture/video/chromeos/stream_buffer_manager.h +++ b/media/capture/video/chromeos/stream_buffer_manager.h
@@ -5,6 +5,11 @@ #ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_STREAM_BUFFER_MANAGER_H_ #define MEDIA_CAPTURE_VIDEO_CHROMEOS_STREAM_BUFFER_MANAGER_H_ +#include <memory> +#include <queue> +#include <unordered_map> +#include <vector> + #include "base/containers/queue.h" #include "base/memory/weak_ptr.h" #include "base/single_thread_task_runner.h" @@ -24,29 +29,65 @@ class CameraBufferFactory; class CameraDeviceContext; +// One stream for preview, one stream for still capture. +constexpr size_t kMaxConfiguredStreams = 2; + +// The JPEG transport header as defined by Android camera HAL v3 API. The JPEG +// transport header is at the end of the blob buffer filled by the HAL. +constexpr uint16_t kCamera3JpegBlobId = 0x00FF; +struct Camera3JpegBlob { + uint16_t jpeg_blob_id; + uint32_t jpeg_size; +}; + +class CAPTURE_EXPORT CaptureMetadataDispatcher { + public: + class ResultMetadataObserver { + public: + virtual ~ResultMetadataObserver() {} + virtual void OnResultMetadataAvailable( + const cros::mojom::CameraMetadataPtr&) = 0; + }; + + virtual ~CaptureMetadataDispatcher() {} + virtual void AddResultMetadataObserver(ResultMetadataObserver* observer) = 0; + virtual void RemoveResultMetadataObserver( + ResultMetadataObserver* observer) = 0; + virtual void SetCaptureMetadata(cros::mojom::CameraMetadataTag tag, + cros::mojom::EntryType type, + size_t count, + std::vector<uint8_t> value) = 0; +}; + // StreamBufferManager is responsible for managing the buffers of the // stream. StreamBufferManager allocates buffers according to the given // stream configuration, and circulates the buffers along with capture // requests and results between Chrome and the camera HAL process. class CAPTURE_EXPORT StreamBufferManager final - : public cros::mojom::Camera3CallbackOps { + : public cros::mojom::Camera3CallbackOps, + public CaptureMetadataDispatcher { public: StreamBufferManager( cros::mojom::Camera3CallbackOpsRequest callback_ops_request, std::unique_ptr<StreamCaptureInterface> capture_interface, CameraDeviceContext* device_context, std::unique_ptr<CameraBufferFactory> camera_buffer_factory, + base::RepeatingCallback<mojom::BlobPtr( + const uint8_t* buffer, + const uint32_t bytesused, + const VideoCaptureFormat& capture_format)> blobify_callback, scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner); - ~StreamBufferManager() final; + ~StreamBufferManager() override; // Sets up the stream context and allocate buffers according to the // configuration specified in |stream|. - void SetUpStreamAndBuffers(VideoCaptureFormat capture_format, - uint32_t partial_result_count, - cros::mojom::Camera3StreamPtr stream); + void SetUpStreamsAndBuffers( + VideoCaptureFormat capture_format, + const cros::mojom::CameraMetadataPtr& static_metadata, + std::vector<cros::mojom::Camera3StreamPtr> streams); - // StartCapture is the entry point to starting the video capture. The way + // StartPreview is the entry point to starting the video capture. The way // the video capture loop works is: // // (1) If there is a free buffer, RegisterBuffer registers the buffer with @@ -60,24 +101,48 @@ // SubmitCaptureResultIfComplete is called to deliver the filled buffer // to Chrome. After the buffer is consumed by Chrome it is enqueued back // to the free buffer queue. Goto (1) to start another capture loop. - void StartCapture(cros::mojom::CameraMetadataPtr settings); + // + // When TakePhoto() is called, an additional BLOB buffer is queued in step (2) + // to let the HAL fill the still capture JPEG image. When the JPEG image is + // returned in (4), it's passed to upper layer through the TakePhotoCallback. + void StartPreview(cros::mojom::CameraMetadataPtr preview_settings); - // Stops the capture loop. After StopCapture is called |callback_ops_| is + // Stops the capture loop. After StopPreview is called |callback_ops_| is // unbound, so no new capture request or result will be processed. - void StopCapture(); + void StopPreview(); + + cros::mojom::Camera3StreamPtr GetStreamConfiguration(StreamType stream_type); + + void TakePhoto(cros::mojom::CameraMetadataPtr settings, + VideoCaptureDevice::TakePhotoCallback callback); + + // CaptureMetadataDispatcher implementations. + void AddResultMetadataObserver(ResultMetadataObserver* observer) override; + void RemoveResultMetadataObserver(ResultMetadataObserver* observer) override; + // Queues a capture setting that will be send along with the earliest next + // capture request. + void SetCaptureMetadata(cros::mojom::CameraMetadataTag tag, + cros::mojom::EntryType type, + size_t count, + std::vector<uint8_t> value) override; + + static uint64_t GetBufferIpcId(StreamType stream_type, size_t index); private: friend class StreamBufferManagerTest; - // Registers a free buffer, if any, to the camera HAL. - void RegisterBuffer(); + // Registers a free buffer, if any, for the give |stream_type| to the camera + // HAL. + void RegisterBuffer(StreamType stream_type); // Calls ProcessCaptureRequest if the buffer specified by |buffer_id| is // successfully registered. - void OnRegisteredBuffer(size_t buffer_id, int32_t result); + void OnRegisteredBuffer(StreamType stream_type, + size_t buffer_id, + int32_t result); - // The capture request contains the buffer handle specified by |buffer_id|. - void ProcessCaptureRequest(size_t buffer_id); + // The capture request contains the buffer handles waiting to be filled. + void ProcessCaptureRequest(); // Calls RegisterBuffer to attempt to register any remaining free buffers. void OnProcessedCaptureRequest(int32_t result); @@ -86,23 +151,27 @@ // ProcessCaptureResult receives the result metadata as well as the filled // buffer from camera HAL. The result metadata may be divided and delivered // in several stages. Before all the result metadata is received the - // partial results are kept in |partial_results_|. - void ProcessCaptureResult(cros::mojom::Camera3CaptureResultPtr result) final; + // partial results are kept in |pending_results_|. + void ProcessCaptureResult( + cros::mojom::Camera3CaptureResultPtr result) override; // Notify receives the shutter time of capture requests and various errors // from camera HAL. The shutter time is used as the timestamp in the video // frame delivered to Chrome. - void Notify(cros::mojom::Camera3NotifyMsgPtr message) final; + void Notify(cros::mojom::Camera3NotifyMsgPtr message) override; void HandleNotifyError(uint32_t frame_number, - uint64_t error_stream_id, + StreamType stream_type, cros::mojom::Camera3ErrorMsgCode error_code); - // Submits the captured buffer of frame |frame_number_| to Chrome if all the - // required metadata and the captured buffer are received. After the buffer - // is submitted the function then enqueues the buffer to free buffer queue for - // the next capture request. - void SubmitCaptureResultIfComplete(uint32_t frame_number); - void SubmitCaptureResult(uint32_t frame_number); + // Submits the captured buffer of frame |frame_number_| for the give + // |stream_type| to Chrome if all the required metadata and the captured + // buffer are received. After the buffer is submitted the function then + // enqueues the buffer to free buffer queue for the next capture request. + void SubmitCaptureResultIfComplete(uint32_t frame_number, + StreamType stream_type); + void SubmitCaptureResult(uint32_t frame_number, StreamType stream_type); + + void ApplyCaptureSettings(cros::mojom::CameraMetadataPtr* capture_settings); mojo::Binding<cros::mojom::Camera3CallbackOps> callback_ops_; @@ -112,6 +181,12 @@ std::unique_ptr<CameraBufferFactory> camera_buffer_factory_; + base::RepeatingCallback<mojom::BlobPtr( + const uint8_t* buffer, + const uint32_t bytesused, + const VideoCaptureFormat& capture_format)> + blobify_callback_; + // Where all the Mojo IPC calls takes place. const scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner_; @@ -122,26 +197,7 @@ // to zero in AllocateAndStart. uint32_t frame_number_; - struct StreamContext { - StreamContext(); - ~StreamContext(); - // The actual pixel format used in the capture request. - VideoCaptureFormat capture_format; - // The camera HAL stream. - cros::mojom::Camera3StreamPtr stream; - // The request settings used in the capture request of this stream. - cros::mojom::CameraMetadataPtr request_settings; - // The allocated buffers of this stream. - std::vector<std::unique_ptr<gfx::GpuMemoryBuffer>> buffers; - // The free buffers of this stream. The queue stores indices into the - // |buffers| vector. - base::queue<size_t> free_buffers; - }; - - // The stream context of the preview stream. - std::unique_ptr<StreamContext> stream_context_; - - // CaptureResult is used to hold the partial capture results for each frame. + // CaptureResult is used to hold the pending capture results for each frame. struct CaptureResult { CaptureResult(); ~CaptureResult(); @@ -153,14 +209,59 @@ // The result metadata. Contains various information about the captured // frame. cros::mojom::CameraMetadataPtr metadata; - // The buffer handle that hold the captured data of this frame. - cros::mojom::Camera3StreamBufferPtr buffer; + // The buffer handles that hold the captured data of this frame. + std::unordered_map<StreamType, cros::mojom::Camera3StreamBufferPtr> buffers; // The set of the partial metadata received. For each capture result, the // total number of partial metadata should equal to // |partial_result_count_|. std::set<uint32_t> partial_metadata_received; + // Incremented for every stream buffer requested for the given frame. + // StreamBufferManager destructs the CaptureResult when + // |unsubmitted_buffer_count| drops to zero. + size_t unsubmitted_buffer_count; + // The callback used to return the captured still capture JPEG buffer. Set + // if and only if the capture request was sent with a still capture buffer. + VideoCaptureDevice::TakePhotoCallback still_capture_callback; }; + struct StreamContext { + StreamContext(); + ~StreamContext(); + // The actual pixel format used in the capture request. + VideoCaptureFormat capture_format; + // The camera HAL stream. + cros::mojom::Camera3StreamPtr stream; + // The allocated buffers of this stream. + std::vector<std::unique_ptr<gfx::GpuMemoryBuffer>> buffers; + // The free buffers of this stream. The queue stores indices into the + // |buffers| vector. + std::queue<size_t> free_buffers; + // The buffers that are registered to the HAL, which can be used as the + // output buffers for capture requests. + std::queue<size_t> registered_buffers; + // The pointers to the pending capture results that have unsubmitted result + // buffers. + std::map<uint32_t, CaptureResult*> capture_results_with_buffer; + }; + + // The context for the set of active streams. + std::unordered_map<StreamType, std::unique_ptr<StreamContext>> + stream_context_; + + // The repeating request settings. The settings come from the default preview + // request settings reported by the HAL. |repeating_request_settings_| is the + // default settings for each capture request. + cros::mojom::CameraMetadataPtr repeating_request_settings_; + + // A queue of oneshot request settings. These are the request settings for + // each still capture requests. |oneshot_request_settings_| overrides + // |repeating_request_settings_| if present. + std::queue<cros::mojom::CameraMetadataPtr> oneshot_request_settings_; + + // The pending callbacks for the TakePhoto requests. + std::queue<VideoCaptureDevice::TakePhotoCallback> + pending_still_capture_callbacks_; + // The number of partial stages. |partial_result_count_| is learned by // querying |static_metadata_|. In case the result count is absent in // |static_metadata_|, it defaults to one which means all the result @@ -173,8 +274,15 @@ // |first_frame_shutter_time_|. base::TimeTicks first_frame_shutter_time_; - // Stores the partial capture results of the current in-flight frames. - std::map<uint32_t, CaptureResult> partial_results_; + // Stores the pending capture results of the current in-flight frames. + std::map<uint32_t, CaptureResult> pending_results_; + + // StreamBufferManager does not own the ResultMetadataObservers. The + // observers are responsible for removing itself before self-destruction. + std::unordered_set<ResultMetadataObserver*> result_metadata_observers_; + + // The list of settings to set/override in the capture request. + std::vector<cros::mojom::CameraMetadataEntryPtr> capture_settings_override_; base::WeakPtrFactory<StreamBufferManager> weak_ptr_factory_;
diff --git a/media/capture/video/chromeos/stream_buffer_manager_unittest.cc b/media/capture/video/chromeos/stream_buffer_manager_unittest.cc index a1714d0..dafe3d3c 100644 --- a/media/capture/video/chromeos/stream_buffer_manager_unittest.cc +++ b/media/capture/video/chromeos/stream_buffer_manager_unittest.cc
@@ -21,6 +21,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "media/capture/video/blob_utils.h" using testing::_; using testing::A; using testing::AtLeast; @@ -109,6 +110,10 @@ std::move(callback_ops_request), std::make_unique<MockStreamCaptureInterface>(), device_context_.get(), std::make_unique<FakeCameraBufferFactory>(), + base::BindRepeating([](const uint8_t* buffer, const uint32_t bytesused, + const VideoCaptureFormat& capture_format) { + return mojom::Blob::New(); + }), base::ThreadTaskRunnerHandle::Get()); } @@ -126,6 +131,39 @@ } } + cros::mojom::CameraMetadataPtr GetFakeStaticMetadata( + int32_t partial_result_count) { + cros::mojom::CameraMetadataPtr static_metadata = + cros::mojom::CameraMetadata::New(); + static_metadata->entry_count = 2; + static_metadata->entry_capacity = 2; + static_metadata->entries = + std::vector<cros::mojom::CameraMetadataEntryPtr>(); + + cros::mojom::CameraMetadataEntryPtr entry = + cros::mojom::CameraMetadataEntry::New(); + entry->index = 0; + entry->tag = + cros::mojom::CameraMetadataTag::ANDROID_REQUEST_PARTIAL_RESULT_COUNT; + entry->type = cros::mojom::EntryType::TYPE_INT32; + entry->count = 1; + uint8_t* as_int8 = reinterpret_cast<uint8_t*>(&partial_result_count); + entry->data.assign(as_int8, as_int8 + entry->count * sizeof(int32_t)); + static_metadata->entries->push_back(std::move(entry)); + + entry = cros::mojom::CameraMetadataEntry::New(); + entry->index = 1; + entry->tag = cros::mojom::CameraMetadataTag::ANDROID_JPEG_MAX_SIZE; + entry->type = cros::mojom::EntryType::TYPE_INT32; + entry->count = 1; + int32_t jpeg_max_size = 65535; + as_int8 = reinterpret_cast<uint8_t*>(&jpeg_max_size); + entry->data.assign(as_int8, as_int8 + entry->count * sizeof(int32_t)); + static_metadata->entries->push_back(std::move(entry)); + + return static_metadata; + } + void RegisterBuffer(uint64_t buffer_id, cros::mojom::Camera3DeviceOps::BufferType type, uint32_t drm_format, @@ -165,25 +203,46 @@ device_context_->client_.get()); } - std::map<uint32_t, StreamBufferManager::CaptureResult>& GetPartialResults() { + std::map<uint32_t, StreamBufferManager::CaptureResult>& GetPendingResults() { EXPECT_NE(nullptr, stream_buffer_manager_.get()); - return stream_buffer_manager_->partial_results_; + return stream_buffer_manager_->pending_results_; } - cros::mojom::Camera3StreamPtr PrepareCaptureStream(uint32_t max_buffers) { - auto stream = cros::mojom::Camera3Stream::New(); - stream->id = 0; - stream->stream_type = cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT; - stream->width = kDefaultCaptureFormat.frame_size.width(); - stream->height = kDefaultCaptureFormat.frame_size.height(); - stream->format = + std::vector<cros::mojom::Camera3StreamPtr> PrepareCaptureStream( + uint32_t max_buffers) { + std::vector<cros::mojom::Camera3StreamPtr> streams; + + auto preview_stream = cros::mojom::Camera3Stream::New(); + preview_stream->id = static_cast<uint64_t>(StreamType::kPreview); + preview_stream->stream_type = + cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT; + preview_stream->width = kDefaultCaptureFormat.frame_size.width(); + preview_stream->height = kDefaultCaptureFormat.frame_size.height(); + preview_stream->format = cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_YCbCr_420_888; - stream->usage = 0; - stream->max_buffers = max_buffers; - stream->data_space = 0; - stream->rotation = + preview_stream->usage = 0; + preview_stream->max_buffers = max_buffers; + preview_stream->data_space = 0; + preview_stream->rotation = cros::mojom::Camera3StreamRotation::CAMERA3_STREAM_ROTATION_0; - return stream; + streams.push_back(std::move(preview_stream)); + + auto still_capture_stream = cros::mojom::Camera3Stream::New(); + still_capture_stream->id = static_cast<uint64_t>(StreamType::kStillCapture); + still_capture_stream->stream_type = + cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT; + still_capture_stream->width = kDefaultCaptureFormat.frame_size.width(); + still_capture_stream->height = kDefaultCaptureFormat.frame_size.height(); + still_capture_stream->format = + cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_BLOB; + still_capture_stream->usage = 0; + still_capture_stream->max_buffers = max_buffers; + still_capture_stream->data_space = 0; + still_capture_stream->rotation = + cros::mojom::Camera3StreamRotation::CAMERA3_STREAM_ROTATION_0; + streams.push_back(std::move(still_capture_stream)); + + return streams; } cros::mojom::Camera3NotifyMsgPtr PrepareErrorNotifyMessage( @@ -192,7 +251,7 @@ auto error_msg = cros::mojom::Camera3ErrorMsg::New(); error_msg->frame_number = frame_number; // There is only the preview stream. - error_msg->error_stream_id = 1; + error_msg->error_stream_id = static_cast<uint64_t>(StreamType::kPreview); error_msg->error_code = error_code; auto notify_msg = cros::mojom::Camera3NotifyMsg::New(); notify_msg->message = cros::mojom::Camera3NotifyMsgMessage::New(); @@ -247,18 +306,20 @@ &StreamBufferManagerTest::QuitCaptureLoop, base::Unretained(this))); EXPECT_CALL( *GetMockCaptureInterface(), - DoRegisterBuffer(0, cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, - _, _, _, _, _)) + DoRegisterBuffer( + StreamBufferManager::GetBufferIpcId(StreamType::kPreview, 0), + cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, _, _, _, _, _)) .Times(AtLeast(1)) .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer)); EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _)) .Times(1) .WillOnce(Invoke(this, &StreamBufferManagerTest::ProcessCaptureRequest)); - stream_buffer_manager_->SetUpStreamAndBuffers( - kDefaultCaptureFormat, /* partial_result_count */ 1, + stream_buffer_manager_->SetUpStreamsAndBuffers( + kDefaultCaptureFormat, + GetFakeStaticMetadata(/* partial_result_count */ 1), PrepareCaptureStream(/* max_buffers */ 1)); - stream_buffer_manager_->StartCapture(cros::mojom::CameraMetadata::New()); + stream_buffer_manager_->StartPreview(cros::mojom::CameraMetadata::New()); // Wait until a captured frame is received by MockVideoCaptureClient. DoLoop(); @@ -269,18 +330,19 @@ TEST_F(StreamBufferManagerTest, PartialResultTest) { GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce( [](StreamBufferManagerTest* test) { - EXPECT_EQ(1u, test->GetPartialResults().size()); + EXPECT_EQ(1u, test->GetPendingResults().size()); // Make sure all the three partial metadata are received before the // captured result is submitted. EXPECT_EQ( - 3u, test->GetPartialResults()[0].partial_metadata_received.size()); + 3u, test->GetPendingResults()[0].partial_metadata_received.size()); test->QuitCaptureLoop(); }, base::Unretained(this))); EXPECT_CALL( *GetMockCaptureInterface(), - DoRegisterBuffer(0, cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, - _, _, _, _, _)) + DoRegisterBuffer( + StreamBufferManager::GetBufferIpcId(StreamType::kPreview, 0), + cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, _, _, _, _, _)) .Times(AtLeast(1)) .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer)); EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _)) @@ -293,20 +355,19 @@ mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult( request->frame_number, cros::mojom::CameraMetadata::New(), 1, std::move(request->output_buffers))); - mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult( request->frame_number, cros::mojom::CameraMetadata::New(), 2, std::vector<cros::mojom::Camera3StreamBufferPtr>())); - mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult( request->frame_number, cros::mojom::CameraMetadata::New(), 3, std::vector<cros::mojom::Camera3StreamBufferPtr>())); })); - stream_buffer_manager_->SetUpStreamAndBuffers( - kDefaultCaptureFormat, /* partial_result_count */ 3, + stream_buffer_manager_->SetUpStreamsAndBuffers( + kDefaultCaptureFormat, + GetFakeStaticMetadata(/* partial_result_count */ 3), PrepareCaptureStream(/* max_buffers */ 1)); - stream_buffer_manager_->StartCapture(cros::mojom::CameraMetadata::New()); + stream_buffer_manager_->StartPreview(cros::mojom::CameraMetadata::New()); // Wait until a captured frame is received by MockVideoCaptureClient. DoLoop(); @@ -327,8 +388,9 @@ InvokeWithoutArgs(this, &StreamBufferManagerTest::QuitCaptureLoop)); EXPECT_CALL( *GetMockCaptureInterface(), - DoRegisterBuffer(0, cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, - _, _, _, _, _)) + DoRegisterBuffer( + StreamBufferManager::GetBufferIpcId(StreamType::kPreview, 0), + cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, _, _, _, _, _)) .Times(1) .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer)); EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _)) @@ -341,10 +403,11 @@ cros::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_DEVICE)); })); - stream_buffer_manager_->SetUpStreamAndBuffers( - kDefaultCaptureFormat, /* partial_result_count */ 1, + stream_buffer_manager_->SetUpStreamsAndBuffers( + kDefaultCaptureFormat, + GetFakeStaticMetadata(/* partial_result_count */ 1), PrepareCaptureStream(/* max_buffers */ 1)); - stream_buffer_manager_->StartCapture(cros::mojom::CameraMetadata::New()); + stream_buffer_manager_->StartPreview(cros::mojom::CameraMetadata::New()); // Wait until the MockVideoCaptureClient is deleted. DoLoop(); @@ -357,17 +420,18 @@ [](StreamBufferManagerTest* test) { // Frame 0 should be dropped, and the frame callback should be called // with frame 1. - EXPECT_EQ(test->GetPartialResults().end(), - test->GetPartialResults().find(0)); - EXPECT_NE(test->GetPartialResults().end(), - test->GetPartialResults().find(1)); + EXPECT_EQ(test->GetPendingResults().end(), + test->GetPendingResults().find(0)); + EXPECT_NE(test->GetPendingResults().end(), + test->GetPendingResults().find(1)); test->QuitCaptureLoop(); }, base::Unretained(this))); EXPECT_CALL( *GetMockCaptureInterface(), - DoRegisterBuffer(0, cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, - _, _, _, _, _)) + DoRegisterBuffer( + StreamBufferManager::GetBufferIpcId(StreamType::kPreview, 0), + cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, _, _, _, _, _)) .Times(AtLeast(2)) .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer)) .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer)); @@ -387,10 +451,11 @@ })) .WillOnce(Invoke(this, &StreamBufferManagerTest::ProcessCaptureRequest)); - stream_buffer_manager_->SetUpStreamAndBuffers( - kDefaultCaptureFormat, /* partial_result_count */ 1, + stream_buffer_manager_->SetUpStreamsAndBuffers( + kDefaultCaptureFormat, + GetFakeStaticMetadata(/* partial_result_count */ 1), PrepareCaptureStream(/* max_buffers */ 1)); - stream_buffer_manager_->StartCapture(cros::mojom::CameraMetadata::New()); + stream_buffer_manager_->StartPreview(cros::mojom::CameraMetadata::New()); // Wait until the MockVideoCaptureClient is deleted. DoLoop(); @@ -402,19 +467,20 @@ GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce( [](StreamBufferManagerTest* test) { // Frame 0 should be submitted. - EXPECT_NE(test->GetPartialResults().end(), - test->GetPartialResults().find(0)); + EXPECT_NE(test->GetPendingResults().end(), + test->GetPendingResults().find(0)); test->QuitCaptureLoop(); }, base::Unretained(this))); EXPECT_CALL( *GetMockCaptureInterface(), - DoRegisterBuffer(0, cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, - _, _, _, _, _)) + DoRegisterBuffer( + StreamBufferManager::GetBufferIpcId(StreamType::kPreview, 0), + cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, _, _, _, _, _)) .Times(AtLeast(1)) - .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer)); + .WillRepeatedly(Invoke(this, &StreamBufferManagerTest::RegisterBuffer)); EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _)) - .Times(1) + .Times(AtLeast(1)) .WillOnce(Invoke([this](cros::mojom::Camera3CaptureRequestPtr& request, base::OnceCallback<void(int32_t)>& callback) { std::move(callback).Run(0); @@ -432,10 +498,11 @@ })) .WillOnce(Invoke(this, &StreamBufferManagerTest::ProcessCaptureRequest)); - stream_buffer_manager_->SetUpStreamAndBuffers( - kDefaultCaptureFormat, /* partial_result_count */ 2, + stream_buffer_manager_->SetUpStreamsAndBuffers( + kDefaultCaptureFormat, + GetFakeStaticMetadata(/* partial_result_count */ 2), PrepareCaptureStream(/* max_buffers */ 1)); - stream_buffer_manager_->StartCapture(cros::mojom::CameraMetadata::New()); + stream_buffer_manager_->StartPreview(cros::mojom::CameraMetadata::New()); // Wait until the MockVideoCaptureClient is deleted. DoLoop(); @@ -448,17 +515,18 @@ [](StreamBufferManagerTest* test) { // Frame 0 should be dropped, and the frame callback should be called // with frame 1. - EXPECT_EQ(test->GetPartialResults().end(), - test->GetPartialResults().find(0)); - EXPECT_NE(test->GetPartialResults().end(), - test->GetPartialResults().find(1)); + EXPECT_EQ(test->GetPendingResults().end(), + test->GetPendingResults().find(0)); + EXPECT_NE(test->GetPendingResults().end(), + test->GetPendingResults().find(1)); test->QuitCaptureLoop(); }, base::Unretained(this))); EXPECT_CALL( *GetMockCaptureInterface(), - DoRegisterBuffer(0, cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, - _, _, _, _, _)) + DoRegisterBuffer( + StreamBufferManager::GetBufferIpcId(StreamType::kPreview, 0), + cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, _, _, _, _, _)) .Times(AtLeast(2)) .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer)) .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer)); @@ -480,13 +548,50 @@ })) .WillOnce(Invoke(this, &StreamBufferManagerTest::ProcessCaptureRequest)); - stream_buffer_manager_->SetUpStreamAndBuffers( - kDefaultCaptureFormat, /* partial_result_count */ 1, + stream_buffer_manager_->SetUpStreamsAndBuffers( + kDefaultCaptureFormat, + GetFakeStaticMetadata(/* partial_result_count */ 1), PrepareCaptureStream(/* max_buffers */ 1)); - stream_buffer_manager_->StartCapture(cros::mojom::CameraMetadata::New()); + stream_buffer_manager_->StartPreview(cros::mojom::CameraMetadata::New()); // Wait until the MockVideoCaptureClient is deleted. DoLoop(); } +// Test that preview and still capture buffers can be correctly submitted. +TEST_F(StreamBufferManagerTest, TakePhotoTest) { + EXPECT_CALL( + *GetMockCaptureInterface(), + DoRegisterBuffer( + StreamBufferManager::GetBufferIpcId(StreamType::kPreview, 0), + cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, _, _, _, _, _)) + .Times(AtLeast(1)) + .WillRepeatedly(Invoke(this, &StreamBufferManagerTest::RegisterBuffer)); + EXPECT_CALL( + *GetMockCaptureInterface(), + DoRegisterBuffer( + StreamBufferManager::GetBufferIpcId(StreamType::kStillCapture, 0), + cros::mojom::Camera3DeviceOps::BufferType::GRALLOC, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer)); + EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _)) + .Times(AtLeast(1)) + .WillRepeatedly( + Invoke(this, &StreamBufferManagerTest::ProcessCaptureRequest)); + + stream_buffer_manager_->SetUpStreamsAndBuffers( + kDefaultCaptureFormat, + GetFakeStaticMetadata(/* partial_result_count */ 1), + PrepareCaptureStream(/* max_buffers */ 1)); + stream_buffer_manager_->StartPreview(cros::mojom::CameraMetadata::New()); + stream_buffer_manager_->TakePhoto( + GetFakeStaticMetadata(/* partial_result_count */ 1), + base::BindOnce([](StreamBufferManagerTest* test, + mojom::BlobPtr blob) { test->QuitCaptureLoop(); }, + base::Unretained(this))); + + // Wait until a captured frame is received by MockVideoCaptureClient. + DoLoop(); +} + } // namespace media
diff --git a/media/capture/video/mock_gpu_memory_buffer_manager.cc b/media/capture/video/mock_gpu_memory_buffer_manager.cc index 3a37cfc..e69e1150 100644 --- a/media/capture/video/mock_gpu_memory_buffer_manager.cc +++ b/media/capture/video/mock_gpu_memory_buffer_manager.cc
@@ -6,6 +6,10 @@ #include <memory> +#if defined(OS_CHROMEOS) +#include "media/capture/video/chromeos/stream_buffer_manager.h" +#endif + using ::testing::Return; namespace media { @@ -17,8 +21,9 @@ public: FakeGpuMemoryBuffer(const gfx::Size& size, gfx::BufferFormat format) : size_(size), format_(format) { - // We use only NV12 in unit tests. - EXPECT_EQ(gfx::BufferFormat::YUV_420_BIPLANAR, format); + // We use only NV12 or R8 in unit tests. + EXPECT_TRUE(format == gfx::BufferFormat::YUV_420_BIPLANAR || + format == gfx::BufferFormat::R_8); size_t y_plane_size = size_.width() * size_.height(); size_t uv_plane_size = size_.width() * size_.height() / 2; @@ -36,6 +41,13 @@ handle_.native_pixmap_handle.planes.push_back(gfx::NativePixmapPlane( size_.width(), handle_.native_pixmap_handle.planes[0].size, uv_plane_size)); + + // For faking a valid JPEG blob buffer. + Camera3JpegBlob* header = reinterpret_cast<Camera3JpegBlob*>( + reinterpret_cast<uintptr_t>(data_.data()) + size_.width() - + sizeof(Camera3JpegBlob)); + header->jpeg_blob_id = kCamera3JpegBlobId; + header->jpeg_size = size_.width(); #endif }
diff --git a/media/capture/video/video_capture_device_unittest.cc b/media/capture/video/video_capture_device_unittest.cc index a390e052..2114368 100644 --- a/media/capture/video/video_capture_device_unittest.cc +++ b/media/capture/video/video_capture_device_unittest.cc
@@ -664,13 +664,6 @@ if (!descriptor) return; -#if defined(OS_CHROMEOS) - // TODO(jcliang): Remove this after we implement TakePhoto. - if (VideoCaptureDeviceFactoryChromeOS::ShouldEnable()) { - return; - } -#endif - #if defined(OS_ANDROID) // TODO(mcasas): fails on Lollipop devices, reconnect https://crbug.com/646840 if (base::android::BuildInfo::GetInstance()->sdk_int() < @@ -713,13 +706,6 @@ if (!descriptor) return; -#if defined(OS_CHROMEOS) - // TODO(jcliang): Remove this after we implement GetPhotoCapabilities. - if (VideoCaptureDeviceFactoryChromeOS::ShouldEnable()) { - return; - } -#endif - #if defined(OS_ANDROID) // TODO(mcasas): fails on Lollipop devices, reconnect https://crbug.com/646840 if (base::android::BuildInfo::GetInstance()->sdk_int() < @@ -745,6 +731,9 @@ base::BindOnce(&MockImageCaptureClient::DoOnGetPhotoState, image_capture_client_); + // On Chrome OS AllocateAndStart() is asynchronous, so wait until we get the + // first frame. + WaitForCapturedFrame(); base::RunLoop run_loop; base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure()); EXPECT_CALL(*image_capture_client_.get(), OnCorrectGetPhotoState())
diff --git a/services/identity/public/cpp/DEPS b/services/identity/public/cpp/DEPS index b596ac3ee..81ceb59 100644 --- a/services/identity/public/cpp/DEPS +++ b/services/identity/public/cpp/DEPS
@@ -2,6 +2,7 @@ "+components/prefs/testing_pref_service.h", "+components/signin/core/browser/account_info.h", "+components/signin/core/browser/profile_management_switches.h", + "+google_apis/gaia/gaia_auth_util.h", "+google_apis/gaia/google_service_auth_error.h", "+google_apis/gaia/oauth2_token_service.h", ]
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc index d84ef79d..9512f72 100644 --- a/services/identity/public/cpp/identity_manager.cc +++ b/services/identity/public/cpp/identity_manager.cc
@@ -4,6 +4,7 @@ #include "services/identity/public/cpp/identity_manager.h" #include "base/threading/sequenced_task_runner_handle.h" +#include "google_apis/gaia/gaia_auth_util.h" namespace identity { @@ -43,7 +44,7 @@ // document the API to use here. DCHECK_EQ(signin_manager_->GetAuthenticatedAccountId(), primary_account_info_.account_id); -#if DCHECK_IS_ON() + // Note: If the primary account's refresh token gets revoked, then the account // gets removed from AccountTrackerService (via // AccountFetcherService::OnRefreshTokenRevoked), and so SigninManager's @@ -54,10 +55,23 @@ primary_account_info_.account_id); DCHECK_EQ(signin_manager_->GetAuthenticatedAccountInfo().gaia, primary_account_info_.gaia); - DCHECK_EQ(signin_manager_->GetAuthenticatedAccountInfo().email, - primary_account_info_.email); + + // TODO(842670): As described in the bug, AccountTrackerService's email + // address can be updated after it is initially set on ChromeOS. Figure out + // right long-term solution for this problem. + if (signin_manager_->GetAuthenticatedAccountInfo().email != + primary_account_info_.email) { + // This update should only be to move it from normalized form to the form + // in which the user entered the email when creating the account. The + // below check verifies that the normalized forms of the two email + // addresses are identical. + DCHECK(gaia::AreEmailsSame( + signin_manager_->GetAuthenticatedAccountInfo().email, + primary_account_info_.email)); + primary_account_info_.email = + signin_manager_->GetAuthenticatedAccountInfo().email; + } } -#endif // DCHECK_IS_ON() #endif // defined(OS_CHROMEOS) return primary_account_info_; }
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc index caa51353..0617583 100644 --- a/services/identity/public/cpp/identity_manager_unittest.cc +++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -24,7 +24,11 @@ #endif // OS_CHROMEOS const char kTestGaiaId[] = "dummyId"; -const char kTestEmail[] = "me@dummy.com"; +const char kTestEmail[] = "me@gmail.com"; + +#if defined(OS_CHROMEOS) +const char kTestEmailWithPeriod[] = "m.e@gmail.com"; +#endif // Subclass of FakeProfileOAuth2TokenService with bespoke behavior. class CustomFakeProfileOAuth2TokenService @@ -61,6 +65,14 @@ base::OnceClosure on_access_token_invalidated_callback_; }; +class AccountTrackerServiceForTest : public AccountTrackerService { + public: + void SetAccountStateFromUserInfo(const std::string& account_id, + const base::DictionaryValue* user_info) { + AccountTrackerService::SetAccountStateFromUserInfo(account_id, user_info); + } +}; + class TestSigninManagerObserver : public SigninManagerBase::Observer { public: explicit TestSigninManagerObserver(SigninManagerBase* signin_manager) @@ -241,7 +253,7 @@ identity_manager_diagnostics_observer() { return identity_manager_diagnostics_observer_.get(); } - AccountTrackerService* account_tracker() { return &account_tracker_; } + AccountTrackerServiceForTest* account_tracker() { return &account_tracker_; } SigninManagerForTest* signin_manager() { return &signin_manager_; } CustomFakeProfileOAuth2TokenService* token_service() { return &token_service_; @@ -268,7 +280,7 @@ private: base::MessageLoop message_loop_; sync_preferences::TestingPrefServiceSyncable pref_service_; - AccountTrackerService account_tracker_; + AccountTrackerServiceForTest account_tracker_; TestSigninClient signin_client_; SigninManagerForTest signin_manager_; CustomFakeProfileOAuth2TokenService token_service_; @@ -474,4 +486,34 @@ } #endif +#if defined(OS_CHROMEOS) +// On ChromeOS, AccountTrackerService first receives the normalized email +// address from GAIA and then later has it updated with the user's +// originally-specified version of their email address (at the time of that +// address' creation). This latter will differ if the user's originally- +// specified address was not in normalized form (e.g., if it contained +// periods). This test simulates such a flow in order to verify that +// IdentityManager correctly reflects the updated version. See crbug.com/842041 +// and crbug.com/842670 for further details. +TEST_F(IdentityManagerTest, IdentityManagerReflectsUpdatedEmailAddress) { + AccountInfo primary_account_info = + identity_manager()->GetPrimaryAccountInfo(); + EXPECT_EQ(kTestGaiaId, primary_account_info.gaia); + EXPECT_EQ(kTestEmail, primary_account_info.email); + + // Simulate the flow wherein the user's email address was updated + // to the originally-created non-normalized version. + base::DictionaryValue user_info; + user_info.SetString("id", kTestGaiaId); + user_info.SetString("email", kTestEmailWithPeriod); + account_tracker()->SetAccountStateFromUserInfo( + primary_account_info.account_id, &user_info); + + // Verify that IdentityManager reflects the update. + primary_account_info = identity_manager()->GetPrimaryAccountInfo(); + EXPECT_EQ(kTestGaiaId, primary_account_info.gaia); + EXPECT_EQ(kTestEmailWithPeriod, primary_account_info.email); +} +#endif + } // namespace identity
diff --git a/services/service_manager/embedder/main.cc b/services/service_manager/embedder/main.cc index fdff39ef..a2208da 100644 --- a/services/service_manager/embedder/main.cc +++ b/services/service_manager/embedder/main.cc
@@ -449,13 +449,6 @@ case ProcessType::kEmbedder: if (delegate->IsEmbedderSubprocess()) CommonSubprocessInit(); - else { - // TODO(https://crbug.com/729596): Use this task runner to start - // ServiceManager. - scoped_refptr<base::SingleThreadTaskRunner> task_runner = - delegate->GetServiceManagerTaskRunnerForEmbedderProcess(); - } - exit_code = delegate->RunEmbedderProcess(); break; }
diff --git a/services/service_manager/embedder/main_delegate.cc b/services/service_manager/embedder/main_delegate.cc index aeef91e..11b7c3fa 100644 --- a/services/service_manager/embedder/main_delegate.cc +++ b/services/service_manager/embedder/main_delegate.cc
@@ -10,14 +10,6 @@ MainDelegate::~MainDelegate() = default; -scoped_refptr<base::SingleThreadTaskRunner> -MainDelegate::GetServiceManagerTaskRunnerForEmbedderProcess() { - // The default implementation is provided for compiling purpose on Windows and - // should never be called. - NOTREACHED(); - return nullptr; -} - bool MainDelegate::IsEmbedderSubprocess() { return false; }
diff --git a/services/service_manager/embedder/main_delegate.h b/services/service_manager/embedder/main_delegate.h index 33b1b47..0c6d11a 100644 --- a/services/service_manager/embedder/main_delegate.h +++ b/services/service_manager/embedder/main_delegate.h
@@ -8,8 +8,6 @@ #include <memory> #include "base/callback_forward.h" -#include "base/memory/scoped_refptr.h" -#include "base/single_thread_task_runner.h" #include "mojo/edk/embedder/configuration.h" #include "services/service_manager/background/background_service_manager.h" #include "services/service_manager/embedder/process_type.h" @@ -49,11 +47,6 @@ // failure. virtual int Initialize(const InitializeParams& params) = 0; - // Creates an thread and returns the SingleThreadTaskRunner on which - // ServiceManager should run. - virtual scoped_refptr<base::SingleThreadTaskRunner> - GetServiceManagerTaskRunnerForEmbedderProcess(); - // Indicates whether this (embedder) process should be treated as a subprocess // for the sake of some platform-specific environment initialization details. virtual bool IsEmbedderSubprocess();
diff --git a/services/ui/public/cpp/gpu/context_provider_command_buffer.cc b/services/ui/public/cpp/gpu/context_provider_command_buffer.cc index 312df8f..d71d2b6e 100644 --- a/services/ui/public/cpp/gpu/context_provider_command_buffer.cc +++ b/services/ui/public/cpp/gpu/context_provider_command_buffer.cc
@@ -268,6 +268,13 @@ return bind_result_; } + std::string type_name = + command_buffer_metrics::ContextTypeToString(context_type_); + std::string unique_context_name = + base::StringPrintf("%s-%p", type_name.c_str(), raster_impl.get()); + raster_impl->TraceBeginCHROMIUM("gpu_toplevel", + unique_context_name.c_str()); + impl_ = raster_impl.get(); raster_interface_ = std::move(raster_impl); helper_ = std::move(raster_helper);
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG index ca76fcf0..be47b65 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -19,7 +19,6 @@ # TODO(skobes): rebaseline crbug.com/811429 fast/text/font-format-support-cbdt-sbix-cff2-vertical.html [ Failure ] -crbug.com/811429 inspector-protocol/layout-fonts/cross-platform-cbdt-sbix-cff2.js [ Failure Pass ] # Crashes/asserts/failures due to inline item reuse. crbug.com/636993 accessibility/removed-continuation-element-causes-crash.html [ Crash ] @@ -104,9 +103,9 @@ crbug.com/591099 animations/animation-ready-reject-script-forbidden.html [ Timeout ] crbug.com/591099 animations/cross-fade-list-style-image.html [ Failure ] crbug.com/591099 animations/interpolation/backdrop-filter-interpolation.html [ Timeout ] -crbug.com/591099 animations/interpolation/line-height-interpolation.html [ Pass Timeout ] +crbug.com/591099 animations/interpolation/line-height-interpolation.html [ Timeout ] crbug.com/591099 animations/interpolation/svg-stroke-dasharray-interpolation.html [ Timeout ] -crbug.com/591099 animations/interpolation/webkit-clip-path-interpolation.html [ Pass Timeout ] +crbug.com/591099 animations/interpolation/webkit-clip-path-interpolation.html [ Timeout ] crbug.com/591099 animations/rotate-transform-equivalent.html [ Failure ] crbug.com/714962 compositing/background-color/view-blending-base-background.html [ Failure ] crbug.com/591099 compositing/draws-content/canvas-background-layer.html [ Failure ] @@ -230,14 +229,8 @@ crbug.com/714962 external/wpt/WebCryptoAPI/import_export/test_rsa_importKey.https.html [ Pass Timeout ] crbug.com/591099 external/wpt/acid/acid3/numbered-tests.html [ Crash ] crbug.com/591099 external/wpt/acid/acid3/test.html [ Crash ] -crbug.com/591099 external/wpt/console/console-counting-label-conversion.any.html [ Pass ] -crbug.com/591099 external/wpt/console/console-counting-label-conversion.any.worker.html [ Pass ] -crbug.com/591099 external/wpt/content-security-policy/navigate-to/meta-refresh-redirected-blocked.sub.html [ Failure Pass Timeout ] -crbug.com/591099 external/wpt/content-security-policy/reporting/report-original-url.sub.html [ Pass Timeout ] -crbug.com/591099 external/wpt/cookies/samesite/iframe.html [ Failure Pass ] crbug.com/591099 external/wpt/credential-management/federatedcredential-framed-get.sub.https.html [ Pass ] crbug.com/591099 external/wpt/credential-management/passwordcredential-framed-get.sub.https.html [ Pass ] -crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-top-below-bfc-001r.xht [ Failure Pass ] crbug.com/714962 external/wpt/css/CSS2/linebox/vertical-align-baseline-005a.xht [ Failure ] crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-insert-001e.xht [ Pass ] crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-insert-001h.xht [ Pass ] @@ -245,51 +238,35 @@ crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-nested-002.xht [ Pass ] crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-remove-006.xht [ Pass ] crbug.com/591099 external/wpt/css/CSS2/normal-flow/root-box-001.xht [ Failure ] -crbug.com/591099 external/wpt/css/CSS2/text/white-space-collapsing-bidi-001.xht [ Pass ] crbug.com/591099 external/wpt/css/CSS2/text/white-space-mixed-003.xht [ Pass ] crbug.com/714962 external/wpt/css/css-backgrounds/background-attachment-local/attachment-local-clipping-color-5.html [ Failure ] crbug.com/714962 external/wpt/css/css-backgrounds/background-attachment-local/attachment-local-clipping-image-5.html [ Failure ] crbug.com/591099 external/wpt/css/css-backgrounds/box-shadow-syntax-001.xht [ Failure ] -crbug.com/591099 external/wpt/css/css-color/t425-hsla-onscreen-b.xht [ Pass ] crbug.com/591099 external/wpt/css/css-display/display-contents-details.html [ Crash ] -crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-list-001-inline.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-list-001-inline.html [ Failure ] crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-list-001-none.html [ Failure ] crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-table-001-inline.html [ Failure ] crbug.com/591099 external/wpt/css/css-display/display-contents-list-001.html [ Failure ] crbug.com/591099 external/wpt/css/css-filter/filtered-block-is-container.html [ Pass ] -crbug.com/591099 external/wpt/css/css-filter/filtered-inline-is-container.html [ Crash Pass ] -crbug.com/591099 external/wpt/css/css-flexbox/flex-minimum-height-flex-items-008.xht [ Pass ] +crbug.com/591099 external/wpt/css/css-filter/filtered-inline-is-container.html [ Crash ] crbug.com/591099 external/wpt/css/css-flexbox/percentage-heights-001.html [ Failure ] crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-1.html [ Pass ] crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-3.html [ Pass ] -crbug.com/591099 external/wpt/css/css-fonts/font-variant-05.xht [ Pass ] -crbug.com/591099 external/wpt/css/css-fonts/font-variant-alternates-14.html [ Pass ] -crbug.com/591099 external/wpt/css/css-fonts/font-variant-alternates-16.html [ Pass ] crbug.com/591099 external/wpt/css/css-fonts/font-variant-ligatures-11.html [ Pass ] crbug.com/591099 external/wpt/css/css-fonts/matching/fixed-stretch-style-over-weight.html [ Pass ] crbug.com/591099 external/wpt/css/css-fonts/matching/stretch-distance-over-weight-distance.html [ Pass ] crbug.com/591099 external/wpt/css/css-fonts/matching/style-ranges-over-weight-direction.html [ Pass ] crbug.com/591099 external/wpt/css/css-fonts/test_font_family_parsing.html [ Timeout ] -crbug.com/591099 external/wpt/css/css-fonts/variations/at-font-face-descriptors.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-fonts/variations/font-parse-numeric-stretch-style-weight.html [ Failure Pass ] crbug.com/591099 external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-009.html [ Failure ] crbug.com/591099 external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-010.html [ Failure ] crbug.com/591099 external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-011.html [ Failure ] crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-007.html [ Failure ] crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-008.html [ Failure ] -crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-009.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-009.html [ Failure ] +crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html [ Failure ] crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-011.html [ Failure ] crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-012.html [ Failure ] -crbug.com/591099 external/wpt/css/css-layout-api/fallback-layout-invalid-fragment.https.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-layout-api/layout-child-text.https.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-paint-api/geometry-border-image-001.https.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-paint-api/parse-input-arguments-009.https.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-paint-api/parse-input-arguments-019.https.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-paint-api/style-before-pseudo.https.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-position/position-relative-table-thead-left-absolute-child.html [ Pass ] crbug.com/591099 external/wpt/css/css-position/position-sticky-writing-modes.html [ Failure ] -crbug.com/591099 external/wpt/css/css-pseudo/first-letter-001.html [ Pass ] crbug.com/591099 external/wpt/css/css-rhythm/ [ Skip ] crbug.com/591099 external/wpt/css/css-scroll-anchoring/clipped-scrollers-skipped.html [ Failure ] crbug.com/591099 external/wpt/css/css-scroll-anchoring/opt-out.html [ Failure ] @@ -298,15 +275,14 @@ crbug.com/714962 external/wpt/css/css-scroll-anchoring/wrapped-text.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-002.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-003.html [ Failure ] -crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-004.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-004.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-006.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-007.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-008.html [ Failure ] -crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-001.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-001.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-002.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-003.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-004.html [ Failure ] -crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-016.html [ Pass ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-radial-gradient-001.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-radial-gradient-002.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-radial-gradient-003.html [ Failure ] @@ -326,7 +302,7 @@ crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-014.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-015.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-016.html [ Failure ] -crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-017.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-017.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-018.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-019.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-020.html [ Failure ] @@ -338,7 +314,7 @@ crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-013.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-014.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-015.html [ Failure ] -crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-016.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-016.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-017.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-018.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-019.html [ Failure ] @@ -357,9 +333,9 @@ crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-014.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-015.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-016.html [ Failure ] -crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-017.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-017.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-018.html [ Failure ] -crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-019.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-019.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-020.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-021.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-022.html [ Failure ] @@ -383,23 +359,21 @@ crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-010.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-011.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-012.html [ Failure ] -crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-013.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-013.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-014.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-015.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-016.html [ Failure ] -crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-017.html [ Pass ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/values/shape-margin-001.html [ Pass ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-004.html [ Timeout ] -crbug.com/591099 external/wpt/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000.html [ Failure Pass ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-004.html [ Timeout ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/values/shape-outside-inset-003.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/shape-outside/values/shape-outside-shape-arguments-000.html [ Pass ] -crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-001.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-001.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-002.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-003.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-004.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-005.html [ Failure ] -crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-006.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-006.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-007.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-008.html [ Failure ] crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-010.html [ Failure ] @@ -414,7 +388,6 @@ crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-019.html [ Failure ] crbug.com/591099 external/wpt/css/css-sizing/intrinsic-percent-non-replaced-001.html [ Failure ] crbug.com/591099 external/wpt/css/css-sizing/intrinsic-percent-non-replaced-003.html [ Failure ] -crbug.com/591099 external/wpt/css/css-tables/fixup-dynamic-anonymous-inline-table-001.html [ Pass ] crbug.com/591099 external/wpt/css/css-tables/height-distribution/percentage-sizing-of-table-cell-children.html [ Failure ] crbug.com/591099 external/wpt/css/css-tables/table-model-fixup-2.html [ Failure ] crbug.com/591099 external/wpt/css/css-tables/width-distribution/td-with-subpixel-padding-vertical-rl.html [ Failure ] @@ -425,12 +398,12 @@ crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-above-right-002.xht [ Failure ] crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-below-left-001.xht [ Failure ] crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-below-left-002.xht [ Failure ] -crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-below-right-001.xht [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-below-right-001.xht [ Failure ] crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-below-right-002.xht [ Failure ] crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-002.html [ Failure ] crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-006.html [ Failure ] crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-007.html [ Failure ] -crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-008.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-008.html [ Failure ] crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-010.html [ Failure ] crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-012.html [ Failure ] crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-021.html [ Failure ] @@ -442,7 +415,6 @@ crbug.com/591099 external/wpt/css/css-text/i18n/css3-text-line-break-jazh-142.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/i18n/css3-text-line-break-opclns-255.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/i18n/css3-text-line-break-opclns-259.html [ Pass ] -crbug.com/591099 external/wpt/css/css-text/letter-spacing/letter-spacing-control-chars-001.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-009.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-011.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-ic-002.html [ Pass ] @@ -452,30 +424,10 @@ crbug.com/591099 external/wpt/css/css-text/white-space/seg-break-transformation-011.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/white-space/seg-break-transformation-012.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/word-break/word-break-break-all-004.html [ Pass ] -crbug.com/591099 external/wpt/css/css-text/word-break/word-break-normal-lo-000.html [ Pass ] -crbug.com/714962 external/wpt/css/css-transforms/transform-abspos-006.html [ Failure Pass ] +crbug.com/714962 external/wpt/css/css-transforms/transform-abspos-006.html [ Failure ] crbug.com/714962 external/wpt/css/css-transforms/transform-abspos-007.html [ Failure ] -crbug.com/591099 external/wpt/css/css-transforms/transform-origin-001.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-transforms/transform-rotate-002.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-transforms/transform-table-005.html [ Failure Pass ] crbug.com/591099 external/wpt/css/css-transforms/transform-transformed-tr-percent-height-child.html [ Failure ] -crbug.com/591099 external/wpt/css/css-transforms/transform3d-matrix3d-002.html [ Failure Pass ] crbug.com/591099 external/wpt/css/css-transforms/transform3d-perspective-008.html [ Pass ] -crbug.com/591099 external/wpt/css/css-transforms/transform3d-translate3d-001.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-transitions/before-load-001.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-typed-om/interfaces.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/border-radius.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/font-stretch.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/line-break.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/line-height.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/page.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/perspective.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/text-decoration-skip.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/word-wrap.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/z-index.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-ui/box-sizing-025.html [ Pass ] -crbug.com/591099 external/wpt/css/css-ui/outline-006.html [ Pass ] -crbug.com/591099 external/wpt/css/css-ui/outline-016.html [ Pass ] crbug.com/591099 external/wpt/css/css-ui/text-overflow-010.html [ Pass ] crbug.com/591099 external/wpt/css/css-ui/text-overflow-015.html [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-icb-vlr-003.xht [ Pass ] @@ -561,7 +513,7 @@ crbug.com/591099 external/wpt/css/css-writing-modes/baseline-inline-non-replaced-004.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/block-flow-direction-vrl-009.xht [ Pass ] crbug.com/591099 external/wpt/css/css-writing-modes/block-flow-direction-vrl-026.xht [ Failure ] -crbug.com/591099 external/wpt/css/css-writing-modes/clearance-calculations-vrl-002.xht [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-writing-modes/clearance-calculations-vrl-002.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/clearance-calculations-vrl-004.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/clearance-calculations-vrl-006.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-002.xht [ Failure ] @@ -569,7 +521,7 @@ crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-006.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-008.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/float-vlr-013.xht [ Failure ] -crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-002.xht [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-002.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-004.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-006.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-010.xht [ Failure ] @@ -612,15 +564,13 @@ crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-003.xht [ Failure ] crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-004.xht [ Failure ] crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-007.xht [ Failure ] -crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-008.xht [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-004.xht [ Pass ] +crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-008.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-013.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/text-baseline-vlr-007.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/text-baseline-vrl-006.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/text-combine-upright-decorations-001.html [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/text-combine-upright-layout-rules-001.html [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/text-orientation-016.xht [ Failure ] -crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-003.xht [ Pass ] crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-005.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-007.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-vlr-023.xht [ Failure ] @@ -630,38 +580,27 @@ crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-vrl-024.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-vrl-026.xht [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/wm-propagation-body-006.xht [ Failure ] -crbug.com/591099 external/wpt/css/cssom-view/window-interface.xht [ Failure Pass ] crbug.com/591099 external/wpt/css/cssom/interfaces.html [ Pass Timeout ] crbug.com/591099 external/wpt/css/geometry/interfaces.worker.html [ Pass ] crbug.com/591099 external/wpt/css/selectors/focus-within-004.html [ Pass ] -crbug.com/591099 external/wpt/css/selectors/selector-required-type-change-002.html [ Pass ] -crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/dependent-builtin.html [ Pass ] -crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/system-symbolic.html [ Pass ] -crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-content-horiz-001b.xhtml [ Pass ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-content-vert-001a.xhtml [ Failure ] -crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-item-vert-001b.html [ Pass ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-002.html [ Failure ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-004.html [ Failure ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-003v.html [ Pass ] -crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-005.html [ Pass ] -crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-justify-content-horiz-005.xhtml [ Pass ] -crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-min-height-auto-002c.html [ Pass ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-011.html [ Failure ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-012.html [ Failure ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-014.html [ Failure ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-015.html [ Failure ] -crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ib-split/emptyspan-4.html [ Pass ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ib-split/remove-from-split-inline-6.html [ Pass ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ib-split/split-inner-inline-2.html [ Pass ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-break-inside-001.html [ Failure ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-007.html [ Failure ] crbug.com/591099 external/wpt/dom/nodes/Element-classlist.html [ Timeout ] -crbug.com/591099 external/wpt/dom/nodes/Element-insertAdjacentText.html [ Failure Pass ] crbug.com/591099 external/wpt/dom/nodes/Element-matches.html [ Timeout ] crbug.com/591099 external/wpt/dom/nodes/Element-webkitMatchesSelector.html [ Timeout ] crbug.com/591099 external/wpt/dom/nodes/Node-compareDocumentPosition.html [ Timeout ] crbug.com/591099 external/wpt/dom/nodes/Node-contains.html [ Timeout ] -crbug.com/591099 external/wpt/dom/nodes/ParentNode-querySelector-All-xht.xht [ Failure Timeout ] +crbug.com/591099 external/wpt/dom/nodes/ParentNode-querySelector-All-xht.xht [ Timeout ] crbug.com/591099 external/wpt/dom/nodes/ParentNode-querySelector-All.html [ Timeout ] crbug.com/591099 external/wpt/dom/ranges/Range-compareBoundaryPoints.html [ Timeout ] crbug.com/591099 external/wpt/dom/ranges/Range-comparePoint.html [ Timeout ] @@ -689,7 +628,7 @@ crbug.com/591099 external/wpt/editing/run/inserttext.html [ Timeout ] crbug.com/591099 external/wpt/editing/run/insertunorderedlist.html [ Timeout ] crbug.com/591099 external/wpt/editing/run/italic.html [ Timeout ] -crbug.com/591099 external/wpt/editing/run/justifycenter.html [ Failure Timeout ] +crbug.com/591099 external/wpt/editing/run/justifycenter.html [ Timeout ] crbug.com/591099 external/wpt/editing/run/justifyfull.html [ Timeout ] crbug.com/591099 external/wpt/editing/run/justifyleft.html [ Timeout ] crbug.com/591099 external/wpt/editing/run/justifyright.html [ Timeout ] @@ -697,10 +636,9 @@ crbug.com/591099 external/wpt/editing/run/outdent.html [ Timeout ] crbug.com/591099 external/wpt/editing/run/removeformat.html [ Timeout ] crbug.com/591099 external/wpt/editing/run/strikethrough.html [ Timeout ] -crbug.com/591099 external/wpt/editing/run/subscript.html [ Failure Timeout ] -crbug.com/591099 external/wpt/editing/run/superscript.html [ Timeout ] +crbug.com/591099 external/wpt/editing/run/subscript.html [ Pass Timeout ] +crbug.com/591099 external/wpt/editing/run/superscript.html [ Pass Timeout ] crbug.com/591099 external/wpt/editing/run/underline.html [ Timeout ] -crbug.com/591099 external/wpt/editing/run/unlink.html [ Failure Pass ] crbug.com/591099 external/wpt/encoding/api-invalid-label.html [ Timeout ] crbug.com/591099 external/wpt/encoding/legacy-mb-japanese/euc-jp/eucjp-decode-cseucpkdfmtjapanese.html [ Timeout ] crbug.com/591099 external/wpt/encoding/legacy-mb-japanese/euc-jp/eucjp-decode-x-euc-jp.html [ Timeout ] @@ -794,25 +732,12 @@ crbug.com/591099 external/wpt/encoding/legacy-mb-tchinese/big5/big5-encode-href-errors-misc.html [ Timeout ] crbug.com/591099 external/wpt/encoding/legacy-mb-tchinese/big5/big5-encode-href.html [ Timeout ] crbug.com/591099 external/wpt/encoding/textdecoder-fatal-single-byte.html [ Timeout ] -crbug.com/591099 external/wpt/fetch/api/request/request-disturbed.html [ Failure Pass ] -crbug.com/591099 external/wpt/fetch/api/response/response-clone.html [ Failure Pass ] -crbug.com/591099 external/wpt/fetch/data-urls/processing.any.html [ Failure Pass ] -crbug.com/591099 external/wpt/fetch/http-cache/vary.html [ Failure Pass ] -crbug.com/591099 external/wpt/fullscreen/api/element-request-fullscreen-timing-manual.html [ Failure Pass ] -crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure ] -crbug.com/591099 external/wpt/graphics-aam/graphics-object_on_html_element-manual.html [ Failure Pass ] +crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure Pass ] crbug.com/591099 external/wpt/html-media-capture/capture_audio_cancel-manual.html [ Failure ] crbug.com/591099 external/wpt/html-media-capture/capture_image_cancel-manual.html [ Failure ] crbug.com/591099 external/wpt/html-media-capture/capture_video_cancel-manual.html [ Failure ] -crbug.com/591099 external/wpt/html/browsers/browsing-the-web/navigating-across-documents/javascript-url-abort/javascript-url-abort-return-value-string.tentative.html [ Failure Pass ] -crbug.com/591099 external/wpt/html/browsers/browsing-the-web/unloading-documents/003.html [ Failure Pass ] -crbug.com/591099 external/wpt/html/browsers/history/the-location-interface/location-stringifier.html [ Failure Pass ] -crbug.com/591099 external/wpt/html/browsers/the-window-object/garbage-collection-and-browsing-contexts/discard_iframe_history_2.html [ Failure Pass ] crbug.com/591099 external/wpt/html/browsers/windows/noreferrer-window-name.html [ Timeout ] crbug.com/591099 external/wpt/html/dom/documents/dom-tree-accessors/Document.currentScript.html [ Pass ] -crbug.com/591099 external/wpt/html/dom/dynamic-markup-insertion/document-write/write-active-document.html [ Failure Pass ] -crbug.com/591099 external/wpt/html/dom/dynamic-markup-insertion/opening-the-input-stream/008.html [ Failure Pass ] -crbug.com/591099 external/wpt/html/dom/dynamic-markup-insertion/opening-the-input-stream/015.html [ Failure Pass ] crbug.com/591099 external/wpt/html/dom/interfaces.https.html [ Timeout ] crbug.com/591099 external/wpt/html/editing/editing-0/autocapitalization/autocapitalize.html [ Pass Timeout ] crbug.com/591099 external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16be.html [ Timeout ] @@ -822,41 +747,26 @@ crbug.com/591099 external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/windows-1252.html [ Timeout ] crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/flow-content-0/dialog.html [ Failure ] crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-fieldset-element-0/legend-block-formatting-context.html [ Failure ] -crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-fieldset-element-0/legend.html [ Failure Pass ] crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-auto.html [ Failure ] crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-percentage.html [ Failure ] crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-inline-sizing/svg-inline.html [ Timeout ] crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-non-snap-to-lines.html [ Failure ] -crbug.com/591099 external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-load-event.html [ Failure Pass ] -crbug.com/591099 external/wpt/html/semantics/forms/autofocus/first-when-later-but-before.html [ Failure Pass ] crbug.com/591099 external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-menu.html [ Failure ] crbug.com/591099 external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-skip-no-boxes.html [ Failure ] crbug.com/591099 external/wpt/html/semantics/interactive-elements/the-dialog-element/abspos-dialog-layout.html [ Failure ] crbug.com/591099 external/wpt/html/semantics/interactive-elements/the-dialog-element/centering.html [ Crash ] -crbug.com/591099 external/wpt/html/semantics/scripting-1/the-script-element/fetch-src/failure.html [ Failure Pass ] -crbug.com/591099 external/wpt/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html [ Failure Pass ] -crbug.com/591099 external/wpt/html/semantics/selectors/pseudo-classes/dir.html [ Failure Pass ] -crbug.com/591099 external/wpt/html/semantics/selectors/pseudo-classes/enabled.html [ Failure Pass ] -crbug.com/591099 external/wpt/html/syntax/parsing/html5lib_innerHTML_adoption01.html [ Failure Pass ] -crbug.com/591099 external/wpt/html/syntax/parsing/html5lib_tests11.html?run_type=write [ Failure Pass ] -crbug.com/591099 external/wpt/html/syntax/parsing/html5lib_tests11.html?run_type=write_single [ Pass ] crbug.com/591099 external/wpt/html/syntax/parsing/named-character-references.html [ Timeout ] crbug.com/591099 external/wpt/html/the-xhtml-syntax/parsing-xhtml-documents/xhtml-mathml-dtd-entity-1.htm [ Pass Timeout ] crbug.com/591099 external/wpt/html/the-xhtml-syntax/parsing-xhtml-documents/xhtml-mathml-dtd-entity-4.htm [ Pass Timeout ] crbug.com/591099 external/wpt/html/the-xhtml-syntax/parsing-xhtml-documents/xhtml-mathml-dtd-entity-7.htm [ Pass Timeout ] -crbug.com/591099 external/wpt/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-2.html [ Failure Pass ] -crbug.com/591099 external/wpt/infrastructure/reftest/reftest.https.html [ Failure Pass ] crbug.com/591099 external/wpt/longtask-timing/longtask-in-sibling-iframe.html [ Pass Timeout ] -crbug.com/591099 external/wpt/media-source/mediasource-addsourcebuffer-mode.html [ Failure Pass ] crbug.com/591099 external/wpt/media-source/mediasource-getvideoplaybackquality.html [ Timeout ] crbug.com/591099 external/wpt/mimesniff/mime-types/parsing.any.html [ Timeout ] crbug.com/591099 external/wpt/mimesniff/mime-types/parsing.any.worker.html [ Timeout ] -crbug.com/591099 external/wpt/mixed-content/video-tag/no-opt-in/cross-origin-http/top-level/swap-scheme-redirect/optionally-blockable/no-opt-in-allows.https.html [ Failure Pass ] crbug.com/591099 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.pattern.basic.nocontext.worker.html [ Crash ] crbug.com/591099 external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.getcontext.worker.html [ Pass ] crbug.com/591099 external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html [ Pass ] crbug.com/591099 external/wpt/payment-request/payment-disabled-by-feature-policy.https.sub.html [ Pass ] -crbug.com/591099 external/wpt/pointerevents/extension/pointerevent_coalesced_events_attributes-manual.html [ Failure Pass ] crbug.com/591099 external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers-manual.html [ Timeout ] crbug.com/591099 external/wpt/pointerevents/pointerevent_click_during_capture-manual.html [ Crash Timeout ] crbug.com/591099 external/wpt/pointerevents/pointerevent_pointerleave_pen-manual.html [ Failure ] @@ -870,7 +780,6 @@ crbug.com/591099 external/wpt/requestidlecallback/callback-invoked.html [ Pass ] crbug.com/591099 external/wpt/requestidlecallback/cancel-invoked.html [ Pass ] crbug.com/591099 external/wpt/requestidlecallback/idlharness.html [ Pass ] -crbug.com/591099 external/wpt/secure-contexts/basic-shared-worker.html [ Failure Pass ] crbug.com/591099 external/wpt/selection/addRange-00.html [ Timeout ] crbug.com/591099 external/wpt/selection/addRange-04.html [ Timeout ] crbug.com/591099 external/wpt/selection/addRange-12.html [ Pass Timeout ] @@ -886,81 +795,39 @@ crbug.com/591099 external/wpt/selection/extend-00.html [ Timeout ] crbug.com/591099 external/wpt/selection/extend-20.html [ Timeout ] crbug.com/591099 external/wpt/selection/selectAllChildren.html [ Timeout ] -crbug.com/591099 external/wpt/server-timing/service_worker_idl.html [ Failure Pass ] -crbug.com/591099 external/wpt/service-workers/service-worker/svg-target-reftest.https.html [ Failure Pass ] crbug.com/591099 external/wpt/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html [ Failure ] -crbug.com/591099 external/wpt/shadow-dom/historical.html [ Failure Pass ] -crbug.com/591099 external/wpt/streams/readable-streams/constructor.dedicatedworker.html [ Failure Pass ] -crbug.com/591099 external/wpt/streams/writable-streams/constructor.html [ Failure Pass ] crbug.com/591099 external/wpt/svg/interfaces.html [ Timeout ] crbug.com/591099 external/wpt/svg/linking/reftests/href-filter-element.html [ Failure ] -crbug.com/591099 external/wpt/svg/path/bearing/relative.svg [ Pass ] -crbug.com/591099 external/wpt/svg/types/scripted/SVGLength-px.html [ Failure Pass ] crbug.com/591099 external/wpt/url/url-setters.html [ Pass Timeout ] -crbug.com/591099 external/wpt/vibration/silent-ignore.html [ Failure Pass ] crbug.com/591099 external/wpt/wasm/wasm_local_iframe_test.html [ Failure ] crbug.com/591099 external/wpt/web-animations/animation-model/animation-types/interpolation-per-property.html [ Timeout ] -crbug.com/591099 external/wpt/web-animations/interfaces/Animation/idlharness.html [ Failure Pass ] -crbug.com/591099 external/wpt/web-animations/interfaces/KeyframeEffect/constructor.html [ Failure Pass ] crbug.com/591099 external/wpt/webaudio/idlharness.https.html [ Timeout ] crbug.com/591099 external/wpt/webmessaging/broadcastchannel/sandbox.html [ Failure ] -crbug.com/591099 external/wpt/webrtc/RTCConfiguration-iceTransportPolicy.html [ Failure Pass ] -crbug.com/591099 external/wpt/webrtc/RTCPeerConnection-addIceCandidate.html [ Failure Pass ] -crbug.com/591099 external/wpt/webrtc/RTCPeerConnection-getDefaultIceServers.html [ Failure Pass ] -crbug.com/591099 external/wpt/webrtc/RTCPeerConnection-iceConnectionState.html [ Failure Pass ] -crbug.com/591099 external/wpt/webrtc/RTCRtpTransceiver-setDirection.html [ Failure Pass ] crbug.com/591099 external/wpt/webrtc/interfaces.html [ Pass Timeout ] crbug.com/591099 external/wpt/webrtc/protocol/video-codecs.html [ Failure ] -crbug.com/591099 external/wpt/websockets/Create-Secure-url-with-space.any.worker.html [ Failure Pass ] -crbug.com/591099 external/wpt/websockets/interfaces/WebSocket/close/close-connecting.html?wss [ Failure Pass ] crbug.com/591099 external/wpt/webstorage/storage_setitem.html [ Pass Timeout ] crbug.com/591099 external/wpt/webvr/idlharness.https.html [ Pass ] -crbug.com/591099 external/wpt/webvtt/api/VTTCue/constructor.html [ Failure Pass ] -crbug.com/591099 external/wpt/webvtt/parsing/file-parsing/tests/settings-line.html [ Failure Pass ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_completely_move_up.html [ Failure Pass ] +crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_completely_move_up.html [ Failure ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_partially_move_up.html [ Failure ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/align_middle.html [ Pass ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/bidi_ruby.html [ Failure ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/u002E_u2028_u05D0.html [ Pass ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/u06E9_no_strong_dir.html [ Pass ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/dom_override_cue_text.html [ Pass ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/9_cues_overlapping_completely.html [ Failure ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/9_cues_overlapping_completely_all_cues_have_same_timestamp.html [ Failure ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/line_0_is_top.html [ Pass ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/line_integer_and_percent_mixed_overlap.html [ Pass ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/color_hex.html [ Pass ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/font_properties.html [ Failure ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/font_shorthand.html [ Failure ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/text-decoration_overline.html [ Pass ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_font_properties.html [ Failure ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_font_shorthand.html [ Failure ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_white-space_nowrap.html [ Pass ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_font_properties.html [ Failure ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_font_shorthand.html [ Failure Pass ] +crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_font_shorthand.html [ Failure ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/font_properties.html [ Failure ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/font_shorthand.html [ Failure ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_font_properties.html [ Failure ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_font_shorthand.html [ Failure ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_text-decoration_line-through.html [ Pass ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/type_selector_root.html [ Pass ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_font_properties.html [ Failure ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_font_shorthand.html [ Failure ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_timestamp_past.html [ Pass ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_white-space_normal_wrapped.html [ Pass ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_animation_with_timestamp.html [ Pass ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_font_properties.html [ Failure Pass ] +crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_font_properties.html [ Failure ] crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_font_shorthand.html [ Failure ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/white-space_pre-line_wrapped.html [ Pass ] -crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/default_styles/underline_object_default_font-style.html [ Pass ] crbug.com/591099 external/wpt/workers/Worker_terminate_event_queue.htm [ Timeout ] -crbug.com/591099 external/wpt/workers/constructors/Worker/DedicatedWorkerGlobalScope-members.worker.html [ Failure Pass ] -crbug.com/591099 external/wpt/workers/interfaces/WorkerUtils/importScripts/002.worker.html [ Failure Pass ] -crbug.com/591099 external/wpt/workers/semantics/encodings/001.html [ Failure Pass ] -crbug.com/591099 external/wpt/xhr/overridemimetype-edge-cases.window.html [ Failure Pass ] -crbug.com/591099 external/wpt/xhr/send-authentication-cors-setrequestheader-no-cred.htm [ Failure Pass ] crbug.com/591099 external/wpt/xhr/send-authentication-prompt-2-manual.htm [ Failure ] -crbug.com/591099 external/wpt/xhr/send-content-type-charset.htm [ Failure Pass ] -crbug.com/591099 external/wpt/xhr/send-no-response-event-order.htm [ Failure Pass ] crbug.com/591099 fast/backgrounds/background-clip-text.html [ Failure ] crbug.com/591099 fast/backgrounds/background-leakage-transforms.html [ Failure ] crbug.com/591099 fast/backgrounds/border-radius-split-background-image.html [ Failure ] @@ -1132,7 +999,7 @@ crbug.com/591099 fast/dom/Window/window-lookup-precedence.html [ Timeout ] crbug.com/591099 fast/dom/Window/window-postmessage-clone-deep-array.html [ Failure ] crbug.com/591099 fast/dom/domstring-attribute-reflection.html [ Timeout ] -crbug.com/591099 fast/dom/element-attribute-js-null.html [ Pass Timeout ] +crbug.com/591099 fast/dom/element-attribute-js-null.html [ Timeout ] crbug.com/714962 fast/dom/elementFromPoint-relative-to-viewport.html [ Failure ] crbug.com/714962 fast/dom/elementsFromPoint/elementsFromPoint-inline.html [ Failure ] crbug.com/714962 fast/dom/inert/inert-inlines.html [ Failure ] @@ -1162,7 +1029,7 @@ crbug.com/591099 fast/events/onclick-list-marker.html [ Failure ] crbug.com/591099 fast/events/pointerevents/mouse-pointer-capture-transition-events.html [ Timeout ] crbug.com/591099 fast/events/pointerevents/mouse-pointer-event-properties.html [ Timeout ] -crbug.com/591099 fast/events/pointerevents/touch-capture.html [ Pass Timeout ] +crbug.com/591099 fast/events/pointerevents/touch-capture.html [ Timeout ] crbug.com/591099 fast/events/select-element.html [ Timeout ] crbug.com/591099 fast/events/sequential-focus-navigation-starting-point.html [ Failure ] crbug.com/591099 fast/events/touch/compositor-touch-hit-rects.html [ Failure ] @@ -1184,7 +1051,7 @@ crbug.com/591099 fast/forms/selection-direction.html [ Timeout ] crbug.com/591099 fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125.html [ Failure ] crbug.com/591099 fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200.html [ Failure ] -crbug.com/591099 fast/forms/text-control-intrinsic-widths.html [ Timeout ] +crbug.com/591099 fast/forms/text-control-intrinsic-widths.html [ Pass Timeout ] crbug.com/591099 fast/forms/textarea/textarea-align.html [ Failure ] crbug.com/591099 fast/forms/textarea/textarea-metrics.html [ Timeout ] crbug.com/591099 fast/forms/time-multiple-fields/time-multiple-fields-stepup-stepdown-from-renderer.html [ Timeout ] @@ -1520,15 +1387,15 @@ crbug.com/591099 fast/text/place-rtl-ellipsis-in-inline-blocks-align-left.html [ Failure ] crbug.com/591099 fast/text/place-rtl-ellipsis-in-inline-blocks-align-right.html [ Failure ] crbug.com/591099 fast/text/place-rtl-ellipsis-in-inline-blocks.html [ Failure ] -crbug.com/714962 fast/text/selection/flexbox-selection-nested.html [ Failure ] +crbug.com/714962 fast/text/selection/flexbox-selection-nested.html [ Failure Pass ] crbug.com/591099 fast/text/selection/flexbox-selection.html [ Failure ] crbug.com/591099 fast/text/selection/justified-selection-at-edge.html [ Failure ] crbug.com/591099 fast/text/selection/khmer-selection.html [ Failure ] crbug.com/714962 fast/text/selection/pre-wrap-overflow-selection.html [ Failure ] crbug.com/591099 fast/text/selection/selection-hard-linebreak.html [ Failure ] -crbug.com/591099 fast/text/selection/selection-rect-rounding.html [ Failure ] +crbug.com/591099 fast/text/selection/selection-rect-rounding.html [ Failure Pass ] crbug.com/591099 fast/text/selection/selection-with-inline-padding.html [ Failure ] -crbug.com/714962 fast/text/selection/shaping-selection-rect.html [ Failure ] +crbug.com/714962 fast/text/selection/shaping-selection-rect.html [ Failure Pass ] crbug.com/591099 fast/text/text-combine-first-line-crash.html [ Crash ] crbug.com/714962 fast/text/unicode-fallback-font.html [ Failure ] crbug.com/591099 fast/text/whitespace/018.html [ Failure ] @@ -1605,20 +1472,17 @@ crbug.com/591099 http/tests/devtools/elements/highlight/highlight-css-shapes-outside.js [ Failure ] crbug.com/714962 http/tests/devtools/elements/inspect-pseudo-element.js [ Timeout ] crbug.com/591099 http/tests/devtools/elements/styles-2/paste-property.js [ Timeout ] -crbug.com/591099 http/tests/devtools/elements/styles-3/styles-add-blank-property.js [ Pass Timeout ] +crbug.com/591099 http/tests/devtools/elements/styles-3/styles-add-blank-property.js [ Timeout ] crbug.com/591099 http/tests/devtools/elements/styles-3/styles-add-new-rule-colon.js [ Pass Timeout ] crbug.com/591099 http/tests/devtools/elements/styles-3/styles-add-new-rule-tab.js [ Timeout ] crbug.com/591099 http/tests/devtools/elements/styles-3/styles-add-new-rule.js [ Timeout ] crbug.com/591099 http/tests/devtools/elements/styles-3/styles-change-node-while-editing.js [ Failure Pass ] crbug.com/591099 http/tests/devtools/elements/styles-3/styles-disable-inherited.js [ Failure ] -crbug.com/591099 http/tests/devtools/elements/styles-4/styles-do-not-detach-sourcemap-on-edits.js [ Pass Timeout ] crbug.com/591099 http/tests/devtools/elements/styles-4/styles-formatting.js [ Timeout ] crbug.com/591099 http/tests/devtools/elements/styles-4/undo-add-new-rule.js [ Pass Timeout ] crbug.com/591099 http/tests/devtools/elements/styles-4/undo-add-property.js [ Pass Timeout ] crbug.com/591099 http/tests/devtools/network/network-datareceived.js [ Failure ] crbug.com/591099 http/tests/devtools/persistence/persistence-merge-editor-tabs.js [ Failure ] -crbug.com/591099 http/tests/devtools/sources/debugger-breakpoints/dom-breakpoints.js [ Pass Timeout ] -crbug.com/591099 http/tests/devtools/sources/debugger-frameworks/frameworks-skip-step-in.js [ Pass Timeout ] crbug.com/591099 http/tests/devtools/sources/debugger-ui/debugger-inline-values.js [ Failure Pass ] crbug.com/591099 http/tests/devtools/sources/debugger/source-frame-breakpoint-decorations.js [ Failure Pass ] crbug.com/591099 http/tests/devtools/text-autosizing-override.js [ Failure ] @@ -1926,7 +1790,7 @@ crbug.com/591099 paint/selection/text-selection-newline-vertical-lr.html [ Failure ] crbug.com/591099 paint/selection/text-selection-newline-vertical-rl.html [ Failure ] crbug.com/591099 paint/selection/text-selection-newline.html [ Failure ] -crbug.com/714962 paint/selection/text-selection-update-style.html [ Failure ] +crbug.com/714962 paint/selection/text-selection-update-style.html [ Failure Pass ] crbug.com/591099 paint/text/selection-no-clip-text.html [ Failure ] crbug.com/714962 paint/text/text-match-highlights-big-line-height.html [ Failure ] crbug.com/591099 payments/payment-request-in-iframe-nested-not-allowed.html [ Failure ] @@ -1939,7 +1803,7 @@ crbug.com/591099 storage/indexeddb/cursor-continue-validity.html [ Timeout ] crbug.com/591099 storage/indexeddb/cursor-key-order.html [ Timeout ] crbug.com/591099 storage/indexeddb/deleted-objects.html [ Pass Timeout ] -crbug.com/591099 storage/indexeddb/exceptions.html [ Timeout ] +crbug.com/591099 storage/indexeddb/exceptions.html [ Pass Timeout ] crbug.com/591099 storage/indexeddb/index-cursor.html [ Timeout ] crbug.com/591099 storage/indexeddb/keypath-basics.html [ Pass Timeout ] crbug.com/591099 storage/indexeddb/mozilla/cursors.html [ Timeout ] @@ -1963,7 +1827,7 @@ crbug.com/591099 svg/parser/whitespace-length-invalid-1.html [ Pass Timeout ] crbug.com/591099 svg/parser/whitespace-length-invalid-2.html [ Pass Timeout ] crbug.com/591099 svg/parser/whitespace-length-invalid-3.html [ Pass Timeout ] -crbug.com/591099 svg/parser/whitespace-length-invalid-4.html [ Timeout ] +crbug.com/591099 svg/parser/whitespace-length-invalid-4.html [ Pass Timeout ] crbug.com/591099 svg/parser/whitespace-number.html [ Timeout ] crbug.com/591099 svg/text/foreignObject-text-clipping-bug.xml [ Failure ] crbug.com/714962 svg/text/tspan-multiple-outline.svg [ Failure ] @@ -2029,13 +1893,6 @@ crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-2d-pattern-in-worker.html [ Pass ] crbug.com/591099 virtual/gpu/fast/canvas/canvas-drawImage-video-imageSmoothingEnabled.html [ Pass ] crbug.com/591099 virtual/gpu/fast/canvas/canvas-imageSmoothingQuality.html [ Pass ] -crbug.com/591099 virtual/incremental-shadow-dom/external/wpt/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html [ Failure ] -crbug.com/714962 virtual/incremental-shadow-dom/fast/dom/shadow/scrollbar.html [ Crash ] -crbug.com/591099 virtual/incremental-shadow-dom/fast/dom/shadow/selections-in-shadow.html [ Pass Timeout ] -crbug.com/591099 virtual/incremental-shadow-dom/html/details_summary/details-writing-mode-align-center.html [ Failure ] -crbug.com/591099 virtual/incremental-shadow-dom/html/details_summary/details-writing-mode-align-left.html [ Failure ] -crbug.com/591099 virtual/incremental-shadow-dom/html/details_summary/details-writing-mode-align-right.html [ Failure ] -crbug.com/591099 virtual/incremental-shadow-dom/html/details_summary/details-writing-mode.html [ Failure ] crbug.com/591099 virtual/layout_ng/ [ Skip ] crbug.com/824918 virtual/layout_ng_experimental/ [ Skip ] crbug.com/836297 virtual/layout_ng_experimental/printing/webgl-oversized-printing.html [ Pass Timeout ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees index 92a2c7d..cdcb3e92 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees
@@ -92,7 +92,6 @@ Bug(none) virtual/htxg-with-network-service/ [ Skip ] Bug(none) virtual/htxg/ [ Skip ] Bug(none) virtual/import-meta-url/ [ Skip ] -Bug(none) virtual/incremental-shadow-dom/ [ Skip ] Bug(none) virtual/layout_ng/ [ Skip ] Bug(none) virtual/layout_ng_experimental/ [ Skip ] Bug(none) virtual/linux-subpixel/ [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 index 78d13318..def8b8a 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -73,7 +73,6 @@ Bug(none) virtual/exotic-color-space/ [ Skip ] Bug(none) virtual/gpu/ [ Skip ] Bug(none) virtual/gpu-rasterization/ [ Skip ] -Bug(none) virtual/incremental-shadow-dom/ [ Skip ] Bug(none) virtual/layout_ng/ [ Skip ] Bug(none) virtual/layout_ng_experimental/ [ Skip ] Bug(none) virtual/linux-subpixel/ [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests index d17c8a3c..3af4c32 100644 --- a/third_party/WebKit/LayoutTests/SlowTests +++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -252,7 +252,6 @@ crbug.com/658211 [ Win7 Debug ] fast/text/line-break-ascii.html [ Slow ] crbug.com/802029 fast/dom/shadow/focus-controller-recursion-crash.html [ Slow ] -crbug.com/802029 virtual/incremental-shadow-dom/fast/dom/shadow/focus-controller-recursion-crash.html [ Slow ] crbug.com/697735 external/wpt/editing/run/backcolor.html [ Slow ] crbug.com/697735 external/wpt/editing/run/bold.html [ Slow ] crbug.com/697735 external/wpt/editing/run/createlink.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/SmokeTests b/third_party/WebKit/LayoutTests/SmokeTests index acd32a5..f44cbf2 100644 --- a/third_party/WebKit/LayoutTests/SmokeTests +++ b/third_party/WebKit/LayoutTests/SmokeTests
@@ -539,6 +539,7 @@ fast/forms/checkbox/checkbox-checked-state-affected-by-default-state.html fast/forms/color/color-setrangetext.html fast/forms/datalist/slider-appearance-with-ticks-crash.html +fast/forms/date/date-chooseronly-defaultValue.html fast/forms/date/date-format-warning.html fast/forms/date-multiple-fields/date-multiple-fields-ax-value-changed-notification.html fast/forms/datetimelocal/datetimelocal-input-type.html
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index b5f6f63..4e60ca3 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1729,27 +1729,6 @@ crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/order/order-with-row-reverse.html [ Failure ] # ====== LayoutNG-only failures until here ====== -# ====== IncrementalShadowDOM-only failures from here ====== - -crbug.com/776656 virtual/incremental-shadow-dom/external/wpt/shadow-dom/untriaged/styles/test-003.html [ Failure ] - -crbug.com/776656 virtual/incremental-shadow-dom/media/controls/controls-cast-do-not-fade-out.html [ Pass Timeout ] - -# These tests are also failing without the flag -crbug.com/832447 virtual/incremental-shadow-dom/media/controls/controls-page-zoom-in.html [ Failure Pass ] -crbug.com/832447 virtual/incremental-shadow-dom/media/controls/controls-page-zoom-out.html [ Failure Pass ] -crbug.com/783154 virtual/incremental-shadow-dom/media/controls/modern/doubletap-to-jump-forwards-too-short.html [ Skip ] -crbug.com/783154 virtual/incremental-shadow-dom/media/controls/modern/doubletap-to-jump-backwards.html [ Skip ] -crbug.com/793771 virtual/incremental-shadow-dom/media/controls/modern/scrubbing.html [ Skip ] -crbug.com/783154 virtual/incremental-shadow-dom/media/controls/modern/doubletap-to-toggle-fullscreen.html [ Skip ] -crbug.com/831720 virtual/incremental-shadow-dom/media/controls/modern/tap-to-hide-controls.html [ Pass Failure ] -crbug.com/789921 virtual/incremental-shadow-dom/media/controls/repaint-on-resize.html [ Failure Pass ] -crbug.com/824775 virtual/incremental-shadow-dom/media/controls/video-controls-with-cast-rendering.html [ Pass Failure ] -crbug.com/722825 virtual/incremental-shadow-dom/media/controls/video-enter-exit-fullscreen-while-hovering-shows-controls.html [ Timeout Pass Failure ] -crbug.com/746128 virtual/incremental-shadow-dom/media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html [ Failure ] - -# ====== IncrementalShadowDOM-only failures until here ====== - crbug.com/840238 http/tests/devtools/elements/shadow/shadow-distribution.js [ Failure ] crbug.com/667560 [ Debug ] http/tests/devtools/elements/styles-3/styles-change-node-while-editing.js [ Pass Failure ] @@ -2825,6 +2804,52 @@ crbug.com/832071 virtual/navigation-mojo-response/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/fetch/corb/img-html-correctly-labeled.sub.html [ Failure ] +crbug.com/626703 external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html [ Failure ] +crbug.com/626703 virtual/outofblink-cors/external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html [ Failure ] +crbug.com/626703 virtual/outofblink-cors/external/wpt/fetch/corb/img-html-correctly-labeled.sub.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-002.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-polygon-005.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-polygon-007.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-circle-008.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-polygon-012.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-circle-003.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip.svg [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-circle-001.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-ellipse-003.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-ellipse-001.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-circle-002.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip.svg [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-ellipse-004.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-polygon-011.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-polygon-013.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-polygon-002.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip-transform.svg [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-003.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-polygon-009.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-circle-005.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-ellipse-002.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-polygon-003.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-polygon-001.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-ellipse-005.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-ellipse-006.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path-svg-content/clip-path-dom-href.svg [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path-svg-content/clip-path-css-transform-002.svg [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-circle-004.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-polygon-010.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-008.svg [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-circle-006.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-003.svg [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/test-mask.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-polygon-006.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-004.svg [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path-svg-content/clip-path-recursion-002.svg [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-polygon-008.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip-transform.svg [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-ellipse-008.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-ellipse-007.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-004.html [ Failure ] +crbug.com/626703 external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-005.svg [ Failure ] crbug.com/626703 [ Mac10.12 ] external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/078.html [ Timeout ] crbug.com/626703 [ Mac10.13 ] external/wpt/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html [ Skip ] crbug.com/626703 [ Retina ] external/wpt/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html [ Skip ] @@ -4693,7 +4718,6 @@ crbug.com/832842 [ Win7 ] virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Failure ] crbug.com/833655 [ Linux ] media/controls/closed-captions-dynamic-update.html [ Skip ] crbug.com/833655 [ Linux ] virtual/new-remote-playback-pipeline/media/controls/closed-captions-dynamic-update.html [ Skip ] -crbug.com/833655 [ Linux ] virtual/incremental-shadow-dom/media/controls/closed-captions-dynamic-update.html [ Skip ] crbug.com/833655 [ Linux ] virtual/video-surface-layer/media/controls/closed-captions-dynamic-update.html [ Skip ] crbug.com/833658 [ Linux Win Mac ] media/video-controls-focus-movement-on-hide.html [ Pass Failure ] crbug.com/833100 [ Mac ] external/wpt/battery-status/battery-full-manual.https.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites index 6f8b1e29..97710c7a 100644 --- a/third_party/WebKit/LayoutTests/VirtualTestSuites +++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -603,41 +603,6 @@ "args": ["--enable-blink-features=FractionalMouseEvent"] }, { - "prefix": "incremental-shadow-dom", - "base": "external/wpt/shadow-dom", - "args": ["--enable-blink-features=SlotInFlatTree,IncrementalShadowDOM"] - }, - { - "prefix": "incremental-shadow-dom", - "base": "fast/dom/shadow", - "args": ["--enable-blink-features=SlotInFlatTree,IncrementalShadowDOM"] - }, - { - "prefix": "incremental-shadow-dom", - "base": "shadow-dom", - "args": ["--enable-blink-features=SlotInFlatTree,IncrementalShadowDOM"] - }, - { - "prefix": "incremental-shadow-dom", - "base": "html/details_summary", - "args": ["--enable-blink-features=SlotInFlatTree,IncrementalShadowDOM"] - }, - { - "prefix": "incremental-shadow-dom", - "base": "http/tests/devtools/elements/shadow", - "args": ["--enable-blink-features=SlotInFlatTree,IncrementalShadowDOM"] - }, - { - "prefix": "incremental-shadow-dom", - "base": "media/controls", - "args": ["--enable-blink-features=SlotInFlatTree,IncrementalShadowDOM"] - }, - { - "prefix": "incremental-shadow-dom", - "base": "external/wpt/css/css-scoping", - "args": ["--enable-blink-features=SlotInFlatTree,IncrementalShadowDOM"] - }, - { "prefix": "unified-autoplay", "base": "external/wpt/feature-policy", "args": ["--autoplay-policy=document-user-activation-required"]
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations index d39cd16..4aa0b0d8 100644 --- a/third_party/WebKit/LayoutTests/W3CImportExpectations +++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -86,7 +86,6 @@ external/wpt/css/css-display/run-in [ Skip ] external/wpt/css/css-exclusions [ Skip ] external/wpt/css/css-gcpm [ Skip ] -external/wpt/css/css-masking [ Skip ] external/wpt/css/css-page [ Skip ] external/wpt/css/css-regions [ Skip ] external/wpt/css/css-round-display [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json index a6f9c8d4..169d4010 100644 --- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json +++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -45841,6 +45841,1818 @@ {} ] ], + "css/css-masking/clip-path-svg-content/clip-path-clip-nested-twice.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-clip-nested-twice.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-clip-rule-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-hole-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-clip-rule-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-003.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-clip-rule-003.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-hole-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-004.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-clip-rule-004.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-005.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-clip-rule-005.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-006.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-clip-rule-006.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-007.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-clip-rule-007.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-003-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-008.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-clip-rule-008.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-004-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-009.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-clip-rule-009.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-010.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-clip-rule-010.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-clip.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-clip.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-content-clip-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-content-clip-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-content-clip-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-content-clip-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-content-clip-003.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-content-clip-003.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-content-invisible.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-content-invisible.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-invisible-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-content-syling.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-content-syling.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-content-use-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-content-use-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-003.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-content-use-003.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-004.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-content-use-004.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-005.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-content-use-005.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-006.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-content-use-006.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-007.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-content-use-007.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-003-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-css-transform-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-css-transform-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-css-transform-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-css-transform-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-css-transform-003.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-css-transform-003.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-003-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-css-transform-004.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-css-transform-004.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-003-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-dom-child-changes.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-dom-child-changes.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-003-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-dom-clippathunits.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-dom-clippathunits.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-003-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-dom-href.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-dom-href.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-003-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-dom-id.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-dom-id.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-003-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-invalid.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-invalid.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-invisible-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-negative-scale.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-negative-scale.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-negative-scale-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-no-content-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-no-content-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-invisible-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-no-content-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-no-content-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-invisible-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-no-content-003.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-no-content-003.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-invisible-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-no-content-004.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-no-content-004.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-invisible-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-003.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-003.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-circle-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-004.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-004.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-on-g-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-on-g-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-on-g-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-on-g-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-on-g-003.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-on-g-003.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-on-g-004.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-on-g-004.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-on-g-005.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-on-g-005.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-on-marker-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-on-marker-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-on-marker-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-on-marker-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-on-marker-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-on-marker-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-on-marker-003.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-on-marker-003.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-on-marker-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-on-svg-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-on-svg-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-on-svg-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-on-svg-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-on-use-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-on-use-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-on-use-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-on-use-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-precision-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-precision-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-precision-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-recursion-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-recursion-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-invisible-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-recursion-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-recursion-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-invisible-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-circle-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-shape-circle-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-circle-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-circle-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-shape-circle-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-circle-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-circle-003.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-shape-circle-003.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-circle-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-circle-004.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-shape-circle-004.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-circle-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-circle-005.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-shape-circle-005.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-circle-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-ellipse-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-shape-ellipse-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-ellipse-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-ellipse-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-shape-ellipse-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-ellipse-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-inset-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-shape-inset-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-shape-inset-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-inset-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-shape-inset-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-shape-inset-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-polygon-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-shape-polygon-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-polygon-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-shape-polygon-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-hole-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-polygon-003.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-shape-polygon-003.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-text-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-text-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-text-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-text-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-text-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-text-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-text-003.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-text-003.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-text-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-text-004.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-text-004.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-text-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-text-005.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-text-005.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-text-003-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-userspaceonuse-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-userspaceonuse-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-with-opacity.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-with-opacity.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/clip-path-with-transform.svg": [ + [ + "/css/css-masking/clip-path-svg-content/clip-path-with-transform.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-nested-clip-path-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-nested-clip-path-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-003.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-nested-clip-path-003.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-004.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-nested-clip-path-004.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-005.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-nested-clip-path-005.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-006.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-nested-clip-path-006.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-007.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-nested-clip-path-007.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-008.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-nested-clip-path-008.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-009.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-nested-clip-path-009.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-010.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-nested-clip-path-010.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-003-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-panning-001.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-nested-clip-path-panning-001.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-panning-002.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-nested-clip-path-panning-002.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip-transform.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip-transform.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-content-clip-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-content-clip-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip-transform.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip-transform.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-content-clip-002-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip.svg": [ + [ + "/css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/mask-content-clip-001-ref.svg", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-circle-001.html": [ + [ + "/css/css-masking/clip-path/clip-path-circle-001.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-circle-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-circle-002.html": [ + [ + "/css/css-masking/clip-path/clip-path-circle-002.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-circle-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-circle-003.html": [ + [ + "/css/css-masking/clip-path/clip-path-circle-003.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-circle-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-circle-004.html": [ + [ + "/css/css-masking/clip-path/clip-path-circle-004.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-circle-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-circle-005.html": [ + [ + "/css/css-masking/clip-path/clip-path-circle-005.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-circle-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-circle-006.html": [ + [ + "/css/css-masking/clip-path/clip-path-circle-006.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-circle-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-circle-007.html": [ + [ + "/css/css-masking/clip-path/clip-path-circle-007.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-circle-2-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-circle-008.html": [ + [ + "/css/css-masking/clip-path/clip-path-circle-008.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-circle-3-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-element-userSpaceOnUse-001.html": [ + [ + "/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-001.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-rectangle-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-element-userSpaceOnUse-002.html": [ + [ + "/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-002.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-rectangle-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-element-userSpaceOnUse-003.html": [ + [ + "/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-003.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-ref-right-green-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-element-userSpaceOnUse-004.html": [ + [ + "/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-004.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-ref-bottom-green-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-ellipse-001.html": [ + [ + "/css/css-masking/clip-path/clip-path-ellipse-001.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-ellipse-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-ellipse-002.html": [ + [ + "/css/css-masking/clip-path/clip-path-ellipse-002.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-ellipse-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-ellipse-003.html": [ + [ + "/css/css-masking/clip-path/clip-path-ellipse-003.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-circle-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-ellipse-004.html": [ + [ + "/css/css-masking/clip-path/clip-path-ellipse-004.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-ellipse-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-ellipse-005.html": [ + [ + "/css/css-masking/clip-path/clip-path-ellipse-005.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-ellipse-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-ellipse-006.html": [ + [ + "/css/css-masking/clip-path/clip-path-ellipse-006.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-circle-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-ellipse-007.html": [ + [ + "/css/css-masking/clip-path/clip-path-ellipse-007.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-ellipse-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-ellipse-008.html": [ + [ + "/css/css-masking/clip-path/clip-path-ellipse-008.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-ellipse-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-polygon-001.html": [ + [ + "/css/css-masking/clip-path/clip-path-polygon-001.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-rectangle-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-polygon-002.html": [ + [ + "/css/css-masking/clip-path/clip-path-polygon-002.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-rectangle-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-polygon-003.html": [ + [ + "/css/css-masking/clip-path/clip-path-polygon-003.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-rectangle-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-polygon-004.html": [ + [ + "/css/css-masking/clip-path/clip-path-polygon-004.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-rectangle-border-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-polygon-005.html": [ + [ + "/css/css-masking/clip-path/clip-path-polygon-005.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-rectangle-border-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-polygon-006.html": [ + [ + "/css/css-masking/clip-path/clip-path-polygon-006.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-square-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-polygon-007.html": [ + [ + "/css/css-masking/clip-path/clip-path-polygon-007.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-stripes-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-polygon-008.html": [ + [ + "/css/css-masking/clip-path/clip-path-polygon-008.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-stripes-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-polygon-009.html": [ + [ + "/css/css-masking/clip-path/clip-path-polygon-009.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-square-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-polygon-010.html": [ + [ + "/css/css-masking/clip-path/clip-path-polygon-010.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-stripes-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-polygon-011.html": [ + [ + "/css/css-masking/clip-path/clip-path-polygon-011.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-stripes-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-polygon-012.html": [ + [ + "/css/css-masking/clip-path/clip-path-polygon-012.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-stripes-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-path/clip-path-polygon-013.html": [ + [ + "/css/css-masking/clip-path/clip-path-polygon-013.html", + [ + [ + "/css/css-masking/clip-path/reference/clip-path-stripes-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-rule/clip-rule-001.html": [ + [ + "/css/css-masking/clip-rule/clip-rule-001.html", + [ + [ + "/css/css-masking/clip-rule/reference/clip-rule-rectangle-border-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip-rule/clip-rule-002.html": [ + [ + "/css/css-masking/clip-rule/clip-rule-002.html", + [ + [ + "/css/css-masking/clip-rule/reference/clip-rule-rectangle-border-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-absolute-positioned-001.html": [ + [ + "/css/css-masking/clip/clip-absolute-positioned-001.html", + [ + [ + "/css/css-masking/clip/reference/clip-absolute-positioned-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-absolute-positioned-002.html": [ + [ + "/css/css-masking/clip/clip-absolute-positioned-002.html", + [ + [ + "/css/css-masking/clip/reference/clip-absolute-positioned-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-negative-values-001.html": [ + [ + "/css/css-masking/clip/clip-negative-values-001.html", + [ + [ + "/css/css-masking/clip/reference/clip-full-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-negative-values-002.html": [ + [ + "/css/css-masking/clip/clip-negative-values-002.html", + [ + [ + "/css/css-masking/clip/reference/clip-full-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-negative-values-003.html": [ + [ + "/css/css-masking/clip/clip-negative-values-003.html", + [ + [ + "/css/css-masking/clip/reference/clip-vertical-stripe-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-negative-values-004.html": [ + [ + "/css/css-masking/clip/clip-negative-values-004.html", + [ + [ + "/css/css-masking/clip/reference/clip-horizontal-stripe-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-no-clipping-001.html": [ + [ + "/css/css-masking/clip/clip-no-clipping-001.html", + [ + [ + "/css/css-masking/clip/reference/clip-no-clipping-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-no-clipping-002.html": [ + [ + "/css/css-masking/clip/clip-no-clipping-002.html", + [ + [ + "/css/css-masking/clip/reference/clip-no-clipping-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-not-absolute-positioned-001.html": [ + [ + "/css/css-masking/clip/clip-not-absolute-positioned-001.html", + [ + [ + "/css/css-masking/clip/reference/clip-no-clipping-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-not-absolute-positioned-002.html": [ + [ + "/css/css-masking/clip/clip-not-absolute-positioned-002.html", + [ + [ + "/css/css-masking/clip/reference/clip-no-clipping-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-not-absolute-positioned-003.html": [ + [ + "/css/css-masking/clip/clip-not-absolute-positioned-003.html", + [ + [ + "/css/css-masking/clip/reference/clip-no-clipping-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-not-absolute-positioned-004.html": [ + [ + "/css/css-masking/clip/clip-not-absolute-positioned-004.html", + [ + [ + "/css/css-masking/clip/reference/clip-no-clipping-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-rect-auto-001.html": [ + [ + "/css/css-masking/clip/clip-rect-auto-001.html", + [ + [ + "/css/css-masking/clip/reference/clip-overflow-hidden-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-rect-auto-002.html": [ + [ + "/css/css-masking/clip/clip-rect-auto-002.html", + [ + [ + "/css/css-masking/clip/reference/clip-no-clipping-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-rect-auto-003.html": [ + [ + "/css/css-masking/clip/clip-rect-auto-003.html", + [ + [ + "/css/css-masking/clip/reference/clip-rect-top-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-rect-auto-004.html": [ + [ + "/css/css-masking/clip/clip-rect-auto-004.html", + [ + [ + "/css/css-masking/clip/reference/clip-rect-right-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-rect-auto-005.html": [ + [ + "/css/css-masking/clip/clip-rect-auto-005.html", + [ + [ + "/css/css-masking/clip/reference/clip-rect-bottom-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-rect-auto-006.html": [ + [ + "/css/css-masking/clip/clip-rect-auto-006.html", + [ + [ + "/css/css-masking/clip/reference/clip-rect-left-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-rect-comma-001.html": [ + [ + "/css/css-masking/clip/clip-rect-comma-001.html", + [ + [ + "/css/css-masking/clip/reference/clip-absolute-positioned-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-rect-comma-002.html": [ + [ + "/css/css-masking/clip/clip-rect-comma-002.html", + [ + [ + "/css/css-masking/clip/reference/clip-no-clipping-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-rect-comma-003.html": [ + [ + "/css/css-masking/clip/clip-rect-comma-003.html", + [ + [ + "/css/css-masking/clip/reference/clip-no-clipping-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/clip/clip-rect-comma-004.html": [ + [ + "/css/css-masking/clip/clip-rect-comma-004.html", + [ + [ + "/css/css-masking/clip/reference/clip-no-clipping-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-masking/test-mask.html": [ + [ + "/css/css-masking/test-mask.html", + [ + [ + "/css/css-masking/test-mask-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-multicol/float-and-block.html": [ [ "/css/css-multicol/float-and-block.html", @@ -89902,7 +91714,7 @@ "/fetch/corb/img-html-correctly-labeled.sub.html", [ [ - "/fetch/corb/img-png-mislabeled-as-html.sub-expected.html", + "/fetch/corb/img-png-mislabeled-as-html.sub-ref.html", "==" ] ], @@ -89914,7 +91726,7 @@ "/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html", [ [ - "/fetch/corb/img-png-mislabeled-as-html.sub-expected.html", + "/fetch/corb/img-png-mislabeled-as-html.sub-ref.html", "==" ] ], @@ -89926,7 +91738,7 @@ "/fetch/corb/img-png-mislabeled-as-html.sub.html", [ [ - "/fetch/corb/img-png-mislabeled-as-html.sub-expected.html", + "/fetch/corb/img-png-mislabeled-as-html.sub-ref.html", "==" ] ], @@ -93650,7 +95462,7 @@ "/svg/extensibility/foreignObject/stacking-context.html", [ [ - "/svg/extensibility/foreignObject/stacking-context-expected.html", + "/svg/extensibility/foreignObject/stacking-context-ref.html", "==" ] ], @@ -112101,7 +113913,7 @@ {} ] ], - "css/css-fonts/support/fonts/font-feature-settings-rendering-2-expected.html": [ + "css/css-fonts/support/fonts/font-feature-settings-rendering-2-ref.html": [ [ {} ] @@ -120571,6 +122383,276 @@ {} ] ], + "css/css-masking/OWNERS": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-circle-001-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-001-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-002-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-003-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-ellipse-001-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-invisible-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-negative-scale-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-on-marker-001-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-on-marker-002-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-precision-001-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-shape-inset-001-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-square-001-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-square-003-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-square-hole-001-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-text-001-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-text-002-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-text-003-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/mask-content-clip-001-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/mask-content-clip-002-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-001-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-002-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-003-ref.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-path/reference/clip-path-circle-2-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip-path/reference/clip-path-circle-3-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip-path/reference/clip-path-circle-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip-path/reference/clip-path-ellipse-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip-path/reference/clip-path-rectangle-border-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip-path/reference/clip-path-rectangle-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip-path/reference/clip-path-ref-bottom-green-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip-path/reference/clip-path-ref-right-green-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip-path/reference/clip-path-square-001-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip-path/reference/clip-path-square-002-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip-path/reference/clip-path-stripes-001-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip-path/reference/clip-path-stripes-002-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip-path/reference/clip-path-stripes-003-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip-path/svg-clipPath.svg": [ + [ + {} + ] + ], + "css/css-masking/clip-rule/reference/clip-rule-rectangle-border-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip/reference/clip-absolute-positioned-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip/reference/clip-full-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip/reference/clip-horizontal-stripe-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip/reference/clip-no-clipping-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip/reference/clip-overflow-hidden-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip/reference/clip-rect-bottom-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip/reference/clip-rect-left-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip/reference/clip-rect-right-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip/reference/clip-rect-top-ref.html": [ + [ + {} + ] + ], + "css/css-masking/clip/reference/clip-vertical-stripe-ref.html": [ + [ + {} + ] + ], + "css/css-masking/parsing/clip-path-invalid-expected.txt": [ + [ + {} + ] + ], + "css/css-masking/parsing/clip-path-valid-expected.txt": [ + [ + {} + ] + ], + "css/css-masking/parsing/clip-valid-expected.txt": [ + [ + {} + ] + ], + "css/css-masking/parsing/resources/parsing-testcommon.js": [ + [ + {} + ] + ], + "css/css-masking/test-mask-ref.html": [ + [ + {} + ] + ], "css/css-multicol/OWNERS": [ [ {} @@ -140206,17 +142288,17 @@ {} ] ], - "fetch/corb/img-html-correctly-labeled.sub-expected.html": [ + "fetch/corb/img-html-correctly-labeled.sub-ref.html": [ [ {} ] ], - "fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-expected.html": [ + "fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html": [ [ {} ] ], - "fetch/corb/img-png-mislabeled-as-html.sub-expected.html": [ + "fetch/corb/img-png-mislabeled-as-html.sub-ref.html": [ [ {} ] @@ -163966,7 +166048,7 @@ {} ] ], - "svg/extensibility/foreignObject/stacking-context-expected.html": [ + "svg/extensibility/foreignObject/stacking-context-ref.html": [ [ {} ] @@ -185681,6 +187763,42 @@ {} ] ], + "css/css-masking/parsing/clip-invalid.html": [ + [ + "/css/css-masking/parsing/clip-invalid.html", + {} + ] + ], + "css/css-masking/parsing/clip-path-invalid.html": [ + [ + "/css/css-masking/parsing/clip-path-invalid.html", + {} + ] + ], + "css/css-masking/parsing/clip-path-valid.html": [ + [ + "/css/css-masking/parsing/clip-path-valid.html", + {} + ] + ], + "css/css-masking/parsing/clip-rule-invalid.html": [ + [ + "/css/css-masking/parsing/clip-rule-invalid.html", + {} + ] + ], + "css/css-masking/parsing/clip-rule-valid.html": [ + [ + "/css/css-masking/parsing/clip-rule-valid.html", + {} + ] + ], + "css/css-masking/parsing/clip-valid.html": [ + [ + "/css/css-masking/parsing/clip-valid.html", + {} + ] + ], "css/css-multicol/extremely-tall-multicol-with-extremely-tall-child-crash.html": [ [ "/css/css-multicol/extremely-tall-multicol-with-extremely-tall-child-crash.html", @@ -287778,7 +289896,7 @@ "69e4080710f24b062203f56aa6ae2d991d4fa19a", "support" ], - "css/css-fonts/support/fonts/font-feature-settings-rendering-2-expected.html": [ + "css/css-fonts/support/fonts/font-feature-settings-rendering-2-ref.html": [ "883083cdde66caca05384d3d6930070454e94fad", "support" ], @@ -296878,6 +298996,850 @@ "f6260209571bdd53be52c698f072c121e3702dd1", "support" ], + "css/css-masking/OWNERS": [ + "a290aef2ba2b950b1a235ab06969d414c057804b", + "support" + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-nested-twice.svg": [ + "a7452833b72b304a2e34b4b77bcd805baea3cc6f", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-001.svg": [ + "ce248504ec0c90294d44bd6266aaeca7067534bf", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-002.svg": [ + "ab01d9ef6db7594d183089f82e8d4684f48b8d1c", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-003.svg": [ + "38ead39641ede378acce6cbfc1087ecebd74d603", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-004.svg": [ + "154df85c39eae233f7e2cd20b3b053fe448aa663", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-005.svg": [ + "3df257a3f68645c29d2081795947091134409638", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-006.svg": [ + "cdb92ea93f1b217d3020ab5d620081d75bdf8d36", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-007.svg": [ + "5a9a15a0a4cee3333093a5d300276e5b2ea218fc", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-008.svg": [ + "db29166ae04ce88353ede0398898d23fa84a8bf1", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-009.svg": [ + "f0a1cc1bcaabf5195ae6ce1f4569c9533963a06d", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-clip-rule-010.svg": [ + "dceed2e0610a76567abcae964bb22590565b8792", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-clip.svg": [ + "8bc1442a628a3268b1b994d1b112a77e1ab28881", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-content-clip-001.svg": [ + "0ec1183523155b2846f19e56e89f57a2f5570b18", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-content-clip-002.svg": [ + "aed2d98746324c9360a663a1b5d9f0c2fba68b78", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-content-clip-003.svg": [ + "60f41530a6fd4ffb0c3d5bd575122573534f0a39", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-content-invisible.svg": [ + "0a825d868c35096b39509862811876cf66b9da57", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-content-syling.svg": [ + "8b63d5f5926f2bd700cca3e7f97a3a7b8188ee3f", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-001.svg": [ + "4c3114a6c4b8758f0b0ab8e2f754418aa095581b", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-002.svg": [ + "58dc648140cffcfe50a5cb4a940a61c02c7d2625", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-003.svg": [ + "9359cf6e060fa9da76d29827e4c78197f60b0129", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-004.svg": [ + "ea1de7faf5914e574f778cd714a3565146a39ff6", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-005.svg": [ + "72461a371fbc8a517ba38dbb27e807e3ab4b185b", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-006.svg": [ + "b806a7aa9739485223f59e28a73a86dc5352908c", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-content-use-007.svg": [ + "1420f79ef281f480ced4b4f4bf6fa354ab7424b5", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-css-transform-001.svg": [ + "c1c9b70c551999a6e935276b347a928d338b3391", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-css-transform-002.svg": [ + "e5b198546145887d78bba04acd7a98a55f73c806", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-css-transform-003.svg": [ + "36ed8914d7a4d6942064e4504bf0c8d2ccce46ca", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-css-transform-004.svg": [ + "ed481130384e1d1e3a234f8491a111bda04d52c3", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-dom-child-changes.svg": [ + "d5e2bba3c840f04a78e0d0364a0d981ddabe1e70", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-dom-clippathunits.svg": [ + "4270adc66eb4da788b62016bd91d291ebfeee2ef", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-dom-href.svg": [ + "89f9e14f50d33b96078f3d12afd71f77e4ae3fc8", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-dom-id.svg": [ + "66940a7882775de37028e02a65c4a0ed50098065", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-invalid.svg": [ + "4b7f3c0b017bbc38d4d7ceab946a75d55c6e6e04", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-negative-scale.svg": [ + "ad299e235fe06dd5cfbdf7d80172cd190a722ba5", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-no-content-001.svg": [ + "20e8af353c5c62df75c8a0f69bda3848817a2749", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-no-content-002.svg": [ + "1e42a0073384eaf6fceea546000da730d82be41b", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-no-content-003.svg": [ + "c774984e5fdb1ca6d3428090702782e2db3dd038", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-no-content-004.svg": [ + "6aba7282aec61132e2200dc5ed89fd5a437f646d", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-001.svg": [ + "98f53cd5d9cf67a30c7b194f80e76a4270129537", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-002.svg": [ + "7ffa43c3aebf24ed510fe269b682f3f21b501438", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-003.svg": [ + "42e773f6d0baee0f71c0ff92f05df7fe5aaaf9ee", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-004.svg": [ + "bedd78a6ff2d8bc4137ecb525508b9c07bfc3b06", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-on-g-001.svg": [ + "3d13f0f0b9f7359b6bc2323bbd7042029d1a5e77", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-on-g-002.svg": [ + "25f7c7b574289a1e82d945aef0c387120733e6d1", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-on-g-003.svg": [ + "3098e4c24c7e2e20c5f94c71b8ef55c0440adf2c", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-on-g-004.svg": [ + "91d2dbd92a60f55ec337ea7a08964d251142e509", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-on-g-005.svg": [ + "8459ab6ed343d06785369da3de772935df4c7b79", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-on-marker-001.svg": [ + "789438dce514d0f6bcc9627a031edb495501b88b", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-on-marker-002.svg": [ + "295fad4d6f3c1868dd2e707181e45fed5c454def", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-on-marker-003.svg": [ + "759402ae51b202787627ffbe5652116bd4319a3e", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-on-svg-001.svg": [ + "d9dd59fa17af2396f1408749812cf6e41b3ece61", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-on-svg-002.svg": [ + "3ca8568b6ba4a18820d3ac923c7cc808e9859941", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-on-use-001.svg": [ + "7a6d030a2f844e8e9c313f20e3e8bdcb11c4ccb8", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-on-use-002.svg": [ + "f6ff3af34693d8bd2df6fda5b15eed6ea9278b65", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-precision-001.svg": [ + "3da4a56cf2510a1e128bfc5de32b8a88412d1ee2", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-recursion-001.svg": [ + "0d2421d2b2391586a5162cd2a356e31449730aca", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-recursion-002.svg": [ + "0ac35571730beb537bebb15759a4e3677eea982c", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-circle-001.svg": [ + "f18e6c736b7e91ee60e38eab7e84200d431b9880", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-circle-002.svg": [ + "2750070425d5ec825858d271886e740e71880e79", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-circle-003.svg": [ + "14c1e7d67a03c3222a63e05b1db2b1c8b29d1673", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-circle-004.svg": [ + "a8bb3fc5d70086d0f1379b017b3ba96f4a58f6d4", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-circle-005.svg": [ + "1c37f9d13b5dee4ddfa80582c8aca3b3946a578f", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-ellipse-001.svg": [ + "2275f7bf79cfd417bc11ae4c0517beda8c5a40c0", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-ellipse-002.svg": [ + "80d7a049559752b4e146199c14aa692a23112f6d", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-inset-001.svg": [ + "260d90a8edafb0cbda5c69755f9d14bf8376d747", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-inset-002.svg": [ + "f0534f5a6ee942328d0710c4bcb131d659740e7d", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-polygon-001.svg": [ + "cbeeb54cb63bfa1da0bba5fb26c4ff9f7f4bcd90", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-polygon-002.svg": [ + "692b0324161e8872b614aa0de29d8290f103ed41", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-shape-polygon-003.svg": [ + "21334ee3e5802c72538726da5e42db7c83a8da41", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-text-001.svg": [ + "31d569ba0ac4a72f1498cdbb597c27b7d451e967", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-text-002.svg": [ + "b7dbcecac84677a6331572f0cd2a4e1926538c4e", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-text-003.svg": [ + "9b8e903d06f82293d604ecbb255d30b6d8820282", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-text-004.svg": [ + "679b6c1946a3798728ddb8c6d567bb7558e6de79", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-text-005.svg": [ + "3da30f6a2eb75d3032cf8027e57c26ffd0f946f4", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-userspaceonuse-001.svg": [ + "ff91c540ee524c339b9c69874e3e0f912e4d15d1", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-with-opacity.svg": [ + "a3959ad66d1b74469fc7b4b73c1a2cefd80cc810", + "reftest" + ], + "css/css-masking/clip-path-svg-content/clip-path-with-transform.svg": [ + "a2a683cc89424f2f60ebf0a762518d91b2dd6ac0", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-001.svg": [ + "39b1783daa3d091586747f4a9f18ae1fc1af236e", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-002.svg": [ + "5b93b0de9a5a28ebf574f23722cf8bbf45829dd9", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-003.svg": [ + "598d4d18d9437f9bae530f5f77e3b296b806e3e4", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-004.svg": [ + "600dfce1fd126e00702097ebf79e4e150f15b1db", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-005.svg": [ + "ab8579a2b60dfba4a29460dd4ddf9681002a8a1f", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-006.svg": [ + "62ba658dff98f8b71b8185b15fbddefa07700299", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-007.svg": [ + "3b9a20ab5566ec40dc99d5af8a67bda616d5ad9d", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-008.svg": [ + "feb9ec1908e017629c3f40cc1ed0ec609a9fd8d1", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-009.svg": [ + "12c713ec92dc7fef6ffb7fff6ad10adce1760355", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-010.svg": [ + "dc226ee10fdd9ae7c1201e3fe65d29403c6fb828", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-panning-001.svg": [ + "340e4e4e626e52a28424909ee9da804935ec7b05", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-nested-clip-path-panning-002.svg": [ + "536d3a166682f5b36740a4181db1784e721bd390", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip-transform.svg": [ + "4fe02b38e0ff7636bfa86802e5075ad652ee92ba", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip.svg": [ + "6dc16e4a8c4e1c3a6de1822c08188876872f2aea", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip-transform.svg": [ + "0ce13d44cf0410dfc0380b25c335ff9ea35b538c", + "reftest" + ], + "css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip.svg": [ + "187ed25dcd2b4b505cde1e51bd1407a1c9f0603b", + "reftest" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-circle-001-ref.svg": [ + "b9da5a465d0b367b31dff70912abc2f7ea162733", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-001-ref.svg": [ + "a307256c432995b9f99e94d3b39de4a3289eeefe", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-002-ref.svg": [ + "6c6cf2f76863a771e587b04306bfe53f0734a5c5", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-003-ref.svg": [ + "c696dbb5f4083a0a94503ef74402895b003e854a", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-ellipse-001-ref.svg": [ + "961df7b47dadb13652f7de7633d72f2476ed9178", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-invisible-ref.svg": [ + "cac19d54abf575d370b09f786c8dbf322dd00c86", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-negative-scale-ref.svg": [ + "c43b548be62a04f295c7e3fb86f247f8552faeb5", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-on-marker-001-ref.svg": [ + "0dd757e78d40e826cc3faa00c9e952df66b78909", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-on-marker-002-ref.svg": [ + "e4a88a9c050716e4955c0c14293fa834a9ca45b3", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-precision-001-ref.svg": [ + "33d8a321ba00fab29a06d5cb7f8ead8192f8b31e", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-shape-inset-001-ref.svg": [ + "8dc9ad7c125d1ed233d6d8c3bea267d29aee8fcc", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-square-001-ref.svg": [ + "37b3fae4fa6ee15f1eabf9b0bc8a0eec64bb39f3", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg": [ + "ef66e3155c340f293da70c7b82c28c9840ea51e7", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-square-003-ref.svg": [ + "063312496b41ff78e5575e7ac797ad64ffdff953", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-square-hole-001-ref.svg": [ + "9b14e04d66bd22ba825be06f61dfe82d0ff66bf4", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-text-001-ref.svg": [ + "f546ac2c0151ebabc5809e3adfc0f69624be05a9", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-text-002-ref.svg": [ + "d2176780046e91451bd6133853fd7cb627e559ca", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/clip-path-text-003-ref.svg": [ + "a455295170d3bacf72458784ebf8fc024df550cc", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/mask-content-clip-001-ref.svg": [ + "3b25631d52662baf24181f484c16cfe5785f871f", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/mask-content-clip-002-ref.svg": [ + "0ebbe7b3ca9870288df510d0b0aa08a7d7944f17", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-001-ref.svg": [ + "042a4399e47f143a758e1a20066910549892c20e", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-002-ref.svg": [ + "848f11e6d616b636484dfd00dd024ac4422c9b3b", + "support" + ], + "css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-003-ref.svg": [ + "64c30657edc5f4b73229645799e6670b0294807b", + "support" + ], + "css/css-masking/clip-path/clip-path-circle-001.html": [ + "f265a132d8ce0920518764cf1551f309875d81cb", + "reftest" + ], + "css/css-masking/clip-path/clip-path-circle-002.html": [ + "1e9b296e1e6e938da880c43d6b8be08824629209", + "reftest" + ], + "css/css-masking/clip-path/clip-path-circle-003.html": [ + "74e58ac4e352136c6901163b56f857dac5474439", + "reftest" + ], + "css/css-masking/clip-path/clip-path-circle-004.html": [ + "398f295d0db75f0cd7672734950623a0ce63f129", + "reftest" + ], + "css/css-masking/clip-path/clip-path-circle-005.html": [ + "258b14ac7e70b362f0c12977662e4db99a94af06", + "reftest" + ], + "css/css-masking/clip-path/clip-path-circle-006.html": [ + "b982c6a6f1e90878bc129e215b2d29d9e620ac63", + "reftest" + ], + "css/css-masking/clip-path/clip-path-circle-007.html": [ + "f077e1687ee241daf43052931e11c71d5085b52d", + "reftest" + ], + "css/css-masking/clip-path/clip-path-circle-008.html": [ + "d9cd99534c2d0bef45b84b97c601998247d8e368", + "reftest" + ], + "css/css-masking/clip-path/clip-path-element-userSpaceOnUse-001.html": [ + "6761d741d8bcb5f23c9cc111f89ce9446ffb45d1", + "reftest" + ], + "css/css-masking/clip-path/clip-path-element-userSpaceOnUse-002.html": [ + "3ac284a03a5a9c338619b708d6343765ae4701d8", + "reftest" + ], + "css/css-masking/clip-path/clip-path-element-userSpaceOnUse-003.html": [ + "5e616c40da278c5b3fdc4351483498da11bf1a25", + "reftest" + ], + "css/css-masking/clip-path/clip-path-element-userSpaceOnUse-004.html": [ + "fca0837d527c68252cf8ad80ecad913450a289cc", + "reftest" + ], + "css/css-masking/clip-path/clip-path-ellipse-001.html": [ + "4f19b1da771cc0074aa2303ca81a8e6af02f5b22", + "reftest" + ], + "css/css-masking/clip-path/clip-path-ellipse-002.html": [ + "791d2a01d12c79c3bef71f4e207e8767943c1870", + "reftest" + ], + "css/css-masking/clip-path/clip-path-ellipse-003.html": [ + "248724f9bcd53e388e30d12961b99206ab7ee706", + "reftest" + ], + "css/css-masking/clip-path/clip-path-ellipse-004.html": [ + "b0d3c13374cf774b00a9474a4e4bafcc56da9635", + "reftest" + ], + "css/css-masking/clip-path/clip-path-ellipse-005.html": [ + "08b41c5ee596f09c0e9cc1aa9e61eb11bd5dfaf1", + "reftest" + ], + "css/css-masking/clip-path/clip-path-ellipse-006.html": [ + "a66ed2871c901b19e46ebeba3d78e4f08c5402e3", + "reftest" + ], + "css/css-masking/clip-path/clip-path-ellipse-007.html": [ + "3f628fc165a225c518bff87a30189e19fddbafc0", + "reftest" + ], + "css/css-masking/clip-path/clip-path-ellipse-008.html": [ + "f795eb9e2412806879c4fde92d8ae2ccd68c5c7c", + "reftest" + ], + "css/css-masking/clip-path/clip-path-polygon-001.html": [ + "66cf22ce5aa64b4c6d5337c4cc775c3300f0bda0", + "reftest" + ], + "css/css-masking/clip-path/clip-path-polygon-002.html": [ + "091255fdbd5f9e5ea18831dd6ea57261518dc42a", + "reftest" + ], + "css/css-masking/clip-path/clip-path-polygon-003.html": [ + "b698a007a60fe93706a295fd216da07026126807", + "reftest" + ], + "css/css-masking/clip-path/clip-path-polygon-004.html": [ + "5a3a5a5e8a5df1be12e067c714b01f282abd04f0", + "reftest" + ], + "css/css-masking/clip-path/clip-path-polygon-005.html": [ + "ac6675dc4258c731d189420e6783f6bc7c4add06", + "reftest" + ], + "css/css-masking/clip-path/clip-path-polygon-006.html": [ + "7be2b64d3ff2110f1861bf40b2d2d13d7b96f345", + "reftest" + ], + "css/css-masking/clip-path/clip-path-polygon-007.html": [ + "ddc6324b3525300586770ede014f97c4ab8b8386", + "reftest" + ], + "css/css-masking/clip-path/clip-path-polygon-008.html": [ + "06b643c2dd5883ab3349c2a11eebbbd30d711483", + "reftest" + ], + "css/css-masking/clip-path/clip-path-polygon-009.html": [ + "9826f51c7f113758f43697dc9964d99ea995e1ca", + "reftest" + ], + "css/css-masking/clip-path/clip-path-polygon-010.html": [ + "918b6a39fe8448911d29ba7fd16069aaa1b19427", + "reftest" + ], + "css/css-masking/clip-path/clip-path-polygon-011.html": [ + "20895dbf1b965265831463c3739e0c8c0c3664dc", + "reftest" + ], + "css/css-masking/clip-path/clip-path-polygon-012.html": [ + "03169910ccb6f712bb26e4481fbc890f48318d6e", + "reftest" + ], + "css/css-masking/clip-path/clip-path-polygon-013.html": [ + "c03b6730ce9cf542261dc335bdb3712946913dc0", + "reftest" + ], + "css/css-masking/clip-path/reference/clip-path-circle-2-ref.html": [ + "a6945323fcd78d3b53eb67a9d001d3ad117a2387", + "support" + ], + "css/css-masking/clip-path/reference/clip-path-circle-3-ref.html": [ + "aeb1dbd540caa1c2a6e1295812cddd4f4cd939f5", + "support" + ], + "css/css-masking/clip-path/reference/clip-path-circle-ref.html": [ + "235cc287098d47f3a952d5034f6ef6a7e5f3bb47", + "support" + ], + "css/css-masking/clip-path/reference/clip-path-ellipse-ref.html": [ + "9bc3bca512a62ab2a603670753995e12c7d211ce", + "support" + ], + "css/css-masking/clip-path/reference/clip-path-rectangle-border-ref.html": [ + "bd28c14af111682131f88319feac46e6ec80cdfa", + "support" + ], + "css/css-masking/clip-path/reference/clip-path-rectangle-ref.html": [ + "f987b164a1a3a9c314cb98ba9385fbfae768413f", + "support" + ], + "css/css-masking/clip-path/reference/clip-path-ref-bottom-green-ref.html": [ + "331ffd9de7831f66e4f7d5cec70300efdc9865eb", + "support" + ], + "css/css-masking/clip-path/reference/clip-path-ref-right-green-ref.html": [ + "2dee4048cb2b75be993fe782b97954813388373a", + "support" + ], + "css/css-masking/clip-path/reference/clip-path-square-001-ref.html": [ + "1c18969e30afa1f8205f43786fd3e8ef55d4c45f", + "support" + ], + "css/css-masking/clip-path/reference/clip-path-square-002-ref.html": [ + "e61874c2bd128b82e7c785415b06cde38114ec2c", + "support" + ], + "css/css-masking/clip-path/reference/clip-path-stripes-001-ref.html": [ + "6590a66b97be0c29be9ba54986b44bad14a2a012", + "support" + ], + "css/css-masking/clip-path/reference/clip-path-stripes-002-ref.html": [ + "3a7a2b5c5fdf8e18bec35462c7cd9a4be29948ad", + "support" + ], + "css/css-masking/clip-path/reference/clip-path-stripes-003-ref.html": [ + "c41a5497d762b23668e27b7a64ff0b23572bbd67", + "support" + ], + "css/css-masking/clip-path/svg-clipPath.svg": [ + "c74b3448c10c2d388603164f33a5d8d82143cf43", + "support" + ], + "css/css-masking/clip-rule/clip-rule-001.html": [ + "554a1bf622c76182e3f8161f67fdebdf42b2fb8e", + "reftest" + ], + "css/css-masking/clip-rule/clip-rule-002.html": [ + "2f726b6718c8631d88e6a8e87f05745ab6504abf", + "reftest" + ], + "css/css-masking/clip-rule/reference/clip-rule-rectangle-border-ref.html": [ + "bd28c14af111682131f88319feac46e6ec80cdfa", + "support" + ], + "css/css-masking/clip/clip-absolute-positioned-001.html": [ + "fa18dcfe8b94fcf68b9bf3617311dac78f9c7ca5", + "reftest" + ], + "css/css-masking/clip/clip-absolute-positioned-002.html": [ + "fe0ccd92a8e243bd6ba667c46cc32b9b550140db", + "reftest" + ], + "css/css-masking/clip/clip-negative-values-001.html": [ + "4f1a669631c9d8e22f16bf986bcb7bcf376f1be9", + "reftest" + ], + "css/css-masking/clip/clip-negative-values-002.html": [ + "eaf22e70dff9ac9b643ac2c3df3849f4ec7cc908", + "reftest" + ], + "css/css-masking/clip/clip-negative-values-003.html": [ + "ff884020449565c339220911c72083156ef55962", + "reftest" + ], + "css/css-masking/clip/clip-negative-values-004.html": [ + "da216aa7845ee91d25de2601f7313baf578417b7", + "reftest" + ], + "css/css-masking/clip/clip-no-clipping-001.html": [ + "fd733a5733f0bc5ef7739a29a1621b34111df0a4", + "reftest" + ], + "css/css-masking/clip/clip-no-clipping-002.html": [ + "7bad941ede4edb393212f69259c0d7592106112b", + "reftest" + ], + "css/css-masking/clip/clip-not-absolute-positioned-001.html": [ + "efb0b493a0df74360579a63e951a33802ecccc3b", + "reftest" + ], + "css/css-masking/clip/clip-not-absolute-positioned-002.html": [ + "13bd62f26b325e8bf0c4f963b02ad7002904b4c8", + "reftest" + ], + "css/css-masking/clip/clip-not-absolute-positioned-003.html": [ + "7a7e2e3f811576d9926b54a68710722c6dcc0adf", + "reftest" + ], + "css/css-masking/clip/clip-not-absolute-positioned-004.html": [ + "c650a01374b2a03cd5f0b6e7cf20dae84264683a", + "reftest" + ], + "css/css-masking/clip/clip-rect-auto-001.html": [ + "e736cd6a808b66b8eefc9f7713d958834b32c1b0", + "reftest" + ], + "css/css-masking/clip/clip-rect-auto-002.html": [ + "7038536497473e6c5ff97526892d306d778b0868", + "reftest" + ], + "css/css-masking/clip/clip-rect-auto-003.html": [ + "56dfab1ff6eb157af35bb8bb460ae41f53cf7c1d", + "reftest" + ], + "css/css-masking/clip/clip-rect-auto-004.html": [ + "dd4a89326385ff7cdccd0386d11178f43057351c", + "reftest" + ], + "css/css-masking/clip/clip-rect-auto-005.html": [ + "eb2905f422574d19d82e65b92803e5dde34d071f", + "reftest" + ], + "css/css-masking/clip/clip-rect-auto-006.html": [ + "781b539b814d7d90ebc71678fc89ead8829126ac", + "reftest" + ], + "css/css-masking/clip/clip-rect-comma-001.html": [ + "de39f7695ae80d7cdeea922f2395d89873fb2eeb", + "reftest" + ], + "css/css-masking/clip/clip-rect-comma-002.html": [ + "70d6467b21e7a4b82665231413624b100e1b0926", + "reftest" + ], + "css/css-masking/clip/clip-rect-comma-003.html": [ + "b54ab663c2743a75664960ac7673ed2be7be5fac", + "reftest" + ], + "css/css-masking/clip/clip-rect-comma-004.html": [ + "d7aa6a378311712bf6bb7f9e4c6810124284fd40", + "reftest" + ], + "css/css-masking/clip/reference/clip-absolute-positioned-ref.html": [ + "7448ec0ee3184b6f95d562c0e360a8844fde9b97", + "support" + ], + "css/css-masking/clip/reference/clip-full-ref.html": [ + "ff2bf578e9433f9dfa2072c66f448e86fd73a9d1", + "support" + ], + "css/css-masking/clip/reference/clip-horizontal-stripe-ref.html": [ + "beb646fbeacdcb1339925b6d58a51bfbb1ede256", + "support" + ], + "css/css-masking/clip/reference/clip-no-clipping-ref.html": [ + "baee9f5ef67d55ae03fe66a00b2d9c972723bd32", + "support" + ], + "css/css-masking/clip/reference/clip-overflow-hidden-ref.html": [ + "98f3e392ba4c54ddd0214ea0bce6a6847e63fca5", + "support" + ], + "css/css-masking/clip/reference/clip-rect-bottom-ref.html": [ + "6a33e33e28c707e2542f7dcef46092d497ce4c6a", + "support" + ], + "css/css-masking/clip/reference/clip-rect-left-ref.html": [ + "313232e967cef8035aa04e7e6c95ee1ded867b69", + "support" + ], + "css/css-masking/clip/reference/clip-rect-right-ref.html": [ + "7b0acf621bb41ade4c5620383bc4e63a4b2dd0ea", + "support" + ], + "css/css-masking/clip/reference/clip-rect-top-ref.html": [ + "700d9d78427c2f60e62859073e8144b4fc096686", + "support" + ], + "css/css-masking/clip/reference/clip-vertical-stripe-ref.html": [ + "8853e79d6e9c3d262ebb38c569e97932f3b27cd4", + "support" + ], + "css/css-masking/parsing/clip-invalid.html": [ + "fad5d0257532a5c1572d41f83d045c92a6fe0d61", + "testharness" + ], + "css/css-masking/parsing/clip-path-invalid-expected.txt": [ + "e115915861f0d4bf48f30612e9c21e2b1c386bf8", + "support" + ], + "css/css-masking/parsing/clip-path-invalid.html": [ + "791ea3c564f629ed8d679499f5483e122ad9f602", + "testharness" + ], + "css/css-masking/parsing/clip-path-valid-expected.txt": [ + "36e3917ed8c4c7b3fb08bd7836654b05d2e4824b", + "support" + ], + "css/css-masking/parsing/clip-path-valid.html": [ + "4ac5715cdba374d3b702157ffce4a0a45009995a", + "testharness" + ], + "css/css-masking/parsing/clip-rule-invalid.html": [ + "5a7673c56ae29a10133ed1395ae1e61ee2a7dd81", + "testharness" + ], + "css/css-masking/parsing/clip-rule-valid.html": [ + "9236b88f0ac03139210fe6f5fd5f9fa08a613c09", + "testharness" + ], + "css/css-masking/parsing/clip-valid-expected.txt": [ + "ba9cff26a57bd2bed5c2fb04c92ba4e5ab86b729", + "support" + ], + "css/css-masking/parsing/clip-valid.html": [ + "e7805a38a0634d760bdc31e4c331da1a56582bc9", + "testharness" + ], + "css/css-masking/parsing/resources/parsing-testcommon.js": [ + "14f32b772f27a9bc75fe90e2ea1d8e4fb3649e95", + "support" + ], + "css/css-masking/test-mask-ref.html": [ + "6307ecf282b941dbe1475bdb603208f4140b2f26", + "support" + ], + "css/css-masking/test-mask.html": [ + "13f1c2ad253ea55e13781544bbfad4900a3a58c1", + "reftest" + ], "css/css-multicol/OWNERS": [ "1cf1640b76a341546126c66b30f35f6f32aef798", "support" @@ -337162,32 +340124,32 @@ "c786c1df10c1edad9b25be4ec112250864c328e5", "support" ], - "fetch/corb/img-html-correctly-labeled.sub-expected.html": [ + "fetch/corb/img-html-correctly-labeled.sub-ref.html": [ "a252054121e7f50a3bcb949ae5a40f278c842c04", "support" ], "fetch/corb/img-html-correctly-labeled.sub.html": [ - "699a8b2c8bb1f089f3ef1827bf8cfe1873849bf8", + "0c080d27dfcc89fc1f7e92be063f4d2d95fa9d6c", "reftest" ], "fetch/corb/img-mime-types-coverage.tentative.sub.html": [ "02da8b9ee9430d552c4cb71fb759e05e939ec05e", "testharness" ], - "fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-expected.html": [ + "fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html": [ "1980633a4167993d90636be2ebba2aa8d72299b7", "support" ], "fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html": [ - "7169e4ebe99797d15f006f6787e84093780fbaa6", + "2005cb1cd7a313d8ca7ee89c32e5bc54c39b2da5", "reftest" ], - "fetch/corb/img-png-mislabeled-as-html.sub-expected.html": [ + "fetch/corb/img-png-mislabeled-as-html.sub-ref.html": [ "730878950e0b7a4097d42e7eaaae79304fe05106", "support" ], "fetch/corb/img-png-mislabeled-as-html.sub.html": [ - "a7775fb534d38a5d5b5827a27f0c16e1268f4d0b", + "cafbaa0cf543dc360a6261258e88339b2ad1dcb3", "reftest" ], "fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html": [ @@ -383274,12 +386236,12 @@ "974affbb2c135c9aaa7a3f27687157b5e1250a9f", "testharness" ], - "svg/extensibility/foreignObject/stacking-context-expected.html": [ + "svg/extensibility/foreignObject/stacking-context-ref.html": [ "6ea850b74b6a03554305ed95df45079bdbcb15dd", "support" ], "svg/extensibility/foreignObject/stacking-context.html": [ - "ef9026d2b8b27a258c3921139c46692292377dfe", + "7e3601ac1fcac50bf989f3767cc81ad84bc99276", "reftest" ], "svg/extensibility/interfaces/foreignObject-graphics.svg": [ @@ -387343,7 +390305,7 @@ "support" ], "webrtc/RTCPeerConnection-setDescription-transceiver.html": [ - "4d0d9a168327e62eefc0d4398874fd944c50b43c", + "a21fe04592ad6941aa4277535d6482519b67ae74", "testharness" ], "webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt": [ @@ -393435,7 +396397,7 @@ "support" ], "worklets/resources/service-worker-interception-tests.js": [ - "e23072b8b5695b7669d855197285b8ec3534b6e7", + "42ebe0dd946d39dcf3c211581a15d0f648a67a08", "support" ], "worklets/resources/service-worker.js": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/idlharness.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/idlharness.tentative.html index e313b04..9835427 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/idlharness.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/idlharness.tentative.html
@@ -43,6 +43,11 @@ ] }); idl_array.add_untested_idls( + `dictionary ExtendableEventInit {};`); + idl_array.add_untested_idls( + `[Global=ExtendableEvent, Exposed=ServiceWorker] + interface ExtendableEvent : Event {};`); + idl_array.add_untested_idls( `[Global=ServiceWorker, Exposed=ServiceWorker] interface ServiceWorkerGlobalScope {};`);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/idlharness_serviceworker.js b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/idlharness_serviceworker.js index e2e838d..ba80413 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/idlharness_serviceworker.js +++ b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/idlharness_serviceworker.js
@@ -16,8 +16,12 @@ idl_array.add_untested_idls( `[Global=Event, Exposed=ServiceWorker] interface Event {};`); + idl_array.add_untested_idls( + `[Global=ExtendableEvent, Exposed=ServiceWorker] + interface ExtendableEvent : Event {};`); idl_array.add_untested_idls('dictionary EventHandler {};'); idl_array.add_untested_idls('dictionary EventInit {};'); + idl_array.add_untested_idls('dictionary ExtendableEventInit {};'); idl_array.add_untested_idls( `[Global=EventTarget, Exposed=ServiceWorker] interface EventTarget {};`); @@ -32,7 +36,8 @@ idl_array.add_objects({ CookieStore: [self.cookieStore], - CookieChangeEvent: [new CookieChangeEvent('change')], + ExtendableCookieChangeEvent: [ + new ExtendableCookieChangeEvent('cookiechange')], }); idl_array.test(); }, 'Interface test');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions.js b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions.js new file mode 100644 index 0000000..3f1b0ff --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions.js
@@ -0,0 +1,113 @@ +self.GLOBAL = { + isWindow: function() { return false; }, + isWorker: function() { return true; }, +}; +importScripts("/resources/testharness.js"); + +self.addEventListener('install', (event) => { + event.waitUntil((async () => { + // The subscribeToChanges calls are not done in parallel on purpose. Having + // multiple in-flight requests introduces failure modes aside from the + // cookie change logic that this test aims to cover. + await cookieStore.subscribeToChanges([ + { name: 'cookie-name1', matchType: 'equals', url: '/scope/path1' }]); + await cookieStore.subscribeToChanges([ + { }, // Test the default values for subscription properties. + { name: 'cookie-prefix', matchType: 'startsWith' }, + ]); + })()); +}); + +// Workaround because add_cleanup doesn't support async functions yet. +// See https://github.com/w3c/web-platform-tests/issues/6075 +async function async_cleanup(cleanup_function) { + try { + await cleanup_function(); + } catch (e) { + // Errors in cleanup functions shouldn't result in test failures. + } +} + +// Resolves when the service worker receives the 'activate' event. +const kServiceWorkerActivatedPromise = new Promise(resolve => { + self.addEventListener('activate', event => { resolve(); }); +}); + +// sort() comparator that uses the < operator. +// +// This is intended to be used for sorting strings. Using < is preferred to +// localeCompare() because the latter has some implementation-dependent +// behavior. +function CompareStrings(a, b) { + return a < b ? -1 : (b < a ? 1 : 0); +} + +promise_test(async testCase => { + await kServiceWorkerActivatedPromise; + + const subscriptions = await cookieStore.getChangeSubscriptions(); + assert_equals(subscriptions.length, 3); + + subscriptions.sort((a, b) => CompareStrings(`${a.name}`, `${b.name}`)); + + assert_equals(subscriptions[0].name, 'cookie-name1'); + assert_equals('equals', subscriptions[0].matchType); + + assert_equals(subscriptions[1].name, 'cookie-prefix'); + assert_equals('startsWith', subscriptions[1].matchType); + + assert_false('name' in subscriptions[2]); + assert_equals('startsWith', subscriptions[2].matchType); +}, 'getChangeSubscriptions returns subscriptions passed to subscribeToChanges'); + +promise_test(async testCase => { + promise_rejects( + testCase, new TypeError(), + cookieStore.subscribeToChanges([{ name: 'cookie-name2' }])); +}, 'subscribeToChanges rejects when called outside the install handler'); + + +// Accumulates cookiechange events dispatched to the service worker. +let g_cookie_changes = []; + +// Resolved when a cookiechange event is received. Rearmed by +// ResetCookieChangeReceivedPromise(). +let g_cookie_change_received_promise = null; +let g_cookie_change_received_promise_resolver = null; +self.addEventListener('cookiechange', (event) => { + g_cookie_changes.push(event); + if (g_cookie_change_received_promise_resolver) + g_cookie_change_received_promise_resolver(); +}); +function RearmCookieChangeReceivedPromise() { + g_cookie_change_received_promise = new Promise((resolve) => { + g_cookie_change_received_promise_resolver = resolve; + }); +} +RearmCookieChangeReceivedPromise(); + +promise_test(async testCase => { + await kServiceWorkerActivatedPromise; + + await cookieStore.set('cookie-name', 'cookie-value'); + + await g_cookie_change_received_promise; + + assert_equals(g_cookie_changes.length, 1); + const event = g_cookie_changes[0] + assert_equals(event.type, 'cookiechange'); + assert_equals(event.changed.length, 1); + assert_equals(event.changed[0].name, 'cookie-name'); + assert_equals(event.changed[0].value, 'cookie-value'); + assert_equals(event.deleted.length, 0); + assert_true(event instanceof ExtendableCookieChangeEvent); + assert_true(event instanceof ExtendableEvent); + + await async_cleanup(() => { + cookieStore.delete('cookie-name'); + g_cookie_changes = []; + RearmCookieChangeReceivedPromise(); + }); +}, 'cookiechange dispatched with cookie change that matches subscription'); + +done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions.tentative.https.html new file mode 100644 index 0000000..723de23 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions.tentative.https.html
@@ -0,0 +1,22 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Async Cookies: cookie change events in ServiceWorker</title> +<link rel="help" href="https://github.com/WICG/cookie-store"> +<link rel="author" href="pwnall@chromium.org" title="Victor Costan"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +'use strict'; + +(async () => { + const scope = 'scope'; + + let registration = await navigator.serviceWorker.getRegistration(scope); + if (registration) + await registration.unregister(); + registration = await navigator.serviceWorker.register( + 'serviceworker_cookieStore_subscriptions.js', {scope}); + + fetch_tests_from_worker(registration.installing); +})(); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions_basic.js b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions_basic.js new file mode 100644 index 0000000..68edc0e --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions_basic.js
@@ -0,0 +1,63 @@ +self.GLOBAL = { + isWindow: function() { return false; }, + isWorker: function() { return true; }, +}; +importScripts("/resources/testharness.js"); + +self.addEventListener('install', (event) => { + event.waitUntil((async () => { + cookieStore.subscribeToChanges([ + { name: 'cookie-name', matchType: 'equals', url: '/scope/path' }]); + })()); +}); + +// Workaround because add_cleanup doesn't support async functions yet. +// See https://github.com/w3c/web-platform-tests/issues/6075 +async function async_cleanup(cleanup_function) { + try { + await cleanup_function(); + } catch (e) { + // Errors in cleanup functions shouldn't result in test failures. + } +} + +// Resolves when the service worker receives the 'activate' event. +const kServiceWorkerActivatedPromise = new Promise(resolve => { + self.addEventListener('activate', event => { resolve(); }); +}); + +promise_test(async testCase => { + await kServiceWorkerActivatedPromise; + + const subscriptions = await cookieStore.getChangeSubscriptions(); + assert_equals(subscriptions.length, 1); + + assert_equals(subscriptions[0].name, 'cookie-name'); + assert_equals('equals', subscriptions[0].matchType); +}, 'getChangeSubscriptions returns a subscription passed to subscribeToChanges'); + + +promise_test(async testCase => { + await kServiceWorkerActivatedPromise; + + cookie_change_received_promise = new Promise((resolve) => { + self.addEventListener('cookiechange', (event) => { + resolve(event); + }); + }); + + await cookieStore.set('cookie-name', 'cookie-value'); + + const event = await cookie_change_received_promise; + assert_equals(event.type, 'cookiechange'); + assert_equals(event.changed.length, 1); + assert_equals(event.changed[0].name, 'cookie-name'); + assert_equals(event.changed[0].value, 'cookie-value'); + assert_equals(event.deleted.length, 0); + assert_true(event instanceof ExtendableCookieChangeEvent); + assert_true(event instanceof ExtendableEvent); + + await async_cleanup(() => { cookieStore.delete('cookie-name'); }); +}, 'cookiechange dispatched with cookie change that matches subscription'); + +done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions_basic.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions_basic.tentative.https.html new file mode 100644 index 0000000..525c3b3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/serviceworker_cookieStore_subscriptions_basic.tentative.https.html
@@ -0,0 +1,22 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Async Cookies: cookie change events in ServiceWorker</title> +<link rel="help" href="https://github.com/WICG/cookie-store"> +<link rel="author" href="pwnall@chromium.org" title="Victor Costan"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +'use strict'; + +(async () => { + const scope = 'scope'; + + let registration = await navigator.serviceWorker.getRegistration(scope); + if (registration) + await registration.unregister(); + registration = await navigator.serviceWorker.register( + 'serviceworker_cookieStore_subscriptions_basic.js', {scope}); + + fetch_tests_from_worker(registration.installing); +})(); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/support/fonts/font-feature-settings-rendering-2-expected.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/support/fonts/font-feature-settings-rendering-2-ref.html similarity index 100% rename from third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/support/fonts/font-feature-settings-rendering-2-expected.html rename to third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/support/fonts/font-feature-settings-rendering-2-ref.html
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/OWNERS new file mode 100644 index 0000000..5f3e240 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/OWNERS
@@ -0,0 +1,3 @@ +# TEAM: paint-dev@chromium.org +# COMPONENT: Blink>Paint +# WPT-NOTIFY: true
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-nested-twice.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-nested-twice.svg new file mode 100644 index 0000000..269e8fee --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-nested-twice.svg
@@ -0,0 +1,23 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath element nested twice</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Check deep referencing of content of one clipPath + element to another clipPath element. A green square should be visible. + </desc> +</g> +<clipPath id="clip3"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<clipPath id="clip2" clip-path="url(#clip3)"> + <circle cx="100" cy="100" r="75"/> +</clipPath> +<clipPath id="clip1" clip-path="url(#clip2)"> + <circle cx="100" cy="100" r="100"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-001.svg new file mode 100644 index 0000000..e5b972f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-001.svg
@@ -0,0 +1,18 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clip-rule property - evenodd</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-rule"/> + <html:link rel="match" href="reference/clip-path-square-hole-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Check if the clip-rule 'evenodd' applies to a content + polygon element of clipPath element. A green square with a + rectangular hole should be visible.</desc> +</g> +<clipPath id="clip1"> + <polygon points="25 25, 175 25, 175 175, 25 175, 25 50, 150 50, 150 150, 50 150, 50 50, 25 50" clip-rule="evenodd" /> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-002.svg new file mode 100644 index 0000000..7729f79 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-002.svg
@@ -0,0 +1,18 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clip-rule property - nonzero</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-rule"/> + <html:link rel="match" href="reference/clip-path-square-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Check if the clip-rule 'nonzero' applies to a content + polygon element of clipPath element. A green square should be + visible.</desc> +</g> +<clipPath id="clip1"> + <polygon points="25 25, 175 25, 175 175, 25 175, 25 50, 150 50, 150 150, 50 150, 50 50, 25 50" clip-rule="nonzero" /> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-003.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-003.svg new file mode 100644 index 0000000..c4f2bf4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-003.svg
@@ -0,0 +1,21 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clip-rule property - evenodd nested clip</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-rule"/> + <html:link rel="match" href="reference/clip-path-square-hole-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Check if the clip-rule 'evenodd' applies to a content + polygon element of clipPath element. A green square with a + rectangular hole should be visible.</desc> +</g> +<clipPath id="clip2"> + <rect x="25" y="25" width="150" height="150"/> +</clipPath> +<clipPath id="clip1" clip-path="url(#clip2)"> + <polygon points="0 0, 200 0, 200 200, 0 200, 0 50, 150 50, 150 150, 50 150, 50 50, 0 50" clip-rule="evenodd" /> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-004.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-004.svg new file mode 100644 index 0000000..2ea61860 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-004.svg
@@ -0,0 +1,21 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clip-rule property - nonzero nested clip</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-rule"/> + <html:link rel="match" href="reference/clip-path-square-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Check that clip-rule 'nonzero' applies to + clipPath element and a second clipPath element can be applied to + the first one. A green square should be visible.</desc> +</g> +<clipPath id="clip2"> + <rect x="25" y="25" width="150" height="150"/> +</clipPath> +<clipPath id="clip1" clip-path="url(#clip2)"> + <polygon points="0 0, 200 0, 200 200, 0 200, 0 50, 150 50, 150 150, 50 150, 50 50, 0 50" clip-rule="nonzero" /> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-005.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-005.svg new file mode 100644 index 0000000..ca49258 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-005.svg
@@ -0,0 +1,19 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath clip-rule evenodd nonzero</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-rule"/> + <html:link rel="match" href="reference/clip-path-clip-rule-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Test two different clip-rules on two different content + elements. You should see two green rectangles. The one on the top left + should have a hole, the shifted one shouldn't.</desc> +</g> +<clipPath id="clip1"> + <polygon points="0 0, 150 0, 150 150, 0 150, 0 25, 125 25, 125 125, 25 125, 25 25, 0 25" clip-rule="evenodd"/> + <polygon points="50 50, 200 50, 200 200, 50 200, 50 75, 175 75, 175 175, 75 175, 75 75, 50 75" clip-rule="nonzero"/> +</clipPath> +<rect x="0" y="0" height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-006.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-006.svg new file mode 100644 index 0000000..da9d1010 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-006.svg
@@ -0,0 +1,20 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath clip-rule nonzero nonzero</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-rule"/> + <html:link rel="match" href="reference/clip-path-clip-rule-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Test two equal clip-rules 'nonzero' on two different + content elements. You should see two solid green rectangles. The first one + on the top left, the second one slightly shifted to the bottom right. + </desc> +</g> +<clipPath id="clip1"> + <polygon points="0 0, 150 0, 150 150, 0 150, 0 25, 125 25, 125 125, 25 125, 25 25, 0 25" clip-rule="nonzero"/> + <polygon points="50 50, 200 50, 200 200, 50 200, 50 75, 175 75, 175 175, 75 175, 75 75, 50 75" clip-rule="nonzero"/> +</clipPath> +<rect x="0" y="0" height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-007.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-007.svg new file mode 100644 index 0000000..d1edb6c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-007.svg
@@ -0,0 +1,19 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath clip-rule nonzero evenodd</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-rule"/> + <html:link rel="match" href="reference/clip-path-clip-rule-003-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Test two different clip-rules on two different content + elements. You should see two green rectangles. The one on the top left + shouldn't have a hole, the shifted one should have.</desc> +</g> +<clipPath id="clip1"> + <polygon points="0 0, 150 0, 150 150, 0 150, 0 25, 125 25, 125 125, 25 125, 25 25, 0 25" clip-rule="nonzero"/> + <polygon points="50 50, 200 50, 200 200, 50 200, 50 75, 175 75, 175 175, 75 175, 75 75, 50 75" clip-rule="evenodd"/> +</clipPath> +<rect x="0" y="0" height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-008.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-008.svg new file mode 100644 index 0000000..66ad9b5c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-008.svg
@@ -0,0 +1,20 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath clip-rule evenodd evenodd</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-rule"/> + <html:link rel="match" href="reference/clip-path-clip-rule-004-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Test two equal clip-rules 'evenodd' on two different + content elements. You should see two green rectangles with a hole. The + first one on the top left, the second one slightly shifted to the bottom + right.</desc> +</g> +<clipPath id="clip1"> + <polygon points="0 0, 150 0, 150 150, 0 150, 0 25, 125 25, 125 125, 25 125, 25 25, 0 25" clip-rule="evenodd"/> + <polygon points="50 50, 200 50, 200 200, 50 200, 50 75, 175 75, 175 175, 75 175, 75 75, 50 75" clip-rule="evenodd"/> +</clipPath> +<rect x="0" y="0" height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-009.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-009.svg new file mode 100644 index 0000000..69d70b4e --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-009.svg
@@ -0,0 +1,18 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath fill-rule</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-rule"/> + <html:link rel="match" href="reference/clip-path-square-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The fill-rule must not affect the winding rule for + clipping. A green square should be visible.</desc> +</g> +<clipPath id="clip1"> + <!-- fill-rule must not affect the winding rule for clipping --> + <polygon points="25 25, 175 25, 175 175, 25 175, 25 50, 150 50, 150 150, 50 150, 50 50, 25 50" fill-rule="evenodd"/> +</clipPath> +<rect x="0" y="0" height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-010.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-010.svg new file mode 100644 index 0000000..594e309 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip-rule-010.svg
@@ -0,0 +1,18 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath clip-rule inheritance</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-rule"/> + <html:link rel="match" href="reference/clip-path-clip-rule-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">inheritance and overriding of inheritance. The one on + the top left should have a hole, the shifted one shouldn't.</desc> +</g> +<clipPath id="clip1" clip-rule="evenodd"> + <polygon points="0 0, 150 0, 150 150, 0 150, 0 25, 125 25, 125 125, 25 125, 25 25, 0 25"/> + <polygon points="50 50, 200 50, 200 200, 50 200, 50 75, 175 75, 175 175, 75 175, 75 75, 50 75" clip-rule="nonzero"/> +</clipPath> +<rect x="0" y="0" height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip.svg new file mode 100644 index 0000000..530fd01 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-clip.svg
@@ -0,0 +1,19 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath references clipPath</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element references another + clipPath element. A green square should be visible.</desc> +</g> +<clipPath id="clip2"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<clipPath id="clip1" clip-path="url(#clip2)"> + <circle cx="100" cy="100" r="100"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-clip-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-clip-001.svg new file mode 100644 index 0000000..9991f16 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-clip-001.svg
@@ -0,0 +1,21 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: content of clipPath clipped 1</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Content element of clipPath references second + clipPath element and should be clipped by it. A green square should + be visible. + </desc> +</g> +<clipPath id="clip2"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<clipPath id="clip1"> + <circle cx="100" cy="100" r="100" clip-path="url(#clip2)"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-clip-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-clip-002.svg new file mode 100644 index 0000000..7677e3f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-clip-002.svg
@@ -0,0 +1,21 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: content of clipPath clipped 2</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">One content element of clipPath references second + clipPath element and should be clipped by it. Second content element + isn't clipped. A green square should be visible.</desc> +</g> +<clipPath id="clip2"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<clipPath id="clip1"> + <circle cx="100" cy="100" r="50"/> + <circle cx="100" cy="100" r="75" clip-path="url(#clip2)"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-clip-003.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-clip-003.svg new file mode 100644 index 0000000..fd1b291 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-clip-003.svg
@@ -0,0 +1,24 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: content of clipPath clipped 3</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Both content elements of clipPath reference + different other clipPath elements and should be clipped by them. A + green square should be visible.</desc> +</g> +<clipPath id="clip2"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<clipPath id="clip3"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<clipPath id="clip1"> + <circle cx="100" cy="100" r="75" clip-path="url(#clip2)"/> + <circle cx="100" cy="100" r="75" clip-path="url(#clip3)"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-invisible.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-invisible.svg new file mode 100644 index 0000000..0696d4b0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-invisible.svg
@@ -0,0 +1,19 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Content of clipPath with visibility: hidden</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-invisible-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">From the spec: "If a child element is made invisible + by display or visibility it does not contribute to the clipping path." + clipPath without content hides the clipped element. Nothing should be + visible. + </desc> +</g> +<clipPath id="clip1"> + <rect width="100" height="100" style="visibility: hidden;"/> +</clipPath> +<rect height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-syling.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-syling.svg new file mode 100644 index 0000000..bfa9d06 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-syling.svg
@@ -0,0 +1,16 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath content styling</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Style properties on content elements of clipPath + must be ignored. A green square should be visible.</desc> +</g> +<clipPath id="clip1" clip-path="url(#clip1)"> + <rect x="50" y="50" width="100" height="100" stroke="black" stroke-wdith="10" stroke-dasharray="10 10" fill="none"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-001.svg new file mode 100644 index 0000000..b70cdde --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-001.svg
@@ -0,0 +1,20 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="testmeta"> + <title>CSS Masking: clipPath reference content with use 1</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Reference content clip shape with use element from + defs section. A green square should be visible.</desc> +</g> +<defs> + <rect id="circle" x="50" y="50" width="100" height="100"/> +</defs> +<clipPath id="clip1"> + <use xlink:href="#circle"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-002.svg new file mode 100644 index 0000000..0596d21c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-002.svg
@@ -0,0 +1,24 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="testmeta"> + <title>CSS Masking: clipPath reference content with use 2</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Reference content clip shape with use element from + defs section. Afterwards, the clipPath element gets clipped. + A green square should be visible.</desc> +</g> +<defs> + <rect id="rect" x="50" y="50" width="150" height="150"/> +</defs> +<clipPath id="clip2"> + <rect width="150" height="150"/> +</clipPath> +<clipPath id="clip1" clip-path="url(#clip2)"> + <use xlink:href="#rect"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-003.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-003.svg new file mode 100644 index 0000000..7935467 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-003.svg
@@ -0,0 +1,26 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="testmeta"> + <title>CSS Masking: clipPath reference content with use 3</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Reference content clip shape with use element from + defs section. Afterwards, the clipPath element gets clipped. + The second clipPath element references the content element with + use as well. A green square should be visible.</desc> +</g> +<defs> + <rect id="rect1" x="50" y="50" width="150" height="150"/> + <rect id="rect2" width="150" height="150"/> +</defs> +<clipPath id="clip2"> + <use xlink:href="#rect2"/> +</clipPath> +<clipPath id="clip1" clip-path="url(#clip2)"> + <use xlink:href="#rect1"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-004.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-004.svg new file mode 100644 index 0000000..8e2e7a6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-004.svg
@@ -0,0 +1,21 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="testmeta"> + <title>CSS Masking: clipPath reference content with use 4</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Reference content clip shape with use element from + defs section. Furthermore, the referenced shape gets transformed. A + green square should be visible.</desc> +</g> +<defs> + <rect id="rect" width="100" height="100"/> +</defs> +<clipPath id="clip1"> + <use xlink:href="#rect" transform="translate(50, 50)"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-005.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-005.svg new file mode 100644 index 0000000..c7d5ec8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-005.svg
@@ -0,0 +1,25 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="testmeta"> + <title>CSS Masking: clipPath reference content with use 5</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The clipPath elements reference the same content + clip shape with use. One use reference gets transformed. The one + clipPath element gets clipped by the other one. A green square should + be visible.</desc> +</g> +<defs> + <rect id="rect" width="150" height="150"/> +</defs> +<clipPath id="clip2"> + <use xlink:href="#rect"/> +</clipPath> +<clipPath id="clip1" clip-path="url(#clip2)"> + <use xlink:href="#rect" transform="translate(50, 50)"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-006.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-006.svg new file mode 100644 index 0000000..6f9d7e06 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-006.svg
@@ -0,0 +1,26 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="testmeta"> + <title>CSS Masking: clipPath reference content with use 6</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The clipPath elements reference two different + content clip shapes with use. One use reference gets transformed. + The one clipPath element gets clipped by the other one. A green square + should be visible.</desc> +</g> +<defs> + <rect id="rect1" width="150" height="150"/> + <rect id="rect2" width="150" height="150"/> +</defs> +<clipPath id="clip2"> + <use xlink:href="#rect1"/> +</clipPath> +<clipPath id="clip1" clip-path="url(#clip2)"> + <use xlink:href="#rect2" transform="translate(50, 50)"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-007.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-007.svg new file mode 100644 index 0000000..7cf0fa0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-use-007.svg
@@ -0,0 +1,25 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="testmeta"> + <title>CSS Masking: clipPath reference content with use 7</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-003-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The clipPath element has a content use + element which references another use element which references a shape. + A green square should be visible.</desc> +</g> +<defs> + <rect width="200" height="200" id="rect"/> + <use id="use" xlink:href="#rect"/> +</defs> +<clipPath id="clip1"> + <use xlink:href="#use" /> +</clipPath> + +<rect width="400" height="400" fill="red" clip-path="url(#clip1)"/> +<rect width="200" height="200" fill="green" /> +</svg> +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-css-transform-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-css-transform-001.svg new file mode 100644 index 0000000..35b21f5f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-css-transform-001.svg
@@ -0,0 +1,16 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath with CSS Transforms</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">CSS Transforms must apply on the clipPath + element. A green square should be visible.</desc> +</g> +<clipPath id="clip1" style="transform: scale(10) translate(5px, 5px);"> + <rect width="10" height="10"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-css-transform-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-css-transform-002.svg new file mode 100644 index 0000000..cc21cb7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-css-transform-002.svg
@@ -0,0 +1,20 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath with CSS Transforms and 2nd content element</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">CSS Transforms must apply on the clipPath + element. This example adds a second content element since that may + cause masking in some implementations. A green square should be + visible.</desc> +</g> +<clipPath id="clip1" style="transform: scale(10) translate(2px, 2px);"> + <rect width="10" height="10"/> + <!-- Second rect may cause masking --> + <rect width="5" height="4"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-css-transform-003.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-css-transform-003.svg new file mode 100644 index 0000000..8f2713d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-css-transform-003.svg
@@ -0,0 +1,18 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath with CSS Transforms on content element</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-003-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">CSS Transforms must apply on content element of the + clipPath element. A green square should be visible.</desc> +</g> +<clipPath id="clip1"> + <rect width="400" height="400" style="transform: scale(.5);"/> +</clipPath> +<rect width="400" height="400" fill="red" clip-path="url(#clip1)"/> +<rect width="200" height="200" fill="green"/> +</svg> +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-css-transform-004.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-css-transform-004.svg new file mode 100644 index 0000000..d290fe1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-css-transform-004.svg
@@ -0,0 +1,19 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath with CSS Transforms on both content elements</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-003-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">CSS Transforms must apply on both content elements of + the clipPath element. A green square should be visible.</desc> +</g> +<clipPath id="clip1"> + <rect width="400" height="400" style="transform: scale(.5)"/> + <!-- Second rect may cause masking. --> + <rect width="400" height="400" style="transform: scale(.5)"/> +</clipPath> +<rect width="400" height="400" fill="red" clip-path="url(#clip1)"/> +<rect width="200" height="200" fill="green"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-dom-child-changes.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-dom-child-changes.svg new file mode 100644 index 0000000..611fb3f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-dom-child-changes.svg
@@ -0,0 +1,26 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Dynamic transform on clipPath content element</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-003-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A transformation is applied on the content element of + clipPath. A green square should be visible.</desc> +</g> +<clipPath id="clip1"> + <rect width="400" height="400"/> +</clipPath> + +<g clip-path="url(#clip1)"> + <rect width="400" height="400" fill="red"/> + <rect width="200" height="200" fill="green"/> +</g> + +<script> +var clip = document.getElementById("clip1"); +var rect = clip.firstChild.nextSibling; +rect.setAttribute("transform", "scale(0.5)"); +</script> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-dom-clippathunits.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-dom-clippathunits.svg new file mode 100644 index 0000000..edfccbd --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-dom-clippathunits.svg
@@ -0,0 +1,26 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Dynamic change of clipPathUnits on clipPath</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-003-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The clipPathUnits attribute on the clipPath + element gets changed dynamically from objectBoundingBox to userSpaceOnUse. + This reduces the clipping area from a size much bigger than the document to + the size of the green rectangle. A green square should be visible.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect width="200" height="200"/> +</clipPath> + +<rect width="400" height="400" fill="red" clip-path="url(#clip1)"/> +<rect width="200" height="200" fill="green"/> + +<script> +var clip = document.getElementById("clip1"); +var enumeration = clip.clipPathUnits; +enumeration.baseVal = 1; // Switch to userSpaceOnUse! +</script> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-dom-href.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-dom-href.svg new file mode 100644 index 0000000..112c132e --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-dom-href.svg
@@ -0,0 +1,25 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Dynamic reference of clipPath element</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-003-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The clip-path property gets applied to the later + clipped rectangle dynamically. A green square should be visible.</desc> +</g> + +<clipPath id="clip1"> + <rect width="200" height="200"/> +</clipPath> + +<g clip-path="url(#noclip)"> + <rect width="400" height="400" fill="red"/> + <rect width="200" height="200" fill="green"/> +</g> + +<script> +document.getElementsByTagName("g")[0].setAttribute("clip-path", "url(#clip1)"); +</script> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-dom-id.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-dom-id.svg new file mode 100644 index 0000000..e8ad7dae --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-dom-id.svg
@@ -0,0 +1,23 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Dynamic change of clipPath id</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-003-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The id of a clipPath element is changed + dynamically. This makes the previous invalid clip path reference + of the group valid. A green square should be visible.</desc> +</g> +<clipPath id="oldclip" clipPathUnits="userSpaceOnUse"> + <rect width="200" height="200"/> +</clipPath> +<g clip-path="url(#newclip)"> + <rect width="400" height="400" fill="red"/> + <rect width="200" height="200" fill="green"/> +</g> +<script> +document.getElementsByTagName("clipPath")[0].setAttribute("id", "newclip"); +</script> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-invalid.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-invalid.svg new file mode 100644 index 0000000..85aa3a825 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-invalid.svg
@@ -0,0 +1,21 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath invalid content element</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-invisible-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">clipPath elements get invalid if the content + element is not a basic shape or a reference to a basic shape. + Invalid clipPath elements let the clipped element disappear. + Nothing should be visible.</desc> +</g> +<clipPath id="clip1"> + <!-- nothing should be visible, containers are not allowed in clipPath --> + <g> + <rect width="100" height="100"/> + </g> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-negative-scale.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-negative-scale.svg new file mode 100644 index 0000000..33d6a78 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-negative-scale.svg
@@ -0,0 +1,40 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="testmeta"> + <title>CSS Masking: clipPath negative scale</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-negative-scale-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Negative scale factors on clipped elements should + be handled correctly by clipPath elements. First clipped, then + scaled.</desc> +</g> +<defs> +<g id="img" transform="translate(10,10)"> + <rect width="200" height="200" fill="red"/> + <rect width="100" height="100" fill="green"/> + <rect width="50" height="50" fill="blue"/> +</g> +</defs> + +<clipPath id="clip"> + <rect x="10" y="10" height="90" width="90"/> +</clipPath> + +<g transform="translate(200, 200)"> +<g transform="matrix(1 0 0 1 -100 -100)" clip-path="url(#clip)"> + <use xlink:href="#img"/> +</g> +<g transform="matrix(-1 0 0 -1 -100 -100)" clip-path="url(#clip)"> + <use xlink:href="#img"/> +</g> +<g transform="matrix(-1 0 0 1 -100 -100)" clip-path="url(#clip)"> + <use xlink:href="#img"/> +</g> +<g transform="matrix(1 0 0 -1 -100 -100)" clip-path="url(#clip)"> + <use xlink:href="#img"/> +</g> +</g> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-no-content-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-no-content-001.svg new file mode 100644 index 0000000..f7943c6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-no-content-001.svg
@@ -0,0 +1,15 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath without content</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-invisible-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">clipPath element without content make the clipped + element disappear. Nothing should be visible.</desc> +</g> +<clipPath id="clip1"> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-no-content-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-no-content-002.svg new file mode 100644 index 0000000..65df617 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-no-content-002.svg
@@ -0,0 +1,17 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath without content 2</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-invisible-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">clipPath element where the clip shape does not + intersect with the clipped element make the clipped element disappear. + Nothing should be visible.</desc> +</g> +<clipPath id="clip1"> + <circle cx="400" cy="400" r="100"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-no-content-003.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-no-content-003.svg new file mode 100644 index 0000000..afd8f70 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-no-content-003.svg
@@ -0,0 +1,20 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath and clipPath without intersection</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-invisible-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">If a clipPath element get clipped and there is no + intersection with the second clipPath element, the originally clipped + element disappears. Nothing should be visible.</desc> +</g> +<clipPath id="clip2"> + <circle cx="400" cy="400" r="100"/> +</clipPath> +<clipPath id="clip1" clip-path="url(#clip2)"> + <rect width="200" height="200"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-no-content-004.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-no-content-004.svg new file mode 100644 index 0000000..92b27af --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-no-content-004.svg
@@ -0,0 +1,23 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath with invalid/empty content</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-invisible-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">If a clipPath element has an invalid or empty + basic shape the clipped element disappears. Nothing should be visible. + </desc> +</g> +<!--It tests that an empty clip path clips the referencing graphic. Bug 15289.--> +<clipPath id="nothing"> +</clipPath> +<clipPath id="emptyrect"> + <rect width="0" height="0"/> +</clipPath> + +<rect width="200" height="200" fill="red" clip-path="url(#nothing)"/> +<rect width="200" height="200" fill="red" clip-path="url(#emptyrect)"/> +</svg> +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-001.svg new file mode 100644 index 0000000..d5ef03a --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-001.svg
@@ -0,0 +1,18 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath with objectBoundingBox</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">clipPathUnits="objectBoundingBox" changes the + behavior of non-percentage values. The dimension of the clipped + element is equal to one unit for the content of clipPath. + You should see a green square.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.25" y="0.25" width="0.5" height="0.5"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-002.svg new file mode 100644 index 0000000..8180ddf9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-002.svg
@@ -0,0 +1,17 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" width="400" height="400"> +<g id="testmeta"> + <title>CSS Masking: clipPath with objectBoundingBox and percentage</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">clipPathUnits="objectBoundingBox" changes the + behavior of percentage values. The behavior is specified by SVG. + You should see a green square.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.0625%" y="0.0625%" width="0.125%" height="0.125%"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-003.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-003.svg new file mode 100644 index 0000000..8a7aa0f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-003.svg
@@ -0,0 +1,17 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath with objectBoundingBox and scaled clipped element</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-circle-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The clipped element has a transform. The transform + should apply "after" the clipping. You should see a full green circle. + </desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <circle cx="0.25" cy="0.25" r="0.25"/> +</clipPath> +<rect width="10" height="10" fill="green" transform="scale(20 20)" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-004.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-004.svg new file mode 100644 index 0000000..215d253 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-objectboundingbox-004.svg
@@ -0,0 +1,20 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Nested clipPath with different clipPathUnits</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The first clipPath element has + clipPathUnits="objectBoundingBox", the second userSpaceOnUse (default). + Both should be handled accordingly. You should see a green square.</desc> +</g> +<clipPath id="clip2"> + <rect x="50" y="50" width="150" height="150"/> +</clipPath> +<clipPath id="clip1" clipPathUnits="objectBoundingBox" clip-path="url(#clip2)"> + <rect width="0.75" height="0.75"/> +</clipPath> +<rect height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-001.svg new file mode 100644 index 0000000..6d837af6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-001.svg
@@ -0,0 +1,18 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath on g element</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element on a g element should clip the + group with it's content. You should see a green square.</desc> +</g> +<clipPath id="clip1"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<g clip-path="url(#clip1)"> + <rect width="200" height="200" fill="green"/> +</g> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-002.svg new file mode 100644 index 0000000..a14287cb --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-002.svg
@@ -0,0 +1,19 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath on g element and child</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element on a g element and it's child + element should clip the child first, then the group with it's content. + You should see a green square.</desc> +</g> +<clipPath id="clip1"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<g clip-path="url(#clip1)"> + <rect width="200" height="200" fill="green" clip-path="url(clip1)"/> +</g> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-003.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-003.svg new file mode 100644 index 0000000..b3eead8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-003.svg
@@ -0,0 +1,19 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath on child of g element</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element on a child of g element should + just clip the child and not the group. You should see a green square. + </desc> +</g> +<clipPath id="clip1"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<g> + <rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</g> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-004.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-004.svg new file mode 100644 index 0000000..32eaf003 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-004.svg
@@ -0,0 +1,22 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Two different clipPaths on g element and child</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element on a child and a differnt + clipPath element on g element should clip their targets independent of + each other but the child first. You should see a green square.</desc> +</g> +<clipPath id="clip2"> + <rect width="150" height="150"/> +</clipPath> +<clipPath id="clip1"> + <rect x="50" y="50" width="150" height="150"/> +</clipPath> +<g clip-path="url(#clip1)"> + <rect width="200" height="200" fill="green" clip-path="url(#clip2)"/> +</g> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-005.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-005.svg new file mode 100644 index 0000000..c621d91 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-g-005.svg
@@ -0,0 +1,25 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Two different clipPaths with objectBoundingBox on g element and child</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element on a child and a differnt + clipPath element on g element should clip their targets independent of + each other but the child first. When both have + clipPathUnits="objectBoundingBox", then the bounding box of each element is + taken. Note that clipping on the child influences the bounding box of the + group. You should see a green square.</desc> +</g> +<clipPath id="clip2" clipPathUnits="objectBoundingBox"> + <rect width="0.75" height="0.75"/> +</clipPath> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.25" y="0.25" width="0.75" height="0.75"/> +</clipPath> +<g clip-path="url(#clip1)"> + <rect width="200" height="200" fill="green" clip-path="url(#clip2)"/> +</g> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-marker-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-marker-001.svg new file mode 100644 index 0000000..ae5df003 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-marker-001.svg
@@ -0,0 +1,21 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath on element with marker</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-on-marker-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element with marker is clipped as a + whole. Note that a marker does not influence the bounding box of an + element. You should see a green square with a blur square in it on the top + left.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect width="1" height="1"/> +</clipPath> +<marker id="marker1" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="100" markerHeight="100"> + <rect width="10" height="10" fill="blue"/> +</marker> +<path d="M50,50 L150,50 L150,150 L50,150 z" marker-start="url(#marker1)" clip-path="url(#clip1)" fill="green"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-marker-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-marker-002.svg new file mode 100644 index 0000000..4f2ffa4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-marker-002.svg
@@ -0,0 +1,22 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath on element with marker</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-on-marker-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element with marker is clipped as a + whole. Note that a marker does not influence the bounding box of an + element. The clipping region includes the whole canvas. Nothing gets + clipped. You should see a green square with a blur square on top of it, + slightly shifted to the top left.</desc> +</g> +<clipPath id="clip1" clipPathUnits="userSpaceOnUse"> + <rect width="100%" height="100%"/> +</clipPath> +<marker id="marker1" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="100" markerHeight="100"> + <rect width="10" height="10" fill="blue"/> +</marker> +<path d="M50,50 L150,50 L150,150 L50,150 z" marker-start="url(#marker1)" clip-path="url(#clip1)" fill="green"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-marker-003.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-marker-003.svg new file mode 100644 index 0000000..45fc0fb --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-marker-003.svg
@@ -0,0 +1,21 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath with objectBoundingBox on element with marker</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-on-marker-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element with marker is clipped as a + whole. Note that a marker does not influence the bounding box of an + element. You should see a green square with a blur square in it on the top + left.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect width="1" height="1"/> +</clipPath> +<marker id="marker1" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="100" markerHeight="100"> + <rect width="10" height="10" fill="blue"/> +</marker> +<path d="M50,50 L150,50 L150,150 L50,150 z" marker-end="url(#marker1)" clip-path="url(#clip1)" fill="green"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-svg-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-svg-001.svg new file mode 100644 index 0000000..e92ce1d1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-svg-001.svg
@@ -0,0 +1,16 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" clip-path="url(#clip1)"> +<g id="testmeta"> + <title>CSS Masking: clipPath on root <svg></title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element can be applied to a root + <svg> element. You should see a green square.</desc> +</g> +<clipPath id="clip1"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<rect width="200" height="200" fill="green"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-svg-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-svg-002.svg new file mode 100644 index 0000000..94067d4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-svg-002.svg
@@ -0,0 +1,20 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" clip-path="url(#clip1)"> +<g id="testmeta"> + <title>CSS Masking: Clipped clipPath on root <svg></title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element can be applied to a root + <svg> element. This clipPath element can be clipped itself. You + should see a green square.</desc> +</g> +<clipPath id="clip2"> + <rect x="25" y="25" width="150" height="150"/> +</clipPath> +<clipPath id="clip1"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip2)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-use-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-use-001.svg new file mode 100644 index 0000000..8a2cf81c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-use-001.svg
@@ -0,0 +1,20 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="testmeta"> + <title>CSS Masking: clipPath on use</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A use element can be clipped by an clipPath + element as well. You should see a green square.</desc> +</g> +<defs> + <rect id="rect" width="200" height="200" fill="green"/> +</defs> +<clipPath id="clip1"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<use xlink:href="#rect" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-use-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-use-002.svg new file mode 100644 index 0000000..22e5ab7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-on-use-002.svg
@@ -0,0 +1,24 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="testmeta"> + <title>CSS Masking: Clipped clipPath on use</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A use element can be clipped by an clipPath + element. The clipPath element can be clipped as well. You should see a + green square.</desc> +</g> +<defs> + <rect id="rect" width="200" height="200" fill="green" clip-path="url(#clip2)"/> +</defs> +<clipPath id="clip2"> + <rect width="150" height="150"/> +</clipPath> +<clipPath id="clip1"> + <rect x="50" y="50" width="150" height="150"/> +</clipPath> +<use xlink:href="#rect" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-precision-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-precision-001.svg new file mode 100644 index 0000000..aa8e5ba7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-precision-001.svg
@@ -0,0 +1,44 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="testmeta"> + <title>CSS Masking: clipPath precision</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/clip-path-precision-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Various comma values should no influence the precision + of the clipPath element. The test should not show any red outlines + around the boxes.</desc> +</g> +<defs> + <g id="paths"> + <path d="M10 10 h20 v20 h-20 v-20 m1 1 v18 h18 v-18 h-18"/> + <rect x="19" y="19" width="2" height="2" /> + <rect x="5.51" y="0.51" width="2" height="32.3" fill="white"/> + <rect x="35.4" y="0.51" width="2" height="32.3" fill="white"/> + </g> +</defs> +<mask id="mask"> +<use xlink:href="#paths" fill="white" x="60" /> +</mask> + +<clipPath id="clipper"> + <path d="M40 10 h20 v20 h-20 v-20 m1 1 v18 h18 v-18 h-18"/> + <rect x="49" y="19" width="2" height="2" /> + <rect x="35.51" y="0.51" width="2" height="32.3" /> + <rect x="65.4" y="0.51" width="2" height="32.3" /> +</clipPath> + +<use xlink:href="#paths" fill="green" /> +<g clip-path="url(#clipper)"> + <rect fill="red" x="38" y="8" width="24" height="24" /> + <use xlink:href="#paths" fill="green" x="30" /> +</g> +<g mask="url(#mask)"> + <rect fill="red" x="68" y="8" width="24" height="24" /> + <use xlink:href="#paths" fill="green" x="60" /> +</g> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-recursion-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-recursion-001.svg new file mode 100644 index 0000000..5d4b7c2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-recursion-001.svg
@@ -0,0 +1,32 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath recursion 1</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/clip-path-invisible-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath recursion counts as invalid clipping + path and makes the element disappear. You should see nothing.</desc> +</g> +<defs> +<clipPath id="clip0"> + <rect width="1" height="1" clip-path="url(#clip)" /> +</clipPath> + +<clipPath id="clip2"> + <rect width="100" height="100" clip-path="url(#clip0)"/> +</clipPath> + +<clipPath id="clip"> + <rect width="1" height="1" clip-path="url(#clip2)"/> +</clipPath> + +<mask id="mask1" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect width="1" height="1" clip-path="url(#clip)" /> +</mask> +</defs> +<circle r="500" mask="url(#mask1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-recursion-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-recursion-002.svg new file mode 100644 index 0000000..ae10c06 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-recursion-002.svg
@@ -0,0 +1,24 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="testmeta"> + <title>CSS Masking: clipPath recursion 2</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-invisible-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath recursion counts as invalid clipping + path and makes the element disappear. You should see nothing.</desc> +</g> +<defs> + <rect x="50" y="150" width="50" height="50" id="rect" fill="none" clip-path="url(#clipPath_1)"/> +</defs> +<clipPath id="clipPath_0"> + <rect x="50" width="50" height="50" clip-path="url(#clipPath_0)"/> +</clipPath> +<clipPath id="clipPath_1"> + <use xlink:href="#rect"/> +</clipPath> +<rect x="50" width="100" height="100" fill="red" clip-path="url(#clipPath_0)"/> +<rect x="50" y="150" width="100" height="100" fill="red" clip-path="url(#clipPath_1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-001.svg new file mode 100644 index 0000000..873947943 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-001.svg
@@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Basic shape circle() on SVG rectangle</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"/> + <html:link rel="match" href="reference/clip-path-circle-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A basic shape function circle() applied to an SVG + rectangle. You should see a full green circle.</desc> +</g> +<rect width="100" height="100" fill="green" style="clip-path: circle()"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-002.svg new file mode 100644 index 0000000..dca307d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-002.svg
@@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Basic shape circle() on SVG rectangle with absolute values</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"/> + <html:link rel="match" href="reference/clip-path-circle-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A basic shape function circle() with absolute values + applied to an SVG rectangle. You should see a full green circle.</desc> +</g> +<rect width="400" height="400" fill="green" style="clip-path: circle(50px at 50px 50px)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-003.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-003.svg new file mode 100644 index 0000000..f0110ee --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-003.svg
@@ -0,0 +1,14 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Basic shape circle() on SVG rectangle with fill-box</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"/> + <html:link rel="match" href="reference/clip-path-circle-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A basic shape function circle() applied to an SVG + rectangle. The specified keyword fill-box defines the reference box + (here objectBoundingBox). You should see a full green circle.</desc> +</g> +<rect width="100" height="100" fill="green" stroke="green" stroke-width="10" style="clip-path: circle() fill-box;"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-004.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-004.svg new file mode 100644 index 0000000..c3db6d6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-004.svg
@@ -0,0 +1,14 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Basic shape circle() on SVG rectangle with stroke-box</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"/> + <html:link rel="match" href="reference/clip-path-circle-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A basic shape function circle() applied to an SVG + rectangle. The specified keyword stroke-box defines the reference box + stroking bounding box. You should see a full green circle.</desc> +</g> +<rect x="10" y="10" width="80" height="80" fill="green" stroke="green" stroke-width="20" style="clip-path: circle() stroke-box;"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-005.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-005.svg new file mode 100644 index 0000000..90a57e7c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-005.svg
@@ -0,0 +1,14 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" width="100" height="100"> +<g id="testmeta"> + <title>CSS Masking: Basic shape circle() on SVG rectangle with view-box</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"/> + <html:link rel="match" href="reference/clip-path-circle-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A basic shape function circle() applied to an SVG + rectangle. The specified keyword view-box defines the viewport as reference + box. You should see a full green circle.</desc> +</g> +<rect width="200" height="200" fill="green" style="clip-path: circle() view-box;"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-ellipse-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-ellipse-001.svg new file mode 100644 index 0000000..511a1976 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-ellipse-001.svg
@@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Basic shape ellipse() on SVG rectangle</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"/> + <html:link rel="match" href="reference/clip-path-ellipse-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A basic shape function ellipse() applied to an SVG + rectangle. You should see a full green ellipse.</desc> +</g> +<rect width="200" height="150" fill="green" style="clip-path: ellipse()"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-ellipse-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-ellipse-002.svg new file mode 100644 index 0000000..08bdc3e --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-ellipse-002.svg
@@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Basic shape ellipse() on SVG rectangle with absolute values</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"/> + <html:link rel="match" href="reference/clip-path-ellipse-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A basic shape function ellipse() with absolute values + applied to an SVG rectangle. You should see a full green ellipse.</desc> +</g> +<rect width="200" height="200" fill="green" style="clip-path: ellipse(100px 75px at 100px 75px)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-inset-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-inset-001.svg new file mode 100644 index 0000000..8176766 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-inset-001.svg
@@ -0,0 +1,16 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Basic shape inset() on SVG rectangle with percentag values</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"/> + <html:link rel="match" href="reference/clip-path-shape-inset-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A basic shape function inset() applied to an SVG + rectangle. Percentage values are relative to a reference box. If not + reference box was specified the objectBoundingBox is used. The inset used + per side is specified by the first 10% argument. The second 10% specify the + border radius. You should see a green square with rounded corners.</desc> +</g> +<rect width="200" height="200" fill="green" style="clip-path: inset(10% round 10%)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-inset-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-inset-002.svg new file mode 100644 index 0000000..2793eda --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-inset-002.svg
@@ -0,0 +1,15 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Basic shape inset() on SVG rectangle with absolute values</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"/> + <html:link rel="match" href="reference/clip-path-shape-inset-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A basic shape function inset() applied to an SVG + rectangle. The inset used per side is specified by the first 20px argument. + The second 20px specify the border radius. You should see a green square + with rounded corners.</desc> +</g> +<rect width="200" height="200" fill="green" style="clip-path: inset(20px round 20px)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-polygon-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-polygon-001.svg new file mode 100644 index 0000000..f474b126 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-polygon-001.svg
@@ -0,0 +1,14 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Basic shape polygon() on SVG rectangle with nonzero</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"/> + <html:link rel="match" href="reference/clip-path-square-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A basic shape function polygon() with absolute values + applied to an SVG rectangle. The clip-rule is specified with nonzero. You + should see a green square.</desc> +</g> +<rect width="200" height="200" fill="green" style="clip-path: polygon(nonzero, 25px 25px, 175px 25px, 175px 175px, 25px 175px, 25px 50px, 150px 50px, 150px 150px, 50px 150px, 50px 50px, 25px 50px)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-polygon-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-polygon-002.svg new file mode 100644 index 0000000..0fd8b1b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-polygon-002.svg
@@ -0,0 +1,14 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Basic shape polygon() on SVG rectangle with evenodd</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"/> + <html:link rel="match" href="reference/clip-path-square-hole-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A basic shape function polygon() with absolute values + applied to an SVG rectangle. The clip-rule is specified with evenodd. You + should see a green square with an rectangular hole.</desc> +</g> +<rect width="200" height="200" fill="green" style="clip-path: polygon(evenodd, 25px 25px, 175px 25px, 175px 175px, 25px 175px, 25px 50px, 150px 50px, 150px 150px, 50px 150px, 50px 50px, 25px 50px)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-polygon-003.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-polygon-003.svg new file mode 100644 index 0000000..91ee3d0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-polygon-003.svg
@@ -0,0 +1,14 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Basic shape polygon() on SVG rectangle with no clip rule</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"/> + <html:link rel="match" href="reference/clip-path-square-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A basic shape function polygon() with absolute values + applied to an SVG rectangle. The clip-rule is not specified and defaults to + nonzero. You should see a green square.</desc> +</g> +<rect width="200" height="200" fill="green" style="clip-path: polygon(25px 25px, 175px 25px, 175px 175px, 25px 175px, 25px 50px, 150px 50px, 150px 150px, 50px 150px, 50px 50px, 25px 50px)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-001.svg new file mode 100644 index 0000000..35f9fa0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-001.svg
@@ -0,0 +1,16 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath with text</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-text-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element can contain text. You should + see a green text "CLIP" and nothing else.</desc> +</g> +<clipPath id="clip1"> + <text x="20" y="150" style="font-size: 60px; font-weight: bold;">CLIP</text> +</clipPath> +<rect height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-002.svg new file mode 100644 index 0000000..d6ae147 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-002.svg
@@ -0,0 +1,17 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath and text with styling</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-text-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element can contain text. Text styling + should not influence the clipping path. You should see a green text "CLIP" + and nothing else.</desc> +</g> +<clipPath id="clip1"> + <text x="20" y="150" style="font-size:60px; font-weight:bold;" stroke="red" stroke-width="10">CLIP</text> +</clipPath> +<rect height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-003.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-003.svg new file mode 100644 index 0000000..ec7a613 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-003.svg
@@ -0,0 +1,18 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath with text and a polygon</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-text-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element can contain text. Text can be + combined with other clipping shapes like polygons. You should see a green + text "CLIP" through the hole of a green rectangle.</desc> +</g> +<clipPath id="clip1"> + <text x="20" y="150" style="font-size:60px; font-weight:bold;" stroke="red" stroke-width="10">CLIP</text> + <polygon points="0 0, 200 0, 200 200, 0 200, 0 50, 150 50, 150 150, 50 150, 50 50, 0 50" clip-rule="evenodd" /> +</clipPath> +<rect height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-004.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-004.svg new file mode 100644 index 0000000..7adbfa2d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-004.svg
@@ -0,0 +1,18 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath and tspan element with styling</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-text-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element can contain text in a + tspan element. Text styling on text element or tspan element should not influence + the clipping path. You should see a green text "CLIP" and nothing else. + </desc> +</g> +<clipPath id="clip1"> + <text x="20" y="150" style="font-size:60px; font-weight:bold;"><tspan stroke="red" fill="none">CLIP</tspan></text> +</clipPath> +<rect height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-005.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-005.svg new file mode 100644 index 0000000..152f401 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-text-005.svg
@@ -0,0 +1,21 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Clipped clipPath with text</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-text-003-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element can contain text. The + clipPath element can be clipped itself with the text. You should see + fragments of a green text "CLIP" and nothing else. + </desc> +</g> +<clipPath id="clip2"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<clipPath id="clip1" clip-path="url(#clip2)"> + <text x="20" y="150" style="font-size:60px; font-weight:bold;">CLIP</text> +</clipPath> +<rect height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-userspaceonuse-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-userspaceonuse-001.svg new file mode 100644 index 0000000..1a3d769 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-userspaceonuse-001.svg
@@ -0,0 +1,20 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Two clipPath elements with different clipPathUnits</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">A clipPath element with clipPathUnits + userSpaceOnUse gets clipped by a clipPath element with cliPathUnits + objectBoundingBox. You should see a green square.</desc> +</g> +<clipPath id="clip2" clipPathUnits="objectBoundingBox"> + <rect width="0.75" height="0.75"/> +</clipPath> +<clipPath id="clip1" clip-path="url(#clip2)"> + <rect x="50" y="50" width="150" height="150"/> +</clipPath> +<rect height="200" width="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-with-opacity.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-with-opacity.svg new file mode 100644 index 0000000..ac944be --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-with-opacity.svg
@@ -0,0 +1,17 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath child with opacity style</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The opacit on the child of the clipPath should + not influence the clipping path. You should see a green square.</desc> +</g> +<clipPath id="clip"> + <rect x="50" y="50" width="100" height="100" opacity=".4"/> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-with-transform.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-with-transform.svg new file mode 100644 index 0000000..b3c3b25d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-with-transform.svg
@@ -0,0 +1,18 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath with transformed child</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-square-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The child of the clipPath element has a transform + that influences the size of the clipping path. You should see a green + square.</desc> +</g> +<clipPath id="clip1"> + <rect width="10" height="10" transform="scale(10) translate(5, 5)"/> +</clipPath> +<rect width="400" height="400" fill="green" clip-path="url(#clip1)"/> +</svg> +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-001.svg new file mode 100644 index 0000000..0dc0f7c0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-001.svg
@@ -0,0 +1,40 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath and mask nesting 1</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-nested-clip-path-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Multiple references between clipPath and + mask elements. You should see a green square with 4 equally + sized and positioned white squares in it.</desc> +</g> +<clipPath id="clip0" clipPathUnits="userSpaceOnUse"> + <rect x="60" y="60" width="30" height="30"/> +</clipPath> + +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.1" y="0.1" width="0.3" height="0.3"/> + <rect x="0.1" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip2" clipPathUnits="userSpaceOnUse"> + <rect x="60" y="10" width="30" height="30" transform="scale(0.01 0.01)"/> + <rect x="0" y="0" width="100" height="100" transform="scale(0.01 0.01)" clip-path="url(#clip0)"/> +</clipPath> + +<clipPath id="clip" clipPathUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip1)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip2)"/> +</clipPath> + +<mask id="mask1" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white"/> + <rect x="0" y="0" width="1" height="1" fill="black" clip-path="url(#clip)" /> +</mask> + +<rect width="200" height="200" fill="green" mask="url(#mask1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-002.svg new file mode 100644 index 0000000..2e611feb --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-002.svg
@@ -0,0 +1,43 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath and mask nesting 2</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-nested-clip-path-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Multiple references between clipPath and + mask elements. You should see a green square with 4 equally + sized and positioned white squares in it.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.1" y="0.1" width="0.3" height="0.3"/> + <rect x="0.1" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip2" clipPathUnits="objectBoundingBox"> + <rect x="0.6" y="0.1" width="0.3" height="0.3"/> + <rect x="0.6" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip" clipPathUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip1)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip2)"/> +</clipPath> + +<mask id="mask1a" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white"/> + <rect x="0" y="0" width="1" height="1" fill="black" clip-path="url(#clip1)" /> +</mask> + +<mask id="mask1b" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white"/> + <rect x="0" y="0" width="1" height="1" fill="black" clip-path="url(#clip2)" /> +</mask> + +<g mask="url(#mask1a)"> + <rect width="200" height="200" fill="green" mask="url(#mask1b)"/> +</g> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-003.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-003.svg new file mode 100644 index 0000000..6221253 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-003.svg
@@ -0,0 +1,51 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath and mask nesting 3</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-nested-clip-path-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Multiple references between clipPath and + mask elements. You should see a green square with 4 equally + sized and positioned white squares in it.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.1" y="0.1" width="0.3" height="0.3"/> + <rect x="0.1" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip2" clipPathUnits="objectBoundingBox"> + <rect x="0.6" y="0.1" width="0.3" height="0.3"/> + <rect x="0.6" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip" clipPathUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip1)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip2)"/> +</clipPath> + +<mask id="mask1a" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white"/> + <rect x="0" y="0" width="1" height="1" fill="black" clip-path="url(#clip1)" /> +</mask> + +<mask id="mask1b" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white"/> + <rect x="0" y="0" width="1" height="1" fill="black" clip-path="url(#clip2)" /> +</mask> + +<mask id="mask2" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white" mask="url(#mask1a)"/> +</mask> + +<mask id="mask3" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white" mask="url(#mask1b)"/> +</mask> + +<g mask="url(#mask3)"> + <rect width="200" height="200" fill="green" mask="url(#mask2)"/> +</g> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-004.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-004.svg new file mode 100644 index 0000000..66bb3b7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-004.svg
@@ -0,0 +1,36 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath and mask nesting 4</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-nested-clip-path-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Multiple references between clipPath and + mask elements. You should see a green square with 4 equally + sized and positioned white squares in it.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.1" y="0.1" width="0.3" height="0.3"/> + <rect x="0.1" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip2" clipPathUnits="objectBoundingBox"> + <rect x="0.6" y="0.1" width="0.3" height="0.3"/> + <rect x="0.6" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip" clipPathUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip1)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip2)"/> +</clipPath> + +<mask id="mask1" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white"/> + <rect x="0" y="0" width="1" height="1" fill="black" clip-path="url(#clip)" /> +</mask> + +<rect width="200" height="200" fill="green" mask="url(#mask1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-005.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-005.svg new file mode 100644 index 0000000..9317ce4e --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-005.svg
@@ -0,0 +1,35 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath and mask nesting 5</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-nested-clip-path-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Multiple references between clipPath and + mask elements. You should see 4 equally sized and positioned green + squares.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.1" y="0.1" width="0.3" height="0.3"/> + <rect x="0.1" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip2" clipPathUnits="objectBoundingBox"> + <rect x="0.6" y="0.1" width="0.3" height="0.3"/> + <rect x="0.6" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip" clipPathUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip1)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip2)"/> +</clipPath> + +<mask id="mask2" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white" clip-path="url(#clip)" /> +</mask> + +<rect width="200" height="200" fill="green" mask="url(#mask2)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-006.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-006.svg new file mode 100644 index 0000000..6ab2a20f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-006.svg
@@ -0,0 +1,35 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath and mask nesting 6</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-nested-clip-path-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Multiple references between clipPath and + mask elements. You should see 4 equally sized and positioned green + squares.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.1" y="0.1" width="0.3" height="0.3"/> + <rect x="0.1" y="0.6" width="0.3" height="0.3"/> + <rect x="0.6" y="0.1" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip2" clipPathUnits="objectBoundingBox"> + <rect x="0.6" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip" clipPathUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip1)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip2)"/> +</clipPath> + +<mask id="mask2" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white" clip-path="url(#clip)" /> +</mask> + +<rect width="200" height="200" fill="green" mask="url(#mask2)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-007.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-007.svg new file mode 100644 index 0000000..27f3724 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-007.svg
@@ -0,0 +1,36 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath and mask nesting 7</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-nested-clip-path-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Multiple references between clipPath and + mask elements. You should see a green square with 4 equally + sized and positioned white squares in it.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.1" y="0.1" width="0.3" height="0.3"/> + <rect x="0.1" y="0.6" width="0.3" height="0.3"/> + <rect x="0.6" y="0.1" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip2" clipPathUnits="objectBoundingBox"> + <rect x="0.6" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip" clipPathUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip1)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip2)"/> +</clipPath> + +<mask id="mask1" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white"/> + <rect x="0" y="0" width="1" height="1" fill="black" clip-path="url(#clip)" /> +</mask> + +<rect width="200" height="200" fill="green" mask="url(#mask1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-008.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-008.svg new file mode 100644 index 0000000..b3f33e19 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-008.svg
@@ -0,0 +1,44 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath and mask nesting 8</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-nested-clip-path-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Multiple references between clipPath and + mask elements. You should see a green square with 4 equally + sized and positioned white squares in it.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.1" y="0.1" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip2" clipPathUnits="objectBoundingBox"> + <rect x="0.1" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip3" clipPathUnits="objectBoundingBox"> + <rect x="0.6" y="0.1" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip4" clipPathUnits="objectBoundingBox"> + <rect x="0.6" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip" clipPathUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip1)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip2)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip3)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip4)"/> +</clipPath> + +<mask id="mask1" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white"/> + <rect x="0" y="0" width="1" height="1" fill="black" clip-path="url(#clip)" /> +</mask> + +<rect width="200" height="200" fill="green" mask="url(#mask1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-009.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-009.svg new file mode 100644 index 0000000..955edd33 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-009.svg
@@ -0,0 +1,43 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: clipPath and mask nesting 9</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-nested-clip-path-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Multiple references between clipPath and + mask elements. You should see 4 equally sized and positioned green + squares.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.1" y="0.1" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip2" clipPathUnits="objectBoundingBox"> + <rect x="0.1" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip3" clipPathUnits="objectBoundingBox"> + <rect x="0.6" y="0.1" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip4" clipPathUnits="objectBoundingBox"> + <rect x="0.6" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip" clipPathUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip1)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip2)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip3)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip4)"/> +</clipPath> + +<mask id="mask2" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white" clip-path="url(#clip)" /> +</mask> + +<rect width="200" height="200" fill="green" mask="url(#mask2)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-010.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-010.svg new file mode 100644 index 0000000..dc1040e --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-010.svg
@@ -0,0 +1,45 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" width="10000" height="400"> +<g id="testmeta"> + <title>CSS Masking: clipPath and mask nesting 10</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-nested-clip-path-003-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Multiple references between clipPath and + mask elements. You should see 2 equally sized and positioned green + squares next to each other.</desc> +</g> +<defs> +<mask id="mask"> + <!-- forcing a repaintRect offset --> + <rect x="100" width="1" height="1" fill="black"/> + <rect x="200" width="8092" height="100" fill="white"/> +</mask> + +<clipPath id="clip1"> + <!-- forcing clipping via masking --> + <path d="M 0 0 V 100 H 10000 V 0 Z"/> +</clipPath> + +<clipPath id="clip2" clip-path="url(#clip1)"> + <path d="M 100 0 H 200 V 200 H 8292 V 0 Z"/> +</clipPath> + +<mask id="crop"> + <rect width="300" height="100" fill="white"/> +</mask> +</defs> + +<g mask="url(#crop)" transform="translate(-100, 0)"> + <rect width="10000" height="400" fill="red" mask="url(#mask)"/> + <rect x="199" width="101" height="100" fill="green"/> +</g> + +<g mask="url(#crop)" transform="translate(100, 0)"> + <rect width="10000" height="400" fill="red" clip-path="url(#clip2)"/> + <rect x="199" width="101" height="100" fill="green"/> +</g> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-panning-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-panning-001.svg new file mode 100644 index 0000000..16890a58 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-panning-001.svg
@@ -0,0 +1,48 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Panning with clipPath and mask nesting 1</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-nested-clip-path-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Multiple references between clipPath and + mask elements. The current viewport gets translated by panning. You + should see a green square with 4 equally sized and positioned white squares + in it.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.1" y="0.1" width="0.3" height="0.3"/> + <rect x="0.1" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip2" clipPathUnits="objectBoundingBox"> + <rect x="0.6" y="0.1" width="0.3" height="0.3"/> + <rect x="0.6" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip" clipPathUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip1)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip2)"/> +</clipPath> + +<mask id="mask1a" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white"/> + <rect x="0" y="0" width="1" height="1" fill="black" clip-path="url(#clip1)" /> +</mask> + +<mask id="mask1b" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white"/> + <rect x="0" y="0" width="1" height="1" fill="black" clip-path="url(#clip2)" /> +</mask> + +<g mask="url(#mask1a)" transform="translate(75, 0)"> + <rect width="200" height="200" fill="green" mask="url(#mask1b)"/> +</g> +<script> +var translate = document.getElementsByTagName('svg')[0].currentTranslate; +translate.x = -75; +</script> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-panning-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-panning-002.svg new file mode 100644 index 0000000..e5e42678 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-nested-clip-path-panning-002.svg
@@ -0,0 +1,56 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Panning with clipPath and mask nesting 2</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-nested-clip-path-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">Multiple references between clipPath and + mask elements. The current viewport gets translated by panning. You + should see a green square with 4 equally sized and positioned white squares + in it.</desc> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <rect x="0.1" y="0.1" width="0.3" height="0.3"/> + <rect x="0.1" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip2" clipPathUnits="objectBoundingBox"> + <rect x="0.6" y="0.1" width="0.3" height="0.3"/> + <rect x="0.6" y="0.6" width="0.3" height="0.3"/> +</clipPath> + +<clipPath id="clip" clipPathUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip1)"/> + <rect x="0" y="0" width="1" height="1" clip-path="url(#clip2)"/> +</clipPath> + +<mask id="mask1a" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white"/> + <rect x="0" y="0" width="1" height="1" fill="black" clip-path="url(#clip1)" /> +</mask> + +<mask id="mask1b" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white"/> + <rect x="0" y="0" width="1" height="1" fill="black" clip-path="url(#clip2)" /> +</mask> + +<mask id="mask2" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white" mask="url(#mask1a)"/> +</mask> + +<mask id="mask3" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="1" fill="white" mask="url(#mask1b)"/> +</mask> + +<g mask="url(#mask3)" transform="translate(75, 0)"> + <rect width="200" height="200" fill="green" mask="url(#mask2)"/> +</g> +<script> +var translate = document.getElementsByTagName('svg')[0].currentTranslate; +translate.x = -75; +</script> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip-transform.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip-transform.svg new file mode 100644 index 0000000..fc1f7688 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip-transform.svg
@@ -0,0 +1,23 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: mask with objectBoundingBox gets clipped 1</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-content-clip-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The mask element with + maskContentUnits="objectBoundingBox" gets clipped. The clipping path has a + transform that scales the content down. You should see a full green circle. + </desc> +</g> +<clipPath id="clip"> + <circle cx="50" cy="50" r="25" transform="scale(0.01 0.01)"/> +</clipPath> +<mask id="mask" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0.25" y="0.25" width="0.5" height="0.5" fill="white" clip-path="url(#clip)"/> +</mask> +<rect x="0" y="0" height="200" width="200" fill="green" mask="url(#mask)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip.svg new file mode 100644 index 0000000..a8d8a12 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip.svg
@@ -0,0 +1,23 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: mask with objectBoundingBox gets clipped 2</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-content-clip-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The mask element with + maskContentUnits="objectBoundingBox" gets clipped. The clipping path has a + coordinates in the mask's user space. You should see a full green circle. + </desc> +</g> +<clipPath id="clip"> + <circle cx="0.5" cy="0.5" r="0.25"/> +</clipPath> +<mask id="mask" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox"> + <rect x="0.25" y="0.25" width="0.5" height="0.5" fill="white" clip-path="url(#clip)"/> +</mask> +<rect x="0" y="0" height="200" width="200" fill="green" mask="url(#mask)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip-transform.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip-transform.svg new file mode 100644 index 0000000..b979ff3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip-transform.svg
@@ -0,0 +1,23 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: mask with userSpaceOnUse gets clipped 1</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-content-clip-002-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The mask element with + maskContentUnits="userSpaceOnUse" gets clipped. The clipping path has a + transform that scales the content down. You should see a full green circle. + </desc> +</g> +<clipPath id="clip" clipPathUnits="userSpaceOnUse"> + <circle cx="50" cy="50" r="25" transform="scale(0.01 0.01)"/> +</clipPath> +<mask id="mask" x="0" y="0" width="200" height="200" maskUnits="userSpaceOnUse" maskContentUnits="objectBoundingBox"> + <rect x="0.25" y="0.25" width="0.5" height="0.5" fill="white" clip-path="url(#clip)"/> +</mask> +<rect x="0" y="0" height="200" width="200" fill="green" mask="url(#mask)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip.svg new file mode 100644 index 0000000..c9f3cf8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip.svg
@@ -0,0 +1,23 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: mask with userSpaceOnUse gets clipped 2</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/> + <html:link rel="match" href="reference/mask-content-clip-001-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert">The mask element with + maskContentUnits="userSpaceOnUse" gets clipped. The clipping path has a + coordinates in the mask's user space. You should see a full green circle. + </desc> +</g> +<clipPath id="clip" clipPathUnits="userSpaceOnUse"> + <circle cx="0.5" cy="0.5" r="0.25"/> +</clipPath> +<mask id="mask" x="0" y="0" width="200" height="200" maskUnits="userSpaceOnUse" maskContentUnits="objectBoundingBox"> + <rect x="0.25" y="0.25" width="0.5" height="0.5" fill="white" clip-path="url(#clip)"/> +</mask> +<rect x="0" y="0" height="200" width="200" fill="green" mask="url(#mask)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-circle-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-circle-001-ref.svg new file mode 100644 index 0000000..56b7fbe --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-circle-001-ref.svg
@@ -0,0 +1,10 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<clipPath id="clip1" clipPathUnits="objectBoundingBox"> + <circle cx="0.25" cy="0.25" r="0.25"/> +</clipPath> +<rect width="200" height="200" fill="green" clip-path="url(#clip1)"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-001-ref.svg new file mode 100644 index 0000000..eaeb6b2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-001-ref.svg
@@ -0,0 +1,8 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<polygon points="0 0, 150 0, 150 150, 0 150, 0 25, 125 25, 125 125, 25 125, 25 25, 0 25" fill-rule="evenodd" fill="green"/> +<polygon points="50 50, 200 50, 200 200, 50 200, 50 75, 175 75, 175 175, 75 175, 75 75, 50 75" fill-rule="nonzero" fill="green"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-002-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-002-ref.svg new file mode 100644 index 0000000..d6c87cd --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-002-ref.svg
@@ -0,0 +1,8 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<polygon points="0 0, 150 0, 150 150, 0 150, 0 25, 125 25, 125 125, 25 125, 25 25, 0 25" fill-rule="nonzero" fill="green"/> +<polygon points="50 50, 200 50, 200 200, 50 200, 50 75, 175 75, 175 175, 75 175, 75 75, 50 75" fill-rule="nonzero" fill="green"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-003-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-003-ref.svg new file mode 100644 index 0000000..3247b87 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-clip-rule-003-ref.svg
@@ -0,0 +1,8 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<polygon points="0 0, 150 0, 150 150, 0 150, 0 25, 125 25, 125 125, 25 125, 25 25, 0 25" fill-rule="nonzero" fill="green"/> +<polygon points="50 50, 200 50, 200 200, 50 200, 50 75, 175 75, 175 175, 75 175, 75 75, 50 75" fill-rule="evenodd" fill="green"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-ellipse-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-ellipse-001-ref.svg new file mode 100644 index 0000000..2532eb3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-ellipse-001-ref.svg
@@ -0,0 +1,12 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<defs> +<clipPath id="clip"> + <ellipse cx="100" cy="75" rx="100" ry="75"/> +</clipPath> +</defs> +<rect width="200" height="150" fill="green" clip-path="url(#clip)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-invisible-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-invisible-ref.svg new file mode 100644 index 0000000..15cfd5f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-invisible-ref.svg
@@ -0,0 +1,6 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-negative-scale-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-negative-scale-ref.svg new file mode 100644 index 0000000..be24efa --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-negative-scale-ref.svg
@@ -0,0 +1,14 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<rect width="90" height="90" fill="green"/> +<rect x="40" y="40" width="50" height="50" fill="blue"/> +<rect x="110" width="90" height="90" fill="green"/> +<rect x="110" y="40" width="50" height="50" fill="blue"/> +<rect y="110" width="90" height="90" fill="green"/> +<rect x="40" y="110" width="50" height="50" fill="blue"/> +<rect x="110" y="110" width="90" height="90" fill="green"/> +<rect x="110" y="110" width="50" height="50" fill="blue"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-on-marker-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-on-marker-001-ref.svg new file mode 100644 index 0000000..693c72e4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-on-marker-001-ref.svg
@@ -0,0 +1,8 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<rect x="50" y="50" width="100" height="100" fill="green"/> +<rect x="50" y="50" width="50" height="50" fill="blue"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-on-marker-002-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-on-marker-002-ref.svg new file mode 100644 index 0000000..21cf9cd --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-on-marker-002-ref.svg
@@ -0,0 +1,8 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<rect x="50" y="50" width="100" height="100" fill="green"/> +<rect width="100" height="100" fill="blue"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-precision-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-precision-001-ref.svg new file mode 100644 index 0000000..4c83c9d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-precision-001-ref.svg
@@ -0,0 +1,18 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<defs> + <g id="paths"> + <path d="M10 10 h20 v20 h-20 v-20 m1 1 v18 h18 v-18 h-18"/> + <rect x="19" y="19" width="2" height="2" /> + <rect x="5.51" y="0.51" width="2" height="32.3" fill="white"/> + <rect x="35.4" y="0.51" width="2" height="32.3" fill="white"/> + </g> +</defs> +<use xlink:href="#paths" fill="green"/> +<use xlink:href="#paths" fill="green" x="30"/> +<use xlink:href="#paths" fill="green" x="60"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-shape-inset-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-shape-inset-001-ref.svg new file mode 100644 index 0000000..e458ad99 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-shape-inset-001-ref.svg
@@ -0,0 +1,12 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<defs> +<clipPath id="clip"> + <rect x="20" y="20" width="160" height="160" rx="20" ry="20"/> +</clipPath> +</defs> +<rect width="200" height="200" fill="green" clip-path="url(#clip)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-square-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-square-001-ref.svg new file mode 100644 index 0000000..8ddfdaa7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-square-001-ref.svg
@@ -0,0 +1,7 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<polygon points="25 25, 175 25, 175 175, 25 175, 25 50, 150 50, 150 150, 50 150, 50 50, 25 50" fill-rule="nonzero" fill="green"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg new file mode 100644 index 0000000..e8e03bf --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-square-002-ref.svg
@@ -0,0 +1,7 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<rect x="50" y="50" width="100" height="100" fill="green"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-square-003-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-square-003-ref.svg new file mode 100644 index 0000000..e7709d4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-square-003-ref.svg
@@ -0,0 +1,8 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<rect width="200" height="200" fill="green" /> +</svg> +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-square-hole-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-square-hole-001-ref.svg new file mode 100644 index 0000000..7e1cb1b3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-square-hole-001-ref.svg
@@ -0,0 +1,7 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<polygon points="25 25, 175 25, 175 175, 25 175, 25 50, 150 50, 150 150, 50 150, 50 50, 25 50" fill-rule="evenodd" fill="green"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-text-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-text-001-ref.svg new file mode 100644 index 0000000..4b3f84b8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-text-001-ref.svg
@@ -0,0 +1,7 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<text x="20" y="150" fill="green" style="font-size:60px; font-weight:bold;">CLIP</text> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-text-002-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-text-002-ref.svg new file mode 100644 index 0000000..fccd7638 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-text-002-ref.svg
@@ -0,0 +1,8 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<text x="20" y="150" fill="green" style="font-size:60px; font-weight:bold;">CLIP</text> +<polygon points="0 0, 200 0, 200 200, 0 200, 0 50, 150 50, 150 150, 50 150, 50 50, 0 50" fill-rule="evenodd" fill="green"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-text-003-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-text-003-ref.svg new file mode 100644 index 0000000..fa2cb815 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-text-003-ref.svg
@@ -0,0 +1,10 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<clipPath id="clip2"> + <rect x="50" y="50" width="100" height="100"/> +</clipPath> +<text x="20" y="150" style="font-size:60px; font-weight:bold;" clip-path="url(#clip2)" fill="green">CLIP</text> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-content-clip-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-content-clip-001-ref.svg new file mode 100644 index 0000000..0aa52333 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-content-clip-001-ref.svg
@@ -0,0 +1,10 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<mask id="mask" x="0" y="0" width="1" height="1"> + <circle cx="100" cy="100" r="50" fill="white"/> +</mask> +<rect x="0" y="0" height="200" width="200" fill="green" mask="url(#mask)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-content-clip-002-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-content-clip-002-ref.svg new file mode 100644 index 0000000..4da47823 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-content-clip-002-ref.svg
@@ -0,0 +1,10 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<mask id="mask" x="0" y="0" width="1" height="1"> + <circle cx="10000" cy="10000" r="5000" fill="white" transform="scale(0.01 0.01)"/> +</mask> +<rect x="0" y="0" height="200" width="200" fill="green" mask="url(#mask)"/> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-001-ref.svg new file mode 100644 index 0000000..e080c95 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-001-ref.svg
@@ -0,0 +1,11 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<rect width="200" height="200" fill="green"/> +<rect x="20" y="20" width="60" height="60" fill="white"/> +<rect x="120" y="20" width="60" height="60" fill="white"/> +<rect x="20" y="120" width="60" height="60" fill="white"/> +<rect x="120" y="120" width="60" height="60" fill="white"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-002-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-002-ref.svg new file mode 100644 index 0000000..7b54566 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-002-ref.svg
@@ -0,0 +1,10 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<rect x="20" y="20" width="60" height="60" fill="green"/> +<rect x="120" y="20" width="60" height="60" fill="green"/> +<rect x="20" y="120" width="60" height="60" fill="green"/> +<rect x="120" y="120" width="60" height="60" fill="green"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-003-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-003-ref.svg new file mode 100644 index 0000000..0133005 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path-svg-content/reference/mask-nested-clip-path-003-ref.svg
@@ -0,0 +1,8 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" width="10000" height="400"> +<g id="testmeta"> + <title>CSS Masking: Reftest reference</title> + <html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/> +</g> +<rect x="99" width="101" height="100" fill="green"/> +<rect x="299" width="101" height="100" fill="green"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-001.html new file mode 100644 index 0000000..d38b909 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-001.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and circle function with absolute values</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="author" title="Denise White" href="mailto:denisegwhite@outlook.com"> + <link rel="author" title="Laury Kenton" href="mailto:webshiva@mac.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"> + <link rel="match" href="reference/clip-path-circle-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'circle' for clipping. Test absolute values for arguments. On pass you + should see a green circle and no red."> +</head> +<body> + <p>The test passes if there is a full green circle.</p> + <div style="width: 200px; height: 200px; background-color: green; clip-path: circle();"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-002.html new file mode 100644 index 0000000..ab672aa --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-002.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and circle function with percentage values</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"> + <link rel="match" href="reference/clip-path-circle-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'circle' for clipping. Test percentage values for arguments. If no + reference box was specified, percentage is relative to border-box. On pass + there should be a green circle."> +</head> +<body> + <p>The test passes if there is a full green circle.</p> + <div style="width: 200px; height: 200px; background-color: green; clip-path: circle(50% at 50% 50%);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-003.html new file mode 100644 index 0000000..6c6eadb --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-003.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and circle function with percentage radius</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"> + <link rel="match" href="reference/clip-path-circle-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'circle' for clipping. Test percentage value as argument for radius and no + position arguments. The circle should be in the center of the element. On + pass there should be a green circle."> +</head> +<body> + <p>The test passes if there is a full green circle.</p> + <div style="width: 200px; height: 200px; background-color: green; clip-path: circle(50%);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-004.html new file mode 100644 index 0000000..6244d38 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-004.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and circle function with percentage position</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"> + <link rel="match" href="reference/clip-path-circle-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'circle' for clipping. Test percentage value as argument for position and + no radius argument. The circle must behave like it has a radius of + 'closest-side'. On pass there should be a green circle."> +</head> +<body> + <p>The test passes if there is a full green circle.</p> + <div style="width: 200px; height: 200px; background-color: green; clip-path: circle(at 50%);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-005.html new file mode 100644 index 0000000..bcabc72d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-005.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and circle function with closest-side</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"> + <link rel="match" href="reference/clip-path-circle-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'circle' for clipping. The circle has a radius of 'closest-side'. This test + has a squred div-box. Therefore, 'closest-side', 50% and 'farthest-side' + show the same behavior. On pass there should be a green circle."> +</head> +<body> + <p>The test passes if there is a full green circle.</p> + <div style="width: 200px; height: 200px; background-color: green; clip-path: circle(closest-side);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-006.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-006.html new file mode 100644 index 0000000..9de416a --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-006.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and circle function with farthest-side</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"> + <link rel="match" href="reference/clip-path-circle-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'circle' for clipping. The circle has a radius of 'farthest-side'. This + test has a squred div-box. Therefore, 'closest-side', 50% and + 'farthest-side' show the same behavior. On pass there should be a green + circle."> +</head> +<body> + <p>The test passes if there is a full green circle.</p> + <div style="width: 200px; height: 200px; background-color: green; clip-path: circle(farthest-side);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-007.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-007.html new file mode 100644 index 0000000..7ff3fdd --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-007.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and circle with closest-side on rectangular div 1</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"> + <link rel="match" href="reference/clip-path-circle-2-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'circle' for clipping. The clipped div box is twice as wide as it is + height. With 'closest-side', there should be a full green circle."> + <style type="text/css"> + body, div { + padding: 0; + margin: 0; + } + </style> +</head> +<body> + <p>The test passes if there is a full green circle.</p> + <div style="width: 400px; height: 200px; background-color: green; clip-path: circle(closest-side);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-008.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-008.html new file mode 100644 index 0000000..31ae8ee5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-circle-008.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and circle with closest-side on rectangular div 2</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path"> + <link rel="match" href="reference/clip-path-circle-3-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'circle' for clipping. The clipped div box is twice as high as it is + wide. With 'closest-side', there should be a full green circle."> + <style type="text/css"> + body, div { + padding: 0; + margin: 0; + } + </style> +</head> +<body> + <p>The test passes if there is a full green circle.</p> + <div style="width: 200px; height: 400px; background-color: green; clip-path: circle(closest-side);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-001.html new file mode 100644 index 0000000..1381f53 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-001.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and external clipPath reference with userSpaceOnUse - 1</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"> + <link rel="match" href="reference/clip-path-rectangle-ref.html"> + <meta name="assert" content="The clip-path property takes an external reference to a clipPath element for clipping. + On pass you should see a green box."> +</head> +<body> + <p>The test passes if there is a green box.</p> + <div style="width: 150px; height: 100px; border: solid red 50px; background-color: green; clip-path: url(#clip);"></div> + + <svg> + <clipPath id="clip"> + <rect x="50" y="50" width="150px" height="100" /> + </clipPath> + </svg> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-002.html new file mode 100644 index 0000000..846c5e7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-002.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and external clipPath reference with userSpaceOnUse - 2</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"> + <link rel="match" href="reference/clip-path-rectangle-ref.html"> + <meta name="assert" content="The clip-path property takes an reference to a clipPath element for clipping. + On pass you should see a green with a blue border."> +</head> +<body> + <p>The test passes if there is a green box with a blue border.</p> + <div style="width: 150px; height: 100px; border: solid blue 50px; background-color: green; clip-path: url(#clip);"></div> + + <svg> + <clipPath id="clip"> + <rect x="0" y="0" width="250px" height="200" /> + </clipPath> + </svg> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-003.html new file mode 100644 index 0000000..5628938 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-003.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and external clipPath reference with userSpaceOnUse with percentage - 1</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"> + <link rel="match" href="reference/clip-path-ref-right-green-ref.html"> + <meta name="assert" content="The clip-path property takes a reference to a clipPath element for clipping. Percentage values + are relative to the viewport for userSpaceOnUse on clipPathUnits. + On pass the left half of the site is white and the right half of the site is blue."> + + <style> + html, body { + width: 100%; + height: 100%; + margin: 0; + } + </style> +</head> +<body> + <div style="width: 100%; height: 100%; background-color: green; clip-path: url(#clip); position: absolute;"></div> + <p style="position: absolute;">The test passes if the left half of the site is white and the right half of the site is blue.</p> + + <svg> + <clipPath id="clip"> + <rect x="50%" y="0" width="50%" height="100%" /> + </clipPath> + </svg> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-004.html new file mode 100644 index 0000000..af65df6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-element-userSpaceOnUse-004.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and external clipPath reference with userSpaceOnUse with percentage - 2</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"> + <link rel="match" href="reference/clip-path-ref-bottom-green-ref.html"> + <meta name="assert" content="The clip-path property takes a reference to a clipPath element for clipping. Percentage values + are relative to the viewport for userSpaceOnUse on clipPathUnits. + On pass the top half of the site is white and the bottom half of the site is green."> + + <style> + html, body { + width: 100%; + height: 100%; + margin: 0; + } + </style> +</head> +<body> + <div style="width: 100%; height: 100%; background-color: green; clip-path: url(#clip); position: absolute;"></div> + <p style="position: absolute;">The test passes if the top half of the site is white and the bottom half of the site is green.</p> + + <svg> + <clipPath id="clip"> + <rect x="0" y="50%" width="100%" height="50%" /> + </clipPath> + </svg> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-001.html new file mode 100644 index 0000000..197f422c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-001.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and ellipse function with absolute values</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-ellipse-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'ellipse' for clipping. Test absolute values for radii and position + arguments. On pass you should see a green ellipse."> +</head> +<body> + <p>The test passes if there is a full green ellipse.</p> + <div style="width: 150px; height: 100px; border: solid red 50px; background-color: green; clip-path: ellipse(75px 50px at 125px 100px);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-002.html new file mode 100644 index 0000000..d6310ded --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-002.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and ellipse function with percentage values</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-ellipse-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'ellipse' for clipping. Test percentage values for radii and position + arguments. Percentage values are relative to a reference box. If no + reference box was specified, percentage values are relative to border-box. + On pass you should see a green ellipse."> +</head> +<body> + <p>The test passes if there is a green ellipse.</p> + <div style="width: 150px; height: 100px; border: solid red 50px; background-color: green; clip-path: ellipse(30% 25% at 50% 50%);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-003.html new file mode 100644 index 0000000..e1c32bf --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-003.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and ellipse function with percentage values on square</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-circle-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'ellipse' for clipping. Test percentage values for radii and position + arguments. Percentage values are relative to a reference box. If no + reference box was specified, percentage values are relative to border-box. + On pass there should be a full green circle."> +</head> +<body> + <p>The test passes if there is a green circle.</p> + <div style="width: 200px; height: 200px; background-color: green; clip-path: ellipse(50% 50% at 50% 50%);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-004.html new file mode 100644 index 0000000..3a56b53 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-004.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and ellipse function with different absolute values on square</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-ellipse-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'ellipse' for clipping. Test absolute values for arguments. On pass you + should see a green ellipse."> +</head> +<body> + <p>The test passes if there is a green ellipse.</p> + <div style="width: 200px; height: 200px; background-color: green; clip-path: ellipse(75px 50px at 125px 100px);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-005.html new file mode 100644 index 0000000..fd364cc --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-005.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and ellipse function with different percentage values on square</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-ellipse-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'ellipse' for clipping. Test percentage values for radii and position + arguments. Percentage values are relative to a reference box. If no + reference box was specified, percentage values are relative to border-box. + Different values for getting an ellipse from a square. On pass you should + see a green ellipse."> +</head> +<body> + <p>The test passes if there is a green ellipse.</p> + <div style="width: 200px; height: 200px; background-color: green; clip-path: ellipse(37.5% 25% at 62.5% 50%);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-006.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-006.html new file mode 100644 index 0000000..e261bac --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-006.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and ellipse function with absolute values</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-circle-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'ellipse' for clipping. Test absolute values for radii and position + arguments. On pass you should see a green circle."> +</head> +<body> + <p>The test passes if there is a green circle.</p> + <div style="width: 150px; height: 100px; border: solid red 50px; background-color: green; clip-path: ellipse();"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-007.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-007.html new file mode 100644 index 0000000..16cfce14 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-007.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and ellipse function with no arguments</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-ellipse-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'ellipse' for clipping. If no further arguments were specified, the radii + are 'closest-side' each. The position is initialised to the center of the + element. On pass there is a full green ellipse."> +</head> +<body> + <p>The test passes if there is a full green ellipse.</p> + <div style="width: 150px; height: 100px; border: solid red 50px; background-color: green; clip-path: ellipse(farthest-side closest-side);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-008.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-008.html new file mode 100644 index 0000000..f56c645 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-ellipse-008.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and ellipse function with 50% 50%</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-ellipse-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'ellipse' for clipping. Test percentage values for radii and position + arguments. Percentage values are relative to a reference box. If no + reference box was specified, percentage values are relative to border-box. + Both radii are specified with percentage values. The position is + initialised to the center of the element. On pass there is a full green + ellipse."> +</head> +<body> + <p>The test passes if there is a full green ellipse.</p> + <div style="width: 150px; height: 100px; border: solid red 50px; background-color: green; clip-path: ellipse(50% 50%);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-001.html new file mode 100644 index 0000000..565d747 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-001.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and polygon function with absolute values</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-rectangle-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'polygon' for clipping. Test absolute value arguments. On pass you should + see a green square and no red."> +</head> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="width: 150px; height: 100px; border: solid red 50px; background-color: green; clip-path: polygon(50px 50px, 200px 50px, 200px 150px, 50px 150px)"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-002.html new file mode 100644 index 0000000..5d1004870 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-002.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and polygon function with percentage values</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-rectangle-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'polygon' for clipping. Test percentage values for arguments. Percentage + values are relative to specified reference box. If no reference box was + specified, percentage values are relative to border-box. A number of + percentage values are specified as coordinates. On pass you should see a + green square and no red."> +</head> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="width: 150px; height: 100px; border: solid red 50px; background-color: green; clip-path: polygon(20% 25%, 80% 25%, 80% 75%, 20% 75%)"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-003.html new file mode 100644 index 0000000..b50f9c4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-003.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and polygon function with absolute and percentage values</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-rectangle-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'polygon' for clipping. Test absolute and percentage value arguments. On + pass you should see a green square and no red."> +</head> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="width: 150px; height: 100px; border: solid red 50px; background-color: green; position: absolute; clip-path: polygon(20% 50px, 200px 25%, 200px 150px, 20% 75%)"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-004.html new file mode 100644 index 0000000..e057d85 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-004.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and polygon function with fill rule evenodd</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-rectangle-border-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape 'polygon' for clipping. + The point list for the polygon creates a 'whole' with the dimension of the background. With + the fill rule 'evenodd', this whole is clipped out. The clipping makes the green background + of the parent div box visible. + On pass you should see a green box with a blue border."> +</head> +<body> + <p>The test passes if there is a green box with a blue border.</p> + <div style="background-color: green; width: 250px;"> + <div style="width: 150px; height: 100px; border: solid blue 50px; background-color: red; clip-path: polygon(evenodd, 0 0, 250px 0, 250px 200px, 0 200px, 0 50px, 200px 50px, 200px 150px, 50px 150px, 50px 50px, 0 50px)"></div> + </div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-005.html new file mode 100644 index 0000000..497e7f3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-005.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path property and polygon function with fill rule nonzero</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-rectangle-border-ref.html"> + <meta name="assert" content="The clip-path property takes the basic shape + 'polygon' for clipping. The point list for the polygon creates a 'hole' + with the dimension of the background of the clipped element. With the fill + rule 'nonzero', this hole is clipped out. The clipping makes the green + background of the parent div box visible. On pass you should see a green + square with a blue border."> +</head> +<body> + <p>The test passes if there is a green square with a blue border.</p> + <div style="background-color: green; width: 250px;"> + <div style="width: 150px; height: 100px; border: solid blue 50px; background-color: red; clip-path: polygon(nonzero, 0 0, 250px 0, 250px 200px, 0 200px, 0 50px, 50px 50px, 50px 150px, 200px 150px, 200px 50px, 0 50px)"></div> + </div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-006.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-006.html new file mode 100644 index 0000000..1b33eaaf --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-006.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path and polygon with padding-box</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-square-001-ref.html"> + <meta name="assert" content="The clip-path property allows specifying + basic shapes and reference boxes. This test checks the usage of the correct + reference box 'padding-box' for the polygon() function by mixing percentage + and absolute values as coordinates. On sucess you should see a green square + and no red."> +</head> +<style> +div { + width: 50px; + height: 50px; + background-color: green; + padding: 25px; + margin: 25px; + border: red solid 50px; +} +</style> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="clip-path: polygon(0% 0%, 100% 0%, 100px 100%, 0 100px) padding-box"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-007.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-007.html new file mode 100644 index 0000000..9b590979 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-007.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path and polygon with border-box</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-stripes-001-ref.html"> + <meta name="assert" content="The clip-path property allows specifying + basic shapes and reference boxes. This test checks the usage of the correct + reference box 'border-box' for the polygon() function by mixing percentage + and absolute values as coordinates. On sucess you should see a green + vertical stripe next to a lime green vertical stripe. Both should be of equal + size."> +<style> +div { + width: 50px; + height: 50px; + background-color: green; + padding: 25px; + margin: 25px; + border: red solid 50px; + border-left: lime solid 50px; +} +</style> +<body> + <p>The test passes if you see a green vertical stripe next to a lime green vertical stripe, both stripes should be of equal size and there should be no red.</p> + <div style="clip-path: polygon(0% 25%, 50% 50px, 100px 75%, 0 150px) border-box"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-008.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-008.html new file mode 100644 index 0000000..454aba6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-008.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path and polygon with margin-box</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-stripes-002-ref.html"> + <meta name="assert" content="The clip-path property allows specifying + basic shapes and reference boxes. This test checks the usage of the correct + reference box 'margin-box' for the polygon() function by mixing percentage + and absolute values as coordinates. On sucess you should see a green + vertical stripe next to a lime green vertical stripe. Both should be of equal + size."> +</head> +<style> +div { + width: 50px; + height: 50px; + background-color: green; + padding: 25px; + margin: 25px; + border: red solid 25px; + border-left: lime solid 25px; +} +</style> +<body> + <p>The test passes if you see a green vertical stripe next to a lime green vertical stripe, both stripes should be of equal size and there should be no red.</p> + <div style="clip-path: polygon(12.5% 25%, 37.5% 50px, 75px 50%, 25px 100px) margin-box"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-009.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-009.html new file mode 100644 index 0000000..7d3ab5bb --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-009.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path and polygon with content-box</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-square-002-ref.html"> + <meta name="assert" content="The clip-path property allows specifying + basic shapes and reference boxes. This test checks the usage of the correct + reference box 'content-box' for the polygon() function by mixing percentage + and absolute values as coordinates. On sucess you should see a green square + and no red."> +</head> +<style> +div { + width: 50px; + height: 50px; + background-color: green; + padding: 25px; + margin: 25px; + border: red solid 25px; +} +</style> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="clip-path: polygon(0% 0px, 50px 0%, 100% 50px, 0px 100%) content-box"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-010.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-010.html new file mode 100644 index 0000000..c60aba2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-010.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path and polygon with fill-box</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-stripes-001-ref.html"> + <meta name="assert" content="The clip-path property allows specifying + basic shapes and reference boxes. This test checks the usage of the correct + reference box. 'fill-box' was specified but is not supported for HTML + elements. The used value should be 'border-box' for the polygon() function + instead. By mixing percentage and absolute values as coordinates we check + the correct used reference box. On sucess you should see a green + vertical stripe next to a lime green vertical stripe. Both should be of equal + size."> +<style> +div { + width: 50px; + height: 50px; + background-color: green; + padding: 25px; + margin: 25px; + border: red solid 50px; + border-left: lime solid 50px; +} +</style> +<body> + <p>The test passes if you see a green vertical stripe next to a lime green vertical stripe, both stripes should be of equal size and there should be no red.</p> + <div style="clip-path: polygon(0% 25%, 50% 50px, 100px 75%, 0 150px) fill-box"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-011.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-011.html new file mode 100644 index 0000000..7acccd1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-011.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path and polygon with stroke-box</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-stripes-001-ref.html"> + <meta name="assert" content="The clip-path property allows specifying + basic shapes and reference boxes. This test checks the usage of the correct + reference box. 'stroke-box' was specified but is not supported for HTML + elements. The used value should be 'border-box' for the polygon() function + instead. By mixing percentage and absolute values as coordinates we check + the correct used reference box. On sucess you should see a green + vertical stripe next to a lime green vertical stripe. Both should be of equal + size."> +<style> +div { + width: 50px; + height: 50px; + background-color: green; + padding: 25px; + margin: 25px; + border: red solid 50px; + border-left: lime solid 50px; +} +</style> +<body> + <p>The test passes if you see a green vertical stripe next to a lime green vertical stripe, both stripes should be of equal size and there should be no red.</p> + <div style="clip-path: polygon(0% 25%, 50% 50px, 100px 75%, 0 150px) stroke-box"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-012.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-012.html new file mode 100644 index 0000000..9a24abf --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-012.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path and polygon with view-box</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-stripes-001-ref.html"> + <meta name="assert" content="The clip-path property allows specifying + basic shapes and reference boxes. This test checks the usage of the correct + reference box. 'view-box' was specified but is not supported for HTML + elements. The used value should be 'border-box' for the polygon() function + instead. By mixing percentage and absolute values as coordinates we check + the correct used reference box. On sucess you should see a green + vertical stripe next to a lime green vertical stripe. Both should be of equal + size."> +<style> +div { + width: 50px; + height: 50px; + background-color: green; + padding: 25px; + margin: 25px; + border: red solid 50px; + border-left: lime solid 50px; +} +</style> +<body> + <p>The test passes if you see a green vertical stripe next to a lime green vertical stripe, both stripes should be of equal size and there should be no red.</p> + <div style="clip-path: polygon(0% 25%, 50% 50px, 100px 75%, 0 150px) view-box"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-013.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-013.html new file mode 100644 index 0000000..8d2c049 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/clip-path-polygon-013.html
@@ -0,0 +1,46 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-path and polygon different units</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="match" href="reference/clip-path-stripes-003-ref.html"> + <meta name="assert" content="Test the support of different units for + polygon coordinates. The test passes if you see a multiple green and blue + stripe pairs. For each pair, the blue and green stripe must be of same + length."> +<style> +div { + width: 100%; + height: 20px; + background-color: green; + padding: 0; + margin: 0; +} +div:nth-child(odd) { + margin-bottom: 5px; + background-color: blue; +} +</style> +<body> + <p>The test passes if you see a multiple green and blue stripe pairs. For each pair, the blue and green stripe must be of same length.</p> + <div style="clip-path: polygon(0 0, 50% 0, 50% 20px, 0 20px)"></div> + <div style="width: 50%"></div> + + <div style="clip-path: polygon(0 0, 20em 0, 20em 20px, 0 20px)"></div> + <div style="width: 20em"></div> + + <div style="clip-path: polygon(0 0, 50vw 0, 50vw 20px, 0 20px)"></div> + <div style="width: 50vw"></div> + + <div style="clip-path: polygon(0 0, 40vh 0, 40vh 20px, 0 20px)"></div> + <div style="width: 40vh"></div> + + <div style="clip-path: polygon(0 0, calc(30% + 15px) 0, calc(30% + 15px) 20px, 0 20px)"></div> + <div style="width: calc(30% + 15px)"></div> + + <div style="clip-path: polygon(0 0, 30ex 0, 30ex 20px, 0 20px)"></div> + <div style="width: 30ex"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-circle-2-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-circle-2-ref.html new file mode 100644 index 0000000..7794d32 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-circle-2-ref.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <style type="text/css"> + body, div { + padding: 0; + margin: 0; + } + </style> +</head> +<body> + <p>The test passes if there is a full green circle.</p> + <div style="width: 200px; height: 200px; border-radius: 100px; background-color: green; position: absolute; left: 100px;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-circle-3-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-circle-3-ref.html new file mode 100644 index 0000000..4cffe883 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-circle-3-ref.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <style type="text/css"> + body, div { + padding: 0; + margin: 0; + } + </style> +</head> +<body> + <p>The test passes if there is a full green circle.</p> + <div style="width: 200px; height: 200px; border-radius: 100px; background-color: green; position: relative; top: 100px;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-circle-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-circle-ref.html new file mode 100644 index 0000000..c427e69 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-circle-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a full green circle.</p> + <div style="width: 200px; height: 200px; border-radius: 100px; background-color: green;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-ellipse-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-ellipse-ref.html new file mode 100644 index 0000000..5adc91a5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-ellipse-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a full green ellipse.</p> + <div style="margin-top: 50px; margin-left: 50px; position: absolute; width: 150px; height: 100px; border-top-right-radius: 75px 50px; border-bottom-right-radius: 75px 50px; border-top-left-radius: 75px 50px; border-bottom-left-radius: 75px 50px; background-color: green;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-rectangle-border-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-rectangle-border-ref.html new file mode 100644 index 0000000..9a61c76 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-rectangle-border-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a green box with a blue border.</p> + <div style="width: 150px; height: 100px; border: solid blue 50px; background-color: green;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-rectangle-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-rectangle-ref.html new file mode 100644 index 0000000..1d3810a7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-rectangle-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a green box.</p> + <div style="margin-top: 50px; margin-left: 50px; position: absolute; width: 150px; height: 100px; background-color: green;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-ref-bottom-green-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-ref-bottom-green-ref.html new file mode 100644 index 0000000..ad6abc4f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-ref-bottom-green-ref.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <style> + html, body { + width: 100%; + height: 100%; + margin: 0; + } + </style> +</head> +<body> + <div style="width: 100%; height: 50%; margin-top: 50%; background-color: green; position: absolute;"></div> + <p style="position: absolute;">The test passes if the top half of the site is white and the bottom half of the site is green.</p> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-ref-right-green-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-ref-right-green-ref.html new file mode 100644 index 0000000..a19be598 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-ref-right-green-ref.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <style> + html, body { + width: 100%; + height: 100%; + margin: 0; + } + </style> +</head> +<body> + <div style="width: 50%; height: 100%; margin-left: 50%; background-color: green; position: absolute;"></div> + <p style="position: absolute;">The test passes if the left half of the site is white and the right half of the site is green.</p> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-square-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-square-001-ref.html new file mode 100644 index 0000000..6bc5a167 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-square-001-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Reftest reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="width: 100px; height: 100px; background-color: green; margin: 75px;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-square-002-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-square-002-ref.html new file mode 100644 index 0000000..5230b0f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-square-002-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Reftest reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="width: 50px; height: 50px; background-color: green; margin: 75px;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-stripes-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-stripes-001-ref.html new file mode 100644 index 0000000..75d08dc --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-stripes-001-ref.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Reftest reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if you see a green vertical stripe next to a lime green vertical stripe, both stripes should be of equal size and there should be no red.</p> + <div style="width: 100px; height: 100px; margin: 75px 0 0 25px; background-color: green;"> + <div style="width: 50px; height: 100px; background-color: lime;"></div> + </div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-stripes-002-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-stripes-002-ref.html new file mode 100644 index 0000000..8dd1c926 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-stripes-002-ref.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Reftest reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if you see a green vertical stripe next to a lime green vertical stripe, both stripes should be of equal size and there should be no red.</p> + <div style="width: 50px; height: 50px; margin: 50px 0 0 25px; background-color: green;"> + <div style="width: 25px; height: 50px; background-color: lime;"></div> + </div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-stripes-003-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-stripes-003-ref.html new file mode 100644 index 0000000..e31282c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/reference/clip-path-stripes-003-ref.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Reftest reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +<style> +div { + height: 20px; + background-color: green; + padding: 0; + margin: 0; +} +div:nth-child(odd) { + margin-bottom: 5px; + background-color: blue; +} +</style> +<body> + <p>The test passes if you see a multiple green and blue stripe pairs. For each pair, the blue and green stripe must be of same length.</p> + <div style="width: 50%"></div> + <div style="width: 50%"></div> + + <div style="width: 20em"></div> + <div style="width: 20em"></div> + + <div style="width: 50vw"></div> + <div style="width: 50vw"></div> + + <div style="width: 40vh"></div> + <div style="width: 40vh"></div> + + <div style="width: calc(30% + 15px)"></div> + <div style="width: calc(30% + 15px)"></div> + + <div style="width: 30ex"></div> + <div style="width: 30ex"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/svg-clipPath.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/svg-clipPath.svg new file mode 100644 index 0000000..d31a1df --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-path/svg-clipPath.svg
@@ -0,0 +1,7 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<defs> + <clipPath id="clip-path-ref-userSpaceOnUse-001"> + <rect x="50" y="50" width="150px" height="100" /> + </clipPath> +</defs> +</svg> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-rule/clip-rule-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-rule/clip-rule-001.html new file mode 100644 index 0000000..a5a0961 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-rule/clip-rule-001.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-rule property on polygon clip rule evenodd</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"> + <link rel="match" href="reference/clip-rule-rectangle-border-ref.html"> + <meta name="assert" content="The clipPath element takes the basic shape 'polygon' for clipping. + The point list for the polygon creates a 'whole' with the dimension of the background. With + the clip rule 'evenodd', this whole is clipped out. The clipping makes the green background + of the parent div box visible. + On pass you should see a green box with a blue border."> +</head> +<body> + <p>The test passes if there is a green box with a blue border.</p> + <div style="background-color: green; width: 250px;"> + <div style="width: 150px; height: 100px; border: solid blue 50px; background-color: red; clip-path: url(#clip);"></div> + </div> + + <svg> + <clipPath id="clip"> + <polygon points="0 0, 250 0, 250 200, 0 200, 0 50, 200 50, 200 150, 50 150, 50 50, 0 50" clip-rule="evenodd" /> + </clipPath> + </svg> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-rule/clip-rule-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-rule/clip-rule-002.html new file mode 100644 index 0000000..5fee625 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-rule/clip-rule-002.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip-rule property on polygon clip rule nonzero</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"> + <link rel="match" href="reference/clip-rule-rectangle-border-ref.html"> + <meta name="assert" content="The clipPath element takes the basic shape 'polygon' for clipping. + The point list for the polygon creates a 'whole' with the dimension of the background. With + the clip rule 'nonzero', this whole is clipped out. The clipping makes the green background + of the parent div box visible. + On pass you should see a green box with a blue border."> +</head> +<body> + <p>The test passes if there is a green box with a blue border.</p> + <div style="background-color: green; width: 250px;"> + <div style="width: 150px; height: 100px; border: solid blue 50px; background-color: red; clip-path: url(#clip);"></div> + </div> + + <svg> + <clipPath id="clip"> + <polygon points="0 0, 250 0, 250 200, 0 200, 0 50, 50 50, 50 150, 200 150, 200 50, 0 50" clip-rule="nonzero" /> + </clipPath> + </svg> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-rule/reference/clip-rule-rectangle-border-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-rule/reference/clip-rule-rectangle-border-ref.html new file mode 100644 index 0000000..9a61c76 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip-rule/reference/clip-rule-rectangle-border-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a green box with a blue border.</p> + <div style="width: 150px; height: 100px; border: solid blue 50px; background-color: green;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-absolute-positioned-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-absolute-positioned-001.html new file mode 100644 index 0000000..c5b0d900 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-absolute-positioned-001.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property and rect function on div with position: absolute</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-absolute-positioned-ref.html"> + <meta name="assert" content="The clip property should clip elements whose + layout are governed by the CSS box model and that are abolutely positioned + with 'position: absolute;'. On pass you should see a green square and no + red."> +</head> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="width: 100px; height: 100px; border: solid red 50px; position: absolute; background-color: green; clip: rect(50px, 150px, 150px, 50px);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-absolute-positioned-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-absolute-positioned-002.html new file mode 100644 index 0000000..53b2517a --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-absolute-positioned-002.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property and rect function on div with position: fixed</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-absolute-positioned-ref.html"> + <meta name="assert" content="The clip property should clip elements whose + layout are governed by the CSS box model and that are abolutely positioned + with 'position: fixed;'. On pass you should see a green square and no + red."> +</head> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="width: 100px; height: 100px; border: solid red 50px; position: fixed; background-color: green; clip: rect(50px, 150px, 150px, 50px);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-negative-values-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-negative-values-001.html new file mode 100644 index 0000000..b295c89b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-negative-values-001.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property does not clip on with negative values - 1</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-full-ref.html"> + <meta name="assert" content="Negative values are permitted on rect function + for clip. Test that whole element is clipped if bottom edge is before top + edge. On pass you should see a green square and no red."> +</head> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="background-color: green; width: 200px; height: 200px;"> + <div style="width: 200px; height: 200px; background-color: red; position: absolute; clip: rect(0, -50px, 200px, 50px);"></div> + </div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-negative-values-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-negative-values-002.html new file mode 100644 index 0000000..dd92e5b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-negative-values-002.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property does not clip on with negative values - 2</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-full-ref.html"> + <meta name="assert" content="Negative values are permitted on rect function + for clip. Test that whole element is clipped if right edge is before left + edge. On pass you should see a green square and no red."> +</head> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="background-color: green; width: 200px; height: 200px;"> + <div style="width: 200px; height: 200px; background-color: red; position: absolute; clip: rect(50px, 200px, -50px, 0);"></div> + </div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-negative-values-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-negative-values-003.html new file mode 100644 index 0000000..51181353 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-negative-values-003.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property does not clip on with negative values - 3</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-vertical-stripe-ref.html"> + <meta name="assert" content="Negative values are permited on rect function + for clip. Test that left edge can be negative. On pass you should see a + vertical blue stripe."> +</head> +<body> + <p>The test passes if there is only a vertical blue stripe.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; position: absolute; clip: rect(0, 50px, 200px, -50px);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-negative-values-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-negative-values-004.html new file mode 100644 index 0000000..1fb5add --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-negative-values-004.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property does not clip on with negative values - 4</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-horizontal-stripe-ref.html"> + <meta name="assert" content="Negative values are permited on rect function + for clip. Test that top edge can be negative. On pass you should see a + horizontal blue stripe."> +</head> +<body> + <p>The test passes if there is only a horizontal blue stripe.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; position: absolute; clip: rect(-50px, 200px, 50px, 0);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-no-clipping-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-no-clipping-001.html new file mode 100644 index 0000000..3a63c2ca --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-no-clipping-001.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property does not clip on 'auto'</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-no-clipping-ref.html"> + <meta name="assert" content="The clip property should on 'auto'. On pass + you should see a green box with a blue border."> +</head> +<body> + <p>The test passes if there is a green square with a blue border.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; position: absolute; clip: auto"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-no-clipping-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-no-clipping-002.html new file mode 100644 index 0000000..a09e6a0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-no-clipping-002.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property does not clip overflowing content on 'auto'.</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-no-clipping-ref.html"> + <meta name="assert" content="The clip property should not clip overflowing + content of elements whose layout are governed by the CSS box model, the + position is absolute and the clip value is 'auto'. On pass you should see a + a green square with a blue border."> +</head> +<body> + <p>The test passes if there is a green square with a blue border.</p> + <div style="width: 100px; height: 100px; position: absolute; clip: auto;"> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green;"></div> + </div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-not-absolute-positioned-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-not-absolute-positioned-001.html new file mode 100644 index 0000000..613f6af --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-not-absolute-positioned-001.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property and rect function on not absolutely positioned div - 1</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-no-clipping-ref.html"> + <meta name="assert" content="The clip property should be ignored on + elements whose layout are governed by the CSS box model and are not + abolutely positioned. On pass you should see a green square with a blue + border."> +</head> +<body> + <p>The test passes if there is a green square with a blue border.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; clip: rect(50px, 150px, 150px, 50px);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-not-absolute-positioned-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-not-absolute-positioned-002.html new file mode 100644 index 0000000..4d07132 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-not-absolute-positioned-002.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property and rect function on not absolutely positioned div - 2</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-no-clipping-ref.html"> + <meta name="assert" content="The clip property should be ignored on + elements whose layout are governed by the CSS box model and are not + abolutely positioned. Creating a stacking context with z-index does not + influence clipping behavior. On pass you should see a green box square with + a blue border."> +</head> +<body> + <p>The test passes if there is a green square with a blue border.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; z-index: 10; clip: rect(50px, 150px, 150px, 50px);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-not-absolute-positioned-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-not-absolute-positioned-003.html new file mode 100644 index 0000000..ee3765db --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-not-absolute-positioned-003.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property and rect function on not absolutely positioned div - 3</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-no-clipping-ref.html"> + <meta name="assert" content="The clip property should be ignored on + elements whose layout are governed by the CSS box model and are not + abolutely positioned. Creating a 3d rednering context does not influence + clipping behavior. On pass you should see a green square with a blue + border."> +</head> +<body style="perspective: 400px;"> + <p>The test passes if there is a green square with a blue border.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; transform-style: preserve-3d; transform: translate3d(0, 0, 0); clip: rect(50px, 150px, 150px, 50px);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-not-absolute-positioned-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-not-absolute-positioned-004.html new file mode 100644 index 0000000..56825d1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-not-absolute-positioned-004.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property and rect function on not absolutely positioned div - 4</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-no-clipping-ref.html"> + <meta name="assert" content="The clip property should be ignored on + elements whose layout are governed by the CSS box model and are not + abolutely positioned. position: relative does not influence clipping + behavior. On pass you should see a green square with a blue border."> +</head> +<body> + <p>The test passes if there is a green square with a blue border.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; position: relative; clip: rect(50px, 150px, 150px, 50px);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-001.html new file mode 100644 index 0000000..6a1a0640 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-001.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property with rect function and auto values clip to border box - 1</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-overflow-hidden-ref.html"> + <meta name="assert" content="A value of 'auto' in the rect function is + equal to the certain edge of the border box. The content should be clipped + to the border box. On pass you see a blue square and a smaller green square + in the bottom right corner of the blue square."> +</head> +<body> + <p>The test passes if there is a blue square and a smaller green square in the bottom right corner of the blue square.</p> + <div style="position: absolute; clip: rect(auto, auto, auto, auto); width: 100px; height: 100px;"> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green;"></div> + </div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-002.html new file mode 100644 index 0000000..0ee4518 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-002.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property with rect function and auto values clip to border box - 2</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-no-clipping-ref.html"> + <meta name="assert" content="A value of 'auto' in the rect function is + equal to the certain edge of the border box. The box shadow should be + clipped, since it is painted outside the border box. On pass you should see + a green square with a blue border."> +</head> +<body> + <p>The test passes if there is a green square with a blue border.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; position: absolute; clip: rect(auto, auto, auto, auto); box-shadow: 0 0 10px red;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-003.html new file mode 100644 index 0000000..5f12ae4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-003.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property with rect function and auto value for top value</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-rect-top-ref.html"> + <meta name="assert" content="A value of 'auto' for 'top' in the rect + function is equal to the top edge of the border box. The box shadow should + be clipped, since it is painted outside the border box. On pass you should see a horizontal green stripe under a horizontal blue stripe."> +</head> +<body> + <p>The test passes if there is a horizontal green stripe under a horizontal blue stripe.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; position: absolute; clip: rect(auto, 150px, 100px, 50px); box-shadow: 0 0 10px red;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-004.html new file mode 100644 index 0000000..d5d5ce9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-004.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property with rect function and auto value for right value</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-rect-right-ref.html"> + <meta name="assert" content="A value of 'auto' for 'right' in the rect + function is equal to the top edge of the border box. The box shadow should + be clipped, since it is painted outside the border box. On pass you should + see a vertical blue stripe on the right side of a vertical green stripe."> +</head> +<body> + <p>The test passes if there is a vertical blue stripe on the right side of a vertical green stripe.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; position: absolute; clip: rect(50px, auto, 150px, 100px); box-shadow: 0 0 10px red;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-005.html new file mode 100644 index 0000000..b2b3b13 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-005.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property with rect function and auto value for bottom value</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-rect-bottom-ref.html"> + <meta name="assert" content="A value of 'auto' for 'bottom' in the rect + function is equal to the top edge of the border box. The box shadow should + be clipped, since it is painted outside the border box. On pass you should + see a horizontal blue stripe under a horizontal green stripe."> +</head> +<body> + <p>The test passes if there is a horizontal blue stripe under a horizontal green stripe.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; position: absolute; clip: rect(100px, 150px, auto, 50px); box-shadow: 0 0 10px red;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-006.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-006.html new file mode 100644 index 0000000..410b93d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-auto-006.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test clip property with rect function and auto value for left value</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-rect-left-ref.html"> + <meta name="assert" content="A value of 'auto' for 'left' in the rect + function is equal to the top edge of the border box. The box shadow should + be clipped, since it is painted outside the border box. On pass you should + see a vertical green stripe on the right side of a vertical blue stripe."> +</head> +<body> + <p>The test passes if there is a vertical green stripe on the right side of a vertical blue stripe.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; position: absolute; clip: rect(50px, 100px, 150px, auto); box-shadow: 0 0 10px red;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-comma-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-comma-001.html new file mode 100644 index 0000000..d15b324 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-comma-001.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test comma separation of rect function on clip - no commas</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-absolute-positioned-ref.html"> + <meta name="assert" content="Values for rect function on clip can be white + space or comma separated, but not both. Otherwise the property setting gets + ignored. Testing rect function with white space separation. On pass you + should see a green square and no red."> +</head> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="width: 100px; height: 100px; border: solid red 50px; background-color: green; position: absolute; clip: rect(50px 150px 150px 50px);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-comma-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-comma-002.html new file mode 100644 index 0000000..aad2aeb --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-comma-002.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test comma separation of rect function on clip - no comma between 1st and 2nd value</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-no-clipping-ref.html"> + <meta name="assert" content="Values for rect function on clip can be white + space or comma separated, but not both. Otherwise the property setting gets + ignored. Testing rect function without comma separation between 1st and 2nd + value. On pass you should see a green square with a blue border."> +</head> +<body> + <p>The test passes if there is a green square with a blue border.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; position: absolute; clip: rect(50px 150px, 150px, 50px);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-comma-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-comma-003.html new file mode 100644 index 0000000..875e971 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-comma-003.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test comma separation of rect function on clip - no comma between 2nd and 3rd value</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-no-clipping-ref.html"> + <meta name="assert" content="Values for rect function on clip can be white + space or comma separated, but not both. Otherwise the property setting gets + ignored. Testing rect function without comma separation between 2nd and 3rd + value. On pass you should see a green square with a blue border."> +</head> +<body> + <p>The test passes if there is a green square with a blue border.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; position: absolute; clip: rect(50px, 150px 150px, 50px);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-comma-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-comma-004.html new file mode 100644 index 0000000..2a8b930 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/clip-rect-comma-004.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Masking: Test comma separation of rect function on clip - no comma between 3rd and 4th value</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> + <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clip-property"> + <link rel="match" href="reference/clip-no-clipping-ref.html"> + <meta name="assert" content="Values for rect function on clip can be white + space or comma separated, but not both. Otherwise the property setting gets + ignored. Testing rect function without comma separation between 3rd and 4th + value. On pass you should see a green square with a blue border."> +</head> +<body> + <p>The test passes if there is a green square with a blue border.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green; position: absolute; clip: rect(50px, 150px, 150px 50px);"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-absolute-positioned-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-absolute-positioned-ref.html new file mode 100644 index 0000000..2a9a49fd --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-absolute-positioned-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="width: 100px; height: 100px; border: 50px solid white; background-color: green;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-full-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-full-ref.html new file mode 100644 index 0000000..f556d5f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-full-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a green square and no red.</p> + <div style="width: 200px; height: 200px; background-color: green;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-horizontal-stripe-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-horizontal-stripe-ref.html new file mode 100644 index 0000000..fccb183 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-horizontal-stripe-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is only a horizontal blue stripe.</p> + <div style="width: 200px; height: 50px; background-color: blue;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-no-clipping-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-no-clipping-ref.html new file mode 100644 index 0000000..724f8c5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-no-clipping-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a green square with a blue border.</p> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-overflow-hidden-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-overflow-hidden-ref.html new file mode 100644 index 0000000..e6a6e12 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-overflow-hidden-ref.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a blue square and a smaller green square in the bottom right corner of the blue square.</p> + <div style="overflow: hidden; width: 100px; height: 100px;"> + <div style="width: 100px; height: 100px; border: solid blue 50px; background-color: green;"></div> + </div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-rect-bottom-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-rect-bottom-ref.html new file mode 100644 index 0000000..9642435bf --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-rect-bottom-ref.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a horizontal blue stripe under a horizontal green stripe.</p> + <div style="background-color: blue; width: 100px; height: 100px; border-left: 50px solid white; border-top: 100px solid white"> + <div style="width: 100px; height: 50px; background-color: green;"></div> + </div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-rect-left-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-rect-left-ref.html new file mode 100644 index 0000000..b6dd6e0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-rect-left-ref.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a vertical green stripe on the right side of a vertical blue stripe.</p> + <div style="background-color: green; width: 100px; height: 100px; border-top: 50px solid white;"> + <div style="width: 50px; height: 100px; background-color: blue;"></div> + </div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-rect-right-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-rect-right-ref.html new file mode 100644 index 0000000..09b90e7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-rect-right-ref.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a vertical blue stripe on the right side of a vertical green stripe.</p> + <div style="background-color: blue; width: 100px; height: 100px; border-left: 100px solid white; border-top: 50px solid white;"> + <div style="width: 50px; height: 100px; background-color: green;"></div> + </div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-rect-top-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-rect-top-ref.html new file mode 100644 index 0000000..5ec30181 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-rect-top-ref.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is a horizontal green stripe under a horizontal blue stripe.</p> + <div style="background-color: green; width: 100px; height: 100px; margin-left: 50px;"> + <div style="width: 100px; height: 50px; background-color: blue;"></div> + </div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-vertical-stripe-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-vertical-stripe-ref.html new file mode 100644 index 0000000..96ccc2c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/clip/reference/clip-vertical-stripe-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>CSS Reftest Reference</title> + <link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"> +</head> +<body> + <p>The test passes if there is only a vertical blue stripe.</p> + <div style="width: 50px; height: 200px; background-color: blue;"></div> +</body> +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-invalid.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-invalid.html new file mode 100644 index 0000000..1ac795b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-invalid.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Masking Module Level 1: parsing clip with invalid values</title> +<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org"> +<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#clip-property"> +<meta name="assert" content="clip supports only the grammar 'rect() | auto'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("clip", "none"); +test_invalid_value("clip", "rect(10px, 20px, 30px)"); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-path-invalid-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-path-invalid-expected.txt new file mode 100644 index 0000000..bafc8294 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-path-invalid-expected.txt
@@ -0,0 +1,28 @@ +This is a testharness.js-based test. +PASS e.style['clip-path'] = "auto" should not set the property value +PASS e.style['clip-path'] = "ray(0deg)" should not set the property value +PASS e.style['clip-path'] = "inset()" should not set the property value +PASS e.style['clip-path'] = "inset(123)" should not set the property value +PASS e.style['clip-path'] = "inset(1% 2% 3% 4% 5%)" should not set the property value +PASS e.style['clip-path'] = "inset(round 0)" should not set the property value +PASS e.style['clip-path'] = "inset(0px round)" should not set the property value +PASS e.style['clip-path'] = "inset(0px round 123)" should not set the property value +PASS e.style['clip-path'] = "inset(0px round 1% 2% 3% 4% 5%)" should not set the property value +PASS e.style['clip-path'] = "inset(0px round / 1px)" should not set the property value +PASS e.style['clip-path'] = "inset(10px round -20px)" should not set the property value +PASS e.style['clip-path'] = "inset(30% round -40%)" should not set the property value +PASS e.style['clip-path'] = "circle(123)" should not set the property value +PASS e.style['clip-path'] = "circle(at)" should not set the property value +PASS e.style['clip-path'] = "circle(10% 20%)" should not set the property value +PASS e.style['clip-path'] = "circle(-10px at 20px 30px)" should not set the property value +PASS e.style['clip-path'] = "circle(-10% at 20% 30%)" should not set the property value +PASS e.style['clip-path'] = "circle(1% 2% at 0% 100%)" should not set the property value +PASS e.style['clip-path'] = "ellipse(farthest-side at)" should not set the property value +PASS e.style['clip-path'] = "ellipse(1% 2% top right)" should not set the property value +FAIL e.style['clip-path'] = "ellipse(3% at 100% 0%)" should not set the property value assert_equals: expected "" but got "ellipse(3% at 100% 0%)" +PASS e.style['clip-path'] = "ellipse(10% -20% at 30% 40%)" should not set the property value +PASS e.style['clip-path'] = "ellipse(-50px 60px at 70% 80%)" should not set the property value +PASS e.style['clip-path'] = "polygon(1%)" should not set the property value +PASS e.style['clip-path'] = "unknown-box" should not set the property value +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-path-invalid.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-path-invalid.html new file mode 100644 index 0000000..3f5940a5f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-path-invalid.html
@@ -0,0 +1,47 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Masking Module Level 1: parsing clip-path with invalid values</title> +<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org"> +<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#the-clip-path"> +<meta name="assert" content="clip-path supports only the grammar '<clip-source> | [ <basic-shape> || <geometry-box> ] | none'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("clip-path", "auto"); +test_invalid_value("clip-path", "ray(0deg)"); + +test_invalid_value("clip-path", "inset()"); +test_invalid_value("clip-path", "inset(123)"); +test_invalid_value("clip-path", "inset(1% 2% 3% 4% 5%)"); +test_invalid_value("clip-path", "inset(round 0)"); +test_invalid_value("clip-path", "inset(0px round)"); +test_invalid_value("clip-path", "inset(0px round 123)"); +test_invalid_value("clip-path", "inset(0px round 1% 2% 3% 4% 5%)"); +test_invalid_value("clip-path", "inset(0px round / 1px)"); +test_invalid_value("clip-path", "inset(10px round -20px)"); +test_invalid_value("clip-path", "inset(30% round -40%)"); + +test_invalid_value("clip-path", "circle(123)"); +test_invalid_value("clip-path", "circle(at)"); +test_invalid_value("clip-path", "circle(10% 20%)"); +test_invalid_value("clip-path", "circle(-10px at 20px 30px)"); +test_invalid_value("clip-path", "circle(-10% at 20% 30%)"); +test_invalid_value("clip-path", "circle(1% 2% at 0% 100%)"); + +test_invalid_value("clip-path", "ellipse(farthest-side at)"); +test_invalid_value("clip-path", "ellipse(1% 2% top right)"); +test_invalid_value("clip-path", "ellipse(3% at 100% 0%)"); +test_invalid_value("clip-path", "ellipse(10% -20% at 30% 40%)"); +test_invalid_value("clip-path", "ellipse(-50px 60px at 70% 80%)"); + +test_invalid_value("clip-path", "polygon(1%)"); + +test_invalid_value("clip-path", "unknown-box"); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt new file mode 100644 index 0000000..3b1e58479 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt
@@ -0,0 +1,37 @@ +This is a testharness.js-based test. +PASS e.style['clip-path'] = "none" should set the property value +PASS e.style['clip-path'] = "inset(100%)" should set the property value +PASS e.style['clip-path'] = "inset(0 1px)" should set the property value +PASS e.style['clip-path'] = "inset(0px 1px 2%)" should set the property value +PASS e.style['clip-path'] = "inset(0px 1px 2% 3em)" should set the property value +PASS e.style['clip-path'] = "inset(0px round 100%)" should set the property value +PASS e.style['clip-path'] = "inset(0px round 0 1px)" should set the property value +PASS e.style['clip-path'] = "inset(0px round 0px 1px 2%)" should set the property value +PASS e.style['clip-path'] = "inset(0px round 0px 1px 2% 3em)" should set the property value +PASS e.style['clip-path'] = "inset(10px round 20% / 0px 1px 2% 3em)" should set the property value +PASS e.style['clip-path'] = "circle()" should set the property value +PASS e.style['clip-path'] = "circle(1px)" should set the property value +PASS e.style['clip-path'] = "circle(closest-side)" should set the property value +PASS e.style['clip-path'] = "circle(at 10% 20%)" should set the property value +PASS e.style['clip-path'] = "circle(farthest-side at center top)" should set the property value +PASS e.style['clip-path'] = "circle(4% at top right)" should set the property value +PASS e.style['clip-path'] = "ellipse()" should set the property value +PASS e.style['clip-path'] = "ellipse(1px closest-side)" should set the property value +PASS e.style['clip-path'] = "ellipse(at 10% 20%)" should set the property value +PASS e.style['clip-path'] = "ellipse(farthest-side 4% at bottom left)" should set the property value +PASS e.style['clip-path'] = "polygon(1% 2%)" should set the property value +PASS e.style['clip-path'] = "polygon(nonzero, 1px 2px, 3em 4em)" should set the property value +PASS e.style['clip-path'] = "polygon(evenodd, 1px 2px, 3em 4em, 5pt 6%)" should set the property value +FAIL e.style['clip-path'] = "border-box" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['clip-path'] = "padding-box" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['clip-path'] = "content-box" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['clip-path'] = "margin-box" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['clip-path'] = "fill-box" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['clip-path'] = "stroke-box" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['clip-path'] = "view-box" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['clip-path'] = "circle(7% at 8% 9%) border-box" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['clip-path'] = "border-box circle(7% at 8% 9%)" should set the property value assert_not_equals: property should be set got disallowed value "" +PASS e.style['clip-path'] = "url(https://example.com/)" should set the property value +PASS e.style['clip-path'] = "url(\"https://example.com/\")" should set the property value +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-path-valid.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-path-valid.html new file mode 100644 index 0000000..d7b27859 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-path-valid.html
@@ -0,0 +1,64 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Masking Module Level 1: parsing clip-path with valid values</title> +<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org"> +<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#the-clip-path"> +<meta name="assert" content="clip-path supports the full grammar '<clip-source> | [ <basic-shape> || <geometry-box> ] | none'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("clip-path", "none"); + +// <basic-shape> +test_valid_value("clip-path", "inset(100%)"); +test_valid_value("clip-path", "inset(0 1px)", "inset(0px 1px)"); +test_valid_value("clip-path", "inset(0px 1px 2%)"); +test_valid_value("clip-path", "inset(0px 1px 2% 3em)"); +test_valid_value("clip-path", "inset(0px round 100%)"); +test_valid_value("clip-path", "inset(0px round 0 1px)", "inset(0px round 0px 1px)"); +test_valid_value("clip-path", "inset(0px round 0px 1px 2%)"); +test_valid_value("clip-path", "inset(0px round 0px 1px 2% 3em)"); +test_valid_value("clip-path", "inset(10px round 20% / 0px 1px 2% 3em)"); + +test_valid_value("clip-path", "circle()", "circle(at 50% 50%)"); +test_valid_value("clip-path", "circle(1px)", "circle(1px at 50% 50%)"); +test_valid_value("clip-path", "circle(closest-side)", "circle(at 50% 50%)"); +test_valid_value("clip-path", "circle(at 10% 20%)"); +test_valid_value("clip-path", "circle(farthest-side at center top)", "circle(farthest-side at 50% 0%)"); +test_valid_value("clip-path", "circle(4% at top right)", "circle(4% at 100% 0%)"); + +test_valid_value("clip-path", "ellipse()", "ellipse(at 50% 50%)"); +test_valid_value("clip-path", "ellipse(1px closest-side)", "ellipse(1px at 50% 50%)"); +test_valid_value("clip-path", "ellipse(at 10% 20%)"); +test_valid_value("clip-path", "ellipse(farthest-side 4% at bottom left)", "ellipse(farthest-side 4% at 0% 100%)"); + +test_valid_value("clip-path", "polygon(1% 2%)"); +test_valid_value("clip-path", "polygon(nonzero, 1px 2px, 3em 4em)", "polygon(1px 2px, 3em 4em)"); +test_valid_value("clip-path", "polygon(evenodd, 1px 2px, 3em 4em, 5pt 6%)"); + +// <geometry-box> +test_valid_value("clip-path", "border-box"); +test_valid_value("clip-path", "padding-box"); +test_valid_value("clip-path", "content-box"); +test_valid_value("clip-path", "margin-box"); +test_valid_value("clip-path", "fill-box"); +test_valid_value("clip-path", "stroke-box"); +test_valid_value("clip-path", "view-box"); + +// basic-shape> <geometry-box> +test_valid_value("clip-path", "circle(7% at 8% 9%) border-box"); + +// <geometry-box> basic-shape> +test_valid_value("clip-path", "border-box circle(7% at 8% 9%)"); + +// <clip-source> +test_valid_value("clip-path", "url(https://example.com/)", ["url(https://example.com/)", "url(\"https://example.com/\")"]); +test_valid_value("clip-path", "url(\"https://example.com/\")", ["url(https://example.com/)", "url(\"https://example.com/\")"]); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-rule-invalid.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-rule-invalid.html new file mode 100644 index 0000000..10f6aee --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-rule-invalid.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Masking Module Level 1: parsing clip-rule with invalid values</title> +<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org"> +<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#the-clip-rule"> +<meta name="assert" content="clip-rule supports only the grammar 'nonzero | evenodd'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("clip-rule", "auto"); +test_invalid_value("clip-rule", "1"); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-rule-valid.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-rule-valid.html new file mode 100644 index 0000000..db22680 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-rule-valid.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Masking Module Level 1: parsing clip-rule with valid values</title> +<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org"> +<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#the-clip-rule"> +<meta name="assert" content="clip-rule supports the full grammar 'nonzero | evenodd'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("clip-rule", "nonzero"); +test_valid_value("clip-rule", "evenodd"); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-valid-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-valid-expected.txt new file mode 100644 index 0000000..fc6bf51 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-valid-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +PASS e.style['clip'] = "auto" should set the property value +PASS e.style['clip'] = "rect(10px, 20px, -30px, 40px)" should set the property value +FAIL e.style['clip'] = "rect(10%, -20%, auto, auto)" should set the property value assert_not_equals: property should be set got disallowed value "" +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-valid.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-valid.html new file mode 100644 index 0000000..24bb782d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/clip-valid.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Masking Module Level 1: parsing clip with valid values</title> +<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org"> +<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#clip-property"> +<meta name="assert" content="clip supports the full grammar 'rect() | auto'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("clip", "auto"); +test_valid_value("clip", "rect(10px, 20px, -30px, 40px)", ["rect(10px, 20px, -30px, 40px)", "rect(10px 20px -30px 40px)"]); +test_valid_value("clip", "rect(10%, -20%, auto, auto)"); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/resources/parsing-testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/resources/parsing-testcommon.js new file mode 100644 index 0000000..b075882 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/parsing/resources/parsing-testcommon.js
@@ -0,0 +1,39 @@ +'use strict'; + +// serializedValue can be the expected serialization of value, +// or an array of permitted serializations, +// or omitted if value should serialize as value. +function test_valid_value(property, value, serializedValue) { + if (arguments.length < 3) + serializedValue = value; + + var stringifiedValue = JSON.stringify(value); + + test(function(){ + var div = document.createElement('div'); + div.style[property] = value; + assert_not_equals(div.style.getPropertyValue(property), "", "property should be set"); + + var div = document.createElement('div'); + div.style[property] = value; + var readValue = div.style.getPropertyValue(property); + if (serializedValue instanceof Array) + assert_in_array(readValue, serializedValue, "serialization should be sound"); + else + assert_equals(readValue, serializedValue, "serialization should be canonical"); + + div.style[property] = readValue; + assert_equals(div.style.getPropertyValue(property), readValue, "serialization should round-trip"); + + }, "e.style['" + property + "'] = " + stringifiedValue + " should set the property value"); +} + +function test_invalid_value(property, value) { + var stringifiedValue = JSON.stringify(value); + + test(function(){ + var div = document.createElement('div'); + div.style[property] = value; + assert_equals(div.style.getPropertyValue(property), ""); + }, "e.style['" + property + "'] = " + stringifiedValue + " should not set the property value"); +}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/test-mask-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/test-mask-ref.html new file mode 100644 index 0000000..938235ac --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/test-mask-ref.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>CSS Masking: mask-repeat:round repeat;</title> +<link rel="author" title="Li Jun" href="mailto:64835173@qq.com"> +<link rel="reviewer" title="Dirk Schulze" href="mailto:dschulze@adobe.com"><!-- 11-09-2013 @TestTWF Shenzhen --> + +<body> + <p>Test passes if there is a blue square and no red.</p> + <div style="width: 200px; height:200px; position: fixed; background-color:blue;"></div> +</body> + +</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/test-mask.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/test-mask.html new file mode 100644 index 0000000..b1e2156 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/test-mask.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<title>CSS Masking: mask-repeat:round repeat;</title> +<link rel="author" title="Li Jun" href="mailto:64835173@qq.com"> +<link rel="reviewer" title="Dirk Schulze" href="mailto:dschulze@adobe.com"><!-- 11-09-2013 @TestTWF Shenzhen --> +<link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-mask-repeat"> +<link rel="match" href="test-mask-ref.html"> +<meta name="assert" content="Test checks that the mask-repeart value "round" is working properly: it should scale to fit the whole area."> +<style> +.test { + width:200px; + height:200px; + white-space:normal; + background:blue; + mask-image:radial-gradient(black, black); + mask-repeat:round; + mask-size:100px 100px; + mask-box-image:none; + mask-origin:border; +}; +</style> +<body> + <p>Test passes if there is a blue square and no red.</p> + <div style="width: 200px; height:200px; position: fixed; background-color:red;"></div> + <div class="test"></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-html-correctly-labeled.sub-expected.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-html-correctly-labeled.sub-ref.html similarity index 100% rename from third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-html-correctly-labeled.sub-expected.html rename to third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-html-correctly-labeled.sub-ref.html
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-html-correctly-labeled.sub.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-html-correctly-labeled.sub.html index b2612b4..78fc09f9 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-html-correctly-labeled.sub.html +++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-html-correctly-labeled.sub.html
@@ -6,6 +6,6 @@ --> <meta charset="utf-8"> <!-- Reference page uses same-origin resources, which are not CORB-eligible. --> -<link rel="match" href="img-png-mislabeled-as-html.sub-expected.html"> +<link rel="match" href="img-png-mislabeled-as-html.sub-ref.html"> <!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> <img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/html-correctly-labeled.html">
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-expected.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html similarity index 100% rename from third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-expected.html rename to third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html index 19d29b20..a4e519d 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html +++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html
@@ -6,6 +6,6 @@ --> <meta charset="utf-8"> <!-- Reference page uses same-origin resources, which are not CORB-eligible. --> -<link rel="match" href="img-png-mislabeled-as-html.sub-expected.html"> +<link rel="match" href="img-png-mislabeled-as-html.sub-ref.html"> <!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> <img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/png-mislabeled-as-html-nosniff.png">
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html.sub-expected.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html.sub-ref.html similarity index 100% rename from third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html.sub-expected.html rename to third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html.sub-ref.html
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html.sub.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html.sub.html index 85d444d..1ae4cfc 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html.sub.html +++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-png-mislabeled-as-html.sub.html
@@ -5,6 +5,6 @@ --> <meta charset="utf-8"> <!-- Reference page uses same-origin resources, which are not CORB-eligible. --> -<link rel="match" href="img-png-mislabeled-as-html.sub-expected.html"> +<link rel="match" href="img-png-mislabeled-as-html.sub-ref.html"> <!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> <img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/png-mislabeled-as-html.png">
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/cookie-store.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/cookie-store.idl index 6d4f359..b38f61e7 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/cookie-store.idl +++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/cookie-store.idl
@@ -13,13 +13,26 @@ }; [ - Exposed=(ServiceWorker,Window), + Exposed=Window, Constructor(DOMString type, optional CookieChangeEventInit eventInitDict) ] interface CookieChangeEvent : Event { readonly attribute CookieList changed; readonly attribute CookieList deleted; }; +dictionary ExtendableCookieChangeEventInit : ExtendableEventInit { + CookieList changed; + CookieList deleted; +}; + +[ + Exposed=ServiceWorker, + Constructor(DOMString type, optional ExtendableCookieChangeEventInit eventInitDict) +] interface ExtendableCookieChangeEvent : ExtendableEvent { + readonly attribute CookieList changed; + readonly attribute CookieList deleted; +}; + enum CookieMatchType { "equals", "startsWith" @@ -59,7 +72,11 @@ Promise<void> delete(USVString name, optional CookieStoreSetOptions options); Promise<void> delete(CookieStoreSetOptions options); - attribute EventHandler onchange; + [Exposed=ServiceWorker] Promise<void> subscribeToChanges(sequence<CookieStoreGetOptions> subscriptions); + + [Exposed=ServiceWorker] Promise<sequence<CookieStoreGetOptions>> getChangeSubscriptions(); + + [Exposed=Window] attribute EventHandler onchange; }; partial interface Window {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context-expected.html b/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context-ref.html similarity index 100% rename from third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context-expected.html rename to third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context-ref.html
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context.html b/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context.html index c60a111..dfad5a1 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context.html +++ b/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/stacking-context.html
@@ -1,6 +1,6 @@ <!doctype HTML> <title>Test that the foreignObject element is a stacking context</title> -<link rel="match" href="stacking-context-expected.html"> +<link rel="match" href="stacking-context-ref.html"> <link rel="help" href="https://svgwg.org/svg2-draft/single-page.html#embedded-ForeignObjectElement"/> <style> * {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setDescription-transceiver.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setDescription-transceiver.html index a44a165..d19b474 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setDescription-transceiver.html +++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-setDescription-transceiver.html
@@ -109,7 +109,7 @@ .then(offer => { return Promise.all([ pc1.setLocalDescription(offer), - pc2.setRemoteDescrption(offer) + pc2.setRemoteDescription(offer) ]) .then(() => { const transceivers = pc2.getTransceivers();
diff --git a/third_party/WebKit/LayoutTests/fast/forms/date/date-chooseronly-defaultValue-expected.html b/third_party/WebKit/LayoutTests/fast/forms/date/date-chooseronly-defaultValue-expected.html new file mode 100644 index 0000000..0daef0e --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/forms/date/date-chooseronly-defaultValue-expected.html
@@ -0,0 +1,4 @@ +<!DOCTYPE html> +<body> +<input type="date" value="2015-07-25"> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/date/date-chooseronly-defaultValue.html b/third_party/WebKit/LayoutTests/fast/forms/date/date-chooseronly-defaultValue.html new file mode 100644 index 0000000..6144d70 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/forms/date/date-chooseronly-defaultValue.html
@@ -0,0 +1,8 @@ +<!DOCTYPE html> +<!-- A test for crbug.com/838898. defaultValue setter should invalidate view. --> +<body> +<input type="date"> +<script> +document.querySelector('input').defaultValue = '2015-07-25'; +</script> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/MediaStream-MediaElement-networkState.html b/third_party/WebKit/LayoutTests/fast/mediastream/MediaStream-MediaElement-networkState.html new file mode 100644 index 0000000..b2d4a26 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/mediastream/MediaStream-MediaElement-networkState.html
@@ -0,0 +1,73 @@ +<!doctype html> +<html> +<head> +<title>The networkState of a media element that has assigned a MediaStream + should be NETWORK_LOADING if the stream is active and NETWORK_IDLE if the + stream is inactive. +</title> +</head> +<body> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> +var t = async_test("Tests that the networkState of a video element playing a " + + "MediaStream is updated correctly."); +t.step(function() { + navigator.mediaDevices.getUserMedia({audio:true, video: true}) + .then(t.step_func(stream => { + var video = document.createElement('video'); + assert_equals(video.networkState, HTMLMediaElement.NETWORK_EMPTY); + video.srcObject = stream; + setTimeout(()=>{ + assert_equals(video.networkState, HTMLMediaElement.NETWORK_LOADING); + stream.getTracks().forEach(track => track.stop()); + assert_equals(video.networkState, HTMLMediaElement.NETWORK_IDLE); + + // Removing and re-adding the stopped audio track does not change the + // network state. + var track = stream.getAudioTracks()[0]; + stream.removeTrack(track); + assert_equals(video.networkState, HTMLMediaElement.NETWORK_IDLE); + stream.addTrack(track); + assert_equals(video.networkState, HTMLMediaElement.NETWORK_IDLE); + + // Removing and re-adding the stopped tracks does not change the + // network state. + var track = stream.getVideoTracks()[0]; + stream.removeTrack(track); + assert_equals(video.networkState, HTMLMediaElement.NETWORK_IDLE); + stream.addTrack(track); + assert_equals(video.networkState, HTMLMediaElement.NETWORK_IDLE); + + var track = stream.getAudioTracks()[0]; + stream.removeTrack(track); + assert_equals(video.networkState, HTMLMediaElement.NETWORK_IDLE); + stream.addTrack(track); + assert_equals(video.networkState, HTMLMediaElement.NETWORK_IDLE); + + // Replacing the existing tracks with new active tracks does change the + // network state. + navigator.mediaDevices.getUserMedia({audio:true, video:true}).then( + t.step_func(stream2 => { + stream.removeTrack(stream.getAudioTracks()[0]); + stream.addTrack(stream2.getAudioTracks()[0]); + assert_equals(video.networkState, HTMLMediaElement.NETWORK_LOADING); + + stream.removeTrack(stream.getAudioTracks()[0]); + assert_equals(video.networkState, HTMLMediaElement.NETWORK_IDLE); + + stream.removeTrack(stream.getVideoTracks()[0]); + stream.addTrack(stream2.getVideoTracks()[0]); + assert_equals(video.networkState, HTMLMediaElement.NETWORK_LOADING); + + stream.removeTrack(stream.getVideoTracks()[0]); + assert_equals(video.networkState, HTMLMediaElement.NETWORK_IDLE); + + t.done(); + }), t.unreached_func); + }); + }), t.unreached_func); +}); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 18a8093..830b00b 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -157,21 +157,16 @@ getter reason getter wasClean method constructor -interface CookieChangeEvent : Event - attribute @@toStringTag - getter changed - getter deleted - method constructor interface CookieStore : EventTarget attribute @@toStringTag - getter onchange method constructor method delete method get method getAll + method getChangeSubscriptions method has method set - setter onchange + method subscribeToChanges interface CountQueuingStrategy method constructor method size @@ -439,6 +434,11 @@ method constructor method dispatchEvent method removeEventListener +interface ExtendableCookieChangeEvent : ExtendableEvent + attribute @@toStringTag + getter changed + getter deleted + method constructor interface ExtendableEvent : Event attribute @@toStringTag method constructor
diff --git a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/external/wpt/css/css-scoping/README.txt b/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/external/wpt/css/css-scoping/README.txt deleted file mode 100644 index 8ba8ab5b..0000000 --- a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/external/wpt/css/css-scoping/README.txt +++ /dev/null
@@ -1,3 +0,0 @@ -# This suite runs the tests in external/wpt/css/css-scoping with -# --enable-blink-features=IncrementalShadowDOM. -# See crbug.com/776656 for details.
diff --git a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/external/wpt/shadow-dom/README.txt b/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/external/wpt/shadow-dom/README.txt deleted file mode 100644 index d0d8b92..0000000 --- a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/external/wpt/shadow-dom/README.txt +++ /dev/null
@@ -1,3 +0,0 @@ -# This suite runs the tests in external/wpt/shadow-dom with -# --enable-blink-features=IncrementalShadowDOM. -# See crbug.com/776656 for details.
diff --git a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/fast/dom/shadow/README.txt b/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/fast/dom/shadow/README.txt deleted file mode 100644 index 3045fb5..0000000 --- a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/fast/dom/shadow/README.txt +++ /dev/null
@@ -1,3 +0,0 @@ -# This suite runs the tests in fast/dom/shadow with -# --enable-blink-features=IncrementalShadowDOM. -# See crbug.com/776656 for details.
diff --git a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/html/details_summary/README.txt b/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/html/details_summary/README.txt deleted file mode 100644 index 17b274a..0000000 --- a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/html/details_summary/README.txt +++ /dev/null
@@ -1,3 +0,0 @@ -# This suite runs the tests in html/details_summary with -# --enable-blink-features=IncrementalShadowDOM. -# See crbug.com/776656 for details.
diff --git a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/http/tests/devtools/elements/shadow/README.txt b/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/http/tests/devtools/elements/shadow/README.txt deleted file mode 100644 index 204f08b..0000000 --- a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/http/tests/devtools/elements/shadow/README.txt +++ /dev/null
@@ -1,4 +0,0 @@ -# This suite runs the tests in http/tests/devtools/elements/shadow with -# --enable-blink-features=IncrementalShadowDOM. -# See crbug.com/776656 for details. -# See crbug.com/840238 for http/tests/devtools/elements/shadow-distribution.js
diff --git a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/http/tests/devtools/elements/shadow/shadow-distribution-expected.txt b/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/http/tests/devtools/elements/shadow/shadow-distribution-expected.txt deleted file mode 100644 index 0e10558..0000000 --- a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/http/tests/devtools/elements/shadow/shadow-distribution-expected.txt +++ /dev/null
@@ -1,257 +0,0 @@ -Tests that elements panel updates dom tree structure upon distribution in shadow dom. - - -Running: createHost1 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot1" name="slot1"> - </slot> - - <slot id="slot2" name="slot2"> - </slot> - - <slot id="slot3"> - </slot> - </div> - -Running: createChild1 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot1" name="slot1"> - </slot> - - <slot id="slot2" name="slot2"> - ↪ <span> - </slot> - - <slot id="slot3"> - </slot> - <span id="child1" slot="slot2"></span> - </div> - -Running: createChild2 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot1" name="slot1"> - </slot> - - <slot id="slot2" name="slot2"> - ↪ <span> - </slot> - - <slot id="slot3"> - ↪ <div> - </slot> - <span id="child1" slot="slot2"></span> - <div id="child2"></div> - </div> - -Running: createChild3 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot1" name="slot1"> - </slot> - - <slot id="slot2" name="slot2"> - ↪ <span> - ↪ <h1> - </slot> - - <slot id="slot3"> - ↪ <div> - </slot> - <span id="child1" slot="slot2"></span> - <div id="child2"></div> - <h1 id="child3" slot="slot2"></h1> - </div> - -Running: createChild4 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot1" name="slot1"> - ↪ <h2> - </slot> - - <slot id="slot2" name="slot2"> - ↪ <span> - ↪ <h1> - </slot> - - <slot id="slot3"> - ↪ <div> - </slot> - <span id="child1" slot="slot2"></span> - <div id="child2"></div> - <h1 id="child3" slot="slot2"></h1> - <h2 id="child4" slot="slot1"></h2> - </div> - -Running: createChild5 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot1" name="slot1"> - ↪ <h2> - </slot> - - <slot id="slot2" name="slot2"> - ↪ <span> - ↪ <h1> - </slot> - - <slot id="slot3"> - ↪ <div> - </slot> - <span id="child1" slot="slot2"></span> - <div id="child2"></div> - <h1 id="child3" slot="slot2"></h1> - <h2 id="child4" slot="slot1"></h2> - <h3 id="child5" slot="slot3"></h3> - </div> - -Running: modifyChild1 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot1" name="slot1"> - ↪ <h2> - </slot> - - <slot id="slot2" name="slot2"> - ↪ <span> - ↪ <h1> - </slot> - - <slot id="slot3"> - ↪ <div> - </slot> - <span id="child1" slot="slot1"></span> - <div id="child2"></div> - <h1 id="child3" slot="slot2"></h1> - <h2 id="child4" slot="slot1"></h2> - <h3 id="child5" slot="slot3"></h3> - </div> - -Running: modifyChild4 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot1" name="slot1"> - ↪ <h2> - </slot> - - <slot id="slot2" name="slot2"> - ↪ <span> - ↪ <h1> - </slot> - - <slot id="slot3"> - ↪ <div> - </slot> - <span id="child1" slot="slot1"></span> - <div id="child2"></div> - <h1 id="child3" slot="slot2"></h1> - <h2 id="child4"></h2> - <h3 id="child5" slot="slot3"></h3> - </div> - -Running: modifySlot1 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot1" name="slot3"> - ↪ <h2> - </slot> - - <slot id="slot2" name="slot2"> - ↪ <span> - ↪ <h1> - </slot> - - <slot id="slot3"> - ↪ <div> - </slot> - <span id="child1" slot="slot1"></span> - <div id="child2"></div> - <h1 id="child3" slot="slot2"></h1> - <h2 id="child4"></h2> - <h3 id="child5" slot="slot3"></h3> - </div> - -Running: modifySlot2 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot1" name="slot3"> - ↪ <h2> - </slot> - - <slot id="slot2" name="slot1"> - ↪ <span> - ↪ <h1> - </slot> - - <slot id="slot3"> - ↪ <div> - </slot> - <span id="child1" slot="slot1"></span> - <div id="child2"></div> - <h1 id="child3" slot="slot2"></h1> - <h2 id="child4"></h2> - <h3 id="child5" slot="slot3"></h3> - </div> - -Running: removeChild3 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot1" name="slot3"> - ↪ <h3> - </slot> - - <slot id="slot2" name="slot1"> - ↪ <span> - </slot> - - <slot id="slot3"> - ↪ <div> - ↪ <h2> - </slot> - <span id="child1" slot="slot1"></span> - <div id="child2"></div> - <h2 id="child4"></h2> - <h3 id="child5" slot="slot3"></h3> - </div> - -Running: removeChild1 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot1" name="slot3"> - ↪ <h3> - </slot> - - <slot id="slot2" name="slot1"> - </slot> - - <slot id="slot3"> - ↪ <div> - ↪ <h2> - </slot> - <div id="child2"></div> - <h2 id="child4"></h2> - <h3 id="child5" slot="slot3"></h3> - </div> - -Running: removeSlot1 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot2" name="slot1"> - </slot> - - <slot id="slot3"> - ↪ <div> - ↪ <h2> - </slot> - <div id="child2"></div> - <h2 id="child4"></h2> - <h3 id="child5" slot="slot3"></h3> - </div> - -Running: createHost2 -- <div id="host2"> - - #shadow-root (open) - - <slot id="slot1" name="slot3"> - </slot> - </div> - -Running: moveChild5FromHost1ToHost2 -- <div id="host2"> - - #shadow-root (open) - - <slot id="slot1" name="slot3"> - ↪ <h3> - </slot> - <h3 id="child5" slot="slot3"></h3> - </div> - -Running: modifyChild4 -- <div id="host1"> - - #shadow-root (open) - - <slot id="slot2" name="slot1"> - </slot> - - <slot id="slot3"> - ↪ <div> - ↪ <h2> - </slot> - <div id="child2"></div> - <h2 id="child4" slot="slot1"></h2> - </div> -
diff --git a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/media/controls/README.txt b/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/media/controls/README.txt deleted file mode 100644 index a39b9612..0000000 --- a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/media/controls/README.txt +++ /dev/null
@@ -1,3 +0,0 @@ -# This suite runs the tests in media/controls/ with -# --enable-blink-features=IncrementalShadowDOM. -# See crbug.com/776656 for details.
diff --git a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/shadow-dom/README.txt b/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/shadow-dom/README.txt deleted file mode 100644 index d8ff258..0000000 --- a/third_party/WebKit/LayoutTests/virtual/incremental-shadow-dom/shadow-dom/README.txt +++ /dev/null
@@ -1,3 +0,0 @@ -# This suite runs the tests in shadow-dom with -# --enable-blink-features=IncrementalShadowDOM. -# See crbug.com/776656 for details.
diff --git a/third_party/abseil-cpp/BUILD.gn b/third_party/abseil-cpp/BUILD.gn index 8dcb9e9..eaaf015 100644 --- a/third_party/abseil-cpp/BUILD.gn +++ b/third_party/abseil-cpp/BUILD.gn
@@ -19,13 +19,23 @@ } config("absl_include_config") { - # Using -isystem instead of include_dirs (-I), so we don't need to suppress - # warnings coming from Abseil. Doing so would mask warnings in our own code. - if (!is_clang && is_win) { - # MSVC doesn't have -isystem, in that case we fallback to include_dirs and - # we use the warning suppression flags defined in :absl_default_cflags_cc. - include_dirs = [ "." ] + # Using -isystem (with clang and GCC) and -imsvc (with clang-cl) instead of + # include_dirs (-I), so we don't need to suppress warnings coming from + # Abseil. Doing so would mask warnings in our own code. + if (is_win) { + if (is_clang) { + # clang-cl: + cflags = [ + "-imsvc", + rebase_path(".", root_build_dir), + ] + } else { + # MSVC doesn't have -isystem, in that case we fallback to include_dirs and + # we use the warning suppression flags defined in :absl_default_cflags_cc. + include_dirs = [ "." ] + } } else { + # GCC or clang: cflags = [ "-isystem", rebase_path(".", root_build_dir), @@ -111,6 +121,7 @@ cflags_cc = [ "/wd4005", # macro-redefinition "/wd4068", # unknown pragma + "/wd4702", # unreachable code ] } }
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn index f2aacce..48c0839 100644 --- a/third_party/blink/public/BUILD.gn +++ b/third_party/blink/public/BUILD.gn
@@ -51,6 +51,11 @@ } config("blink_headers_config") { + include_dirs = [ + "..", + "$root_gen_dir/third_party/blink", + ] + # Allow :blink_headers to include v8.h without linking to it. configs = [ "//v8:external_config" ] }
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn index 945c74ff..79c32790 100644 --- a/third_party/blink/public/mojom/BUILD.gn +++ b/third_party/blink/public/mojom/BUILD.gn
@@ -17,6 +17,7 @@ "blob/serialized_blob.mojom", "clipboard/clipboard.mojom", "color_chooser/color_chooser.mojom", + "cookie_store/cookie_store.mojom", "feature_policy/feature_policy.mojom", "file/file_utilities.mojom", "frame/find_in_page.mojom",
diff --git a/third_party/blink/public/mojom/cookie_store/OWNERS b/third_party/blink/public/mojom/cookie_store/OWNERS new file mode 100644 index 0000000..ef6dfad9e --- /dev/null +++ b/third_party/blink/public/mojom/cookie_store/OWNERS
@@ -0,0 +1,7 @@ +file://content/browser/cookie_store/OWNERS + +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS + +# TEAM: storage-dev@chromium.org +# COMPONENT: Blink>Storage>CookiesAPI
diff --git a/third_party/blink/public/mojom/cookie_store/cookie_store.mojom b/third_party/blink/public/mojom/cookie_store/cookie_store.mojom new file mode 100644 index 0000000..5e32abe --- /dev/null +++ b/third_party/blink/public/mojom/cookie_store/cookie_store.mojom
@@ -0,0 +1,33 @@ +// 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. + +module blink.mojom; + +import "services/network/public/mojom/restricted_cookie_manager.mojom"; +import "url/mojom/url.mojom"; + +struct CookieChangeSubscription { + url.mojom.Url url; + network.mojom.CookieMatchType match_type; + string name; +}; + +// Tracks ServiceWorker subscriptions to cookie changes. +// +// Most code should access the cookie store via the RestrictedCookieManager +// interface in //services/network. This interface manages service worker +// subscriptions to cookie changes, which currently fall outside the network +// service's scope. The implementation lives in the browser process, because it +// has the ability to wake up service workers in order to dispatch events to +// them. +interface CookieStore { + // Adds the given subscriptions to the registration's subscription list. + AppendSubscriptions( + int64 service_worker_registration_id, + array<CookieChangeSubscription> subscriptions) => (bool success); + + // Returns all cookie change subscriptions for a service worker registration. + GetSubscriptions(int64 service_worker_registration_id) + => (array<CookieChangeSubscription> subscriptions, bool success); +};
diff --git a/third_party/blink/public/platform/web_media_stream.h b/third_party/blink/public/platform/web_media_stream.h index 4ab4d49..244875decb 100644 --- a/third_party/blink/public/platform/web_media_stream.h +++ b/third_party/blink/public/platform/web_media_stream.h
@@ -38,9 +38,12 @@ class BLINK_PLATFORM_EXPORT WebMediaStreamObserver { public: // TrackAdded is called when |track| is added to the observed MediaStream. - virtual void TrackAdded(const blink::WebMediaStreamTrack&) = 0; + virtual void TrackAdded(const blink::WebMediaStreamTrack&) {} // TrackRemoved is called when |track| is added to the observed MediaStream. - virtual void TrackRemoved(const blink::WebMediaStreamTrack&) = 0; + virtual void TrackRemoved(const blink::WebMediaStreamTrack&) {} + // ActiveStateChanged is called when the observed MediaStream becomes either + // active or inactive. + virtual void ActiveStateChanged(bool is_active) {} protected: virtual ~WebMediaStreamObserver() = default;
diff --git a/third_party/blink/public/web/modules/serviceworker/web_service_worker_context_client.h b/third_party/blink/public/web/modules/serviceworker/web_service_worker_context_client.h index 7e3f00d8..53d6787 100644 --- a/third_party/blink/public/web/modules/serviceworker/web_service_worker_context_client.h +++ b/third_party/blink/public/web/modules/serviceworker/web_service_worker_context_client.h
@@ -175,6 +175,11 @@ mojom::ServiceWorkerEventStatus, double event_dispatch_time) {} + // Called after 'cookiechange' events are handled by the service worker. + virtual void DidHandleCookieChangeEvent(int event_id, + mojom::ServiceWorkerEventStatus, + double event_dispatch_time) {} + // Called after ExtendableMessageEvent was handled by the service worker. virtual void DidHandleExtendableMessageEvent(int event_id, mojom::ServiceWorkerEventStatus,
diff --git a/third_party/blink/public/web/modules/serviceworker/web_service_worker_context_proxy.h b/third_party/blink/public/web/modules/serviceworker/web_service_worker_context_proxy.h index 9b93a0cd..70c82df 100644 --- a/third_party/blink/public/web/modules/serviceworker/web_service_worker_context_proxy.h +++ b/third_party/blink/public/web/modules/serviceworker/web_service_worker_context_proxy.h
@@ -87,6 +87,12 @@ const WebString& developer_id, const WebString& unique_id, const WebVector<WebBackgroundFetchSettledFetch>& fetches) = 0; + // TODO(pwnall): Use blink::CanonicalCookie, after https://crrev.com/c/991196 + // lands. + virtual void DispatchCookieChangeEvent(int event_id, + const WebString& cookie_name, + const WebString& cookie_value, + bool is_cookie_delete) = 0; virtual void DispatchExtendableMessageEvent( int event_id, TransferableMessage,
diff --git a/third_party/blink/renderer/BUILD.gn b/third_party/blink/renderer/BUILD.gn index 2b61563..4b32bb2 100644 --- a/third_party/blink/renderer/BUILD.gn +++ b/third_party/blink/renderer/BUILD.gn
@@ -77,6 +77,13 @@ # config ----------------------------------------------------------------------- config("config") { + include_dirs = [ + ".", + "..", + "$root_gen_dir/third_party/blink/renderer", + "$root_gen_dir/third_party/blink", + ] + cflags = [] defines = []
diff --git a/third_party/blink/renderer/bindings/core/v8/BUILD.gn b/third_party/blink/renderer/bindings/core/v8/BUILD.gn index 448e39f48..d70c1ed8 100644 --- a/third_party/blink/renderer/bindings/core/v8/BUILD.gn +++ b/third_party/blink/renderer/bindings/core/v8/BUILD.gn
@@ -169,7 +169,7 @@ # link.exe. But link.exe cannot make binary smaller than its size limit from # many obj files for bindings_core_impl.lib. bindings_core_generated_interface_files = - [ "$bindings_core_v8_output_dir/V8GeneratedCoreBindings.cpp" ] + [ "$bindings_core_v8_output_dir/v8_generated_core_bindings.cc" ] } else { bindings_core_generated_interface_files = process_file_template( @@ -204,7 +204,7 @@ aggregate_generated_bindings("generate_bindings_core_v8_all_interfaces") { sources = core_definition_idl_files outputs = [ - "$bindings_core_v8_output_dir/V8GeneratedCoreBindings.cpp", + "$bindings_core_v8_output_dir/v8_generated_core_bindings.cc", ] component = "core" public_deps = [
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc index 5cdb87f..44f53ee 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
@@ -158,9 +158,6 @@ v8::HandleScope scope(isolate); switch (type) { case v8::kGCTypeScavenge: - if (ThreadState::Current()) - ThreadState::Current()->WillStartV8GC(BlinkGC::kV8MinorGC); - TRACE_EVENT_BEGIN1("devtools.timeline,v8", "MinorGC", "usedHeapSizeBefore", UsedHeapSize(isolate)); VisitWeakHandlesForMinorGC(isolate); @@ -211,10 +208,6 @@ case v8::kGCTypeScavenge: TRACE_EVENT_END1("devtools.timeline,v8", "MinorGC", "usedHeapSizeAfter", UsedHeapSize(isolate)); - // TODO(haraken): Remove this. See the comment in gcPrologue. - if (ThreadState::Current()) - ThreadState::Current()->ScheduleV8FollowupGCIfNeeded( - BlinkGC::kV8MinorGC); break; case v8::kGCTypeMarkSweepCompact: TRACE_EVENT_END1("devtools.timeline,v8", "MajorGC", "usedHeapSizeAfter",
diff --git a/third_party/blink/renderer/bindings/modules/BUILD.gn b/third_party/blink/renderer/bindings/modules/BUILD.gn index 443c728..d851317 100644 --- a/third_party/blink/renderer/bindings/modules/BUILD.gn +++ b/third_party/blink/renderer/bindings/modules/BUILD.gn
@@ -25,6 +25,7 @@ "//third_party/blink/renderer/modules/background_fetch/background_fetched_event.idl", "//third_party/blink/renderer/modules/background_sync/sync_event.idl", "//third_party/blink/renderer/modules/cookie_store/cookie_change_event.idl", + "//third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.idl", "//third_party/blink/renderer/modules/device_orientation/device_motion_event.idl", "//third_party/blink/renderer/modules/device_orientation/device_orientation_event.idl", "//third_party/blink/renderer/modules/encryptedmedia/media_encrypted_event.idl",
diff --git a/third_party/blink/renderer/bindings/modules/v8/generated.gni b/third_party/blink/renderer/bindings/modules/v8/generated.gni index e80ffce0..271c55a 100644 --- a/third_party/blink/renderer/bindings/modules/v8/generated.gni +++ b/third_party/blink/renderer/bindings/modules/v8/generated.gni
@@ -10,7 +10,7 @@ bindings_modules_v8_output_dir = "$bindings_output_dir/modules/v8" bindings_modules_generated_init_partial_interfaces_file = - "$bindings_modules_v8_output_dir/initPartialInterfacesInModules.cpp" + "$bindings_modules_v8_output_dir/init_partial_interfaces_in_modules.cc" # TODO(bashi): It would be better to have a way to update this list automatically. bindings_modules_generated_union_type_files = [ @@ -120,4 +120,4 @@ ] bindings_generated_v8_context_snapshot_external_references_file = - "$bindings_modules_v8_output_dir/V8ContextSnapshotExternalReferences.cpp" + "$bindings_modules_v8_output_dir/v8_context_snapshot_external_references.cc"
diff --git a/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_external_references.h b/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_external_references.h index 30dcbc8..5dd7b09a 100644 --- a/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_external_references.h +++ b/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_external_references.h
@@ -20,7 +20,7 @@ public: // The definition of this method is auto-generated in - // V8ContextSnapshotExternalReferences.cpp. + // v8_context_snapshot_external_references.cc. static const intptr_t* GetTable(); };
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index ae1b1fa..13eb3dc6 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -41,7 +41,10 @@ } config("core_include_dirs") { - include_dirs = [] + include_dirs = [ + "..", + "$root_gen_dir/third_party/blink/renderer", + ] if (is_android && use_openmax_dl_fft) { include_dirs += [ "//third_party/openmax_dl" ] } @@ -1577,6 +1580,7 @@ ":core_include_dirs", "//tools/v8_context_snapshot:use_v8_context_snapshot", ] + include_dirs = [ "$root_gen_dir/third_party/blink/renderer" ] cflags = [] defines = []
diff --git a/third_party/blink/renderer/core/css/CSSProperties.json5 b/third_party/blink/renderer/core/css/CSSProperties.json5 index 4871182..f53c8dfb 100644 --- a/third_party/blink/renderer/core/css/CSSProperties.json5 +++ b/third_party/blink/renderer/core/css/CSSProperties.json5
@@ -741,7 +741,6 @@ field_template: "primitive", default_value: "1.0", type_name: "float", - computed_style_custom_functions: ["setter"], custom_apply_functions_all: true, priority: "High", },
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h index 7aec7b3..9dab6e1 100644 --- a/third_party/blink/renderer/core/dom/element.h +++ b/third_party/blink/renderer/core/dom/element.h
@@ -966,7 +966,6 @@ scoped_refptr<ComputedStyle> PropagateInheritedProperties(StyleRecalcChange); StyleRecalcChange RecalcOwnStyle(StyleRecalcChange); - void RecalcOwnStyleForReattach(); void RecalcShadowIncludingDescendantStylesForReattach(); void RecalcShadowRootStylesForReattach();
diff --git a/third_party/blink/renderer/core/events/event_type_names.json5 b/third_party/blink/renderer/core/events/event_type_names.json5 index dd857e3e..50a3684f 100644 --- a/third_party/blink/renderer/core/events/event_type_names.json5 +++ b/third_party/blink/renderer/core/events/event_type_names.json5
@@ -77,6 +77,7 @@ "contextmenu", "contextrestored", "controllerchange", + "cookiechange", "copy", "crossoriginmessage", "cuechange",
diff --git a/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.cc b/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.cc index 785db8e8..628c385 100644 --- a/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.cc +++ b/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.cc
@@ -109,6 +109,11 @@ ToHTMLElement(node)->setTextContent(display_value); } +void ChooserOnlyTemporalInputTypeView::ValueAttributeChanged() { + if (!GetElement().HasDirtyValue()) + UpdateView(); +} + void ChooserOnlyTemporalInputTypeView::DidSetValue(const String& value, bool value_changed) { if (value_changed)
diff --git a/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.h b/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.h index 9dbfb0a..a69e2d8 100644 --- a/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.h +++ b/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.h
@@ -54,6 +54,7 @@ // InputTypeView functions: void CreateShadowSubtree() override; void ClosePopupView() override; + void ValueAttributeChanged() override; void DidSetValue(const String&, bool value_changed) override; void HandleDOMActivateEvent(Event*) override; void UpdateView() override;
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h index c32ad2d..8f37a92 100644 --- a/third_party/blink/renderer/core/style/computed_style.h +++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -795,8 +795,6 @@ SetZIndexInternal(0); } - // zoom - bool SetZoom(float); bool SetEffectiveZoom(float); // -webkit-clip-path @@ -2543,13 +2541,6 @@ UpdatePropertySpecificDifferencesCompositingReasonsUsedStylePreserve3D); }; -inline bool ComputedStyle::SetZoom(float f) { - if (Zoom() == f) - return false; - SetZoomInternal(f); - return true; -} - inline bool ComputedStyle::SetEffectiveZoom(float f) { // Clamp the effective zoom value to a smaller (but hopeful still large // enough) range, to avoid overflow in derived computations.
diff --git a/third_party/blink/renderer/modules/cookie_store/BUILD.gn b/third_party/blink/renderer/modules/cookie_store/BUILD.gn index 49ff14f..378a0479 100644 --- a/third_party/blink/renderer/modules/cookie_store/BUILD.gn +++ b/third_party/blink/renderer/modules/cookie_store/BUILD.gn
@@ -10,6 +10,8 @@ "cookie_change_event.h", "cookie_store.cc", "cookie_store.h", + "extendable_cookie_change_event.cc", + "extendable_cookie_change_event.h", "global_cookie_store.cc", "global_cookie_store.h", ]
diff --git a/third_party/blink/renderer/modules/cookie_store/OWNERS b/third_party/blink/renderer/modules/cookie_store/OWNERS index 6b2cb0f..b23c10fd 100644 --- a/third_party/blink/renderer/modules/cookie_store/OWNERS +++ b/third_party/blink/renderer/modules/cookie_store/OWNERS
@@ -1,8 +1,8 @@ # Primary pwnall@chromium.org -# Seconday +# Secondary jsbell@chromium.org # TEAM: storage-dev@chromium.org -# COMPONENT: Blink>Storage +# COMPONENT: Blink>Storage>CookiesAPI
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_change_event.h b/third_party/blink/renderer/modules/cookie_store/cookie_change_event.h index 7fdf59b..97842405 100644 --- a/third_party/blink/renderer/modules/cookie_store/cookie_change_event.h +++ b/third_party/blink/renderer/modules/cookie_store/cookie_change_event.h
@@ -8,6 +8,7 @@ #include "third_party/blink/renderer/modules/cookie_store/cookie_list_item.h" #include "third_party/blink/renderer/modules/event_modules.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { @@ -22,7 +23,7 @@ // Used by Blink. // - // The caller is expected to create a HeapVector and std::move() it into this + // The caller is expected to create HeapVectors and std::move() them into this // method. static CookieChangeEvent* Create(const AtomicString& type, HeapVector<CookieListItem> changed,
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_change_event.idl b/third_party/blink/renderer/modules/cookie_store/cookie_change_event.idl index b9a93ed7..629a4a6 100644 --- a/third_party/blink/renderer/modules/cookie_store/cookie_change_event.idl +++ b/third_party/blink/renderer/modules/cookie_store/cookie_change_event.idl
@@ -2,10 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Used to signal cookie changes to Document contexts. // https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md +// +// See extendable_cookie_change_event.idl for the equivalent event in +// ServiceWorker contexts. [ - Exposed=(ServiceWorker,Window), + Exposed=Window, RuntimeEnabled=AsyncCookies, Constructor(DOMString type, optional CookieChangeEventInit eventInitDict) ] interface CookieChangeEvent : Event {
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc index 341e662..e54686eb5 100644 --- a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc +++ b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
@@ -19,6 +19,7 @@ #include "third_party/blink/renderer/modules/event_modules.h" #include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope.h" +#include "third_party/blink/renderer/modules/serviceworkers/service_worker_registration.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" @@ -178,6 +179,44 @@ return canonical_cookie; } +// Returns null if and only if an exception is thrown. +blink::mojom::blink::CookieChangeSubscriptionPtr ToBackendSubscription( + const KURL& default_cookie_url, + const CookieStoreGetOptions& subscription, + ExceptionState& exception_state) { + auto backend_subscription = + blink::mojom::blink::CookieChangeSubscription::New(); + + if (subscription.hasURL()) { + KURL subscription_url(default_cookie_url, subscription.url()); + // TODO(crbug.com/729800): Check that the URL is under default_cookie_url. + backend_subscription->url = subscription_url; + } else { + backend_subscription->url = default_cookie_url; + } + + if (subscription.matchType() == "startsWith") { + backend_subscription->match_type = + network::mojom::blink::CookieMatchType::STARTS_WITH; + } else { + DCHECK_EQ(subscription.matchType(), WTF::String("equals")); + backend_subscription->match_type = + network::mojom::blink::CookieMatchType::EQUALS; + } + + if (subscription.hasName()) { + backend_subscription->name = subscription.name(); + } else { + // No name provided. Use a filter that matches all cookies. This overrides + // a user-provided matchType. + backend_subscription->match_type = + network::mojom::blink::CookieMatchType::STARTS_WITH; + backend_subscription->name = g_empty_string; + } + + return backend_subscription; +} + void ToCookieListItem( const network::mojom::blink::CanonicalCookiePtr& canonical_cookie, bool is_deleted, // True for the information from a cookie deletion event. @@ -187,6 +226,29 @@ cookie.setValue(canonical_cookie->value); } +void ToCookieChangeSubscription( + const blink::mojom::blink::CookieChangeSubscription& backend_subscription, + CookieStoreGetOptions& subscription) { + subscription.setURL(backend_subscription.url); + + if (backend_subscription.match_type != + network::mojom::blink::CookieMatchType::STARTS_WITH || + !backend_subscription.name.IsEmpty()) { + subscription.setName(backend_subscription.name); + } + + switch (backend_subscription.match_type) { + case network::mojom::blink::CookieMatchType::STARTS_WITH: + subscription.setMatchType(WTF::String("startsWith")); + break; + case network::mojom::blink::CookieMatchType::EQUALS: + subscription.setMatchType(WTF::String("equals")); + break; + } + + subscription.setURL(backend_subscription.url); +} + const KURL& DefaultCookieURL(ExecutionContext* execution_context) { DCHECK(execution_context); @@ -201,7 +263,7 @@ return scope->Url(); } -const KURL DefaultSiteForCookies(ExecutionContext* execution_context) { +KURL DefaultSiteForCookies(ExecutionContext* execution_context) { DCHECK(execution_context); if (execution_context->IsDocument()) { @@ -215,7 +277,7 @@ return scope->Url(); } -} // anonymous namespace +} // namespace CookieStore::~CookieStore() = default; @@ -291,6 +353,71 @@ true /* is_deletion */, exception_state); } +ScriptPromise CookieStore::subscribeToChanges( + ScriptState* script_state, + const HeapVector<CookieStoreGetOptions>& subscriptions, + ExceptionState& exception_state) { + DCHECK(GetExecutionContext()->IsServiceWorkerGlobalScope()); + + Vector<blink::mojom::blink::CookieChangeSubscriptionPtr> + backend_subscriptions; + backend_subscriptions.ReserveInitialCapacity(subscriptions.size()); + for (const CookieStoreGetOptions& subscription : subscriptions) { + blink::mojom::blink::CookieChangeSubscriptionPtr backend_subscription = + ToBackendSubscription(default_cookie_url_, subscription, + exception_state); + if (backend_subscription.is_null()) + return ScriptPromise(); // ToBackendSubscription has thrown an exception. + backend_subscriptions.emplace_back(std::move(backend_subscription)); + } + + if (!subscription_backend_) { + exception_state.ThrowDOMException(kInvalidStateError, + "CookieStore backend went away"); + return ScriptPromise(); + } + + ServiceWorkerGlobalScope* scope = + ToServiceWorkerGlobalScope(GetExecutionContext()); + + if (!scope->IsInstalling()) { + exception_state.ThrowTypeError("Outside the installation phase"); + return ScriptPromise(); + } + + ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); + int64_t service_worker_registration_id = + scope->registration()->WebRegistration()->RegistrationId(); + subscription_backend_->AppendSubscriptions( + service_worker_registration_id, std::move(backend_subscriptions), + WTF::Bind(&CookieStore::OnSubscribeToCookieChangesResult, + WrapPersistent(resolver))); + return resolver->Promise(); +} + +ScriptPromise CookieStore::getChangeSubscriptions( + ScriptState* script_state, + ExceptionState& exception_state) { + DCHECK(GetExecutionContext()->IsServiceWorkerGlobalScope()); + + if (!subscription_backend_) { + exception_state.ThrowDOMException(kInvalidStateError, + "CookieStore backend went away"); + return ScriptPromise(); + } + + ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); + ServiceWorkerGlobalScope* scope = + ToServiceWorkerGlobalScope(GetExecutionContext()); + int64_t service_worker_registration_id = + scope->registration()->WebRegistration()->RegistrationId(); + subscription_backend_->GetSubscriptions( + service_worker_registration_id, + WTF::Bind(&CookieStore::OnGetCookieChangeSubscriptionResult, + WrapPersistent(resolver))); + return resolver->Promise(); +} + void CookieStore::ContextDestroyed(ExecutionContext* execution_context) { StopObserving(); backend_.reset(); @@ -365,9 +492,11 @@ CookieStore::CookieStore( ExecutionContext* execution_context, - network::mojom::blink::RestrictedCookieManagerPtr backend) + network::mojom::blink::RestrictedCookieManagerPtr backend, + blink::mojom::blink::CookieStorePtr subscription_backend) : ContextLifecycleObserver(execution_context), backend_(std::move(backend)), + subscription_backend_(std::move(subscription_backend)), change_listener_binding_(this), default_cookie_url_(DefaultCookieURL(execution_context)), default_site_for_cookies_(DefaultSiteForCookies(execution_context)) { @@ -489,6 +618,49 @@ resolver->Resolve(); } +// static +void CookieStore::OnSubscribeToCookieChangesResult( + ScriptPromiseResolver* resolver, + bool backend_success) { + ScriptState* script_state = resolver->GetScriptState(); + if (!script_state->ContextIsValid()) + return; + + if (!backend_success) { + resolver->Reject(DOMException::Create( + kUnknownError, + "An unknown error occured while subscribing to cookie changes.")); + return; + } + resolver->Resolve(); +} + +// static +void CookieStore::OnGetCookieChangeSubscriptionResult( + ScriptPromiseResolver* resolver, + Vector<blink::mojom::blink::CookieChangeSubscriptionPtr> backend_result, + bool backend_success) { + ScriptState* script_state = resolver->GetScriptState(); + if (!script_state->ContextIsValid()) + return; + + if (!backend_success) { + resolver->Reject(DOMException::Create( + kUnknownError, + "An unknown error occured while reading cookie change subscriptions.")); + return; + } + + HeapVector<CookieStoreGetOptions> subscriptions; + subscriptions.ReserveInitialCapacity(backend_result.size()); + for (const auto& backend_subscription : backend_result) { + CookieStoreGetOptions& subscription = subscriptions.emplace_back(); + ToCookieChangeSubscription(*backend_subscription, subscription); + } + + resolver->Resolve(std::move(subscriptions)); +} + void CookieStore::StartObserving() { if (change_listener_binding_ || !backend_) return;
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store.h b/third_party/blink/renderer/modules/cookie_store/cookie_store.h index bc0ce11..8a9bd420 100644 --- a/third_party/blink/renderer/modules/cookie_store/cookie_store.h +++ b/third_party/blink/renderer/modules/cookie_store/cookie_store.h
@@ -7,6 +7,7 @@ #include "mojo/public/cpp/bindings/binding.h" #include "services/network/public/mojom/restricted_cookie_manager.mojom-blink.h" +#include "third_party/blink/public/mojom/cookie_store/cookie_store.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/exception_state.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" @@ -35,8 +36,10 @@ static CookieStore* Create( ExecutionContext* execution_context, - network::mojom::blink::RestrictedCookieManagerPtr backend) { - return new CookieStore(execution_context, std::move(backend)); + network::mojom::blink::RestrictedCookieManagerPtr backend, + blink::mojom::blink::CookieStorePtr subscription_backend) { + return new CookieStore(execution_context, std::move(backend), + std::move(subscription_backend)); } ScriptPromise getAll(ScriptState*, @@ -76,6 +79,11 @@ const String& name, const CookieStoreSetOptions&, ExceptionState&); + ScriptPromise subscribeToChanges( + ScriptState*, + const HeapVector<CookieStoreGetOptions>& subscriptions, + ExceptionState&); + ScriptPromise getChangeSubscriptions(ScriptState*, ExceptionState&); // GarbageCollected void Trace(blink::Visitor* visitor) override { @@ -109,7 +117,8 @@ Vector<network::mojom::blink::CanonicalCookiePtr>); CookieStore(ExecutionContext*, - network::mojom::blink::RestrictedCookieManagerPtr backend); + network::mojom::blink::RestrictedCookieManagerPtr backend, + blink::mojom::blink::CookieStorePtr subscription_backend); // Common code in CookieStore::{get,getAll,has}. // @@ -152,6 +161,13 @@ static void OnSetCanonicalCookieResult(ScriptPromiseResolver*, bool backend_result); + static void OnSubscribeToCookieChangesResult(ScriptPromiseResolver*, + bool backend_result); + static void OnGetCookieChangeSubscriptionResult( + ScriptPromiseResolver*, + Vector<blink::mojom::blink::CookieChangeSubscriptionPtr> backend_result, + bool backend_success); + // Called when a change event listener is added. // // This is idempotent during the time intervals between StopObserving() calls. @@ -163,6 +179,12 @@ // Wraps an always-on Mojo pipe for sending requests to the Network Service. network::mojom::blink::RestrictedCookieManagerPtr backend_; + // Wraps a Mojo pipe for managing service worker cookie change subscriptions. + // + // This pipe is always connected in service worker execution contexts, and + // never connected in document contexts. + blink::mojom::blink::CookieStorePtr subscription_backend_; + // Wraps a Mojo pipe used to receive cookie change notifications. // // This binding is set up on-demand, when the cookie store has at least one
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store.idl b/third_party/blink/renderer/modules/cookie_store/cookie_store.idl index 0c633bc..b6692ec 100644 --- a/third_party/blink/renderer/modules/cookie_store/cookie_store.idl +++ b/third_party/blink/renderer/modules/cookie_store/cookie_store.idl
@@ -33,5 +33,12 @@ [CallWith=ScriptState, ImplementedAs=Delete, RaisesException] Promise<void> delete( CookieStoreSetOptions options); - attribute EventHandler onchange; + [Exposed=ServiceWorker, CallWith=ScriptState, RaisesException] + Promise<void> subscribeToChanges( + sequence<CookieStoreGetOptions> subscriptions); + + [Exposed=ServiceWorker, CallWith=ScriptState, RaisesException] + Promise<sequence<CookieStoreGetOptions>> getChangeSubscriptions(); + + [Exposed=Window] attribute EventHandler onchange; };
diff --git a/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.cc b/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.cc new file mode 100644 index 0000000..6de8c05 --- /dev/null +++ b/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.cc
@@ -0,0 +1,65 @@ +// 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 "third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.h" + +#include "third_party/blink/public/platform/web_string.h" +#include "third_party/blink/renderer/modules/cookie_store/cookie_list_item.h" +#include "third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event_init.h" +#include "third_party/blink/renderer/modules/event_modules.h" +#include "third_party/blink/renderer/modules/serviceworkers/extendable_event_init.h" +#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace blink { + +ExtendableCookieChangeEvent::~ExtendableCookieChangeEvent() = default; + +const AtomicString& ExtendableCookieChangeEvent::InterfaceName() const { + return EventNames::ExtendableCookieChangeEvent; +} + +void ExtendableCookieChangeEvent::Trace(blink::Visitor* visitor) { + ExtendableEvent::Trace(visitor); + visitor->Trace(changed_); + visitor->Trace(deleted_); +} + +ExtendableCookieChangeEvent::ExtendableCookieChangeEvent( + const AtomicString& type, + HeapVector<CookieListItem> changed, + HeapVector<CookieListItem> deleted, + WaitUntilObserver* wait_until_observer) + : ExtendableEvent(type, ExtendableEventInit(), wait_until_observer), + changed_(std::move(changed)), + deleted_(std::move(deleted)) {} + +ExtendableCookieChangeEvent::ExtendableCookieChangeEvent( + const AtomicString& type, + const ExtendableCookieChangeEventInit& initializer) + : ExtendableEvent(type, initializer) { + if (initializer.hasChanged()) + changed_ = initializer.changed(); + if (initializer.hasDeleted()) + deleted_ = initializer.deleted(); +} + +// static +void ExtendableCookieChangeEvent::ToCookieChangeListItem( + const WebString& cookie_name, + const WebString& cookie_value, + bool is_cookie_delete, + HeapVector<CookieListItem>& changed, + HeapVector<CookieListItem>& deleted) { + if (is_cookie_delete) { + CookieListItem& cookie = deleted.emplace_back(); + cookie.setName(cookie_name); + } else { + CookieListItem& cookie = changed.emplace_back(); + cookie.setName(cookie_name); + cookie.setValue(cookie_value); + } +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.h b/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.h new file mode 100644 index 0000000..af810bf --- /dev/null +++ b/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.h
@@ -0,0 +1,81 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_COOKIE_STORE_EXTENDABLE_COOKIE_CHANGE_EVENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_COOKIE_STORE_EXTENDABLE_COOKIE_CHANGE_EVENT_H_ + +#include "third_party/blink/renderer/modules/cookie_store/cookie_list_item.h" +#include "third_party/blink/renderer/modules/event_modules.h" +#include "third_party/blink/renderer/modules/serviceworkers/extendable_event.h" +#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace blink { + +class ExtendableCookieChangeEventInit; +class WaitUntilObserver; +class WebString; + +class ExtendableCookieChangeEvent final : public ExtendableEvent { + DEFINE_WRAPPERTYPEINFO(); + + public: + // Used by Blink. + // + // The caller is expected to create HeapVectors and std::move() them into this + // method. + static ExtendableCookieChangeEvent* Create( + const AtomicString& type, + HeapVector<CookieListItem> changed, + HeapVector<CookieListItem> deleted, + WaitUntilObserver* wait_until_observer) { + return new ExtendableCookieChangeEvent( + type, std::move(changed), std::move(deleted), wait_until_observer); + } + + // Used by JavaScript, via the V8 bindings. + static ExtendableCookieChangeEvent* Create( + const AtomicString& type, + const ExtendableCookieChangeEventInit& initializer) { + return new ExtendableCookieChangeEvent(type, initializer); + } + + ~ExtendableCookieChangeEvent() override; + + const HeapVector<CookieListItem>& changed() const { return changed_; } + const HeapVector<CookieListItem>& deleted() const { return deleted_; } + + // Event + const AtomicString& InterfaceName() const override; + + // GarbageCollected + void Trace(blink::Visitor*) override; + + // Helper for converting backend event information into a CookieChangeEvent. + // + // TODO(pwnall): Switch to blink::CanonicalCookie when + // https://crrev.com/c/991196 lands. + static void ToCookieChangeListItem(const WebString& cookie_name, + const WebString& cookie_value, + bool is_cookie_delete, + HeapVector<CookieListItem>& changed, + HeapVector<CookieListItem>& deleted); + + private: + ExtendableCookieChangeEvent(const AtomicString& type, + HeapVector<CookieListItem> changed, + HeapVector<CookieListItem> deleted, + WaitUntilObserver*); + ExtendableCookieChangeEvent( + const AtomicString& type, + const ExtendableCookieChangeEventInit& initializer); + + HeapVector<CookieListItem> changed_; + HeapVector<CookieListItem> deleted_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_COOKIE_STORE_EXTENDABLE_COOKIE_CHANGE_EVENT_H_
diff --git a/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.idl b/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.idl new file mode 100644 index 0000000..1901997 --- /dev/null +++ b/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.idl
@@ -0,0 +1,17 @@ +// 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. + +// Used to signal cookie changes to ServiceWorker contexts. +// https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md +// +// See cookie_change_event.idl for the equivalent event in Document contexts. + +[ + Exposed=ServiceWorker, + RuntimeEnabled=AsyncCookies, + Constructor(DOMString type, optional ExtendableCookieChangeEventInit eventInitDict) +] interface ExtendableCookieChangeEvent : ExtendableEvent { + readonly attribute CookieList changed; + readonly attribute CookieList deleted; +};
diff --git a/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event_init.idl b/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event_init.idl new file mode 100644 index 0000000..27cab8c75 --- /dev/null +++ b/third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event_init.idl
@@ -0,0 +1,10 @@ +// 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. + +// https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md + +dictionary ExtendableCookieChangeEventInit : ExtendableEventInit { + CookieList changed; + CookieList deleted; +};
diff --git a/third_party/blink/renderer/modules/cookie_store/global_cookie_store.cc b/third_party/blink/renderer/modules/cookie_store/global_cookie_store.cc index 4e5316e..816e45a 100644 --- a/third_party/blink/renderer/modules/cookie_store/global_cookie_store.cc +++ b/third_party/blink/renderer/modules/cookie_store/global_cookie_store.cc
@@ -43,18 +43,18 @@ if (!cookie_store_) { ExecutionContext* execution_context = scope.GetExecutionContext(); - network::mojom::blink::RestrictedCookieManagerPtr cookie_manager_ptr; service_manager::InterfaceProvider* interface_provider = execution_context->GetInterfaceProvider(); if (!interface_provider) return nullptr; - interface_provider->GetInterface(mojo::MakeRequest(&cookie_manager_ptr)); - cookie_store_ = - CookieStore::Create(execution_context, std::move(cookie_manager_ptr)); + cookie_store_ = BuildCookieStore(execution_context, interface_provider); } return cookie_store_; } + CookieStore* BuildCookieStore(ExecutionContext*, + service_manager::InterfaceProvider*); + void Trace(blink::Visitor* visitor) override { visitor->Trace(cookie_store_); Supplement<T>::Trace(visitor); @@ -67,6 +67,31 @@ Member<CookieStore> cookie_store_; }; +template <> +CookieStore* GlobalCookieStoreImpl<LocalDOMWindow>::BuildCookieStore( + ExecutionContext* execution_context, + service_manager::InterfaceProvider* interface_provider) { + network::mojom::blink::RestrictedCookieManagerPtr cookie_manager_ptr; + interface_provider->GetInterface(mojo::MakeRequest(&cookie_manager_ptr)); + + return CookieStore::Create(execution_context, std::move(cookie_manager_ptr), + blink::mojom::blink::CookieStorePtr()); +} + +template <> +CookieStore* GlobalCookieStoreImpl<WorkerGlobalScope>::BuildCookieStore( + ExecutionContext* execution_context, + service_manager::InterfaceProvider* interface_provider) { + network::mojom::blink::RestrictedCookieManagerPtr cookie_manager_ptr; + interface_provider->GetInterface(mojo::MakeRequest(&cookie_manager_ptr)); + + blink::mojom::blink::CookieStorePtr cookie_store_ptr; + interface_provider->GetInterface(mojo::MakeRequest(&cookie_store_ptr)); + + return CookieStore::Create(execution_context, std::move(cookie_manager_ptr), + std::move(cookie_store_ptr)); +} + // static template <typename T> const char GlobalCookieStoreImpl<T>::kSupplementName[] =
diff --git a/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.idl b/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.idl index eebb8b7..118b777 100644 --- a/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.idl +++ b/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.idl
@@ -8,5 +8,5 @@ RuntimeEnabled=AsyncCookies, ImplementedAs=GlobalCookieStore ] partial interface ServiceWorkerGlobalScope { - [Replaceable, SameObject] readonly attribute CookieStore cookieStore; + [Replaceable, SameObject] readonly attribute CookieStore cookieStore; };
diff --git a/third_party/blink/renderer/modules/exported/BUILD.gn b/third_party/blink/renderer/modules/exported/BUILD.gn index 686411e..0e7590d5 100644 --- a/third_party/blink/renderer/modules/exported/BUILD.gn +++ b/third_party/blink/renderer/modules/exported/BUILD.gn
@@ -44,4 +44,6 @@ "//third_party/blink/renderer:config", "//third_party/blink/renderer/core:blink_core_pch", ] + + include_dirs = [ "$root_gen_dir/third_party/blink/renderer" ] }
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni index 4c50a588..961d9f0 100644 --- a/third_party/blink/renderer/modules/modules_idl_files.gni +++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -97,6 +97,7 @@ "clipboard/clipboard.idl", "cookie_store/cookie_change_event.idl", "cookie_store/cookie_store.idl", + "cookie_store/extendable_cookie_change_event.idl", "credentialmanager/authenticator_assertion_response.idl", "credentialmanager/authenticator_attestation_response.idl", "credentialmanager/authenticator_response.idl", @@ -472,6 +473,7 @@ "cookie_store/cookie_list_item.idl", "cookie_store/cookie_store_get_options.idl", "cookie_store/cookie_store_set_options.idl", + "cookie_store/extendable_cookie_change_event_init.idl", "credentialmanager/authentication_extensions_client_inputs.idl", "credentialmanager/authentication_extensions_client_outputs.idl", "credentialmanager/authenticator_selection_criteria.idl",
diff --git a/third_party/blink/renderer/modules/serviceworkers/DEPS b/third_party/blink/renderer/modules/serviceworkers/DEPS index 41e9842..8c6d4bf9 100644 --- a/third_party/blink/renderer/modules/serviceworkers/DEPS +++ b/third_party/blink/renderer/modules/serviceworkers/DEPS
@@ -12,6 +12,7 @@ "service_worker_global_scope_proxy\.cc": [ "+third_party/blink/renderer/modules/background_fetch", "+third_party/blink/renderer/modules/background_sync", + "+third_party/blink/renderer/modules/cookie_store", "+third_party/blink/renderer/modules/exported", "+third_party/blink/renderer/modules/notifications", "+third_party/blink/renderer/modules/payments",
diff --git a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_client.cc b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_client.cc index d22b142..3a6fe4c 100644 --- a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_client.cc +++ b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_client.cc
@@ -119,6 +119,13 @@ event_dispatch_time); } +void ServiceWorkerGlobalScopeClient::DidHandleCookieChangeEvent( + int event_id, + mojom::ServiceWorkerEventStatus status, + double event_dispatch_time) { + client_.DidHandleCookieChangeEvent(event_id, status, event_dispatch_time); +} + void ServiceWorkerGlobalScopeClient::DidHandleExtendableMessageEvent( int event_id, mojom::ServiceWorkerEventStatus status,
diff --git a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_client.h b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_client.h index 60364bb..21fbacc 100644 --- a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_client.h +++ b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_client.h
@@ -95,6 +95,9 @@ void DidHandleBackgroundFetchedEvent(int event_id, mojom::ServiceWorkerEventStatus, double event_dispatch_time); + void DidHandleCookieChangeEvent(int event_id, + mojom::ServiceWorkerEventStatus, + double event_dispatch_time); void DidHandleExtendableMessageEvent(int event_id, mojom::ServiceWorkerEventStatus, double event_dispatch_time);
diff --git a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_proxy.cc index 4522320..91f1dbc 100644 --- a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_proxy.cc +++ b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_proxy.cc
@@ -61,6 +61,7 @@ #include "third_party/blink/renderer/modules/background_fetch/background_fetch_settled_event_init.h" #include "third_party/blink/renderer/modules/background_fetch/background_fetch_update_event.h" #include "third_party/blink/renderer/modules/background_sync/sync_event.h" +#include "third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.h" #include "third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h" #include "third_party/blink/renderer/modules/notifications/notification.h" #include "third_party/blink/renderer/modules/notifications/notification_event.h" @@ -246,6 +247,30 @@ WorkerGlobalScope()->DispatchExtendableEvent(event, observer); } +void ServiceWorkerGlobalScopeProxy::DispatchCookieChangeEvent( + int event_id, + const WebString& cookie_name, + const WebString& cookie_value, + bool is_cookie_delete) { + DCHECK(WorkerGlobalScope()->IsContextThread()); + WaitUntilObserver* observer = WaitUntilObserver::Create( + WorkerGlobalScope(), WaitUntilObserver::kCookieChange, event_id); + + HeapVector<CookieListItem> changed; + HeapVector<CookieListItem> deleted; + ExtendableCookieChangeEvent::ToCookieChangeListItem( + cookie_name, cookie_value, is_cookie_delete, changed, deleted); + Event* event = ExtendableCookieChangeEvent::Create( + EventTypeNames::cookiechange, std::move(changed), std::move(deleted), + observer); + + // TODO(pwnall): When switching to blink::CanonicalCookie, handle the case + // when (changed.IsEmpty() && deleted.IsEmpty()). + + // TODO(pwnall): Investigate dispatching this on cookieStore. + WorkerGlobalScope()->DispatchExtendableEvent(event, observer); +} + void ServiceWorkerGlobalScopeProxy::DispatchExtendableMessageEvent( int event_id, TransferableMessage message,
diff --git a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_proxy.h b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_proxy.h index 365d5d2..a012b73a 100644 --- a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_proxy.h +++ b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_proxy.h
@@ -99,6 +99,10 @@ const WebString& developer_id, const WebString& unique_id, const WebVector<WebBackgroundFetchSettledFetch>& fetches) override; + void DispatchCookieChangeEvent(int event_id, + const WebString& cookie_name, + const WebString& cookie_value, + bool is_cookie_delete) override; void DispatchExtendableMessageEvent( int event_id, TransferableMessage,
diff --git a/third_party/blink/renderer/modules/serviceworkers/wait_until_observer.cc b/third_party/blink/renderer/modules/serviceworkers/wait_until_observer.cc index 1493899..28d48f76 100644 --- a/third_party/blink/renderer/modules/serviceworkers/wait_until_observer.cc +++ b/third_party/blink/renderer/modules/serviceworkers/wait_until_observer.cc
@@ -259,6 +259,10 @@ client->DidHandleCanMakePaymentEvent(event_id_, status, event_dispatch_time_); break; + case kCookieChange: + client->DidHandleCookieChangeEvent(event_id_, status, + event_dispatch_time_); + break; case kFetch: client->DidHandleFetchEvent(event_id_, status, event_dispatch_time_); break;
diff --git a/third_party/blink/renderer/modules/serviceworkers/wait_until_observer.h b/third_party/blink/renderer/modules/serviceworkers/wait_until_observer.h index 0005c02..b1ef6e6 100644 --- a/third_party/blink/renderer/modules/serviceworkers/wait_until_observer.h +++ b/third_party/blink/renderer/modules/serviceworkers/wait_until_observer.h
@@ -29,6 +29,7 @@ kAbortPayment, kActivate, kCanMakePayment, + kCookieChange, kFetch, kInstall, kMessage,
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index 185d207a..4c11cc9e 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -166,6 +166,11 @@ import("//build/config/pch.gni") config("blink_platform_config") { + include_dirs = [ + #"$angle_path/include", + "$root_gen_dir/third_party/blink/renderer", + ] + configs = [ "//third_party/blink/renderer:config", "//third_party/blink/renderer:inside_blink", @@ -1973,6 +1978,8 @@ ] defines = [ "INSIDE_BLINK" ] + + include_dirs = [ "$root_gen_dir/third_party/blink/renderer" ] } executable("image_decode_bench") {
diff --git a/third_party/blink/renderer/platform/heap/heap_test.cc b/third_party/blink/renderer/platform/heap/heap_test.cc index 9d108d9..e902bb28 100644 --- a/third_party/blink/renderer/platform/heap/heap_test.cc +++ b/third_party/blink/renderer/platform/heap/heap_test.cc
@@ -2370,7 +2370,13 @@ PreciselyCollectGarbage(); } -TEST(HeapTest, LargeHashMap) { +// This test often fails on Android (https://crbug.com/843032). +#if defined(OS_ANDROID) +#define MAYBE_LargeHashMap DISABLED_LargeHashMap +#else +#define MAYBE_LargeHashMap LargeHashMap +#endif +TEST(HeapTest, MAYBE_LargeHashMap) { ClearOutOldGarbage(); size_t size = (1 << 27) / sizeof(Member<IntWrapper>); Persistent<HeapHashMap<int, Member<IntWrapper>>> map =
diff --git a/third_party/blink/renderer/platform/heap/thread_state.cc b/third_party/blink/renderer/platform/heap/thread_state.cc index 7e6c794..9aa09e4 100644 --- a/third_party/blink/renderer/platform/heap/thread_state.cc +++ b/third_party/blink/renderer/platform/heap/thread_state.cc
@@ -478,6 +478,7 @@ VLOG(2) << "[state:" << this << "] ScheduleV8FollowupGCIfNeeded: v8_gc_type=" << ((gc_type == BlinkGC::kV8MajorGC) ? "MajorGC" : "MinorGC"); DCHECK(CheckThread()); + DCHECK_EQ(BlinkGC::kV8MajorGC, gc_type); ThreadHeap::ReportMemoryUsageForTracing(); if (IsGCForbidden()) @@ -489,14 +490,13 @@ DCHECK(!IsSweepingInProgress()); DCHECK(!SweepForbidden()); - if ((gc_type == BlinkGC::kV8MajorGC && ShouldForceMemoryPressureGC()) || - ShouldScheduleV8FollowupGC()) { + if (ShouldForceMemoryPressureGC() || ShouldScheduleV8FollowupGC()) { VLOG(2) << "[state:" << this << "] " << "ScheduleV8FollowupGCIfNeeded: Scheduled precise GC"; SchedulePreciseGC(); return; } - if (gc_type == BlinkGC::kV8MajorGC && ShouldScheduleIdleGC()) { + if (ShouldScheduleIdleGC()) { VLOG(2) << "[state:" << this << "] " << "ScheduleV8FollowupGCIfNeeded: Scheduled idle GC"; ScheduleIdleGC(); @@ -512,8 +512,8 @@ // completeSweep() here, because gcPrologue for a major GC is called // not at the point where the major GC started but at the point where // the major GC requests object grouping. - if (gc_type == BlinkGC::kV8MajorGC) - CompleteSweep(); + DCHECK_EQ(BlinkGC::kV8MajorGC, gc_type); + CompleteSweep(); } void ThreadState::SchedulePageNavigationGCIfNeeded(
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.cc b/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.cc index 6c80a55..d2373f3 100644 --- a/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.cc +++ b/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.cc
@@ -80,9 +80,10 @@ break; } - for (auto*& observer : observers_) { + // Iterate over a copy of |observers_| to avoid re-entrancy issues. + Vector<WebMediaStreamObserver*> observers = observers_; + for (auto*& observer : observers) observer->TrackAdded(component); - } } void MediaStreamDescriptor::RemoveComponent(MediaStreamComponent* component) { @@ -100,9 +101,10 @@ break; } - for (auto*& observer : observers_) { + // Iterate over a copy of |observers_| to avoid re-entrancy issues. + Vector<WebMediaStreamObserver*> observers = observers_; + for (auto*& observer : observers) observer->TrackRemoved(component); - } } void MediaStreamDescriptor::AddRemoteTrack(MediaStreamComponent* component) { @@ -119,6 +121,17 @@ RemoveComponent(component); } +void MediaStreamDescriptor::SetActive(bool active) { + if (active == active_) + return; + + active_ = active; + // Iterate over a copy of |observers_| to avoid re-entrancy issues. + Vector<WebMediaStreamObserver*> observers = observers_; + for (auto*& observer : observers) + observer->ActiveStateChanged(active_); +} + void MediaStreamDescriptor::AddObserver(WebMediaStreamObserver* observer) { DCHECK_EQ(observers_.Find(observer), kNotFound); observers_.push_back(observer);
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h b/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h index 5ab2a53..7f12f28 100644 --- a/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h +++ b/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h
@@ -102,7 +102,7 @@ void RemoveRemoteTrack(MediaStreamComponent*); bool Active() const { return active_; } - void SetActive(bool active) { active_ = active; } + void SetActive(bool active); void AddObserver(WebMediaStreamObserver*); void RemoveObserver(WebMediaStreamObserver*);
diff --git a/third_party/blink/renderer/platform/scheduler/base/task_queue_manager.h b/third_party/blink/renderer/platform/scheduler/base/task_queue_manager.h index 252811a6..9881945 100644 --- a/third_party/blink/renderer/platform/scheduler/base/task_queue_manager.h +++ b/third_party/blink/renderer/platform/scheduler/base/task_queue_manager.h
@@ -5,6 +5,9 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_MANAGER_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_MANAGER_H_ +#include <memory> +#include <utility> + #include "base/message_loop/message_loop.h" #include "base/single_thread_task_runner.h" #include "third_party/blink/renderer/platform/platform_export.h" @@ -79,6 +82,10 @@ virtual void EnableCrashKeys(const char* file_name_crash_key, const char* function_name_crash_key) = 0; + // Returns the portion of tasks for which CPU time is recorded or 0 if not + // sampled. + virtual double GetSamplingRateForRecordingCPUTime() const = 0; + // Creates a task queue with the given type, |spec| and args. Must be called // on the thread this class was created on. // TODO(altimin): TaskQueueManager should not create TaskQueues.
diff --git a/third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.cc b/third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.cc index bafa891..4a6ddf9 100644 --- a/third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.cc +++ b/third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.cc
@@ -4,9 +4,8 @@ #include "third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.h" -#include <memory> #include <queue> -#include <set> +#include <vector> #include "base/bind.h" #include "base/bit_cast.h" @@ -436,9 +435,11 @@ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"), "TaskQueueManagerImpl::NotifyDidProcessTaskObservers"); - ThreadTicks task_end_thread_time; - if (executing_task.should_record_thread_time) - task_end_thread_time = ThreadTicks::Now(); + Optional<TimeDelta> thread_time; + if (executing_task.should_record_thread_time) { + auto task_end_thread_time = ThreadTicks::Now(); + thread_time = task_end_thread_time - executing_task.task_start_thread_time; + } if (!executing_task.task_queue->GetShouldNotifyObservers()) return; @@ -476,8 +477,7 @@ if (task_start_time_sec && task_end_time_sec) { executing_task.task_queue->OnTaskCompleted( executing_task.pending_task, executing_task.task_start_time, - time_after_task->Now(), - task_end_thread_time - executing_task.task_start_thread_time); + time_after_task->Now(), thread_time); } } @@ -647,6 +647,12 @@ kSamplingRateForRecordingCPUTime; } +double TaskQueueManagerImpl::GetSamplingRateForRecordingCPUTime() const { + if (!ThreadTicks::IsSupported()) + return 0; + return kSamplingRateForRecordingCPUTime; +} + MSVC_DISABLE_OPTIMIZE() bool TaskQueueManagerImpl::Validate() { return memory_corruption_sentinel_ == kMemoryCorruptionSentinelValue;
diff --git a/third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.h b/third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.h index d117491..8a03d9c 100644 --- a/third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.h +++ b/third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.h
@@ -5,8 +5,13 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_MANAGER_IMPL_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_MANAGER_IMPL_H_ +#include <list> #include <map> +#include <memory> #include <random> +#include <set> +#include <unordered_map> +#include <utility> #include "base/atomic_sequence_num.h" #include "base/cancelable_callback.h" @@ -103,6 +108,7 @@ void SetWorkBatchSize(int work_batch_size) override; void EnableCrashKeys(const char* file_name_crash_key, const char* function_name_crash_key) override; + double GetSamplingRateForRecordingCPUTime() const override; // Implementation of SequencedTaskSource: Optional<PendingTask> TakeTask() override;
diff --git a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc index 73ef6a6..795459fb0 100644 --- a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc +++ b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
@@ -4,6 +4,8 @@ #include "third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h" +#include <utility> + #include "base/time/default_tick_clock.h" #include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event_argument.h" @@ -135,5 +137,11 @@ return base::TimeTicks::Now(); } +double SchedulerHelper::GetSamplingRateForRecordingCPUTime() const { + if (task_queue_manager_) + return task_queue_manager_->GetSamplingRateForRecordingCPUTime(); + return 0; +} + } // namespace scheduler } // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h index 75780415..f93b258 100644 --- a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h +++ b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_SCHEDULER_HELPER_H_ #include <stddef.h> +#include <memory> #include "base/macros.h" #include "base/message_loop/message_loop.h" @@ -89,6 +90,7 @@ void RegisterTimeDomain(base::sequence_manager::TimeDomain* time_domain); void UnregisterTimeDomain(base::sequence_manager::TimeDomain* time_domain); bool GetAndClearSystemIsQuiescentBit(); + double GetSamplingRateForRecordingCPUTime() const; // Test helpers. void SetWorkBatchSizeForTesting(size_t work_batch_size);
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc index 9f119e9..87e3483 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -4,7 +4,8 @@ #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h" -#include <memory> +#include <algorithm> +#include <utility> #include "base/bind.h" #include "base/debug/stack_trace.h" @@ -2475,7 +2476,7 @@ base::TimeTicks start, base::TimeTicks end, base::Optional<base::TimeDelta> thread_time) { - if (!ShouldRecordTaskUkm()) + if (!ShouldRecordTaskUkm(thread_time.has_value())) return; if (queue && queue->GetFrameScheduler()) { @@ -2652,10 +2653,29 @@ return main_thread_only().is_audio_playing; } -bool MainThreadSchedulerImpl::ShouldRecordTaskUkm() { - // This function returns true with probability of kSamplingRateForTaskUkm. +bool MainThreadSchedulerImpl::ShouldIgnoreTaskForUkm(bool has_thread_time, + double* sampling_rate) { + const double thread_time_sampling_rate = + helper_.GetSamplingRateForRecordingCPUTime(); + if (thread_time_sampling_rate && *sampling_rate < thread_time_sampling_rate) { + if (!has_thread_time) + return true; + *sampling_rate /= thread_time_sampling_rate; + } + return false; +} + +bool MainThreadSchedulerImpl::ShouldRecordTaskUkm(bool has_thread_time) { + double sampling_rate = kSamplingRateForTaskUkm; + + // If thread_time is sampled as well, try to align UKM sampling with it so + // that we only record UKMs for tasks that also record thread_time. + if (ShouldIgnoreTaskForUkm(has_thread_time, &sampling_rate)) { + return false; + } + return main_thread_only().uniform_distribution( - main_thread_only().random_generator) < kSamplingRateForTaskUkm; + main_thread_only().random_generator) < sampling_rate; } // static
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h index 549cbca..a6b4d33 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -5,7 +5,11 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_MAIN_THREAD_SCHEDULER_IMPL_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_MAIN_THREAD_SCHEDULER_IMPL_H_ +#include <map> +#include <memory> #include <random> +#include <set> +#include <string> #include "base/atomicops.h" #include "base/gtest_prod_util.h" @@ -50,6 +54,7 @@ namespace main_thread_scheduler_impl_unittest { class MainThreadSchedulerImplForTest; class MainThreadSchedulerImplTest; +FORWARD_DECLARE_TEST(MainThreadSchedulerImplTest, ShouldIgnoreTaskForUkm); FORWARD_DECLARE_TEST(MainThreadSchedulerImplTest, Tracing); } // namespace main_thread_scheduler_impl_unittest class PageSchedulerImpl; @@ -314,6 +319,9 @@ friend class main_thread_scheduler_impl_unittest::MainThreadSchedulerImplTest; FRIEND_TEST_ALL_PREFIXES( main_thread_scheduler_impl_unittest::MainThreadSchedulerImplTest, + ShouldIgnoreTaskForUkm); + FRIEND_TEST_ALL_PREFIXES( + main_thread_scheduler_impl_unittest::MainThreadSchedulerImplTest, Tracing); enum class ExpensiveTaskPolicy { kRun, kBlock, kThrottle }; @@ -442,7 +450,7 @@ class PollableNeedsUpdateFlag { public: - PollableNeedsUpdateFlag(base::Lock* write_lock); + explicit PollableNeedsUpdateFlag(base::Lock* write_lock); ~PollableNeedsUpdateFlag(); // Set the flag. May only be called if |write_lock| is held. @@ -589,7 +597,14 @@ // TaskQueueThrottler. void VirtualTimeResumed(); - bool ShouldRecordTaskUkm(); + // Returns true if the current task should not be reported in UKM because no + // thread time was recorded for it. Also updates |sampling_rate| to account + // for the ignored tasks by sampling the remaining tasks with higher + // probability. + bool ShouldIgnoreTaskForUkm(bool has_thread_time, double* sampling_rate); + + // Returns true with probability of kSamplingRateForTaskUkm. + bool ShouldRecordTaskUkm(bool has_thread_time); // Probabilistically record all task metadata for the current task. // If task belongs to a per-frame queue, this task is attributed to
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc index fd4b8c0..7fe643df 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
@@ -3919,6 +3919,27 @@ EXPECT_EQ(base::Time::Now(), base::Time::FromJsTime(1000000.0)); } +TEST_F(MainThreadSchedulerImplTest, ShouldIgnoreTaskForUkm) { + bool supports_thread_ticks = base::ThreadTicks::IsSupported(); + double sampling_rate; + + sampling_rate = 0.0001; + EXPECT_FALSE(scheduler_->ShouldIgnoreTaskForUkm(true, &sampling_rate)); + if (supports_thread_ticks) { + EXPECT_EQ(0.01, sampling_rate); + } else { + EXPECT_EQ(0.0001, sampling_rate); + } + + sampling_rate = 0.0001; + if (supports_thread_ticks) { + EXPECT_TRUE(scheduler_->ShouldIgnoreTaskForUkm(false, &sampling_rate)); + } else { + EXPECT_FALSE(scheduler_->ShouldIgnoreTaskForUkm(false, &sampling_rate)); + EXPECT_EQ(0.0001, sampling_rate); + } +} + } // namespace main_thread_scheduler_impl_unittest } // namespace scheduler } // namespace blink
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 3e242c8..638e8a4 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -40906,6 +40906,7 @@ <int value="27" label="NAVIGATION_HINT"/> <int value="28" label="CAN_MAKE_PAYMENT"/> <int value="29" label="ABORT_PAYMENT"/> + <int value="30" label="COOKIE_CHANGE"/> </enum> <enum name="ServiceWorkerPreparationType"> @@ -45714,6 +45715,8 @@ <int value="50" label="kErrorCodeOmahaUpdateIgnoredOverCellular"/> <int value="51" label="kErrorCodePayloadTimestampError"/> <int value="52" label="kErrorCodeUpdatedButNotActive"/> + <int value="53" label="kErrorCodeNoUpdate"/> + <int value="54" label="kErrorCodeRollbackNotPossible"/> </enum> <enum name="UpdateEngineInstallDateProvisioningSource">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index d6e4a11..d831889 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -48298,6 +48298,9 @@ </histogram> <histogram name="Net.PreconnectMotivation" enum="PreconnectMotivation"> + <obsolete> + Deprecated May 2018 + </obsolete> <owner>csharrison@chromium.org</owner> <summary> When a preconnection is made, indicate what the motivation was. @@ -48335,6 +48338,9 @@ <histogram name="Net.PreconnectSubresourceEval" enum="PreconnectSubresourceEval"> + <obsolete> + Deprecated May 2018 + </obsolete> <owner>csharrison@chromium.org</owner> <summary> What did we decide to do about a predicted resource, based on the historical @@ -48349,6 +48355,9 @@ </histogram> <histogram name="Net.PreconnectSubresourceExpectation"> + <obsolete> + Deprecated May 2018 + </obsolete> <owner>csharrison@chromium.org</owner> <summary> The expected number of connections, times 100, that we'll make to a given @@ -48416,6 +48425,9 @@ </histogram> <histogram name="Net.Predictor.Startup.DBSize" units="bytes"> + <obsolete> + Deprecated May 2018 + </obsolete> <owner>csharrison@chromium.org</owner> <summary> The approximate size in bytes of the predictor's database on startup. @@ -84199,6 +84211,15 @@ </summary> </histogram> +<histogram name="ServiceWorker.CookieChangeEvent.Time" units="ms"> + <owner>pwnall@chromium.org</owner> + <summary> + The time taken between dispatching a CookieChangeEvent to a Service Worker + and receiving a message that it finished handling the event. Includes the + time for the waitUntil() promise to settle. + </summary> +</histogram> + <histogram name="ServiceWorker.Database.DestroyDatabaseResult" enum="ServiceWorkerDatabaseStatus"> <owner>nhiroki@chromium.org</owner> @@ -118041,6 +118062,7 @@ <histogram_suffixes name="ServiceWorker.EventType" separator="_"> <suffix name="ACTIVATE" label="ACTIVATE"/> + <suffix name="COOKIE_CHANGE" label="COOKIE_CHANGE"/> <suffix name="FETCH_MAIN_FRAME" label="FETCH_MAIN_FRAME"/> <suffix name="FETCH_SHARED_WORKER" label="FETCH_SHARED_WORKER"/> <suffix name="FETCH_SUB_FRAME" label="FETCH_SUB_FRAME"/> @@ -118227,6 +118249,7 @@ <suffix name="ntp" label="Custom histogram for New Tab Page"/> <suffix name="plus" label="Custom histogram for Google+"/> <affected-histogram name="ServiceWorker.EventDispatchingDelay_ACTIVATE"/> + <affected-histogram name="ServiceWorker.EventDispatchingDelay_COOKIE_CHANGE"/> <affected-histogram name="ServiceWorker.EventDispatchingDelay_FETCH_MAIN_FRAME"/> <affected-histogram
diff --git a/ui/file_manager/file_manager/background/js/background.js b/ui/file_manager/file_manager/background/js/background.js index 6119aeb..c8febdb90 100644 --- a/ui/file_manager/file_manager/background/js/background.js +++ b/ui/file_manager/file_manager/background/js/background.js
@@ -491,21 +491,19 @@ FileBrowserBackgroundImpl.prototype.onMountCompletedInternal_ = function( event) { // If there is no focused window, then create a new one opened on the - // mounted FSP volume. + // mounted volume. this.findFocusedWindow_() .then(function(key) { let statusOK = event.status === 'success' || event.status === 'error_path_already_mounted'; let volumeTypeOK = - event.volumeMetadata.source === VolumeManagerCommon.Source.FILE || - VolumeManagerCommon.getProvidedFileSystemIdFromVolumeId( - event.volumeId) === - VolumeManagerCommon.ProvidedFileSystem.CROSTINI; - if (key === null && event.eventType === 'mount' && statusOK && - event.volumeMetadata.mountContext === 'user' && + (event.volumeMetadata.volumeType === + VolumeManagerCommon.VolumeType.PROVIDED && + event.volumeMetadata.source === VolumeManagerCommon.Source.FILE) || event.volumeMetadata.volumeType === - VolumeManagerCommon.VolumeType.PROVIDED && - volumeTypeOK) { + VolumeManagerCommon.VolumeType.CROSTINI; + if (key === null && event.eventType === 'mount' && statusOK && + event.volumeMetadata.mountContext === 'user' && volumeTypeOK) { this.navigateToVolumeWhenReady_(event.volumeMetadata.volumeId); } }.bind(this))
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_util.js b/ui/file_manager/file_manager/background/js/volume_manager_util.js index 372579b3..4a7393d 100644 --- a/ui/file_manager/file_manager/background/js/volume_manager_util.js +++ b/ui/file_manager/file_manager/background/js/volume_manager_util.js
@@ -77,6 +77,9 @@ break; } break; + case VolumeManagerCommon.VolumeType.CROSTINI: + localizedLabel = str('LINUX_FILES_ROOT_LABEL'); + break; default: // TODO(mtomasz): Calculate volumeLabel for all types of volumes in the // C++ layer.
diff --git a/ui/file_manager/file_manager/common/js/volume_manager_common.js b/ui/file_manager/file_manager/common/js/volume_manager_common.js index dca5b10b..f95b4a78 100644 --- a/ui/file_manager/file_manager/common/js/volume_manager_common.js +++ b/ui/file_manager/file_manager/common/js/volume_manager_common.js
@@ -328,26 +328,6 @@ volumeId.split(':', 2)[1]); }; - -/** - * List of known FSP-provided fileSystemId values. - * - * @enum {string} - * @const - */ -VolumeManagerCommon.ProvidedFileSystem = { - CROSTINI: 'crostini', -}; - -/** - * Obtains fileSystemId from volumeId of FSP-provided mount. - * @param {string} volumeId Volume ID. - * @return {string|undefined} - */ -VolumeManagerCommon.getProvidedFileSystemIdFromVolumeId = function(volumeId) { - return volumeId ? volumeId.split(':', 3)[2] : undefined; -}; - /** * Fake entries for virtual folders which hold Google Drive offline files, * Google Drive "Shared with me" files, and mixed Recent files.
diff --git a/ui/file_manager/file_manager/foreground/css/file_types.css b/ui/file_manager/file_manager/foreground/css/file_types.css index efddfa0..ef1680e 100644 --- a/ui/file_manager/file_manager/foreground/css/file_types.css +++ b/ui/file_manager/file_manager/foreground/css/file_types.css
@@ -431,16 +431,16 @@ url(../images/volumes/2x/recent_active.png) 2x); } -[sftp-mount-icon='linux-files'], -[volume-subtype='crostini'] { +[root-type-icon='crostini'], +[volume-type-icon='crostini'] { /* Need !important to override inline style applied to provided volumes. */ background-image: -webkit-image-set( url(../images/volumes/linux_files.png) 1x, url(../images/volumes/2x/linux_files.png) 2x) !important; } -.tree-row[selected] [sftp-mount-icon='linux-files'], -.tree-row[selected] [volume-subtype='crostini'] { +.tree-row[selected] [root-type-icon='crostini'], +.tree-row[selected] [volume-type-icon='crostini'] { /* Need !important to override inline style applied to provided volumes. */ background-image: -webkit-image-set( url(../images/volumes/linux_files_active.png) 1x,
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js index dccba56..04c98d2 100644 --- a/ui/file_manager/file_manager/foreground/js/directory_contents.js +++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -316,6 +316,47 @@ }; /** + * Shows an empty list and spinner whilst starting and mounting the + * crostini container. + * + * This function is only called once to start and mount the crostini + * container. When FilesApp starts, the related fake root entry for + * crostini is shown which uses this CrostiniMounter as its ContentScanner. + * + * When the sshfs mount completes, it will show up as a disk volume. + * NavigationListModel.reorderNavigationItems_ will detect that crostini + * is mounted as a disk volume and hide the fake root item while the + * disk volume exists. + * + * @constructor + * @extends {ContentScanner} + */ +function CrostiniMounter() { + ContentScanner.call(this); +} + +/** + * Extends ContentScanner. + */ +CrostiniMounter.prototype.__proto__ = ContentScanner.prototype; + +/** + * @override + */ +CrostiniMounter.prototype.scan = function( + entriesCallback, successCallback, errorCallback) { + chrome.fileManagerPrivate.mountCrostiniContainer(() => { + if (chrome.runtime.lastError) { + console.error( + 'mountCrostiniContainer error: ', chrome.runtime.lastError.message); + errorCallback(util.createDOMError(util.FileError.NOT_READABLE_ERR)); + return; + } + successCallback(); + }); +}; + +/** * This class manages filters and determines a file should be shown or not. * When filters are changed, a 'changed' event is fired. * @@ -941,3 +982,18 @@ return new RecentContentScanner(query, recentRootEntry.sourceRestriction); }); }; + +/** + * Creates a DirectoryContents instance to show the sshfs crostini files. + * + * @param {FileListContext} context File list context. + * @param {!FakeEntry} crostiniRootEntry Fake directory entry representing the + * root of recent files. + * @return {DirectoryContents} Created DirectoryContents instance. + */ +DirectoryContents.createForCrostiniMounter = function( + context, crostiniRootEntry) { + return new DirectoryContents(context, true, crostiniRootEntry, function() { + return new CrostiniMounter(); + }); +};
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js index 86629d0..87a007ac 100644 --- a/ui/file_manager/file_manager/foreground/js/directory_model.js +++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -1168,11 +1168,9 @@ // then redirect to it in the focused window. // Note, that this is a temporary solution for https://crbug.com/427776. if (window.isFocused() && event.added.length === 1 && - event.added[0].volumeType === VolumeManagerCommon.VolumeType.PROVIDED && - (event.added[0].source === VolumeManagerCommon.Source.FILE || - VolumeManagerCommon.getProvidedFileSystemIdFromVolumeId( - event.added[0].volumeId) === - VolumeManagerCommon.ProvidedFileSystem.CROSTINI)) { + ((event.added[0].volumeType === VolumeManagerCommon.VolumeType.PROVIDED && + event.added[0].source === VolumeManagerCommon.Source.FILE) || + event.added[0].volumeType === VolumeManagerCommon.VolumeType.CROSTINI)) { event.added[0].resolveDisplayRoot().then(function(displayRoot) { // Resolving a display root on FSP volumes is instant, despite the // asynchronous call. @@ -1202,6 +1200,10 @@ return DirectoryContents.createForRecent( context, /** @type {!FakeEntry} */ (entry), query); } + if (entry.rootType == VolumeManagerCommon.RootType.CROSTINI) { + return DirectoryContents.createForCrostiniMounter( + context, /** @type {!FakeEntry} */ (entry)); + } if (query && canUseDriveSearch) { // Drive search. return DirectoryContents.createForDriveSearch(
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js index 46ce88b..6c9be25 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -1168,20 +1168,35 @@ assert(this.volumeManager_), assert(this.folderShortcutsModel_), fakeEntriesVisible && !DialogType.isFolderDialog(this.launchParams_.type) ? - new NavigationModelRecentItem(str('RECENT_ROOT_LABEL'), { - isDirectory: true, - rootType: VolumeManagerCommon.RootType.RECENT, - toURL: function() { - return 'fake-entry://recent'; - }, - sourceRestriction: this.getSourceRestriction_() - }) : + new NavigationModelFakeItem( + str('RECENT_ROOT_LABEL'), NavigationModelItemType.RECENT, { + isDirectory: true, + rootType: VolumeManagerCommon.RootType.RECENT, + toURL: function() { + return 'fake-entry://recent'; + }, + sourceRestriction: this.getSourceRestriction_() + }) : null, addNewServicesVisible ? new NavigationModelMenuItem( str('ADD_NEW_SERVICES_BUTTON_LABEL'), '#add-new-services-menu', 'add-new-services') : null); + // Check if crostini is enabled to create linuxFilesItem. + chrome.fileManagerPrivate.isCrostiniEnabled((enabled) => { + if (!enabled) + return; + this.directoryTree.dataModel.linuxFilesItem = new NavigationModelFakeItem( + str('LINUX_FILES_ROOT_LABEL'), NavigationModelItemType.CROSTINI, { + isDirectory: true, + rootType: VolumeManagerCommon.RootType.CROSTINI, + toURL: function() { + return 'fake-entry://linux-files'; + }, + }); + this.directoryTree.redraw(false); + }); this.ui_.initDirectoryTree(directoryTree); };
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js index fc555c305..1530fdf 100644 --- a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js +++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
@@ -10,7 +10,7 @@ VOLUME: 'volume', MENU: 'menu', RECENT: 'recent', - SFTP_MOUNT: 'sftp_mount', + CROSTINI: 'crostini', }; /** @@ -111,20 +111,21 @@ }; /** - * Item of NavigationListModel for a Recent view. + * Item of NavigationListModel for a fake item such as Recent or Linux Files. * * @param {string} label Label on the menu button. - * @param {!FakeEntry} entry Fake entry for the Recent root folder. + * @param {NavigationModelItemType} type + * @param {!FakeEntry} entry Fake entry for the root folder. * @constructor * @extends {NavigationModelItem} * @struct */ -function NavigationModelRecentItem(label, entry) { - NavigationModelItem.call(this, label, NavigationModelItemType.RECENT); +function NavigationModelFakeItem(label, type, entry) { + NavigationModelItem.call(this, label, type); this.entry_ = entry; } -NavigationModelRecentItem.prototype = /** @struct */ { +NavigationModelFakeItem.prototype = /** @struct */ { __proto__: NavigationModelItem.prototype, get entry() { return this.entry_; @@ -132,49 +133,11 @@ }; /** - * Item of NavigationListModel for an SFTP Mount as used by Linux files. - * - * @param {string} label Label on the item. - * @param {!FakeEntry} entry Fake entry for the SFTP Mount root folder. - * @param {string} icon CSS icon. - * @constructor - * @extends {NavigationModelItem} - * @struct - */ -function NavigationModelSFTPMountItem(label, entry, icon) { - NavigationModelItem.call(this, label, NavigationModelItemType.SFTP_MOUNT); - this.entry_ = entry; - this.icon_ = icon; -} - -NavigationModelSFTPMountItem.prototype = /** @struct */ { - __proto__: NavigationModelItem.prototype, - get entry() { - return this.entry_; - }, - get icon() { - return this.icon_; - }, - /** - * Start crostini container and mount it. - */ - mount: function() { - chrome.fileManagerPrivate.mountCrostiniContainer(() => { - // TODO(crbug.com/834103): implement crostini error handling. - if (chrome.runtime.lastError) { - console.error( - 'mountCrostiniContainer error: ', chrome.runtime.lastError.message); - } - }); - }, -}; - -/** * A navigation list model. This model combines multiple models. * @param {!VolumeManagerWrapper} volumeManager VolumeManagerWrapper instance. * @param {(!cr.ui.ArrayDataModel|!FolderShortcutsDataModel)} shortcutListModel * The list of folder shortcut. - * @param {NavigationModelRecentItem} recentModelItem Recent folder. + * @param {NavigationModelFakeItem} recentModelItem Recent folder. * @param {NavigationModelMenuItem} addNewServicesItem Add new services item. * @constructor * @extends {cr.EventTarget} @@ -196,7 +159,7 @@ this.shortcutListModel_ = shortcutListModel; /** - * @private {NavigationModelRecentItem} + * @private {NavigationModelFakeItem} * @const */ this.recentModelItem_ = recentModelItem; @@ -205,7 +168,7 @@ * Root folder for crostini Linux Files. * This field will be set asynchronously after calling * chrome.fileManagerPrivate.isCrostiniEnabled. - * @private {NavigationModelSFTPMountItem} + * @private {NavigationModelFakeItem} */ this.linuxFilesItem_ = null; @@ -256,24 +219,6 @@ this.shortcutList_.push(entryToModelItem(shortcutEntry)); } - // Check if crostini is enabled to create linuxFilesItem_. - chrome.fileManagerPrivate.isCrostiniEnabled((enabled) => { - if (!enabled) - return; - - this.linuxFilesItem_ = new NavigationModelSFTPMountItem( - str('LINUX_FILES_ROOT_LABEL'), { - isDirectory: true, - rootType: VolumeManagerCommon.RootType.CROSTINI, - toURL: function() { - return 'fake-entry://linux-files'; - }, - }, - 'linux-files'); - // Reorder items to ensure Linux Files is shown. - this.reorderNavigationItems_(); - }); - // Reorder volumes, shortcuts, and optional items for initial display. this.reorderNavigationItems_(); @@ -388,8 +333,22 @@ */ NavigationListModel.prototype = { __proto__: cr.EventTarget.prototype, - get length() { return this.length_(); }, - get folderShortcutList() { return this.shortcutList_; } + get length() { + return this.length_(); + }, + get folderShortcutList() { + return this.shortcutList_; + }, + /** + * Set the crostini Linux Files root and reorder items. + * This setter is provided separate to the constructor since + * this field is set async after calling fileManagerPrivate.isCrostiniEnabled. + * @param {NavigationModelFakeItem} item Linux Files root. + */ + set linuxFilesItem(item) { + this.linuxFilesItem_ = item; + this.reorderNavigationItems_(); + }, }; /** @@ -407,9 +366,8 @@ // Check if Linux files already mounted. let linuxFilesMounted = false; for (let i = 0; i < this.volumeList_.length; i++) { - if (VolumeManagerCommon.getProvidedFileSystemIdFromVolumeId( - this.volumeList_[i].volumeInfo.volumeId) === - VolumeManagerCommon.ProvidedFileSystem.CROSTINI) { + if (this.volumeList_[i].volumeInfo.volumeType === + VolumeManagerCommon.VolumeType.CROSTINI) { linuxFilesMounted = true; break; }
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js index 9ec752ce..b570a2bf8 100644 --- a/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js
@@ -20,15 +20,7 @@ // Override VolumeInfo.prototype.resolveDisplayRoot. VolumeInfoImpl.prototype.resolveDisplayRoot = function() {}; - // Mock chrome.fileManagerPrivate.isCrostiniEnabled. // TODO(crbug.com/834103): Add integration test for Crostini. - chrome.fileManagerPrivate = { - crostiniEnabled: false, - isCrostiniEnabled: function(callback) { - callback(this.crostiniEnabled); - }, - }; - drive = new MockFileSystem('drive'); hoge = new MockFileSystem('removable:hoge'); } @@ -37,17 +29,16 @@ var volumeManager = new MockVolumeManagerWrapper(); var shortcutListModel = new MockFolderShortcutDataModel( [new MockFileEntry(drive, '/root/shortcut')]); - var fakeEntry = { - toURL: function() { - return 'fake-entry://recent'; - } - }; - var recentItem = new NavigationModelRecentItem('recent-label', fakeEntry); - chrome.fileManagerPrivate.crostiniEnabled = true; + var recentItem = new NavigationModelFakeItem( + 'recent-label', NavigationModelItemType.RECENT, + {toURL: () => 'fake-entry://recent'}); var addNewServicesItem = new NavigationModelMenuItem( 'menu-button-label', '#add-new-services', 'menu-button-icon'); var model = new NavigationListModel( volumeManager, shortcutListModel, recentItem, addNewServicesItem); + model.linuxFilesItem = new NavigationModelFakeItem( + 'linux-files-label', NavigationModelItemType.CROSTINI, + {toURL: () => 'fake-entry://linux-files'}); assertEquals(6, model.length); assertEquals('drive', model.item(0).volumeInfo.volumeId);
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js index d660c78..9031aec1a 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js +++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -700,13 +700,6 @@ 'volume-subtype', VolumeManagerCommon.getMediaViewRootTypeFromVolumeId( volumeInfo.volumeId)); - } else if ( - volumeInfo.volumeType === VolumeManagerCommon.VolumeType.PROVIDED) { - icon.setAttribute( - 'volume-subtype', - VolumeManagerCommon.getProvidedFileSystemIdFromVolumeId( - volumeInfo.volumeId) || - ''); } else { icon.setAttribute('volume-subtype', volumeInfo.deviceType || ''); } @@ -1116,21 +1109,24 @@ }; //////////////////////////////////////////////////////////////////////////////// -// RecentItem +// FakeItem /** - * @param {!NavigationModelRecentItem} modelItem + * FakeItem is used by Recent and Linux Files. + * @param {!VolumeManagerCommon.RootType} rootType root type. + * @param {!NavigationModelFakeItem} modelItem * @param {!DirectoryTree} tree Current tree, which contains this item. * @extends {cr.ui.TreeItem} * @constructor */ -function RecentItem(modelItem, tree) { +function FakeItem(rootType, modelItem, tree) { var item = new cr.ui.TreeItem(); // Get the original label id defined by TreeItem, before overwriting // prototype. var labelId = item.labelElement.id; - item.__proto__ = RecentItem.prototype; + item.__proto__ = FakeItem.prototype; + item.rootType_ = rootType; item.parentTree_ = tree; item.modelItem_ = modelItem; item.dirEntry_ = modelItem.entry; @@ -1140,12 +1136,12 @@ var icon = queryRequiredElement('.icon', item); icon.classList.add('item-icon'); - icon.setAttribute('root-type-icon', 'recent'); + icon.setAttribute('root-type-icon', rootType); return item; } -RecentItem.prototype = { +FakeItem.prototype = { __proto__: cr.ui.TreeItem.prototype, get entry() { return this.dirEntry_; @@ -1162,24 +1158,24 @@ * @param {!DirectoryEntry|!FakeEntry} entry * @return {boolean} True if the parent item is found. */ -RecentItem.prototype.searchAndSelectByEntry = function(entry) { +FakeItem.prototype.searchAndSelectByEntry = function(entry) { return false; }; /** * @override */ -RecentItem.prototype.handleClick = function(e) { +FakeItem.prototype.handleClick = function(e) { this.activate(); DirectoryItemTreeBaseMethods.recordUMASelectedEntry.call( - this, e, VolumeManagerCommon.RootType.RECENT, true); + this, e, this.rootType_, true); }; /** * @param {!DirectoryEntry} entry */ -RecentItem.prototype.selectByEntry = function(entry) { +FakeItem.prototype.selectByEntry = function(entry) { if (util.isSameEntry(entry, this.entry)) this.selected = true; }; @@ -1187,60 +1183,11 @@ /** * Executes the command. */ -RecentItem.prototype.activate = function() { +FakeItem.prototype.activate = function() { this.parentTree_.directoryModel.activateDirectoryEntry(this.entry); }; //////////////////////////////////////////////////////////////////////////////// -// SFTPMountItem - -/** - * A TreeItem which represents a directory to be mounted using SFTP. - * - * @param {!NavigationModelSFTPMountItem} modelItem - * @param {!DirectoryTree} tree Current tree, which contains this item. - * @extends {cr.ui.TreeItem} - * @constructor - */ -function SFTPMountItem(modelItem, tree) { - var item = new cr.ui.TreeItem(); - item.__proto__ = SFTPMountItem.prototype; - - item.parentTree_ = tree; - item.modelItem_ = modelItem; - item.innerHTML = TREE_ITEM_INNER_HTML; - item.label = modelItem.label; - - var icon = queryRequiredElement('.icon', item); - icon.classList.add('item-icon'); - icon.setAttribute('sftp-mount-icon', item.modelItem_.icon); - - return item; -} - -SFTPMountItem.prototype = { - __proto__: cr.ui.TreeItem.prototype, - get entry() { - return null; - }, - get modelItem() { - return this.modelItem_; - }, - get labelElement() { - return this.firstElementChild.querySelector('.label'); - } -}; - -/** - * @override - */ -SFTPMountItem.prototype.handleClick = function(e) { - this.selected = true; - this.modelItem_.mount(); -}; - - -//////////////////////////////////////////////////////////////////////////////// // DirectoryTree /** @@ -1426,10 +1373,16 @@ this.addAt(new MenuItem(modelItem, this), itemIndex); break; case NavigationModelItemType.RECENT: - this.addAt(new RecentItem(modelItem, this), itemIndex); + this.addAt( + new FakeItem( + VolumeManagerCommon.RootType.RECENT, modelItem, this), + itemIndex); break; - case NavigationModelItemType.SFTP_MOUNT: - this.addAt(new SFTPMountItem(modelItem, this), itemIndex); + case NavigationModelItemType.CROSTINI: + this.addAt( + new FakeItem( + VolumeManagerCommon.RootType.CROSTINI, modelItem, this), + itemIndex); break; } }
diff --git a/ui/file_manager/file_manager/test/js/chrome_file_manager.js b/ui/file_manager/file_manager/test/js/chrome_file_manager.js index d1511fc..50c053d 100644 --- a/ui/file_manager/file_manager/test/js/chrome_file_manager.js +++ b/ui/file_manager/file_manager/test/js/chrome_file_manager.js
@@ -118,9 +118,16 @@ grantAccess: (entryUrls, callback) => { setTimeout(callback, 0); }, + isCrostiniEnabled: (callback) => { + setTimeout(callback, 0, true); + }, isUMAEnabled: (callback) => { setTimeout(callback, 0, false); }, + mountCrostiniContainer: (callback) => { + // Simulate startup of vm and container by taking 3s. + setTimeout(callback, 3000); + }, onAppsUpdated: { addListener: () => {}, },
diff --git a/ui/file_manager/file_manager/test/scripts/create_test_main.py b/ui/file_manager/file_manager/test/scripts/create_test_main.py index 1b344d9..f2552ac8 100755 --- a/ui/file_manager/file_manager/test/scripts/create_test_main.py +++ b/ui/file_manager/file_manager/test/scripts/create_test_main.py
@@ -133,14 +133,17 @@ # * background/js/background_common_scripts.js # * background/js/background_scripts.js # into <script> tags in main.html. -# Add polymer lib at start. +# Add polymer libs at start. bg_scripts = read('background/js/background_scripts.js').split('\n') includes2scripts('foreground/js/main_scripts.js') includes2scripts('background/js/background_common_scripts.js') includes2scripts('background/js/background_scripts.js') main_html = replaceline(main_html, 'foreground/js/main_scripts.js', [ ('<link rel="import" href="../../../third_party/polymer/v1_0/' - 'components-chromium/polymer/polymer.html">')] + scripts) + 'components-chromium/polymer/polymer.html">'), + ('<link rel="import" href="../../../third_party/polymer/v1_0/' + 'components-chromium/paper-progress/paper-progress.html">'), + ] + scripts) # Load QuickView in iframe rather than webview. # Change references in files_quick_view.html to use updated