summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/common
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/common')
-rw-r--r--chromium/third_party/blink/common/BUILD.gn21
-rw-r--r--chromium/third_party/blink/common/DEPS2
-rw-r--r--chromium/third_party/blink/common/feature_policy/document_policy.cc13
-rw-r--r--chromium/third_party/blink/common/feature_policy/feature_policy.cc12
-rw-r--r--chromium/third_party/blink/common/features.cc134
-rw-r--r--chromium/third_party/blink/common/input/OWNERS2
-rw-r--r--chromium/third_party/blink/common/input/synthetic_web_input_event_builders.cc267
-rw-r--r--chromium/third_party/blink/common/input/synthetic_web_input_event_builders_unittest.cc56
-rw-r--r--chromium/third_party/blink/common/input/web_coalesced_input_event.cc2
-rw-r--r--chromium/third_party/blink/common/input/web_coalesced_input_event_mojom_traits.cc542
-rw-r--r--chromium/third_party/blink/common/input/web_mouse_wheel_event.cc28
-rw-r--r--chromium/third_party/blink/common/loader/throttling_url_loader.cc119
-rw-r--r--chromium/third_party/blink/common/loader/throttling_url_loader_unittest.cc238
-rw-r--r--chromium/third_party/blink/common/loader/url_loader_throttle.cc5
-rw-r--r--chromium/third_party/blink/common/manifest/manifest.cc3
-rw-r--r--chromium/third_party/blink/common/manifest/manifest_mojom_traits.cc16
-rw-r--r--chromium/third_party/blink/common/mediastream/media_devices.cc19
-rw-r--r--chromium/third_party/blink/common/mediastream/media_stream_request.cc25
-rw-r--r--chromium/third_party/blink/common/mime_util/mime_util.cc8
-rw-r--r--chromium/third_party/blink/common/mime_util/mime_util_unittest.cc3
-rw-r--r--chromium/third_party/blink/common/origin_trials/trial_token.cc28
-rw-r--r--chromium/third_party/blink/common/origin_trials/trial_token_unittest.cc113
-rw-r--r--chromium/third_party/blink/common/origin_trials/trial_token_validator.cc38
-rw-r--r--chromium/third_party/blink/common/origin_trials/trial_token_validator_unittest.cc83
-rw-r--r--chromium/third_party/blink/common/page/OWNERS2
-rw-r--r--chromium/third_party/blink/common/page/drag_mojom_traits.cc101
-rw-r--r--chromium/third_party/blink/common/peerconnection/OWNERS4
-rw-r--r--chromium/third_party/blink/common/peerconnection/peer_connection_tracker_mojom_traits.cc58
-rw-r--r--chromium/third_party/blink/common/privacy_budget/BUILD.gn65
-rw-r--r--chromium/third_party/blink/common/privacy_budget/README.md6
-rw-r--r--chromium/third_party/blink/common/privacy_budget/identifiability_internal_templates_unittest.cc107
-rw-r--r--chromium/third_party/blink/common/privacy_budget/identifiability_metric_builder.cc4
-rw-r--r--chromium/third_party/blink/common/privacy_budget/identifiability_metric_builder_unittest.cc140
-rw-r--r--chromium/third_party/blink/common/privacy_budget/identifiability_metrics.cc60
-rw-r--r--chromium/third_party/blink/common/privacy_budget/identifiability_metrics_unittest.cc42
-rw-r--r--chromium/third_party/blink/common/privacy_budget/identifiability_study_participation.cc5
-rw-r--r--chromium/third_party/blink/common/privacy_budget/identifiability_study_settings.cc139
-rw-r--r--chromium/third_party/blink/common/privacy_budget/identifiability_study_settings_unittest.cc144
-rw-r--r--chromium/third_party/blink/common/privacy_budget/identifiable_token_builder.cc139
-rw-r--r--chromium/third_party/blink/common/privacy_budget/identifiable_token_builder_atomic_fuzzer.cc27
-rw-r--r--chromium/third_party/blink/common/privacy_budget/identifiable_token_builder_fuzzer.cc25
-rw-r--r--chromium/third_party/blink/common/privacy_budget/identifiable_token_builder_unittest.cc193
-rw-r--r--chromium/third_party/blink/common/privacy_budget/identifiable_token_unittest.cc131
-rw-r--r--chromium/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc12
-rw-r--r--chromium/third_party/blink/common/switches.cc73
45 files changed, 3125 insertions, 129 deletions
diff --git a/chromium/third_party/blink/common/BUILD.gn b/chromium/third_party/blink/common/BUILD.gn
index b78a02d4d23..51d73075497 100644
--- a/chromium/third_party/blink/common/BUILD.gn
+++ b/chromium/third_party/blink/common/BUILD.gn
@@ -28,6 +28,10 @@ blink_python_runner("make_generated_document_policy_features") {
]
}
+config("blink_common_implementation") {
+ defines = [ "BLINK_COMMON_IMPLEMENTATION=1" ]
+}
+
jumbo_source_set("common") {
# No target should directly depend on this target since this is just the
# source set rather than the actual component that can be linked to.
@@ -38,7 +42,7 @@ jumbo_source_set("common") {
"//third_party/blink/public:all_blink",
]
- defines = [ "BLINK_COMMON_IMPLEMENTATION=1" ]
+ configs += [ ":blink_common_implementation" ]
sources = [
# NOTE: Please do not add public headers that need to be referenced from
@@ -70,7 +74,9 @@ jumbo_source_set("common") {
"indexeddb/indexeddb_key_path.cc",
"indexeddb/indexeddb_key_range.cc",
"indexeddb/indexeddb_metadata.cc",
+ "input/synthetic_web_input_event_builders.cc",
"input/web_coalesced_input_event.cc",
+ "input/web_coalesced_input_event_mojom_traits.cc",
"input/web_gesture_event.cc",
"input/web_input_event.cc",
"input/web_keyboard_event.cc",
@@ -109,12 +115,11 @@ jumbo_source_set("common") {
"notifications/platform_notification_data.cc",
"origin_trials/trial_token.cc",
"origin_trials/trial_token_validator.cc",
+ "page/drag_mojom_traits.cc",
"page/page_zoom.cc",
+ "peerconnection/peer_connection_tracker_mojom_traits.cc",
"peerconnection/webrtc_ip_handling_policy.cc",
"permissions/permission_utils.cc",
- "privacy_budget/identifiability_metric_builder.cc",
- "privacy_budget/identifiability_metrics.cc",
- "privacy_budget/identifiability_study_participation.cc",
"scheduler/web_scheduler_tracked_feature.cc",
"service_worker/service_worker_status_code.cc",
"service_worker/service_worker_type_converters.cc",
@@ -130,6 +135,7 @@ jumbo_source_set("common") {
public_deps = [
":make_generated_document_policy_features",
+ "//third_party/blink/common/privacy_budget:privacy_budget",
"//third_party/blink/public/common:headers",
]
@@ -143,6 +149,7 @@ jumbo_source_set("common") {
"//services/metrics/public/cpp:ukm_builders",
"//services/metrics/public/mojom:mojom",
"//services/network/public/cpp:cpp",
+ "//ui/events:events_base",
]
# iOS doesn't use and must not depend on //media
@@ -173,7 +180,9 @@ test("blink_common_unittests") {
"//services/metrics/public/cpp:metrics_cpp",
"//services/metrics/public/cpp:ukm_builders",
"//services/metrics/public/mojom:mojom",
+ "//third_party/blink/common/privacy_budget:unit_tests",
"//third_party/blink/public/common",
+ "//ui/gfx:test_support",
]
if (is_android) {
deps += [
@@ -195,6 +204,7 @@ jumbo_source_set("common_unittests_sources") {
"feature_policy/policy_value_unittest.cc",
"frame/user_activation_state_unittest.cc",
"indexeddb/indexeddb_key_unittest.cc",
+ "input/synthetic_web_input_event_builders_unittest.cc",
"input/web_input_event_unittest.cc",
"loader/mime_sniffing_throttle_unittest.cc",
"loader/throttling_url_loader_unittest.cc",
@@ -206,9 +216,6 @@ jumbo_source_set("common_unittests_sources") {
"notifications/notification_mojom_traits_unittest.cc",
"origin_trials/trial_token_unittest.cc",
"origin_trials/trial_token_validator_unittest.cc",
- "privacy_budget/identifiability_metric_builder_unittest.cc",
- "privacy_budget/identifiability_metrics_unittest.cc",
- "privacy_budget/identifiable_surface_unittest.cc",
"test/run_all_unittests.cc",
"user_agent/user_agent_metadata_unittest.cc",
"web_package/web_package_request_matcher_unittest.cc",
diff --git a/chromium/third_party/blink/common/DEPS b/chromium/third_party/blink/common/DEPS
index c8417f12416..ab1f1e98223 100644
--- a/chromium/third_party/blink/common/DEPS
+++ b/chromium/third_party/blink/common/DEPS
@@ -25,9 +25,11 @@ include_rules = [
"+third_party/blink/public/common",
"+third_party/blink/public/mojom",
"+third_party/icu/source/common/unicode/unistr.h",
+ "+ui/events/base_event_utils.h",
"+ui/gfx/transform.h",
"+ui/gfx/geometry",
"+ui/gfx/win/direct_write.h",
+ "+ui/latency/mojom/latency_info_mojom_traits.h",
"+url",
]
specific_include_rules = {
diff --git a/chromium/third_party/blink/common/feature_policy/document_policy.cc b/chromium/third_party/blink/common/feature_policy/document_policy.cc
index 400e3ba65c1..eae3df3e119 100644
--- a/chromium/third_party/blink/common/feature_policy/document_policy.cc
+++ b/chromium/third_party/blink/common/feature_policy/document_policy.cc
@@ -153,19 +153,6 @@ const base::Optional<std::string> DocumentPolicy::GetFeatureEndpoint(
}
}
-bool DocumentPolicy::IsFeatureSupported(
- mojom::DocumentPolicyFeature feature) const {
- // TODO(iclelland): Generate this switch block
- switch (feature) {
- case mojom::DocumentPolicyFeature::kFontDisplay:
- case mojom::DocumentPolicyFeature::kUnoptimizedLosslessImages:
- case mojom::DocumentPolicyFeature::kForceLoadAtTop:
- return true;
- default:
- return false;
- }
-}
-
void DocumentPolicy::UpdateFeatureState(const FeatureState& feature_state) {
for (const auto& feature_and_value : feature_state) {
internal_feature_state_[static_cast<size_t>(feature_and_value.first)] =
diff --git a/chromium/third_party/blink/common/feature_policy/feature_policy.cc b/chromium/third_party/blink/common/feature_policy/feature_policy.cc
index b34f95be071..f44c96edb2c 100644
--- a/chromium/third_party/blink/common/feature_policy/feature_policy.cc
+++ b/chromium/third_party/blink/common/feature_policy/feature_policy.cc
@@ -384,8 +384,6 @@ const FeaturePolicy::FeatureList& FeaturePolicy::GetDefaultFeatureList() {
static base::NoDestructor<FeatureList> default_feature_list(
{{mojom::FeaturePolicyFeature::kAccelerometer,
FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
- {mojom::FeaturePolicyFeature::kAccessibilityEvents,
- FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
{mojom::FeaturePolicyFeature::kAmbientLightSensor,
FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
{mojom::FeaturePolicyFeature::kAutoplay,
@@ -420,7 +418,9 @@ const FeaturePolicy::FeatureList& FeaturePolicy::GetDefaultFeatureList() {
FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
{mojom::FeaturePolicyFeature::kClientHintWidth,
FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
- {mojom::FeaturePolicyFeature::kClipboard,
+ {mojom::FeaturePolicyFeature::kClipboardRead,
+ FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
+ {mojom::FeaturePolicyFeature::kClipboardWrite,
FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
{mojom::FeaturePolicyFeature::kCamera,
FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
@@ -453,10 +453,6 @@ const FeaturePolicy::FeatureList& FeaturePolicy::GetDefaultFeatureList() {
FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
{mojom::FeaturePolicyFeature::kIdleDetection,
FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
- {mojom::FeaturePolicyFeature::kLazyLoad,
- FeatureDefault(FeaturePolicy::FeatureDefault::EnableForAll)},
- {mojom::FeaturePolicyFeature::kLoadingFrameDefaultEager,
- FeatureDefault(FeaturePolicy::FeatureDefault::EnableForAll)},
{mojom::FeaturePolicyFeature::kMagnetometer,
FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
{mojom::FeaturePolicyFeature::kMicrophone,
@@ -495,8 +491,6 @@ const FeaturePolicy::FeatureList& FeaturePolicy::GetDefaultFeatureList() {
FeatureDefault(FeaturePolicy::FeatureDefault::EnableForAll)},
{mojom::FeaturePolicyFeature::kScreenWakeLock,
FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
- {mojom::FeaturePolicyFeature::kWebVr,
- FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
{mojom::FeaturePolicyFeature::kWebXr,
FeatureDefault(FeaturePolicy::FeatureDefault::EnableForSelf)},
{mojom::FeaturePolicyFeature::kStorageAccessAPI,
diff --git a/chromium/third_party/blink/common/features.cc b/chromium/third_party/blink/common/features.cc
index 986267c41cb..322e4e42b1d 100644
--- a/chromium/third_party/blink/common/features.cc
+++ b/chromium/third_party/blink/common/features.cc
@@ -18,10 +18,15 @@ const base::Feature kBlockingDownloadsInAdFrameWithoutUserActivation{
"BlockingDownloadsInAdFrameWithoutUserActivation",
base::FEATURE_ENABLED_BY_DEFAULT};
-// Enable defer commits to avoid flash of unstyled content.
+// Enable defer commits to avoid flash of unstyled content, for same origin
+// navigation only.
const base::Feature kPaintHolding{"PaintHolding",
base::FEATURE_ENABLED_BY_DEFAULT};
+// Enable defer commits to avoid flash of unstyled content, for all navigation.
+const base::Feature kPaintHoldingCrossOrigin{"PaintHoldingCrossOrigin",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enable eagerly setting up a CacheStorage interface pointer and
// passing it to service workers on startup as an optimization.
// TODO(crbug/1077916): Re-enable once the issue with COOP/COEP is fixed.
@@ -51,8 +56,8 @@ const base::Feature kFreezeUserAgent{"FreezeUserAgent",
// When enabled, use the maximum possible bounds in compositing overlap testing
// for fixed position elements.
-const base::Feature kMaxOverlapBoundsForFixed{
- "MaxOverlapBoundsForFixed", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kMaxOverlapBoundsForFixed{"MaxOverlapBoundsForFixed",
+ base::FEATURE_ENABLED_BY_DEFAULT};
// Enable Display Locking JavaScript APIs.
const base::Feature kDisplayLocking{"DisplayLocking",
@@ -61,6 +66,9 @@ const base::Feature kDisplayLocking{"DisplayLocking",
const base::Feature kJSONModules{"JSONModules",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kForceSynchronousHTMLParsing{
+ "ForceSynchronousHTMLParsing", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enables top-level await in modules.
const base::Feature kTopLevelAwait{"TopLevelAwait",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -68,6 +76,13 @@ const base::Feature kTopLevelAwait{"TopLevelAwait",
// Enable LayoutNG.
const base::Feature kLayoutNG{"LayoutNG", base::FEATURE_ENABLED_BY_DEFAULT};
+// Enable LayoutNGRuby by default. This feature is for a kill switch.
+const base::Feature kLayoutNGRuby{"LayoutNGRuby",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kFragmentItem{"FragmentItem",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kMixedContentAutoupgrade{"AutoupgradeMixedContent",
base::FEATURE_ENABLED_BY_DEFAULT};
@@ -92,17 +107,23 @@ const base::Feature kPlzDedicatedWorker{"PlzDedicatedWorker",
base::FEATURE_DISABLED_BY_DEFAULT};
// Enable Portals. https://crbug.com/865123.
-const base::Feature kPortals{"Portals", base::FEATURE_DISABLED_BY_DEFAULT};
+// For the current origin trial (https://crbug.com/1040212), this is enabled on
+// Android only.
+const base::Feature kPortals {
+ "Portals",
+#if defined(OS_ANDROID)
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
// When kPortals is enabled, allow portals to load content that is third-party
// (cross-origin) to the hosting page. Otherwise has no effect.
//
-// This will be disabled by default by the time Portals is generally available,
-// either in origin trial or shipped.
-//
// https://crbug.com/1013389
const base::Feature kPortalsCrossOrigin{"PortalsCrossOrigin",
- base::FEATURE_ENABLED_BY_DEFAULT};
+ base::FEATURE_DISABLED_BY_DEFAULT};
// Enable limiting previews loading hints to specific resource types.
const base::Feature kPreviewsResourceLoadingHintsSpecificResourceTypes{
@@ -178,6 +199,30 @@ const base::Feature kWebRtcMultiplexCodec{"WebRTC-MultiplexCodec",
const base::Feature kWebRtcHideLocalIpsWithMdns{
"WebRtcHideLocalIpsWithMdns", base::FEATURE_ENABLED_BY_DEFAULT};
+// When enabled, wake ups from throttleable TaskQueues are limited to 1 per
+// minute in a page that has been backgrounded for 5 minutes.
+//
+// Intensive wake up throttling is enforced in addition to other throttling
+// mechanisms:
+// - 1 wake up per second in a background page or hidden cross-origin frame
+// - 1% CPU time in a page that has been backgrounded for 10 seconds
+//
+// Feature tracking bug: https://crbug.com/1075553
+//
+// Note that the base::Feature should not be read from;
+// rather the provided accessors should be used, which also take into account
+// the managed policy override of the feature.
+const base::Feature kIntensiveWakeUpThrottling{
+ "IntensiveWakeUpThrottling", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// When enabled, no throttling is applied to a page when it uses WebRTC.
+//
+// This allows a page to use a timer to do video processing on frames. An
+// event-driven mechanism should be provided to do video processing. When it is
+// available, this feature should be removed. https://crbug.com/1101806
+const base::Feature kOptOutWebRTCFromAllThrottling{
+ "OptOutWebRTCFromAllThrottling", base::FEATURE_DISABLED_BY_DEFAULT};
+
#if BUILDFLAG(RTC_USE_H264) && BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS)
// Run-time feature for the |rtc_use_h264| encoder/decoder.
const base::Feature kWebRtcH264WithOpenH264FFmpeg{
@@ -235,10 +280,6 @@ const base::Feature kAllowSyncXHRInPageDismissal{
const base::Feature kFontAccess{"FontAccess",
base::FEATURE_DISABLED_BY_DEFAULT};
-// Allows Web Components v0 to be re-enabled.
-const base::Feature kWebComponentsV0Enabled{"WebComponentsV0Enabled",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
// Prefetch request properties are updated to be privacy-preserving. See
// crbug.com/988956.
const base::Feature kPrefetchPrivacyChanges{"PrefetchPrivacyChanges",
@@ -256,7 +297,7 @@ const base::Feature kDecodeJpeg420ImagesToYUV{
// Decodes lossy WebP images to YUV instead of RGBX and stores in this format
// in the image decode cache. See crbug.com/900264 for details on the feature.
const base::Feature kDecodeLossyWebPImagesToYUV{
- "DecodeLossyWebPImagesToYUV", base::FEATURE_DISABLED_BY_DEFAULT};
+ "DecodeLossyWebPImagesToYUV", base::FEATURE_ENABLED_BY_DEFAULT};
// Enables cache-aware WebFonts loading. See https://crbug.com/570205.
// The feature is disabled on Android for WebView API issue discussed at
@@ -279,7 +320,7 @@ const base::Feature kAudioWorkletRealtimeThread{
"AudioWorkletRealtimeThread", base::FEATURE_DISABLED_BY_DEFAULT};
// A feature to reduce the set of resources fetched by No-State Prefetch.
-const base::Feature kLightweightNoStatePrefetch{
+const base::Feature kLightweightNoStatePrefetch {
"LightweightNoStatePrefetch",
#if defined(OS_ANDROID)
base::FEATURE_ENABLED_BY_DEFAULT
@@ -288,10 +329,6 @@ const base::Feature kLightweightNoStatePrefetch{
#endif
};
-// A feature to enable web fonts to be fetched by No-State Prefetch.
-const base::Feature kLightweightNoStatePrefetch_FetchFonts{
- "LightweightNoStatePrefetch_FetchFonts", base::FEATURE_DISABLED_BY_DEFAULT};
-
// Automatically convert light-themed pages to use a Blink-generated dark theme
const base::Feature kForceWebContentsDarkMode{
"WebContentsForceDark", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -413,6 +450,11 @@ const base::Feature kSubresourceRedirect{"SubresourceRedirect",
const base::Feature kCompositeCrossOriginIframes{
"CompositeCrossOriginIframes", base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, enforces new interoperable semantics for 3D transforms.
+// See crbug.com/1008483.
+const base::Feature kTransformInterop{"TransformInterop",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled, beacons (and friends) have ResourceLoadPriority::kLow,
// not ResourceLoadPriority::kVeryLow.
const base::Feature kSetLowPriorityForBeacon{"SetLowPriorityForBeacon",
@@ -459,13 +501,11 @@ const base::Feature kLowLatencyWebGLSwapChain{"LowLatencyWebGLSwapChain",
const base::Feature kDawn2dCanvas{"Dawn2dCanvas",
base::FEATURE_DISABLED_BY_DEFAULT};
-// Enables forcing additional rendering of subframes for the purpose of sticky
-// frame tracking.
-const base::Feature kForceExtraRenderingToTrackStickyFrame{
- "ForceExtraRenderingToTrackStickyFrame", base::FEATURE_DISABLED_BY_DEFAULT};
-
const base::Feature kCSSReducedFontLoadingInvalidations{
- "CSSReducedFontLoadingInvalidations", base::FEATURE_DISABLED_BY_DEFAULT};
+ "CSSReducedFontLoadingInvalidations", base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kCSSReducedFontLoadingLayoutInvalidations{
+ "CSSReducedFontLoadingLayoutInvalidations",
+ base::FEATURE_DISABLED_BY_DEFAULT};
// When enabled, frees up CachedMetadata after consumption by script resources
// and modules. Needed for the experiment in http://crbug.com/1045052.
@@ -478,9 +518,18 @@ const base::Feature kSuppressContentTypeForBeaconMadeWithArrayBufferView{
"SuppressContentTypeForBeaconMadeWithArrayBufferView",
base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kBlockFlowHandlesWebkitLineClamp{
+ "BlockFlowHandlesWebkitLineClamp", base::FEATURE_ENABLED_BY_DEFAULT};
+
const base::Feature kBlockHTMLParserOnStyleSheets{
"BlockHTMLParserOnStyleSheets", base::FEATURE_DISABLED_BY_DEFAULT};
+// Kill switch for the new <link disabled> behavior.
+// TODO(crbug.com/1087043): Remove this once the feature has
+// landed and no compat issues are reported.
+const base::Feature kLinkDisabledNewSpecBehavior{
+ "LinkDisabledNewSpecBehavior", base::FEATURE_ENABLED_BY_DEFAULT};
+
// Slightly delays rendering if there are fonts being preloaded, so that
// they don't miss the first paint if they can be loaded fast enough (e.g.,
// from the disk cache)
@@ -494,10 +543,22 @@ const base::FeatureParam<int> kFontPreloadingDelaysRenderingParam{
&kFontPreloadingDelaysRendering, "delay-in-ms", 100};
const base::Feature kFlexGaps{"FlexGaps", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kFlexNG{"FlexNG", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kFlexNG{"FlexNG", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kKeepScriptResourceAlive{"KeepScriptResourceAlive",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kDelayAsyncScriptExecution{
+ "DelayAsyncScriptExecution", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::FeatureParam<DelayAsyncScriptDelayType>::Option
+ delay_async_script_execution_delay_types[] = {
+ {DelayAsyncScriptDelayType::kFinishedParsing, "finished_parsing"},
+ {DelayAsyncScriptDelayType::kFirstPaintOrFinishedParsing,
+ "first_paint_or_finished_parsing"}};
+const base::FeatureParam<DelayAsyncScriptDelayType>
+ kDelayAsyncScriptExecutionDelayParam{
+ &kDelayAsyncScriptExecution, "delay_type",
+ DelayAsyncScriptDelayType::kFinishedParsing,
+ &delay_async_script_execution_delay_types};
// The AppCache feature is a kill-switch for the entire AppCache feature,
// both backend and API. If disabled, then it will turn off the backend and
@@ -507,10 +568,10 @@ const base::Feature kAppCache{"AppCache", base::FEATURE_ENABLED_BY_DEFAULT};
// browser will require origin trial tokens in order to load or store manifests
// and their contents.
const base::Feature kAppCacheRequireOriginTrial{
- "AppCacheRequireOriginTrial", base::FEATURE_DISABLED_BY_DEFAULT};
+ "AppCacheRequireOriginTrial", base::FEATURE_ENABLED_BY_DEFAULT};
// Enables the AV1 Image File Format (AVIF).
-const base::Feature kAVIF{"AVIF", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAVIF{"AVIF", base::FEATURE_ENABLED_BY_DEFAULT};
// Make all pending 'display: auto' web fonts enter the swap or failure period
// immediately before reaching the LCP time limit (~2500ms), so that web fonts
@@ -543,6 +604,12 @@ const base::Feature kThrottleInstallingServiceWorker{
const base::FeatureParam<int> kInstallingServiceWorkerOutstandingThrottledLimit{
&kThrottleInstallingServiceWorker, "limit", 5};
+const base::Feature kInputPredictorTypeChoice{
+ "InputPredictorTypeChoice", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kResamplingInputEvents{"ResamplingInputEvents",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kResamplingScrollEvents{"ResamplingScrollEvents",
base::FEATURE_ENABLED_BY_DEFAULT};
@@ -587,5 +654,18 @@ const char kSkipTouchEventFilterFilteringProcessParamValueBrowser[] = "browser";
const char kSkipTouchEventFilterFilteringProcessParamValueBrowserAndRenderer[] =
"browser_and_renderer";
+// Improves support for WebXR on computers with multiple GPUs.
+const base::Feature kWebXrMultiGpu{"WebXRMultiGpu",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables dependency support in blink::MatchedPropertiesCache, which allows
+// caching of previously uncachable objects.
+const base::Feature kCSSMatchedPropertiesCacheDependencies{
+ "CSSMatchedPropertiesCacheDependencies", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Whether ParkableStrings can be written out to disk.
+const base::Feature kParkableStringsToDisk{"ParkableStringsToDisk",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace features
} // namespace blink
diff --git a/chromium/third_party/blink/common/input/OWNERS b/chromium/third_party/blink/common/input/OWNERS
new file mode 100644
index 00000000000..d5fefd82012
--- /dev/null
+++ b/chromium/third_party/blink/common/input/OWNERS
@@ -0,0 +1,2 @@
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/third_party/blink/common/input/synthetic_web_input_event_builders.cc b/chromium/third_party/blink/common/input/synthetic_web_input_event_builders.cc
new file mode 100644
index 00000000000..d274fc5e485
--- /dev/null
+++ b/chromium/third_party/blink/common/input/synthetic_web_input_event_builders.cc
@@ -0,0 +1,267 @@
+// Copyright 2013 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/public/common/input/synthetic_web_input_event_builders.h"
+
+#include "base/check_op.h"
+#include "ui/events/base_event_utils.h"
+
+namespace blink {
+
+WebMouseEvent SyntheticWebMouseEventBuilder::Build(
+ blink::WebInputEvent::Type type) {
+ return WebMouseEvent(type, WebInputEvent::kNoModifiers,
+ WebInputEvent::GetStaticTimeStampForTests());
+}
+
+WebMouseEvent SyntheticWebMouseEventBuilder::Build(
+ blink::WebInputEvent::Type type,
+ float window_x,
+ float window_y,
+ int modifiers,
+ blink::WebPointerProperties::PointerType pointer_type) {
+ DCHECK(WebInputEvent::IsMouseEventType(type));
+ WebMouseEvent result(type, modifiers,
+ WebInputEvent::GetStaticTimeStampForTests());
+ result.SetPositionInWidget(window_x, window_y);
+ result.SetPositionInScreen(window_x, window_y);
+ result.SetModifiers(modifiers);
+ result.pointer_type = pointer_type;
+ result.id = WebMouseEvent::kMousePointerId;
+ return result;
+}
+
+WebMouseWheelEvent SyntheticWebMouseWheelEventBuilder::Build(
+ WebMouseWheelEvent::Phase phase) {
+ WebMouseWheelEvent result(WebInputEvent::Type::kMouseWheel,
+ WebInputEvent::kNoModifiers,
+ WebInputEvent::GetStaticTimeStampForTests());
+ result.phase = phase;
+ result.event_action =
+ WebMouseWheelEvent::GetPlatformSpecificDefaultEventAction(result);
+ return result;
+}
+
+WebMouseWheelEvent SyntheticWebMouseWheelEventBuilder::Build(
+ float x,
+ float y,
+ float dx,
+ float dy,
+ int modifiers,
+ ui::ScrollGranularity delta_units) {
+ return Build(x, y, 0, 0, dx, dy, modifiers, delta_units);
+}
+
+WebMouseWheelEvent SyntheticWebMouseWheelEventBuilder::Build(
+ float x,
+ float y,
+ float global_x,
+ float global_y,
+ float dx,
+ float dy,
+ int modifiers,
+ ui::ScrollGranularity delta_units) {
+ WebMouseWheelEvent result(WebInputEvent::Type::kMouseWheel, modifiers,
+ WebInputEvent::GetStaticTimeStampForTests());
+ result.SetPositionInScreen(global_x, global_y);
+ result.SetPositionInWidget(x, y);
+ result.delta_units = delta_units;
+ result.delta_x = dx;
+ result.delta_y = dy;
+ if (dx)
+ result.wheel_ticks_x = dx > 0.0f ? 1.0f : -1.0f;
+ if (dy)
+ result.wheel_ticks_y = dy > 0.0f ? 1.0f : -1.0f;
+
+ result.event_action =
+ WebMouseWheelEvent::GetPlatformSpecificDefaultEventAction(result);
+ return result;
+}
+
+WebGestureEvent SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::Type type,
+ blink::WebGestureDevice source_device,
+ int modifiers) {
+ DCHECK(WebInputEvent::IsGestureEventType(type));
+ WebGestureEvent result(type, modifiers,
+ WebInputEvent::GetStaticTimeStampForTests(),
+ source_device);
+ if (type == WebInputEvent::Type::kGestureTap ||
+ type == WebInputEvent::Type::kGestureTapUnconfirmed ||
+ type == WebInputEvent::Type::kGestureDoubleTap) {
+ result.data.tap.tap_count = 1;
+ result.data.tap.width = 10;
+ result.data.tap.height = 10;
+ }
+
+ result.SetNeedsWheelEvent(result.IsTouchpadZoomEvent());
+
+ return result;
+}
+
+WebGestureEvent SyntheticWebGestureEventBuilder::BuildScrollBegin(
+ float dx_hint,
+ float dy_hint,
+ blink::WebGestureDevice source_device,
+ int pointer_count) {
+ WebGestureEvent result =
+ Build(WebInputEvent::Type::kGestureScrollBegin, source_device);
+ result.data.scroll_begin.delta_x_hint = dx_hint;
+ result.data.scroll_begin.delta_y_hint = dy_hint;
+ result.data.scroll_begin.pointer_count = pointer_count;
+ return result;
+}
+
+WebGestureEvent SyntheticWebGestureEventBuilder::BuildScrollUpdate(
+ float dx,
+ float dy,
+ int modifiers,
+ blink::WebGestureDevice source_device) {
+ WebGestureEvent result = Build(WebInputEvent::Type::kGestureScrollUpdate,
+ source_device, modifiers);
+ result.data.scroll_update.delta_x = dx;
+ result.data.scroll_update.delta_y = dy;
+ return result;
+}
+
+WebGestureEvent SyntheticWebGestureEventBuilder::BuildPinchUpdate(
+ float scale,
+ float anchor_x,
+ float anchor_y,
+ int modifiers,
+ blink::WebGestureDevice source_device) {
+ WebGestureEvent result =
+ Build(WebInputEvent::Type::kGesturePinchUpdate, source_device, modifiers);
+ result.data.pinch_update.scale = scale;
+ result.SetPositionInWidget(gfx::PointF(anchor_x, anchor_y));
+ result.SetPositionInScreen(gfx::PointF(anchor_x, anchor_y));
+ return result;
+}
+
+WebGestureEvent SyntheticWebGestureEventBuilder::BuildFling(
+ float velocity_x,
+ float velocity_y,
+ blink::WebGestureDevice source_device) {
+ WebGestureEvent result =
+ Build(WebInputEvent::Type::kGestureFlingStart, source_device);
+ result.data.fling_start.velocity_x = velocity_x;
+ result.data.fling_start.velocity_y = velocity_y;
+ return result;
+}
+
+SyntheticWebTouchEvent::SyntheticWebTouchEvent() : WebTouchEvent() {
+ unique_touch_event_id = ui::GetNextTouchEventId();
+ SetTimestamp(WebInputEvent::GetStaticTimeStampForTests());
+ pointer_id_ = 0;
+}
+
+void SyntheticWebTouchEvent::ResetPoints() {
+ int activePointCount = 0;
+ unsigned count = 0;
+ for (unsigned int i = 0; i < kTouchesLengthCap; ++i) {
+ switch (touches[i].state) {
+ case WebTouchPoint::State::kStatePressed:
+ case WebTouchPoint::State::kStateMoved:
+ case WebTouchPoint::State::kStateStationary:
+ touches[i].state = WebTouchPoint::State::kStateStationary;
+ ++activePointCount;
+ ++count;
+ break;
+ case WebTouchPoint::State::kStateReleased:
+ case WebTouchPoint::State::kStateCancelled:
+ touches[i] = WebTouchPoint();
+ ++count;
+ break;
+ case WebTouchPoint::State::kStateUndefined:
+ break;
+ }
+ if (count >= touches_length)
+ break;
+ }
+ touches_length = activePointCount;
+ type_ = WebInputEvent::Type::kUndefined;
+ moved_beyond_slop_region = false;
+ unique_touch_event_id = ui::GetNextTouchEventId();
+}
+
+int SyntheticWebTouchEvent::PressPoint(float x,
+ float y,
+ float radius_x,
+ float radius_y,
+ float rotation_angle,
+ float force) {
+ int index = FirstFreeIndex();
+ if (index == -1)
+ return -1;
+ WebTouchPoint& point = touches[index];
+ point.id = pointer_id_++;
+ point.SetPositionInWidget(x, y);
+ point.SetPositionInScreen(x, y);
+ point.state = WebTouchPoint::State::kStatePressed;
+ point.radius_x = radius_x;
+ point.radius_y = radius_y;
+ point.rotation_angle = rotation_angle;
+ point.force = force;
+ point.tilt_x = point.tilt_y = 0;
+ point.pointer_type = blink::WebPointerProperties::PointerType::kTouch;
+ ++touches_length;
+ SetType(WebInputEvent::Type::kTouchStart);
+ dispatch_type = WebInputEvent::DispatchType::kBlocking;
+ return index;
+}
+
+void SyntheticWebTouchEvent::MovePoint(int index,
+ float x,
+ float y,
+ float radius_x,
+ float radius_y,
+ float rotation_angle,
+ float force) {
+ CHECK_GE(index, 0);
+ CHECK_LT(index, kTouchesLengthCap);
+ // Always set this bit to avoid otherwise unexpected touchmove suppression.
+ // The caller can opt-out explicitly, if necessary.
+ moved_beyond_slop_region = true;
+ WebTouchPoint& point = touches[index];
+ point.SetPositionInWidget(x, y);
+ point.SetPositionInScreen(x, y);
+ point.state = WebTouchPoint::State::kStateMoved;
+ point.radius_x = radius_x;
+ point.radius_y = radius_y;
+ point.rotation_angle = rotation_angle;
+ point.force = force;
+ SetType(WebInputEvent::Type::kTouchMove);
+ dispatch_type = WebInputEvent::DispatchType::kBlocking;
+}
+
+void SyntheticWebTouchEvent::ReleasePoint(int index) {
+ CHECK_GE(index, 0);
+ CHECK_LT(index, kTouchesLengthCap);
+ touches[index].state = WebTouchPoint::State::kStateReleased;
+ touches[index].force = 0.f;
+ SetType(WebInputEvent::Type::kTouchEnd);
+ dispatch_type = WebInputEvent::DispatchType::kBlocking;
+}
+
+void SyntheticWebTouchEvent::CancelPoint(int index) {
+ CHECK_GE(index, 0);
+ CHECK_LT(index, kTouchesLengthCap);
+ touches[index].state = WebTouchPoint::State::kStateCancelled;
+ SetType(WebInputEvent::Type::kTouchCancel);
+ dispatch_type = WebInputEvent::DispatchType::kEventNonBlocking;
+}
+
+void SyntheticWebTouchEvent::SetTimestamp(base::TimeTicks timestamp) {
+ SetTimeStamp(timestamp);
+}
+
+int SyntheticWebTouchEvent::FirstFreeIndex() {
+ for (size_t i = 0; i < kTouchesLengthCap; ++i) {
+ if (touches[i].state == WebTouchPoint::State::kStateUndefined)
+ return i;
+ }
+ return -1;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/common/input/synthetic_web_input_event_builders_unittest.cc b/chromium/third_party/blink/common/input/synthetic_web_input_event_builders_unittest.cc
new file mode 100644
index 00000000000..87e5dd776d3
--- /dev/null
+++ b/chromium/third_party/blink/common/input/synthetic_web_input_event_builders_unittest.cc
@@ -0,0 +1,56 @@
+// 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/public/common/input/synthetic_web_input_event_builders.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TEST(SyntheticWebInputEventBuilders, BuildWebTouchEvent) {
+ SyntheticWebTouchEvent event;
+
+ event.PressPoint(1, 2);
+ EXPECT_EQ(1U, event.touches_length);
+ EXPECT_EQ(0, event.touches[0].id);
+ EXPECT_EQ(WebTouchPoint::State::kStatePressed, event.touches[0].state);
+ EXPECT_EQ(gfx::PointF(1, 2), event.touches[0].PositionInWidget());
+ event.ResetPoints();
+
+ event.PressPoint(3, 4);
+ EXPECT_EQ(2U, event.touches_length);
+ EXPECT_EQ(1, event.touches[1].id);
+ EXPECT_EQ(WebTouchPoint::State::kStatePressed, event.touches[1].state);
+ EXPECT_EQ(gfx::PointF(3, 4), event.touches[1].PositionInWidget());
+ event.ResetPoints();
+
+ event.MovePoint(1, 5, 6);
+ EXPECT_EQ(2U, event.touches_length);
+ EXPECT_EQ(1, event.touches[1].id);
+ EXPECT_EQ(WebTouchPoint::State::kStateMoved, event.touches[1].state);
+ EXPECT_EQ(gfx::PointF(5, 6), event.touches[1].PositionInWidget());
+ event.ResetPoints();
+
+ event.ReleasePoint(0);
+ EXPECT_EQ(2U, event.touches_length);
+ EXPECT_EQ(0, event.touches[0].id);
+ EXPECT_EQ(WebTouchPoint::State::kStateReleased, event.touches[0].state);
+ event.ResetPoints();
+
+ event.MovePoint(1, 7, 8);
+ EXPECT_EQ(1U, event.touches_length);
+ EXPECT_EQ(1, event.touches[1].id);
+ EXPECT_EQ(WebTouchPoint::State::kStateMoved, event.touches[1].state);
+ EXPECT_EQ(gfx::PointF(7, 8), event.touches[1].PositionInWidget());
+ EXPECT_EQ(WebTouchPoint::State::kStateUndefined, event.touches[0].state);
+ event.ResetPoints();
+
+ event.PressPoint(9, 10);
+ EXPECT_EQ(2U, event.touches_length);
+ EXPECT_EQ(2, event.touches[0].id);
+ EXPECT_EQ(WebTouchPoint::State::kStatePressed, event.touches[0].state);
+ EXPECT_EQ(gfx::PointF(9, 10), event.touches[0].PositionInWidget());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/common/input/web_coalesced_input_event.cc b/chromium/third_party/blink/common/input/web_coalesced_input_event.cc
index ac9c083c1bc..05682411d0a 100644
--- a/chromium/third_party/blink/common/input/web_coalesced_input_event.cc
+++ b/chromium/third_party/blink/common/input/web_coalesced_input_event.cc
@@ -90,6 +90,8 @@ WebCoalescedInputEvent::WebCoalescedInputEvent(
predicted_events_.emplace_back(predicted_event->Clone());
}
+WebCoalescedInputEvent::~WebCoalescedInputEvent() = default;
+
bool WebCoalescedInputEvent::CanCoalesceWith(
const WebCoalescedInputEvent& other) const {
return event_->CanCoalesce(*other.event_);
diff --git a/chromium/third_party/blink/common/input/web_coalesced_input_event_mojom_traits.cc b/chromium/third_party/blink/common/input/web_coalesced_input_event_mojom_traits.cc
new file mode 100644
index 00000000000..5fa31403c3a
--- /dev/null
+++ b/chromium/third_party/blink/common/input/web_coalesced_input_event_mojom_traits.cc
@@ -0,0 +1,542 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/public/common/input/web_coalesced_input_event_mojom_traits.h"
+
+#include "base/i18n/char_iterator.h"
+#include "mojo/public/cpp/base/time_mojom_traits.h"
+#include "third_party/blink/public/common/input/web_gesture_event.h"
+#include "third_party/blink/public/common/input/web_keyboard_event.h"
+#include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
+#include "ui/latency/mojom/latency_info_mojom_traits.h"
+
+namespace mojo {
+namespace {
+
+void CopyString(base::char16* dst, const base::string16& text) {
+ base::i18n::UTF16CharIterator iter(&text);
+ size_t pos = 0;
+ while (!iter.end() && pos < blink::WebKeyboardEvent::kTextLengthCap - 1) {
+ dst[pos++] = iter.get();
+ iter.Advance();
+ }
+ dst[pos] = '\0';
+}
+
+blink::mojom::PointerDataPtr PointerDataFromPointerProperties(
+ const blink::WebPointerProperties& pointer,
+ blink::mojom::MouseDataPtr mouse_data) {
+ return blink::mojom::PointerData::New(
+ pointer.id, pointer.force, pointer.tilt_x, pointer.tilt_y,
+ pointer.tangential_pressure, pointer.twist, pointer.button,
+ pointer.pointer_type, pointer.movement_x, pointer.movement_y,
+ pointer.is_raw_movement_event, pointer.PositionInWidget(),
+ pointer.PositionInScreen(), std::move(mouse_data));
+}
+
+void PointerPropertiesFromPointerData(
+ const blink::mojom::PointerDataPtr& pointer_data,
+ blink::WebPointerProperties* pointer_properties) {
+ pointer_properties->id = pointer_data->pointer_id;
+ pointer_properties->force = pointer_data->force;
+ pointer_properties->tilt_x = pointer_data->tilt_x;
+ pointer_properties->tilt_y = pointer_data->tilt_y;
+ pointer_properties->tangential_pressure = pointer_data->tangential_pressure;
+ pointer_properties->twist = pointer_data->twist;
+ pointer_properties->button = pointer_data->button;
+ pointer_properties->pointer_type = pointer_data->pointer_type;
+ pointer_properties->movement_x = pointer_data->movement_x;
+ pointer_properties->movement_y = pointer_data->movement_y;
+ pointer_properties->is_raw_movement_event =
+ pointer_data->is_raw_movement_event;
+}
+
+void TouchPointPropertiesFromPointerData(
+ const blink::mojom::TouchPointPtr& mojo_touch_point,
+ blink::WebTouchPoint* touch_point) {
+ PointerPropertiesFromPointerData(mojo_touch_point->pointer_data, touch_point);
+ touch_point->state = mojo_touch_point->state;
+ touch_point->radius_x = mojo_touch_point->radius_x;
+ touch_point->radius_y = mojo_touch_point->radius_y;
+ touch_point->rotation_angle = mojo_touch_point->rotation_angle;
+ touch_point->SetPositionInWidget(
+ mojo_touch_point->pointer_data->widget_position.x(),
+ mojo_touch_point->pointer_data->widget_position.y());
+ touch_point->SetPositionInScreen(
+ mojo_touch_point->pointer_data->screen_position.x(),
+ mojo_touch_point->pointer_data->screen_position.y());
+}
+
+// TODO(dtapuska): Remove once SetPositionInXXX moves to WebPointerProperties.
+void MouseEventPropertiesFromPointerData(
+ const blink::mojom::PointerDataPtr& pointer_data,
+ blink::WebMouseEvent* mouse_event) {
+ PointerPropertiesFromPointerData(pointer_data, mouse_event);
+ mouse_event->SetPositionInWidget(pointer_data->widget_position.x(),
+ pointer_data->widget_position.y());
+ mouse_event->SetPositionInScreen(pointer_data->screen_position.x(),
+ pointer_data->screen_position.y());
+}
+
+} // namespace
+
+bool StructTraits<blink::mojom::EventDataView,
+ std::unique_ptr<blink::WebCoalescedInputEvent>>::
+ Read(blink::mojom::EventDataView event,
+ std::unique_ptr<blink::WebCoalescedInputEvent>* out) {
+ DCHECK(!out->get());
+
+ blink::WebInputEvent::Type type;
+ if (!event.ReadType(&type))
+ return false;
+
+ base::TimeTicks timestamp;
+ if (!event.ReadTimestamp(&timestamp))
+ return false;
+
+ std::unique_ptr<blink::WebInputEvent> input_event;
+ if (blink::WebInputEvent::IsKeyboardEventType(type)) {
+ blink::mojom::KeyDataPtr key_data;
+ if (!event.ReadKeyData<blink::mojom::KeyDataPtr>(&key_data))
+ return false;
+
+ input_event.reset(
+ new blink::WebKeyboardEvent(type, event.modifiers(), timestamp));
+
+ blink::WebKeyboardEvent* key_event =
+ static_cast<blink::WebKeyboardEvent*>(input_event.get());
+ key_event->windows_key_code = key_data->windows_key_code;
+ key_event->native_key_code = key_data->native_key_code;
+ key_event->dom_code = key_data->dom_code;
+ key_event->dom_key = key_data->dom_key;
+ key_event->is_system_key = key_data->is_system_key;
+ key_event->is_browser_shortcut = key_data->is_browser_shortcut;
+ CopyString(key_event->text, key_data->text);
+ CopyString(key_event->unmodified_text, key_data->unmodified_text);
+ } else if (blink::WebInputEvent::IsGestureEventType(type)) {
+ blink::mojom::GestureDataPtr gesture_data;
+ if (!event.ReadGestureData<blink::mojom::GestureDataPtr>(&gesture_data))
+ return false;
+ input_event.reset(new blink::WebGestureEvent(
+ type, event.modifiers(), timestamp, gesture_data->source_device));
+
+ blink::WebGestureEvent* gesture_event =
+ static_cast<blink::WebGestureEvent*>(input_event.get());
+ gesture_event->SetPositionInWidget(gesture_data->widget_position);
+ gesture_event->SetPositionInScreen(gesture_data->screen_position);
+ gesture_event->is_source_touch_event_set_non_blocking =
+ gesture_data->is_source_touch_event_set_non_blocking;
+ gesture_event->primary_pointer_type = gesture_data->primary_pointer_type;
+ gesture_event->SetSourceDevice(gesture_data->source_device);
+ gesture_event->unique_touch_event_id = gesture_data->unique_touch_event_id;
+
+ if (gesture_data->contact_size) {
+ switch (type) {
+ default:
+ break;
+ case blink::WebInputEvent::Type::kGestureTapDown:
+ gesture_event->data.tap_down.width =
+ gesture_data->contact_size->width();
+ gesture_event->data.tap_down.height =
+ gesture_data->contact_size->height();
+ break;
+ case blink::WebInputEvent::Type::kGestureShowPress:
+ gesture_event->data.show_press.width =
+ gesture_data->contact_size->width();
+ gesture_event->data.show_press.height =
+ gesture_data->contact_size->height();
+ break;
+ case blink::WebInputEvent::Type::kGestureTap:
+ case blink::WebInputEvent::Type::kGestureTapUnconfirmed:
+ case blink::WebInputEvent::Type::kGestureDoubleTap:
+ gesture_event->data.tap.width = gesture_data->contact_size->width();
+ gesture_event->data.tap.height = gesture_data->contact_size->height();
+ break;
+ case blink::WebInputEvent::Type::kGestureLongPress:
+ case blink::WebInputEvent::Type::kGestureLongTap:
+ gesture_event->data.long_press.width =
+ gesture_data->contact_size->width();
+ gesture_event->data.long_press.height =
+ gesture_data->contact_size->height();
+ break;
+ case blink::WebInputEvent::Type::kGestureTwoFingerTap:
+ gesture_event->data.two_finger_tap.first_finger_width =
+ gesture_data->contact_size->width();
+ gesture_event->data.two_finger_tap.first_finger_height =
+ gesture_data->contact_size->height();
+ break;
+ }
+ }
+
+ if (gesture_data->scroll_data) {
+ switch (type) {
+ default:
+ break;
+ case blink::WebInputEvent::Type::kGestureScrollBegin:
+ gesture_event->data.scroll_begin.delta_x_hint =
+ gesture_data->scroll_data->delta_x;
+ gesture_event->data.scroll_begin.delta_y_hint =
+ gesture_data->scroll_data->delta_y;
+ gesture_event->data.scroll_begin.delta_hint_units =
+ gesture_data->scroll_data->delta_units;
+ gesture_event->data.scroll_begin.target_viewport =
+ gesture_data->scroll_data->target_viewport;
+ gesture_event->data.scroll_begin.inertial_phase =
+ gesture_data->scroll_data->inertial_phase;
+ gesture_event->data.scroll_begin.synthetic =
+ gesture_data->scroll_data->synthetic;
+ gesture_event->data.scroll_begin.pointer_count =
+ gesture_data->scroll_data->pointer_count;
+ break;
+ case blink::WebInputEvent::Type::kGestureScrollEnd:
+ gesture_event->data.scroll_end.delta_units =
+ gesture_data->scroll_data->delta_units;
+ gesture_event->data.scroll_end.inertial_phase =
+ gesture_data->scroll_data->inertial_phase;
+ gesture_event->data.scroll_end.synthetic =
+ gesture_data->scroll_data->synthetic;
+ break;
+ case blink::WebInputEvent::Type::kGestureScrollUpdate:
+ gesture_event->data.scroll_update.delta_x =
+ gesture_data->scroll_data->delta_x;
+ gesture_event->data.scroll_update.delta_y =
+ gesture_data->scroll_data->delta_y;
+ gesture_event->data.scroll_update.delta_units =
+ gesture_data->scroll_data->delta_units;
+ gesture_event->data.scroll_update.inertial_phase =
+ gesture_data->scroll_data->inertial_phase;
+ if (gesture_data->scroll_data->update_details) {
+ gesture_event->data.scroll_update.velocity_x =
+ gesture_data->scroll_data->update_details->velocity_x;
+ gesture_event->data.scroll_update.velocity_y =
+ gesture_data->scroll_data->update_details->velocity_y;
+ }
+ break;
+ }
+ }
+
+ if (gesture_data->pinch_begin_data &&
+ type == blink::WebInputEvent::Type::kGesturePinchBegin) {
+ gesture_event->data.pinch_begin.needs_wheel_event =
+ gesture_data->pinch_begin_data->needs_wheel_event;
+ }
+
+ if (gesture_data->pinch_update_data &&
+ type == blink::WebInputEvent::Type::kGesturePinchUpdate) {
+ gesture_event->data.pinch_update.zoom_disabled =
+ gesture_data->pinch_update_data->zoom_disabled;
+ gesture_event->data.pinch_update.scale =
+ gesture_data->pinch_update_data->scale;
+ gesture_event->data.pinch_update.needs_wheel_event =
+ gesture_data->pinch_update_data->needs_wheel_event;
+ }
+
+ if (gesture_data->pinch_end_data &&
+ type == blink::WebInputEvent::Type::kGesturePinchEnd) {
+ gesture_event->data.pinch_end.needs_wheel_event =
+ gesture_data->pinch_end_data->needs_wheel_event;
+ }
+
+ if (gesture_data->tap_data) {
+ switch (type) {
+ default:
+ break;
+ case blink::WebInputEvent::Type::kGestureTap:
+ case blink::WebInputEvent::Type::kGestureTapUnconfirmed:
+ case blink::WebInputEvent::Type::kGestureDoubleTap:
+ gesture_event->data.tap.tap_count = gesture_data->tap_data->tap_count;
+ gesture_event->data.tap.needs_wheel_event =
+ gesture_data->tap_data->needs_wheel_event;
+ break;
+ }
+ }
+
+ if (gesture_data->fling_data) {
+ switch (type) {
+ default:
+ break;
+ case blink::WebInputEvent::Type::kGestureFlingStart:
+ gesture_event->data.fling_start.velocity_x =
+ gesture_data->fling_data->velocity_x;
+ gesture_event->data.fling_start.velocity_y =
+ gesture_data->fling_data->velocity_y;
+ gesture_event->data.fling_start.target_viewport =
+ gesture_data->fling_data->target_viewport;
+ break;
+ case blink::WebInputEvent::Type::kGestureFlingCancel:
+ gesture_event->data.fling_cancel.target_viewport =
+ gesture_data->fling_data->target_viewport;
+ gesture_event->data.fling_cancel.prevent_boosting =
+ gesture_data->fling_data->prevent_boosting;
+ break;
+ }
+ }
+
+ } else if (blink::WebInputEvent::IsTouchEventType(type)) {
+ blink::mojom::TouchDataPtr touch_data;
+ if (!event.ReadTouchData<blink::mojom::TouchDataPtr>(&touch_data))
+ return false;
+
+ input_event.reset(
+ new blink::WebTouchEvent(type, event.modifiers(), timestamp));
+
+ blink::WebTouchEvent* touch_event =
+ static_cast<blink::WebTouchEvent*>(input_event.get());
+ std::vector<blink::mojom::TouchPointPtr> touches;
+ unsigned i;
+ for (i = 0; i < touch_data->touches.size() &&
+ i < blink::WebTouchEvent::kTouchesLengthCap;
+ ++i) {
+ blink::WebTouchPoint& touch_point = touch_event->touches[i];
+ TouchPointPropertiesFromPointerData(touch_data->touches[i], &touch_point);
+ }
+
+ touch_event->touches_length = i;
+ touch_event->dispatch_type = touch_data->cancelable;
+ touch_event->moved_beyond_slop_region =
+ touch_data->moved_beyond_slop_region;
+ touch_event->hovering = touch_data->hovering;
+ touch_event->touch_start_or_first_touch_move =
+ touch_data->touch_start_or_first_move;
+ touch_event->unique_touch_event_id = touch_data->unique_touch_event_id;
+ } else if (blink::WebInputEvent::IsMouseEventType(type) ||
+ type == blink::WebInputEvent::Type::kMouseWheel) {
+ blink::mojom::PointerDataPtr pointer_data;
+ if (!event.ReadPointerData<blink::mojom::PointerDataPtr>(&pointer_data))
+ return false;
+
+ if (blink::WebInputEvent::IsMouseEventType(type)) {
+ input_event.reset(
+ new blink::WebMouseEvent(type, event.modifiers(), timestamp));
+ } else {
+ input_event.reset(
+ new blink::WebMouseWheelEvent(type, event.modifiers(), timestamp));
+ }
+
+ blink::WebMouseEvent* mouse_event =
+ static_cast<blink::WebMouseEvent*>(input_event.get());
+
+ MouseEventPropertiesFromPointerData(pointer_data, mouse_event);
+ if (pointer_data->mouse_data) {
+ mouse_event->click_count = pointer_data->mouse_data->click_count;
+
+ if (type == blink::WebInputEvent::Type::kMouseWheel &&
+ pointer_data->mouse_data->wheel_data) {
+ blink::WebMouseWheelEvent* wheel_event =
+ static_cast<blink::WebMouseWheelEvent*>(mouse_event);
+ blink::mojom::WheelDataPtr& wheel_data =
+ pointer_data->mouse_data->wheel_data;
+ wheel_event->delta_x = wheel_data->delta_x;
+ wheel_event->delta_y = wheel_data->delta_y;
+ wheel_event->wheel_ticks_x = wheel_data->wheel_ticks_x;
+ wheel_event->wheel_ticks_y = wheel_data->wheel_ticks_y;
+ wheel_event->acceleration_ratio_x = wheel_data->acceleration_ratio_x;
+ wheel_event->acceleration_ratio_y = wheel_data->acceleration_ratio_y;
+ wheel_event->phase =
+ static_cast<blink::WebMouseWheelEvent::Phase>(wheel_data->phase);
+ wheel_event->momentum_phase =
+ static_cast<blink::WebMouseWheelEvent::Phase>(
+ wheel_data->momentum_phase);
+ wheel_event->dispatch_type = wheel_data->cancelable;
+ wheel_event->event_action =
+ static_cast<blink::WebMouseWheelEvent::EventAction>(
+ wheel_data->event_action);
+ wheel_event->delta_units =
+ static_cast<ui::ScrollGranularity>(wheel_data->delta_units);
+ }
+ }
+
+ } else {
+ return false;
+ }
+
+ ui::LatencyInfo latency_info;
+ if (!event.ReadLatency(&latency_info))
+ return false;
+ out->reset(
+ new blink::WebCoalescedInputEvent(std::move(input_event), latency_info));
+ return true;
+}
+
+// static
+blink::mojom::KeyDataPtr
+StructTraits<blink::mojom::EventDataView,
+ std::unique_ptr<blink::WebCoalescedInputEvent>>::
+ key_data(const std::unique_ptr<blink::WebCoalescedInputEvent>& event) {
+ if (!blink::WebInputEvent::IsKeyboardEventType(event->Event().GetType()))
+ return nullptr;
+ const blink::WebKeyboardEvent* key_event =
+ static_cast<const blink::WebKeyboardEvent*>(event->EventPointer());
+ return blink::mojom::KeyData::New(
+ key_event->dom_key, key_event->dom_code, key_event->windows_key_code,
+ key_event->native_key_code, key_event->is_system_key,
+ key_event->is_browser_shortcut, key_event->text,
+ key_event->unmodified_text);
+}
+
+// static
+blink::mojom::PointerDataPtr
+StructTraits<blink::mojom::EventDataView,
+ std::unique_ptr<blink::WebCoalescedInputEvent>>::
+ pointer_data(const std::unique_ptr<blink::WebCoalescedInputEvent>& event) {
+ bool is_wheel_event =
+ event->Event().GetType() == blink::WebInputEvent::Type::kMouseWheel;
+ if (!blink::WebInputEvent::IsMouseEventType(event->Event().GetType()) &&
+ !is_wheel_event) {
+ return nullptr;
+ }
+ const blink::WebMouseEvent* mouse_event =
+ static_cast<const blink::WebMouseEvent*>(event->EventPointer());
+
+ blink::mojom::WheelDataPtr wheel_data;
+ if (is_wheel_event) {
+ const blink::WebMouseWheelEvent* wheel_event =
+ static_cast<const blink::WebMouseWheelEvent*>(mouse_event);
+ wheel_data = blink::mojom::WheelData::New(
+ wheel_event->delta_x, wheel_event->delta_y, wheel_event->wheel_ticks_x,
+ wheel_event->wheel_ticks_y, wheel_event->acceleration_ratio_x,
+ wheel_event->acceleration_ratio_y, wheel_event->phase,
+ wheel_event->momentum_phase, wheel_event->dispatch_type,
+ static_cast<uint8_t>(wheel_event->event_action),
+ static_cast<uint8_t>(wheel_event->delta_units));
+ }
+
+ return PointerDataFromPointerProperties(
+ *mouse_event, blink::mojom::MouseData::New(mouse_event->click_count,
+ std::move(wheel_data)));
+}
+
+// static
+blink::mojom::GestureDataPtr
+StructTraits<blink::mojom::EventDataView,
+ std::unique_ptr<blink::WebCoalescedInputEvent>>::
+ gesture_data(const std::unique_ptr<blink::WebCoalescedInputEvent>& event) {
+ if (!blink::WebInputEvent::IsGestureEventType(event->Event().GetType()))
+ return nullptr;
+ const blink::WebGestureEvent* gesture_event =
+ static_cast<const blink::WebGestureEvent*>(event->EventPointer());
+ auto gesture_data = blink::mojom::GestureData::New();
+ gesture_data->screen_position = gesture_event->PositionInScreen();
+ gesture_data->widget_position = gesture_event->PositionInWidget();
+ gesture_data->source_device = gesture_event->SourceDevice();
+ gesture_data->is_source_touch_event_set_non_blocking =
+ gesture_event->is_source_touch_event_set_non_blocking;
+ gesture_data->primary_pointer_type = gesture_event->primary_pointer_type;
+ gesture_data->unique_touch_event_id = gesture_event->unique_touch_event_id;
+ switch (gesture_event->GetType()) {
+ default:
+ break;
+ case blink::WebInputEvent::Type::kGestureTapDown:
+ gesture_data->contact_size =
+ gfx::Size(gesture_event->data.tap_down.width,
+ gesture_event->data.tap_down.height);
+ break;
+ case blink::WebInputEvent::Type::kGestureShowPress:
+ gesture_data->contact_size =
+ gfx::Size(gesture_event->data.show_press.width,
+ gesture_event->data.show_press.height);
+ break;
+ case blink::WebInputEvent::Type::kGestureTap:
+ case blink::WebInputEvent::Type::kGestureTapUnconfirmed:
+ case blink::WebInputEvent::Type::kGestureDoubleTap:
+ gesture_data->contact_size = gfx::Size(gesture_event->data.tap.width,
+ gesture_event->data.tap.height);
+ gesture_data->tap_data =
+ blink::mojom::TapData::New(gesture_event->data.tap.tap_count,
+ gesture_event->data.tap.needs_wheel_event);
+ break;
+ case blink::WebInputEvent::Type::kGestureLongPress:
+ case blink::WebInputEvent::Type::kGestureLongTap:
+ gesture_data->contact_size =
+ gfx::Size(gesture_event->data.long_press.width,
+ gesture_event->data.long_press.height);
+ break;
+
+ case blink::WebInputEvent::Type::kGestureTwoFingerTap:
+ gesture_data->contact_size =
+ gfx::Size(gesture_event->data.two_finger_tap.first_finger_width,
+ gesture_event->data.two_finger_tap.first_finger_height);
+ break;
+ case blink::WebInputEvent::Type::kGestureScrollBegin:
+ gesture_data->scroll_data = blink::mojom::ScrollData::New(
+ gesture_event->data.scroll_begin.delta_x_hint,
+ gesture_event->data.scroll_begin.delta_y_hint,
+ gesture_event->data.scroll_begin.delta_hint_units,
+ gesture_event->data.scroll_begin.target_viewport,
+ gesture_event->data.scroll_begin.inertial_phase,
+ gesture_event->data.scroll_begin.synthetic,
+ gesture_event->data.scroll_begin.pointer_count, nullptr);
+ break;
+ case blink::WebInputEvent::Type::kGestureScrollEnd:
+ gesture_data->scroll_data = blink::mojom::ScrollData::New(
+ 0, 0, gesture_event->data.scroll_end.delta_units, false,
+ gesture_event->data.scroll_end.inertial_phase,
+ gesture_event->data.scroll_end.synthetic, 0, nullptr);
+ break;
+ case blink::WebInputEvent::Type::kGestureScrollUpdate:
+ gesture_data->scroll_data = blink::mojom::ScrollData::New(
+ gesture_event->data.scroll_update.delta_x,
+ gesture_event->data.scroll_update.delta_y,
+ gesture_event->data.scroll_update.delta_units, false,
+ gesture_event->data.scroll_update.inertial_phase, false, 0,
+ blink::mojom::ScrollUpdate::New(
+ gesture_event->data.scroll_update.velocity_x,
+ gesture_event->data.scroll_update.velocity_y));
+ break;
+ case blink::WebInputEvent::Type::kGestureFlingStart:
+ gesture_data->fling_data = blink::mojom::FlingData::New(
+ gesture_event->data.fling_start.velocity_x,
+ gesture_event->data.fling_start.velocity_y,
+ gesture_event->data.fling_start.target_viewport, false);
+ break;
+ case blink::WebInputEvent::Type::kGestureFlingCancel:
+ gesture_data->fling_data = blink::mojom::FlingData::New(
+ 0, 0, gesture_event->data.fling_cancel.target_viewport,
+ gesture_event->data.fling_cancel.prevent_boosting);
+ break;
+ case blink::WebInputEvent::Type::kGesturePinchBegin:
+ gesture_data->pinch_begin_data = blink::mojom::PinchBeginData::New(
+ gesture_event->data.pinch_begin.needs_wheel_event);
+ break;
+ case blink::WebInputEvent::Type::kGesturePinchUpdate:
+ gesture_data->pinch_update_data = blink::mojom::PinchUpdateData::New(
+ gesture_event->data.pinch_update.scale,
+ gesture_event->data.pinch_update.zoom_disabled,
+ gesture_event->data.pinch_update.needs_wheel_event);
+ break;
+ case blink::WebInputEvent::Type::kGesturePinchEnd:
+ gesture_data->pinch_end_data = blink::mojom::PinchEndData::New(
+ gesture_event->data.pinch_end.needs_wheel_event);
+ break;
+ }
+ return gesture_data;
+}
+
+// static
+blink::mojom::TouchDataPtr
+StructTraits<blink::mojom::EventDataView,
+ std::unique_ptr<blink::WebCoalescedInputEvent>>::
+ touch_data(const std::unique_ptr<blink::WebCoalescedInputEvent>& event) {
+ if (!blink::WebInputEvent::IsTouchEventType(event->Event().GetType()))
+ return nullptr;
+
+ const blink::WebTouchEvent* touch_event =
+ static_cast<const blink::WebTouchEvent*>(event->EventPointer());
+ auto touch_data = blink::mojom::TouchData::New(
+ touch_event->dispatch_type, touch_event->moved_beyond_slop_region,
+ touch_event->touch_start_or_first_touch_move, touch_event->hovering,
+ touch_event->unique_touch_event_id,
+ std::vector<blink::mojom::TouchPointPtr>());
+ for (unsigned i = 0; i < touch_event->touches_length; ++i) {
+ blink::mojom::PointerDataPtr pointer_data =
+ PointerDataFromPointerProperties(touch_event->touches[i], nullptr);
+ touch_data->touches.emplace_back(blink::mojom::TouchPoint::New(
+ touch_event->touches[i].state, touch_event->touches[i].radius_x,
+ touch_event->touches[i].radius_y,
+ touch_event->touches[i].rotation_angle, std::move(pointer_data)));
+ }
+ return touch_data;
+}
+
+} // namespace mojo
diff --git a/chromium/third_party/blink/common/input/web_mouse_wheel_event.cc b/chromium/third_party/blink/common/input/web_mouse_wheel_event.cc
index 2400f799bd7..a7f5411a38d 100644
--- a/chromium/third_party/blink/common/input/web_mouse_wheel_event.cc
+++ b/chromium/third_party/blink/common/input/web_mouse_wheel_event.cc
@@ -110,4 +110,32 @@ WebMouseWheelEvent WebMouseWheelEvent::FlattenTransform() const {
return result;
}
+// static
+WebMouseWheelEvent::EventAction
+WebMouseWheelEvent::GetPlatformSpecificDefaultEventAction(
+ const WebMouseWheelEvent& event) {
+#if defined(USE_AURA)
+ // Scroll events generated from the mouse wheel when the control key is held
+ // don't trigger scrolling. Instead, they may cause zooming.
+ if (event.delta_units != ui::ScrollGranularity::kScrollByPrecisePixel &&
+ (event.GetModifiers() & WebInputEvent::kControlKey)) {
+ return blink::WebMouseWheelEvent::EventAction::kPageZoom;
+ }
+
+ if (event.delta_x == 0 && (event.GetModifiers() & WebInputEvent::kShiftKey))
+ return blink::WebMouseWheelEvent::EventAction::kScrollHorizontal;
+#endif
+ if (event.rails_mode == WebInputEvent::kRailsModeHorizontal ||
+ (event.delta_x != 0 && event.delta_y == 0)) {
+ return blink::WebMouseWheelEvent::EventAction::kScrollHorizontal;
+ }
+
+ if (event.rails_mode == WebInputEvent::kRailsModeVertical ||
+ (event.delta_x == 0 && event.delta_y != 0)) {
+ return blink::WebMouseWheelEvent::EventAction::kScrollVertical;
+ }
+
+ return blink::WebMouseWheelEvent::EventAction::kScroll;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/common/loader/throttling_url_loader.cc b/chromium/third_party/blink/common/loader/throttling_url_loader.cc
index 878131ce029..181ef0f4960 100644
--- a/chromium/third_party/blink/common/loader/throttling_url_loader.cc
+++ b/chromium/third_party/blink/common/loader/throttling_url_loader.cc
@@ -12,6 +12,7 @@
#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
#include "net/url_request/redirect_util.h"
+#include "services/network/public/cpp/cors/cors.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
@@ -28,6 +29,43 @@ void MergeRemovedHeaders(std::vector<std::string>* removed_headers_A,
}
}
+#if DCHECK_IS_ON()
+void CheckThrottleWillNotCauseCorsPreflight(
+ const std::set<std::string>& initial_headers,
+ const std::set<std::string>& initial_cors_exempt_headers,
+ const net::HttpRequestHeaders& headers,
+ const net::HttpRequestHeaders& cors_exempt_headers,
+ const std::vector<std::string> cors_exempt_header_list) {
+ base::flat_set<std::string> cors_exempt_header_flat_set(
+ cors_exempt_header_list);
+ for (auto& header : headers.GetHeaderVector()) {
+ if (initial_headers.find(header.key) == initial_headers.end() &&
+ !network::cors::IsCorsSafelistedHeader(header.key, header.value)) {
+ bool is_cors_exempt = cors_exempt_header_flat_set.count(header.key);
+ NOTREACHED()
+ << "Throttle added cors unsafe header " << header.key
+ << (is_cors_exempt
+ ? " . Header is cors exempt so should have "
+ "been added to RequestHeaders::cors_exempt_headers "
+ "instead of "
+ "of RequestHeaders::cors_exempt_headers."
+ : "");
+ }
+ }
+
+ for (auto& header : cors_exempt_headers.GetHeaderVector()) {
+ if (cors_exempt_header_flat_set.count(header.key) == 0 &&
+ initial_cors_exempt_headers.find(header.key) ==
+ initial_cors_exempt_headers.end()) {
+ NOTREACHED() << "Throttle added cors exempt header " << header.key
+ << " but it wasn't configured as cors exempt by the "
+ "browser. See "
+ << "StoragePartition::UpdateCorsMitigationList().";
+ }
+ }
+}
+#endif
+
} // namespace
const char ThrottlingURLLoader::kFollowRedirectReason[] = "FollowRedirect";
@@ -133,6 +171,14 @@ class ThrottlingURLLoader::ForwardingThrottleDelegate
loader_->RestartWithURLResetAndFlags(additional_load_flags);
}
+ void RestartWithURLResetAndFlagsNow(int additional_load_flags) override {
+ if (!loader_)
+ return;
+
+ ScopedDelegateCall scoped_delegate_call(this);
+ loader_->RestartWithURLResetAndFlagsNow(additional_load_flags);
+ }
+
void Detach() { loader_ = nullptr; }
private:
@@ -173,13 +219,16 @@ ThrottlingURLLoader::StartInfo::StartInfo(
int32_t in_request_id,
uint32_t in_options,
network::ResourceRequest* in_url_request,
- scoped_refptr<base::SingleThreadTaskRunner> in_task_runner)
+ scoped_refptr<base::SingleThreadTaskRunner> in_task_runner,
+ base::Optional<std::vector<std::string>> in_cors_exempt_header_list)
: url_loader_factory(std::move(in_url_loader_factory)),
routing_id(in_routing_id),
request_id(in_request_id),
options(in_options),
url_request(*in_url_request),
- task_runner(std::move(in_task_runner)) {}
+ task_runner(std::move(in_task_runner)) {
+ cors_exempt_header_list = std::move(in_cors_exempt_header_list);
+}
ThrottlingURLLoader::StartInfo::~StartInfo() = default;
@@ -212,11 +261,14 @@ std::unique_ptr<ThrottlingURLLoader> ThrottlingURLLoader::CreateLoaderAndStart(
network::ResourceRequest* url_request,
network::mojom::URLLoaderClient* client,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ base::Optional<std::vector<std::string>> cors_exempt_header_list) {
+ DCHECK(url_request);
std::unique_ptr<ThrottlingURLLoader> loader(new ThrottlingURLLoader(
std::move(throttles), client, traffic_annotation));
loader->Start(std::move(factory), routing_id, request_id, options,
- url_request, std::move(task_runner));
+ url_request, std::move(task_runner),
+ std::move(cors_exempt_header_list));
return loader;
}
@@ -224,7 +276,7 @@ ThrottlingURLLoader::~ThrottlingURLLoader() {
if (inside_delegate_calls_ > 0) {
// A throttle is calling into this object. In this case, delay destruction
// of the throttles, so that throttles don't need to worry about any
- // delegate calls may destory them synchronously.
+ // delegate calls may destroy them synchronously.
for (auto& entry : throttles_)
entry.delegate->Detach();
@@ -351,7 +403,8 @@ void ThrottlingURLLoader::Start(
int32_t request_id,
uint32_t options,
network::ResourceRequest* url_request,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ base::Optional<std::vector<std::string>> cors_exempt_header_list) {
DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
DCHECK(!loader_completed_);
@@ -362,7 +415,28 @@ void ThrottlingURLLoader::Start(
for (auto& entry : throttles_) {
auto* throttle = entry.throttle.get();
bool throttle_deferred = false;
+
+#if DCHECK_IS_ON()
+ std::set<std::string> initial_headers, initial_cors_exempt_headers;
+ if (cors_exempt_header_list) {
+ for (auto& header : url_request->headers.GetHeaderVector())
+ initial_headers.insert(header.key);
+
+ for (auto& header : url_request->cors_exempt_headers.GetHeaderVector())
+ initial_cors_exempt_headers.insert(header.key);
+ }
+#endif
+
throttle->WillStartRequest(url_request, &throttle_deferred);
+
+#if DCHECK_IS_ON()
+ if (cors_exempt_header_list) {
+ CheckThrottleWillNotCauseCorsPreflight(
+ initial_headers, initial_cors_exempt_headers, url_request->headers,
+ url_request->cors_exempt_headers, *cors_exempt_header_list);
+ }
+#endif
+
if (original_url_ != url_request->url) {
DCHECK(throttle_will_start_redirect_url_.is_empty())
<< "ThrottlingURLLoader doesn't support multiple throttles "
@@ -384,9 +458,9 @@ void ThrottlingURLLoader::Start(
}
}
- start_info_ =
- std::make_unique<StartInfo>(factory, routing_id, request_id, options,
- url_request, std::move(task_runner));
+ start_info_ = std::make_unique<StartInfo>(
+ factory, routing_id, request_id, options, url_request,
+ std::move(task_runner), std::move(cors_exempt_header_list));
if (deferred)
deferred_stage_ = DEFERRED_START;
else
@@ -534,6 +608,13 @@ void ThrottlingURLLoader::RestartWithURLResetAndFlags(
has_pending_restart_ = true;
}
+void ThrottlingURLLoader::RestartWithURLResetAndFlagsNow(
+ int additional_load_flags) {
+ RestartWithURLResetAndFlags(additional_load_flags);
+ if (!did_receive_response_)
+ RestartWithFlagsNow();
+}
+
void ThrottlingURLLoader::OnReceiveResponse(
network::mojom::URLResponseHeadPtr response_head) {
DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
@@ -541,6 +622,7 @@ void ThrottlingURLLoader::OnReceiveResponse(
DCHECK(deferring_throttles_.empty());
TRACE_EVENT1("loading", "ThrottlingURLLoader::OnReceiveResponse", "url",
response_url_.possibly_invalid_spec());
+ did_receive_response_ = true;
// Dispatch BeforeWillProcessResponse().
if (!throttles_.empty()) {
@@ -611,6 +693,19 @@ void ThrottlingURLLoader::OnReceiveRedirect(
throttle->WillRedirectRequest(
&redirect_info_copy, *response_head, &throttle_deferred,
&removed_headers, &modified_headers, &modified_cors_exempt_headers);
+
+ if (!weak_ptr)
+ return;
+
+#if DCHECK_IS_ON()
+ if (start_info_->cors_exempt_header_list) {
+ CheckThrottleWillNotCauseCorsPreflight(
+ std::set<std::string>(), std::set<std::string>(), modified_headers,
+ modified_cors_exempt_headers,
+ *start_info_->cors_exempt_header_list);
+ }
+#endif
+
if (redirect_info_copy.new_url != redirect_info.new_url) {
DCHECK(throttle_will_redirect_redirect_url_.is_empty())
<< "ThrottlingURLLoader doesn't support multiple throttles "
@@ -618,8 +713,6 @@ void ThrottlingURLLoader::OnReceiveRedirect(
throttle_will_redirect_redirect_url_ = redirect_info_copy.new_url;
}
- if (!weak_ptr)
- return;
if (!HandleThrottleResult(throttle, throttle_deferred, &deferred))
return;
@@ -865,8 +958,10 @@ void ThrottlingURLLoader::InterceptResponse(
original_client_receiver) {
response_intercepted_ = true;
- if (original_loader)
+ if (original_loader) {
+ url_loader_->ResumeReadingBodyFromNet();
*original_loader = url_loader_.Unbind();
+ }
url_loader_.Bind(std::move(new_loader));
if (original_client_receiver)
diff --git a/chromium/third_party/blink/common/loader/throttling_url_loader_unittest.cc b/chromium/third_party/blink/common/loader/throttling_url_loader_unittest.cc
index 27cc2858487..c1fe940d655 100644
--- a/chromium/third_party/blink/common/loader/throttling_url_loader_unittest.cc
+++ b/chromium/third_party/blink/common/loader/throttling_url_loader_unittest.cc
@@ -2110,6 +2110,244 @@ TEST_F(ThrottlingURLLoaderTest, MultipleRestartWithURLResetAndFlags) {
}
}
+// Verify RestartWithURLResetAndFlagsNow() behaves similar to
+// RestartWithURLResetAndFlags() while called during BeforeWillProcessResponse()
+// processing, and verify that it restarts with the original URL.
+TEST_F(ThrottlingURLLoaderTest, RestartWithURLResetAndFlagsNow) {
+ base::RunLoop run_loop1;
+ base::RunLoop run_loop2;
+ base::RunLoop run_loop3;
+
+ // URL for internal redirect.
+ GURL modified_url = GURL("www.example.uk.com");
+ throttle_->set_modify_url_in_will_start(modified_url);
+
+ // Check that the initial loader uses the default load flags (0).
+ factory_.set_on_create_loader_and_start(base::BindRepeating(
+ [](const base::RepeatingClosure& quit_closure,
+ const network::ResourceRequest& url_request) {
+ EXPECT_EQ(0, url_request.load_flags);
+ quit_closure.Run();
+ },
+ run_loop1.QuitClosure()));
+
+ // Set the client to actually follow redirects to allow URL resetting to
+ // occur.
+ client_.set_on_received_redirect_callback(base::BindLambdaForTesting([&]() {
+ net::HttpRequestHeaders modified_headers;
+ loader_->FollowRedirect({} /* removed_headers */,
+ std::move(modified_headers),
+ {} /* modified_cors_exempt_headers */);
+ }));
+
+ // Restart the request when processing BeforeWillProcessResponse(), using
+ // different load flags (1), and an URL reset.
+ throttle_->set_before_will_process_response_callback(base::BindRepeating(
+ [](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) {
+ delegate->RestartWithURLResetAndFlagsNow(1);
+ }));
+
+ CreateLoaderAndStart();
+
+ run_loop1.Run();
+
+ EXPECT_EQ(1u, factory_.create_loader_and_start_called());
+ EXPECT_EQ(1u, throttle_->will_start_request_called());
+ EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+ EXPECT_EQ(0u, throttle_->before_will_process_response_called());
+ EXPECT_EQ(0u, throttle_->will_process_response_called());
+ EXPECT_EQ(throttle_->observed_response_url(), modified_url);
+
+ // The next time we intercept CreateLoaderAndStart() should be for the
+ // restarted request (load flags of 1).
+ factory_.set_on_create_loader_and_start(base::BindRepeating(
+ [](const base::RepeatingClosure& quit_closure,
+ const network::ResourceRequest& url_request) {
+ EXPECT_EQ(1, url_request.load_flags);
+ quit_closure.Run();
+ },
+ run_loop2.QuitClosure()));
+
+ factory_.NotifyClientOnReceiveResponse();
+
+ run_loop2.Run();
+
+ // Now that the restarted request has been made, clear
+ // BeforeWillProcessResponse() so it doesn't restart the request yet again.
+ throttle_->set_before_will_process_response_callback(
+ TestURLLoaderThrottle::ThrottleCallback());
+
+ client_.set_on_complete_callback(
+ base::BindLambdaForTesting([&run_loop3](int error) {
+ EXPECT_EQ(net::OK, error);
+ run_loop3.Quit();
+ }));
+
+ // Complete the response.
+ factory_.NotifyClientOnReceiveResponse();
+ factory_.NotifyClientOnComplete(net::OK);
+
+ run_loop3.Run();
+
+ EXPECT_EQ(2u, factory_.create_loader_and_start_called());
+ EXPECT_EQ(1u, throttle_->will_start_request_called());
+ EXPECT_EQ(1u, throttle_->will_redirect_request_called());
+ EXPECT_EQ(2u, throttle_->before_will_process_response_called());
+ EXPECT_EQ(1u, throttle_->will_process_response_called());
+ EXPECT_EQ(throttle_->observed_response_url(), request_url);
+}
+
+// Verify RestartWithURLResetAndFlagsNow() behaves similar to
+// RestartWithURLResetAndFlags() while called during BeforeWillProcessResponse()
+// processing, and verify that it restarts with the original URL.
+TEST_F(ThrottlingURLLoaderTest,
+ RestartWithURLResetAndFlagsNowBeforeProcessResponse) {
+ base::RunLoop run_loop1;
+ base::RunLoop run_loop2;
+ base::RunLoop run_loop3;
+
+ // URL for internal redirect.
+ GURL modified_url = GURL("www.example.uk.com");
+ throttle_->set_modify_url_in_will_start(modified_url);
+
+ // Check that the initial loader uses the default load flags (0).
+ factory_.set_on_create_loader_and_start(base::BindRepeating(
+ [](const base::RepeatingClosure& quit_closure,
+ const network::ResourceRequest& url_request) {
+ EXPECT_EQ(0, url_request.load_flags);
+ quit_closure.Run();
+ },
+ run_loop1.QuitClosure()));
+
+ // Set the client to actually follow redirects to allow URL resetting to
+ // occur.
+ client_.set_on_received_redirect_callback(base::BindLambdaForTesting([&]() {
+ net::HttpRequestHeaders modified_headers;
+ loader_->FollowRedirect({} /* removed_headers */,
+ std::move(modified_headers),
+ {} /* modified_cors_exempt_headers */);
+ }));
+
+ CreateLoaderAndStart();
+
+ run_loop1.Run();
+
+ EXPECT_EQ(1u, factory_.create_loader_and_start_called());
+ EXPECT_EQ(1u, throttle_->will_start_request_called());
+ EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+ EXPECT_EQ(0u, throttle_->before_will_process_response_called());
+ EXPECT_EQ(0u, throttle_->will_process_response_called());
+ EXPECT_EQ(throttle_->observed_response_url(), modified_url);
+
+ // Restarting the request should restart the request immediately.
+ throttle_->delegate()->RestartWithURLResetAndFlagsNow(1);
+
+ // The next time we intercept CreateLoaderAndStart() should be for the
+ // restarted request (load flags of 1).
+ factory_.set_on_create_loader_and_start(base::BindRepeating(
+ [](const base::RepeatingClosure& quit_closure,
+ const network::ResourceRequest& url_request) {
+ EXPECT_EQ(1, url_request.load_flags);
+ quit_closure.Run();
+ },
+ run_loop2.QuitClosure()));
+
+ run_loop2.Run();
+
+ EXPECT_EQ(2u, factory_.create_loader_and_start_called());
+ EXPECT_EQ(1u, throttle_->will_redirect_request_called());
+ EXPECT_EQ(0u, throttle_->before_will_process_response_called());
+ EXPECT_EQ(0u, throttle_->will_process_response_called());
+
+ client_.set_on_complete_callback(
+ base::BindLambdaForTesting([&run_loop3](int error) {
+ EXPECT_EQ(net::OK, error);
+ run_loop3.Quit();
+ }));
+
+ // Complete the response.
+ factory_.NotifyClientOnReceiveResponse();
+ factory_.NotifyClientOnComplete(net::OK);
+
+ run_loop3.Run();
+
+ EXPECT_EQ(2u, factory_.create_loader_and_start_called());
+ EXPECT_EQ(1u, throttle_->will_start_request_called());
+ EXPECT_EQ(1u, throttle_->will_redirect_request_called());
+ EXPECT_EQ(1u, throttle_->before_will_process_response_called());
+ EXPECT_EQ(1u, throttle_->will_process_response_called());
+ EXPECT_EQ(throttle_->observed_response_url(), request_url);
+}
+
+// Verify RestartWithURLResetAndFlagsNow() does not restart request if
+// BeforeWillProcessResponse() has already been called.
+TEST_F(ThrottlingURLLoaderTest,
+ RestartWithURLResetAndFlagsNowAfterProcessResponse) {
+ base::RunLoop run_loop1;
+ base::RunLoop run_loop2;
+ base::RunLoop run_loop3;
+ base::RunLoop run_loop4;
+
+ // URL for internal redirect.
+ GURL modified_url = GURL("www.example.uk.com");
+ throttle_->set_modify_url_in_will_start(modified_url);
+
+ // Check that the initial loader uses the default load flags (0).
+ factory_.set_on_create_loader_and_start(base::BindRepeating(
+ [](const base::RepeatingClosure& quit_closure,
+ const network::ResourceRequest& url_request) {
+ EXPECT_EQ(0, url_request.load_flags);
+ quit_closure.Run();
+ },
+ run_loop1.QuitClosure()));
+
+ // Set the client to actually follow redirects to allow URL resetting to
+ // occur.
+ client_.set_on_received_redirect_callback(base::BindLambdaForTesting([&]() {
+ net::HttpRequestHeaders modified_headers;
+ loader_->FollowRedirect({} /* removed_headers */,
+ std::move(modified_headers),
+ {} /* modified_cors_exempt_headers */);
+ }));
+
+ CreateLoaderAndStart();
+ run_loop1.Run();
+
+ throttle_->set_before_will_process_response_callback(
+ base::BindLambdaForTesting(
+ [&run_loop3](blink::URLLoaderThrottle::Delegate* delegate,
+ bool* defer) { run_loop3.Quit(); }));
+
+ factory_.NotifyClientOnReceiveResponse();
+ run_loop3.Run();
+
+ EXPECT_EQ(1u, factory_.create_loader_and_start_called());
+ EXPECT_EQ(1u, throttle_->will_start_request_called());
+ EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+ EXPECT_EQ(1u, throttle_->before_will_process_response_called());
+ EXPECT_EQ(1u, throttle_->will_process_response_called());
+
+ // Restarting the request should not have any effect.
+ throttle_->delegate()->RestartWithURLResetAndFlagsNow(1);
+
+ client_.set_on_complete_callback(
+ base::BindLambdaForTesting([&run_loop4](int error) {
+ EXPECT_EQ(net::OK, error);
+ run_loop4.Quit();
+ }));
+
+ // Complete the response.
+ factory_.NotifyClientOnComplete(net::OK);
+ run_loop4.Run();
+
+ EXPECT_EQ(1u, factory_.create_loader_and_start_called());
+ EXPECT_EQ(1u, throttle_->will_start_request_called());
+ EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+ EXPECT_EQ(1u, throttle_->before_will_process_response_called());
+ EXPECT_EQ(1u, throttle_->will_process_response_called());
+ EXPECT_EQ(throttle_->observed_response_url(), request_url);
+}
+
// Call RestartWithURLResetAndFlags() from multiple throttles after having
// deferred BeforeWillProcessResponse() in each. Ensures that the request is
// started exactly once, using the combination of all additional load flags,
diff --git a/chromium/third_party/blink/common/loader/url_loader_throttle.cc b/chromium/third_party/blink/common/loader/url_loader_throttle.cc
index 16b98ba1664..b74c6e1e8d8 100644
--- a/chromium/third_party/blink/common/loader/url_loader_throttle.cc
+++ b/chromium/third_party/blink/common/loader/url_loader_throttle.cc
@@ -37,6 +37,11 @@ void URLLoaderThrottle::Delegate::RestartWithURLResetAndFlags(
NOTIMPLEMENTED();
}
+void URLLoaderThrottle::Delegate::RestartWithURLResetAndFlagsNow(
+ int additional_load_flags) {
+ NOTIMPLEMENTED();
+}
+
URLLoaderThrottle::Delegate::~Delegate() {}
URLLoaderThrottle::~URLLoaderThrottle() {}
diff --git a/chromium/third_party/blink/common/manifest/manifest.cc b/chromium/third_party/blink/common/manifest/manifest.cc
index 942311867cf..1d2db2b8b70 100644
--- a/chromium/third_party/blink/common/manifest/manifest.cc
+++ b/chromium/third_party/blink/common/manifest/manifest.cc
@@ -49,7 +49,8 @@ bool Manifest::IsEmpty() const {
icons.empty() && shortcuts.empty() && !share_target.has_value() &&
related_applications.empty() && file_handlers.empty() &&
!prefer_related_applications && !theme_color && !background_color &&
- gcm_sender_id.is_null() && scope.is_empty();
+ gcm_sender_id.is_null() && scope.is_empty() &&
+ protocol_handlers.empty();
}
} // namespace blink
diff --git a/chromium/third_party/blink/common/manifest/manifest_mojom_traits.cc b/chromium/third_party/blink/common/manifest/manifest_mojom_traits.cc
index 91878c1eea7..f345be0bdc7 100644
--- a/chromium/third_party/blink/common/manifest/manifest_mojom_traits.cc
+++ b/chromium/third_party/blink/common/manifest/manifest_mojom_traits.cc
@@ -75,6 +75,9 @@ bool StructTraits<blink::mojom::ManifestDataView, ::blink::Manifest>::Read(
if (!data.ReadFileHandlers(&out->file_handlers))
return false;
+ if (!data.ReadProtocolHandlers(&out->protocol_handlers))
+ return false;
+
if (!data.ReadRelatedApplications(&out->related_applications))
return false;
@@ -241,4 +244,17 @@ bool StructTraits<blink::mojom::ManifestFileHandlerDataView,
return true;
}
+bool StructTraits<blink::mojom::ManifestProtocolHandlerDataView,
+ ::blink::Manifest::ProtocolHandler>::
+ Read(blink::mojom::ManifestProtocolHandlerDataView data,
+ ::blink::Manifest::ProtocolHandler* out) {
+ if (!data.ReadProtocol(&out->protocol))
+ return false;
+
+ if (!data.ReadUrl(&out->url))
+ return false;
+
+ return true;
+}
+
} // namespace mojo
diff --git a/chromium/third_party/blink/common/mediastream/media_devices.cc b/chromium/third_party/blink/common/mediastream/media_devices.cc
index 3661b4b6587..0a67e4592ee 100644
--- a/chromium/third_party/blink/common/mediastream/media_devices.cc
+++ b/chromium/third_party/blink/common/mediastream/media_devices.cc
@@ -7,28 +7,31 @@
namespace blink {
-WebMediaDeviceInfo::WebMediaDeviceInfo()
- : video_facing(media::VideoFacingMode::MEDIA_VIDEO_FACING_NONE) {}
+WebMediaDeviceInfo::WebMediaDeviceInfo() = default;
WebMediaDeviceInfo::WebMediaDeviceInfo(const WebMediaDeviceInfo& other) =
default;
WebMediaDeviceInfo::WebMediaDeviceInfo(WebMediaDeviceInfo&& other) = default;
-WebMediaDeviceInfo::WebMediaDeviceInfo(const std::string& device_id,
- const std::string& label,
- const std::string& group_id,
- media::VideoFacingMode video_facing)
+WebMediaDeviceInfo::WebMediaDeviceInfo(
+ const std::string& device_id,
+ const std::string& label,
+ const std::string& group_id,
+ media::VideoFacingMode video_facing,
+ const base::Optional<bool>& pan_tilt_zoom_supported)
: device_id(device_id),
label(label),
group_id(group_id),
- video_facing(video_facing) {}
+ video_facing(video_facing),
+ pan_tilt_zoom_supported(pan_tilt_zoom_supported) {}
WebMediaDeviceInfo::WebMediaDeviceInfo(
const media::VideoCaptureDeviceDescriptor& descriptor)
: device_id(descriptor.device_id),
label(descriptor.GetNameAndModel()),
- video_facing(descriptor.facing) {}
+ video_facing(descriptor.facing),
+ pan_tilt_zoom_supported(descriptor.pan_tilt_zoom_supported()) {}
WebMediaDeviceInfo::~WebMediaDeviceInfo() = default;
diff --git a/chromium/third_party/blink/common/mediastream/media_stream_request.cc b/chromium/third_party/blink/common/mediastream/media_stream_request.cc
index 39323c1819c..a870fc4ea38 100644
--- a/chromium/third_party/blink/common/mediastream/media_stream_request.cc
+++ b/chromium/third_party/blink/common/mediastream/media_stream_request.cc
@@ -69,11 +69,13 @@ MediaStreamDevice::MediaStreamDevice(
const std::string& id,
const std::string& name,
media::VideoFacingMode facing,
- const base::Optional<std::string>& group_id)
+ const base::Optional<std::string>& group_id,
+ const base::Optional<bool>& pan_tilt_zoom_supported)
: type(type),
id(id),
video_facing(facing),
group_id(group_id),
+ pan_tilt_zoom_supported(pan_tilt_zoom_supported),
name(name) {}
MediaStreamDevice::MediaStreamDevice(mojom::MediaStreamType type,
@@ -93,21 +95,22 @@ MediaStreamDevice::MediaStreamDevice(mojom::MediaStreamType type,
DCHECK(input.IsValid());
}
-MediaStreamDevice::MediaStreamDevice(const MediaStreamDevice& other) {
- type = other.type;
- id = other.id;
- video_facing = other.video_facing;
- group_id = other.group_id;
- matched_output_device_id = other.matched_output_device_id;
- name = other.name;
- input = other.input;
- session_id_ = other.session_id_;
+MediaStreamDevice::MediaStreamDevice(const MediaStreamDevice& other)
+ : type(other.type),
+ id(other.id),
+ video_facing(other.video_facing),
+ group_id(other.group_id),
+ pan_tilt_zoom_supported(other.pan_tilt_zoom_supported),
+ matched_output_device_id(other.matched_output_device_id),
+ name(other.name),
+ input(other.input),
+ session_id_(other.session_id_) {
DCHECK(!session_id_.has_value() || !session_id_->is_empty());
if (other.display_media_info.has_value())
display_media_info = other.display_media_info->Clone();
}
-MediaStreamDevice::~MediaStreamDevice() {}
+MediaStreamDevice::~MediaStreamDevice() = default;
MediaStreamDevice& MediaStreamDevice::operator=(
const MediaStreamDevice& other) {
diff --git a/chromium/third_party/blink/common/mime_util/mime_util.cc b/chromium/third_party/blink/common/mime_util/mime_util.cc
index 60820758886..2c2fcc8c152 100644
--- a/chromium/third_party/blink/common/mime_util/mime_util.cc
+++ b/chromium/third_party/blink/common/mime_util/mime_util.cc
@@ -137,12 +137,10 @@ MimeUtil::MimeUtil() {
for (const char* type : kSupportedImageTypes)
image_types_.insert(type);
#if BUILDFLAG(ENABLE_AV1_DECODER)
- // TODO(wtc): Add "image/avif" and "image/avif-sequence" to the
- // kSupportedImageTypes array when the AVIF feature is shipped.
- if (base::FeatureList::IsEnabled(features::kAVIF)) {
+ // TODO(wtc): Add "image/avif" to the kSupportedImageTypes array when the AVIF
+ // feature is shipped.
+ if (base::FeatureList::IsEnabled(features::kAVIF))
image_types_.insert("image/avif");
- image_types_.insert("image/avif-sequence");
- }
#endif
for (const char* type : kUnsupportedTextTypes)
unsupported_text_types_.insert(type);
diff --git a/chromium/third_party/blink/common/mime_util/mime_util_unittest.cc b/chromium/third_party/blink/common/mime_util/mime_util_unittest.cc
index e6f54a14849..97666923c4c 100644
--- a/chromium/third_party/blink/common/mime_util/mime_util_unittest.cc
+++ b/chromium/third_party/blink/common/mime_util/mime_util_unittest.cc
@@ -21,11 +21,8 @@ TEST(MimeUtilTest, LookupTypes) {
#if BUILDFLAG(ENABLE_AV1_DECODER)
EXPECT_EQ(IsSupportedImageMimeType("image/avif"),
base::FeatureList::IsEnabled(features::kAVIF));
- EXPECT_EQ(IsSupportedImageMimeType("image/avif-sequence"),
- base::FeatureList::IsEnabled(features::kAVIF));
#else
EXPECT_FALSE(IsSupportedImageMimeType("image/avif"));
- EXPECT_FALSE(IsSupportedImageMimeType("image/avif-sequence"));
#endif
EXPECT_FALSE(IsSupportedImageMimeType("image/lolcat"));
EXPECT_FALSE(IsSupportedImageMimeType("Image/LolCat"));
diff --git a/chromium/third_party/blink/common/origin_trials/trial_token.cc b/chromium/third_party/blink/common/origin_trials/trial_token.cc
index 0ebecd23d9a..7204a383e8a 100644
--- a/chromium/third_party/blink/common/origin_trials/trial_token.cc
+++ b/chromium/third_party/blink/common/origin_trials/trial_token.cc
@@ -56,6 +56,8 @@ const uint8_t kVersion3 = 3;
// enabled in the stable M50 release which would have used those tokens.
const uint8_t kVersion2 = 2;
+const char* kUsageSubset = "subset";
+
} // namespace
TrialToken::~TrialToken() = default;
@@ -216,6 +218,7 @@ std::unique_ptr<TrialToken> TrialToken::Parse(const std::string& token_payload,
// Initialize optional version 3 fields to default values.
bool is_third_party = false;
+ UsageRestriction usage = UsageRestriction::kNone;
if (version == kVersion3) {
// The |isThirdParty| flag is optional. If found, ensure it is a valid
@@ -227,10 +230,27 @@ std::unique_ptr<TrialToken> TrialToken::Parse(const std::string& token_payload,
}
is_third_party = is_third_party_value->GetBool();
}
+
+ // The |usage| field is optional and can only be set if |isThirdParty| flag
+ // is true. If found, ensure its value is either empty or "subset".
+ std::string* usage_value = datadict->FindStringKey("usage");
+ if (usage_value) {
+ if (!is_third_party) {
+ return nullptr;
+ }
+ if (usage_value->empty()) {
+ usage = UsageRestriction::kNone;
+ } else if (*usage_value == kUsageSubset) {
+ usage = UsageRestriction::kSubset;
+ } else {
+ return nullptr;
+ }
+ }
}
return base::WrapUnique(new TrialToken(origin, is_subdomain, *feature_name,
- expiry_timestamp, is_third_party));
+ expiry_timestamp, is_third_party,
+ usage));
}
bool TrialToken::ValidateOrigin(const url::Origin& origin) const {
@@ -272,11 +292,13 @@ TrialToken::TrialToken(const url::Origin& origin,
bool match_subdomains,
const std::string& feature_name,
uint64_t expiry_timestamp,
- bool is_third_party)
+ bool is_third_party,
+ UsageRestriction usage_restriction)
: origin_(origin),
match_subdomains_(match_subdomains),
feature_name_(feature_name),
expiry_time_(base::Time::FromDoubleT(expiry_timestamp)),
- is_third_party_(is_third_party) {}
+ is_third_party_(is_third_party),
+ usage_restriction_(usage_restriction) {}
} // namespace blink
diff --git a/chromium/third_party/blink/common/origin_trials/trial_token_unittest.cc b/chromium/third_party/blink/common/origin_trials/trial_token_unittest.cc
index f38a74431f8..7f7e4a12718 100644
--- a/chromium/third_party/blink/common/origin_trials/trial_token_unittest.cc
+++ b/chromium/third_party/blink/common/origin_trials/trial_token_unittest.cc
@@ -158,6 +158,44 @@ const uint8_t kSampleNonThirdPartyTokenSignature[] = {
0xb6, 0x0f, 0x83, 0x97, 0xca, 0x51, 0x76, 0xa5, 0x06, 0xd7, 0xd0,
0x61, 0x5a, 0x78, 0xb3, 0x9f, 0x94, 0xdb, 0x28, 0x03};
+// This is a good third party trial token with usage restriction set to subset,
+// signed with the above test private key. Generate this token with the
+// command:
+// generate_token.py valid.example.com Frobulate --version 3 --is-third-party
+// --expire-timestamp=1458766277 --usage-restriction subset
+const char kSampleThirdPartyUsageSubsetToken[] =
+ "A27Ee1Bm6HYjEu2Zz1DbGNUaPuM8x0Tnk15Gyx8TRKZg72+JUXgCccMxlLIjVh4l"
+ "enOES58tfJxrRCorBAKmBwcAAACCeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l"
+ "eGFtcGxlLmNvbTo0NDMiLCAiaXNUaGlyZFBhcnR5IjogdHJ1ZSwgInVzYWdlIjog"
+ "InN1YnNldCIsICJmZWF0dXJlIjogIkZyb2J1bGF0ZSIsICJleHBpcnkiOiAxNDU4"
+ "NzY2Mjc3fQ==";
+const uint8_t kSampleThirdPartyUsageSubsetTokenSignature[] = {
+ 0x6e, 0xc4, 0x7b, 0x50, 0x66, 0xe8, 0x76, 0x23, 0x12, 0xed, 0x99,
+ 0xcf, 0x50, 0xdb, 0x18, 0xd5, 0x1a, 0x3e, 0xe3, 0x3c, 0xc7, 0x44,
+ 0xe7, 0x93, 0x5e, 0x46, 0xcb, 0x1f, 0x13, 0x44, 0xa6, 0x60, 0xef,
+ 0x6f, 0x89, 0x51, 0x78, 0x02, 0x71, 0xc3, 0x31, 0x94, 0xb2, 0x23,
+ 0x56, 0x1e, 0x25, 0x7a, 0x73, 0x84, 0x4b, 0x9f, 0x2d, 0x7c, 0x9c,
+ 0x6b, 0x44, 0x2a, 0x2b, 0x04, 0x02, 0xa6, 0x07, 0x07};
+
+// This is a good third party trial token with usage restriction set to none,
+// signed with the above test private key. Generate this token with the
+// command:
+// generate_token.py valid.example.com Frobulate --version 3 --is-third-party
+// --expire-timestamp=1458766277 --usage-restriction ""
+const char kSampleThirdPartyUsageEmptyToken[] =
+ "A+gXf6yZgfN8NADWvnEhQ/GKycwCg34USmDlQ9UXTP6jDGJLBV+jI1npSUI0W/YW"
+ "hNyNYbzBaE2iCJSGCD56pwwAAAB8eyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l"
+ "eGFtcGxlLmNvbTo0NDMiLCAiaXNUaGlyZFBhcnR5IjogdHJ1ZSwgInVzYWdlIjog"
+ "IiIsICJmZWF0dXJlIjogIkZyb2J1bGF0ZSIsICJleHBpcnkiOiAxNDU4NzY2Mjc3"
+ "fQ==";
+const uint8_t kSampleThirdPartyUsageEmptyTokenSignature[] = {
+ 0xe8, 0x17, 0x7f, 0xac, 0x99, 0x81, 0xf3, 0x7c, 0x34, 0x00, 0xd6,
+ 0xbe, 0x71, 0x21, 0x43, 0xf1, 0x8a, 0xc9, 0xcc, 0x02, 0x83, 0x7e,
+ 0x14, 0x4a, 0x60, 0xe5, 0x43, 0xd5, 0x17, 0x4c, 0xfe, 0xa3, 0x0c,
+ 0x62, 0x4b, 0x05, 0x5f, 0xa3, 0x23, 0x59, 0xe9, 0x49, 0x42, 0x34,
+ 0x5b, 0xf6, 0x16, 0x84, 0xdc, 0x8d, 0x61, 0xbc, 0xc1, 0x68, 0x4d,
+ 0xa2, 0x08, 0x94, 0x86, 0x08, 0x3e, 0x7a, 0xa7, 0x0c};
+
const char kExpectedFeatureName[] = "Frobulate";
// This is an excessively long feature name (100 characters). This is valid, as
// there is no explicit limit on feature name length. Excessive refers to the
@@ -233,6 +271,15 @@ const char kSampleThirdPartyTokenJSON[] =
"{\"origin\": \"https://valid.example.com:443\", \"isThirdParty\": true, "
"\"feature\": \"Frobulate\", \"expiry\": 1458766277}";
+const char kSampleThirdPartyTokenUsageSubsetJSON[] =
+ "{\"origin\": \"https://valid.example.com:443\", \"isThirdParty\": true, "
+ "\"usage\": \"subset\", \"feature\": \"Frobulate\", \"expiry\": "
+ "1458766277}";
+
+const char kSampleThirdPartyTokenUsageEmptyJSON[] =
+ "{\"origin\": \"https://valid.example.com:443\", \"isThirdParty\": true, "
+ "\"usage\": \"\", \"feature\": \"Frobulate\", \"expiry\": 1458766277}";
+
// Various ill-formed trial tokens. These should all fail to parse.
const char* kInvalidTokens[] = {
// Empty String
@@ -276,6 +323,14 @@ const char* kInvalidTokensVersion3[] = {
"\"a\", \"expiry\": 1458766277}",
"{\"origin\": \"https://a.a\", \"isThirdParty\": 1, \"feature\": \"a\", "
"\"expiry\": 1458766277}",
+ // Invalid value in usage field
+ "{\"origin\": \"https://a.a\", \"isThirdParty\": true, \"usage\": "
+ "\"cycle\", \"feature\": \"a\", "
+ "\"expiry\": 1458766277}",
+ // usage in non third party token
+ "{\"origin\": \"https://a.a\", \"isThirdParty\": false, \"usage\": "
+ "\"subset\", \"feature\": \"a\", "
+ "\"expiry\": 1458766277}",
};
// Valid token JSON. The feature name matches matches kExpectedLongFeatureName
@@ -652,6 +707,14 @@ class TrialTokenTest : public testing::Test {
expected_non_third_party_signature_(std::string(
reinterpret_cast<const char*>(kSampleNonThirdPartyTokenSignature),
base::size(kSampleNonThirdPartyTokenSignature))),
+ expected_third_party_usage_empty_signature_(
+ std::string(reinterpret_cast<const char*>(
+ kSampleThirdPartyUsageEmptyTokenSignature),
+ base::size(kSampleThirdPartyUsageEmptyTokenSignature))),
+ expected_third_party_usage_subset_signature_(std::string(
+ reinterpret_cast<const char*>(
+ kSampleThirdPartyUsageSubsetTokenSignature),
+ base::size(kSampleThirdPartyUsageSubsetTokenSignature))),
correct_public_key_(
base::StringPiece(reinterpret_cast<const char*>(kTestPublicKey),
base::size(kTestPublicKey))),
@@ -717,6 +780,8 @@ class TrialTokenTest : public testing::Test {
std::string expected_nonsubdomain_signature_;
std::string expected_third_party_signature_;
std::string expected_non_third_party_signature_;
+ std::string expected_third_party_usage_empty_signature_;
+ std::string expected_third_party_usage_subset_signature_;
private:
base::StringPiece correct_public_key_;
@@ -805,6 +870,32 @@ TEST_F(TrialTokenTest, ExtractNonThirdPartyValidSignature) {
EXPECT_EQ(expected_non_third_party_signature_, token_signature);
}
+TEST_F(TrialTokenTest, ExtractThirdPartyUsageEmptyValidSignature) {
+ std::string token_payload;
+ std::string token_signature;
+ uint8_t token_version;
+ OriginTrialTokenStatus status =
+ Extract(kSampleThirdPartyUsageEmptyToken, correct_public_key(),
+ &token_payload, &token_signature, &token_version);
+ ASSERT_EQ(OriginTrialTokenStatus::kSuccess, status);
+ EXPECT_EQ(kVersion3, token_version);
+ EXPECT_STREQ(kSampleThirdPartyTokenUsageEmptyJSON, token_payload.c_str());
+ EXPECT_EQ(expected_third_party_usage_empty_signature_, token_signature);
+}
+
+TEST_F(TrialTokenTest, ExtractThirdPartyUsageSubsetValidSignature) {
+ std::string token_payload;
+ std::string token_signature;
+ uint8_t token_version;
+ OriginTrialTokenStatus status =
+ Extract(kSampleThirdPartyUsageSubsetToken, correct_public_key(),
+ &token_payload, &token_signature, &token_version);
+ ASSERT_EQ(OriginTrialTokenStatus::kSuccess, status);
+ EXPECT_EQ(kVersion3, token_version);
+ EXPECT_STREQ(kSampleThirdPartyTokenUsageSubsetJSON, token_payload.c_str());
+ EXPECT_EQ(expected_third_party_usage_subset_signature_, token_signature);
+}
+
TEST_F(TrialTokenTest, ExtractInvalidSignature) {
OriginTrialTokenStatus status =
ExtractStatusOnly(kInvalidSignatureToken, correct_public_key());
@@ -1044,6 +1135,28 @@ TEST_F(TrialTokenTest, ParseValidThirdPartyTokenInvalidVersion) {
EXPECT_EQ(expected_expiry_, token->expiry_time());
}
+TEST_F(TrialTokenTest, ParseValidThirdPartyUsageSubsetToken) {
+ std::unique_ptr<TrialToken> token =
+ Parse(kSampleThirdPartyTokenUsageSubsetJSON, kVersion3);
+ ASSERT_TRUE(token);
+ EXPECT_EQ(kExpectedFeatureName, token->feature_name());
+ EXPECT_TRUE(token->is_third_party());
+ EXPECT_EQ(TrialToken::UsageRestriction::kSubset, token->usage_restriction());
+ EXPECT_EQ(expected_origin_, token->origin());
+ EXPECT_EQ(expected_expiry_, token->expiry_time());
+}
+
+TEST_F(TrialTokenTest, ParseValidThirdPartyUsageEmptyToken) {
+ std::unique_ptr<TrialToken> token =
+ Parse(kSampleThirdPartyTokenUsageEmptyJSON, kVersion3);
+ ASSERT_TRUE(token);
+ EXPECT_EQ(kExpectedFeatureName, token->feature_name());
+ EXPECT_TRUE(token->is_third_party());
+ EXPECT_EQ(TrialToken::UsageRestriction::kNone, token->usage_restriction());
+ EXPECT_EQ(expected_origin_, token->origin());
+ EXPECT_EQ(expected_expiry_, token->expiry_time());
+}
+
// Test overall extraction and parsing, to ensure output status matches returned
// token, and signature is provided.
// Test Version 2.
diff --git a/chromium/third_party/blink/common/origin_trials/trial_token_validator.cc b/chromium/third_party/blink/common/origin_trials/trial_token_validator.cc
index 9da9e1b3fb2..62f53232651 100644
--- a/chromium/third_party/blink/common/origin_trials/trial_token_validator.cc
+++ b/chromium/third_party/blink/common/origin_trials/trial_token_validator.cc
@@ -32,8 +32,12 @@ TrialTokenResult::TrialTokenResult(OriginTrialTokenStatus status)
: status(status) {}
TrialTokenResult::TrialTokenResult(OriginTrialTokenStatus status,
std::string name,
- base::Time expiry)
- : status(status), feature_name(name), expiry_time(expiry) {}
+ base::Time expiry,
+ bool is_third_party)
+ : status(status),
+ feature_name(name),
+ expiry_time(expiry),
+ is_third_party(is_third_party) {}
TrialTokenResult::~TrialTokenResult() = default;
TrialTokenValidator::TrialTokenValidator() {}
@@ -58,6 +62,14 @@ TrialTokenResult TrialTokenValidator::ValidateToken(
base::StringPiece token,
const url::Origin& origin,
base::Time current_time) const {
+ return ValidateToken(token, origin, nullptr, current_time);
+}
+
+TrialTokenResult TrialTokenValidator::ValidateToken(
+ base::StringPiece token,
+ const url::Origin& origin,
+ const url::Origin* third_party_origin,
+ base::Time current_time) const {
OriginTrialPolicy* policy = Policy();
if (!policy->IsOriginTrialsSupported())
@@ -78,7 +90,18 @@ TrialTokenResult TrialTokenValidator::ValidateToken(
if (status != OriginTrialTokenStatus::kSuccess)
return TrialTokenResult(status);
- status = trial_token->IsValid(origin, current_time);
+ // If the third_party flag is set on the token, we match it against third
+ // party origin if it exists. Otherwise match against document origin.
+ if (trial_token->is_third_party()) {
+ if (third_party_origin) {
+ status = trial_token->IsValid(*third_party_origin, current_time);
+ } else {
+ status = OriginTrialTokenStatus::kWrongOrigin;
+ }
+ } else {
+ status = trial_token->IsValid(origin, current_time);
+ }
+
if (status != OriginTrialTokenStatus::kSuccess)
return TrialTokenResult(status);
@@ -88,8 +111,15 @@ TrialTokenResult TrialTokenValidator::ValidateToken(
if (policy->IsTokenDisabled(trial_token->signature()))
return TrialTokenResult(OriginTrialTokenStatus::kTokenDisabled);
+ if (trial_token->is_third_party() &&
+ trial_token->usage_restriction() ==
+ TrialToken::UsageRestriction::kSubset &&
+ policy->IsFeatureDisabledForUser(trial_token->feature_name()))
+ return TrialTokenResult(OriginTrialTokenStatus::kFeatureDisabledForUser);
+
return TrialTokenResult(status, trial_token->feature_name(),
- trial_token->expiry_time());
+ trial_token->expiry_time(),
+ trial_token->is_third_party());
}
bool TrialTokenValidator::RequestEnablesFeature(const net::URLRequest* request,
diff --git a/chromium/third_party/blink/common/origin_trials/trial_token_validator_unittest.cc b/chromium/third_party/blink/common/origin_trials/trial_token_validator_unittest.cc
index ee53ace58da..8433c9e6309 100644
--- a/chromium/third_party/blink/common/origin_trials/trial_token_validator_unittest.cc
+++ b/chromium/third_party/blink/common/origin_trials/trial_token_validator_unittest.cc
@@ -101,6 +101,7 @@ const char kSampleToken2[] =
// The token should be valid for this origin and for this feature.
const char kAppropriateOrigin[] = "https://valid.example.com";
const char kAppropriateFeatureName[] = "Frobulate";
+const char kAppropriateThirdPartyFeatureName[] = "FrobulateThirdParty";
const char kInappropriateFeatureName[] = "Grokalyze";
const char kInappropriateOrigin[] = "https://invalid.example.com";
@@ -142,6 +143,30 @@ const char kInsecureOriginToken[] =
"YW1wbGUuY29tOjgwIiwgImZlYXR1cmUiOiAiRnJvYnVsYXRlIiwgImV4cGlyeSI6"
"IDIwMDAwMDAwMDB9";
+// Well-formed token, for match against third party origins.
+// Generate this token with the command (in tools/origin_trials):
+// generate_token.py 3 valid.example.com Frobulate
+// --is-third-party --expire-timestamp=2000000000
+const char kThirdPartyToken[] =
+ "A8ZESIWJHtuoIZyWgaHUPEhuc4CnbiETy5D4"
+ "PeABEP8NB8oI2fUfF9N53elgnNuyL0ltq+fzMta1pgU3VYLyuAcAAABveyJvcmln"
+ "aW4iOiAiaHR0cHM6Ly92YWxpZC5leGFtcGxlLmNvbTo0NDMiLCAiaXNUaGlyZFBh"
+ "cnR5IjogdHJ1ZSwgImZlYXR1cmUiOiAiRnJvYnVsYXRlIiwgImV4cGlyeSI6IDIw"
+ "MDAwMDAwMDB9";
+
+// Well-formed token, for match against third party origins and its usage
+// set to user subset exclusion.
+// Generate this token with the command (in tools/origin_trials):
+// generate_token.py valid.example.com FrobulateThirdParty
+// --version 3 --is-third-party --usage-restriction subset
+// --expire-timestamp=2000000000
+const char kThirdPartyUsageSubsetToken[] =
+ "A3mGpVqzEea9V9Nl6Qr2LS84PxTf2ZnWdtU6cNZvGmX1rRX5khvJSYuYSCP0J8Ca"
+ "XLG+MH6jT+3IH7CWVASK0gcAAACMeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5l"
+ "eGFtcGxlLmNvbTo0NDMiLCAiaXNUaGlyZFBhcnR5IjogdHJ1ZSwgInVzYWdlIjog"
+ "InN1YnNldCIsICJmZWF0dXJlIjogIkZyb2J1bGF0ZVRoaXJkUGFydHkiLCAiZXhw"
+ "aXJ5IjogMjAwMDAwMDAwMH0=";
+
// This timestamp is set to a time after the expiry timestamp of kExpiredToken,
// but before the expiry timestamp of kValidToken.
double kNowTimestamp = 1500000000;
@@ -159,6 +184,10 @@ class TestOriginTrialPolicy : public OriginTrialPolicy {
return disabled_features_.count(feature.as_string()) > 0;
}
+ bool IsFeatureDisabledForUser(base::StringPiece feature) const override {
+ return disabled_features_for_user_.count(feature.as_string()) > 0;
+ }
+
// Test setup methods
void SetPublicKeys(const uint8_t keys[][32], const int keys_size) {
keys_.clear();
@@ -170,6 +199,9 @@ class TestOriginTrialPolicy : public OriginTrialPolicy {
void DisableFeature(const std::string& feature) {
disabled_features_.insert(feature);
}
+ void DisableFeatureForUser(const std::string& feature) {
+ disabled_features_for_user_.insert(feature);
+ }
void DisableToken(const std::string& token) {
disabled_tokens_.insert(token);
}
@@ -182,6 +214,7 @@ class TestOriginTrialPolicy : public OriginTrialPolicy {
private:
std::vector<base::StringPiece> keys_;
std::set<std::string> disabled_features_;
+ std::set<std::string> disabled_features_for_user_;
std::set<std::string> disabled_tokens_;
};
@@ -216,6 +249,10 @@ class TrialTokenValidatorTest : public testing::Test {
policy_.DisableFeature(feature);
}
+ void DisableFeatureForUser(const std::string& feature) {
+ policy_.DisableFeatureForUser(feature);
+ }
+
void DisableToken(const std::string& token_signature) {
policy_.DisableToken(token_signature);
}
@@ -241,12 +278,40 @@ TEST_F(TrialTokenValidatorTest, ValidateValidToken) {
EXPECT_EQ(blink::OriginTrialTokenStatus::kSuccess, result.status);
EXPECT_EQ(kAppropriateFeatureName, result.feature_name);
EXPECT_EQ(kSampleTokenExpiryTime, result.expiry_time);
+ EXPECT_EQ(false, result.is_third_party);
// All signing keys should be able to validate their tokens.
result = validator_.ValidateToken(kSampleToken2, appropriate_origin_, Now());
EXPECT_EQ(blink::OriginTrialTokenStatus::kSuccess, result.status);
EXPECT_EQ(kAppropriateFeatureName, result.feature_name);
EXPECT_EQ(kSampleTokenExpiryTime, result.expiry_time);
+ EXPECT_EQ(false, result.is_third_party);
+}
+
+TEST_F(TrialTokenValidatorTest, ValidateThirdPartyTokenFromExternalScript) {
+ TrialTokenResult result = validator_.ValidateToken(
+ kThirdPartyToken, inappropriate_origin_, &appropriate_origin_, Now());
+ EXPECT_EQ(blink::OriginTrialTokenStatus::kSuccess, result.status);
+ EXPECT_EQ(kAppropriateFeatureName, result.feature_name);
+ EXPECT_EQ(kSampleTokenExpiryTime, result.expiry_time);
+ EXPECT_EQ(true, result.is_third_party);
+}
+
+TEST_F(TrialTokenValidatorTest,
+ ValidateThirdPartyTokenFromInappropriateScriptOrigin) {
+ EXPECT_EQ(blink::OriginTrialTokenStatus::kWrongOrigin,
+ validator_
+ .ValidateToken(kThirdPartyToken, appropriate_origin_,
+ &inappropriate_origin_, Now())
+ .status);
+}
+
+TEST_F(TrialTokenValidatorTest, ValidateThirdPartyTokenNotFromExternalScript) {
+ EXPECT_EQ(
+ blink::OriginTrialTokenStatus::kWrongOrigin,
+ validator_
+ .ValidateToken(kThirdPartyToken, appropriate_origin_, nullptr, Now())
+ .status);
}
TEST_F(TrialTokenValidatorTest, ValidateInappropriateOrigin) {
@@ -308,6 +373,24 @@ TEST_F(TrialTokenValidatorTest, ValidatorRespectsDisabledFeatures) {
.status);
}
+TEST_F(TrialTokenValidatorTest, ValidatorRespectsDisabledFeaturesForUser) {
+ // Token should be valid if the feature is not disabled for user.
+ TrialTokenResult result = validator_.ValidateToken(
+ kThirdPartyUsageSubsetToken, inappropriate_origin_, &appropriate_origin_,
+ Now());
+ EXPECT_EQ(blink::OriginTrialTokenStatus::kSuccess, result.status);
+ EXPECT_EQ(kAppropriateThirdPartyFeatureName, result.feature_name);
+ EXPECT_EQ(kSampleTokenExpiryTime, result.expiry_time);
+ // Token should be invalid when the feature is disabled for user.
+ DisableFeatureForUser(kAppropriateThirdPartyFeatureName);
+ EXPECT_EQ(
+ blink::OriginTrialTokenStatus::kFeatureDisabledForUser,
+ validator_
+ .ValidateToken(kThirdPartyUsageSubsetToken, inappropriate_origin_,
+ &appropriate_origin_, Now())
+ .status);
+}
+
TEST_F(TrialTokenValidatorTest, ValidatorRespectsDisabledTokens) {
TrialTokenResult result =
validator_.ValidateToken(kSampleToken, appropriate_origin_, Now());
diff --git a/chromium/third_party/blink/common/page/OWNERS b/chromium/third_party/blink/common/page/OWNERS
new file mode 100644
index 00000000000..d5fefd82012
--- /dev/null
+++ b/chromium/third_party/blink/common/page/OWNERS
@@ -0,0 +1,2 @@
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/third_party/blink/common/page/drag_mojom_traits.cc b/chromium/third_party/blink/common/page/drag_mojom_traits.cc
new file mode 100644
index 00000000000..54dc3f1e7a2
--- /dev/null
+++ b/chromium/third_party/blink/common/page/drag_mojom_traits.cc
@@ -0,0 +1,101 @@
+// Copyright 2020 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/public/common/page/drag_mojom_traits.h"
+
+#include "base/notreached.h"
+
+namespace {
+
+constexpr int allow_all =
+ blink::kWebDragOperationCopy | blink::kWebDragOperationLink |
+ blink::kWebDragOperationGeneric | blink::kWebDragOperationPrivate |
+ blink::kWebDragOperationMove | blink::kWebDragOperationDelete;
+
+} // namespace
+
+namespace mojo {
+
+// static
+blink::mojom::DragOperation
+EnumTraits<blink::mojom::DragOperation, blink::WebDragOperation>::ToMojom(
+ blink::WebDragOperation op) {
+ switch (op) {
+ case blink::kWebDragOperationNone:
+ return blink::mojom::DragOperation::kNone;
+ case blink::kWebDragOperationCopy:
+ return blink::mojom::DragOperation::kCopy;
+ case blink::kWebDragOperationLink:
+ return blink::mojom::DragOperation::kLink;
+ case blink::kWebDragOperationGeneric:
+ return blink::mojom::DragOperation::kGeneric;
+ case blink::kWebDragOperationPrivate:
+ return blink::mojom::DragOperation::kPrivate;
+ case blink::kWebDragOperationMove:
+ return blink::mojom::DragOperation::kMove;
+ case blink::kWebDragOperationDelete:
+ return blink::mojom::DragOperation::kDelete;
+ default:
+ // blink::kWebDragOperationEvery is not handled on purpose, as
+ // DragOperation should only represent a single operation.
+ NOTREACHED();
+ return blink::mojom::DragOperation::kNone;
+ }
+}
+
+// static
+bool EnumTraits<blink::mojom::DragOperation, blink::WebDragOperation>::
+ FromMojom(blink::mojom::DragOperation op, blink::WebDragOperation* out) {
+ switch (op) {
+ case blink::mojom::DragOperation::kNone:
+ *out = blink::kWebDragOperationNone;
+ return true;
+ case blink::mojom::DragOperation::kCopy:
+ *out = blink::kWebDragOperationCopy;
+ return true;
+ case blink::mojom::DragOperation::kLink:
+ *out = blink::kWebDragOperationLink;
+ return true;
+ case blink::mojom::DragOperation::kGeneric:
+ *out = blink::kWebDragOperationGeneric;
+ return true;
+ case blink::mojom::DragOperation::kPrivate:
+ *out = blink::kWebDragOperationPrivate;
+ return true;
+ case blink::mojom::DragOperation::kMove:
+ *out = blink::kWebDragOperationMove;
+ return true;
+ case blink::mojom::DragOperation::kDelete:
+ *out = blink::kWebDragOperationDelete;
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+// static
+bool StructTraits<blink::mojom::AllowedDragOperationsDataView,
+ blink::WebDragOperationsMask>::
+ Read(blink::mojom::AllowedDragOperationsDataView data,
+ blink::WebDragOperationsMask* out) {
+ int op_mask = blink::kWebDragOperationNone;
+ if (data.allow_copy())
+ op_mask |= blink::kWebDragOperationCopy;
+ if (data.allow_link())
+ op_mask |= blink::kWebDragOperationLink;
+ if (data.allow_generic())
+ op_mask |= blink::kWebDragOperationGeneric;
+ if (data.allow_private())
+ op_mask |= blink::kWebDragOperationPrivate;
+ if (data.allow_move())
+ op_mask |= blink::kWebDragOperationMove;
+ if (data.allow_delete())
+ op_mask |= blink::kWebDragOperationDelete;
+ if (op_mask == allow_all)
+ op_mask = blink::kWebDragOperationEvery;
+ *out = static_cast<blink::WebDragOperationsMask>(op_mask);
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/third_party/blink/common/peerconnection/OWNERS b/chromium/third_party/blink/common/peerconnection/OWNERS
new file mode 100644
index 00000000000..5ab7d5845f7
--- /dev/null
+++ b/chromium/third_party/blink/common/peerconnection/OWNERS
@@ -0,0 +1,4 @@
+file://third_party/blink/renderer/modules/peerconnection/OWNERS
+
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/third_party/blink/common/peerconnection/peer_connection_tracker_mojom_traits.cc b/chromium/third_party/blink/common/peerconnection/peer_connection_tracker_mojom_traits.cc
new file mode 100644
index 00000000000..030a61e64db
--- /dev/null
+++ b/chromium/third_party/blink/common/peerconnection/peer_connection_tracker_mojom_traits.cc
@@ -0,0 +1,58 @@
+// Copyright 2020 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/public/common/peerconnection/peer_connection_tracker_mojom_traits.h"
+
+#include "base/notreached.h"
+
+namespace mojo {
+
+// static
+blink::mojom::DeviceThermalState
+EnumTraits<blink::mojom::DeviceThermalState,
+ base::PowerObserver::DeviceThermalState>::
+ ToMojom(base::PowerObserver::DeviceThermalState type) {
+ switch (type) {
+ case base::PowerObserver::DeviceThermalState::kUnknown:
+ return blink::mojom::DeviceThermalState::kUnknown;
+ case base::PowerObserver::DeviceThermalState::kNominal:
+ return blink::mojom::DeviceThermalState::kNominal;
+ case base::PowerObserver::DeviceThermalState::kFair:
+ return blink::mojom::DeviceThermalState::kFair;
+ case base::PowerObserver::DeviceThermalState::kSerious:
+ return blink::mojom::DeviceThermalState::kSerious;
+ case base::PowerObserver::DeviceThermalState::kCritical:
+ return blink::mojom::DeviceThermalState::kCritical;
+ }
+ NOTREACHED();
+ return blink::mojom::DeviceThermalState::kUnknown;
+}
+
+// static
+bool EnumTraits<blink::mojom::DeviceThermalState,
+ base::PowerObserver::DeviceThermalState>::
+ FromMojom(blink::mojom::DeviceThermalState input,
+ base::PowerObserver::DeviceThermalState* out) {
+ switch (input) {
+ case blink::mojom::DeviceThermalState::kUnknown:
+ *out = base::PowerObserver::DeviceThermalState::kUnknown;
+ return true;
+ case blink::mojom::DeviceThermalState::kNominal:
+ *out = base::PowerObserver::DeviceThermalState::kNominal;
+ return true;
+ case blink::mojom::DeviceThermalState::kFair:
+ *out = base::PowerObserver::DeviceThermalState::kFair;
+ return true;
+ case blink::mojom::DeviceThermalState::kSerious:
+ *out = base::PowerObserver::DeviceThermalState::kSerious;
+ return true;
+ case blink::mojom::DeviceThermalState::kCritical:
+ *out = base::PowerObserver::DeviceThermalState::kCritical;
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+} // namespace mojo
diff --git a/chromium/third_party/blink/common/privacy_budget/BUILD.gn b/chromium/third_party/blink/common/privacy_budget/BUILD.gn
new file mode 100644
index 00000000000..975c6672e73
--- /dev/null
+++ b/chromium/third_party/blink/common/privacy_budget/BUILD.gn
@@ -0,0 +1,65 @@
+# Copyright 2020 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("//testing/libfuzzer/fuzzer_test.gni")
+
+source_set("privacy_budget") {
+ configs += [ "//third_party/blink/common:blink_common_implementation" ]
+
+ sources = [
+ "identifiability_metric_builder.cc",
+ "identifiability_metrics.cc",
+ "identifiability_study_participation.cc",
+ "identifiability_study_settings.cc",
+ "identifiable_token_builder.cc",
+ ]
+
+ deps = [
+ "//base",
+ "//services/metrics/public/cpp:ukm_builders",
+ "//services/metrics/public/mojom",
+ "//third_party/blink/public/common/privacy_budget:privacy_budget",
+ "//third_party/blink/public/mojom:web_feature_mojo_bindings",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+
+ sources = [
+ "identifiability_internal_templates_unittest.cc",
+ "identifiability_metric_builder_unittest.cc",
+ "identifiability_metrics_unittest.cc",
+ "identifiability_study_settings_unittest.cc",
+ "identifiable_surface_unittest.cc",
+ "identifiable_token_builder_unittest.cc",
+ "identifiable_token_unittest.cc",
+ ]
+
+ deps = [
+ "//base",
+ "//services/metrics/public/cpp:metrics_cpp",
+ "//services/metrics/public/cpp:ukm_builders",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//third_party/blink/public/common",
+ "//third_party/blink/public/common/privacy_budget:internal",
+ ]
+}
+
+fuzzer_test("identifiable_token_builder_fuzzer") {
+ sources = [ "identifiable_token_builder_fuzzer.cc" ]
+ deps = [
+ "//base",
+ "//third_party/blink/public/common",
+ ]
+}
+
+fuzzer_test("identifiable_token_builder_atomic_fuzzer") {
+ sources = [ "identifiable_token_builder_atomic_fuzzer.cc" ]
+ deps = [
+ "//base",
+ "//third_party/blink/public/common",
+ ]
+}
diff --git a/chromium/third_party/blink/common/privacy_budget/README.md b/chromium/third_party/blink/common/privacy_budget/README.md
new file mode 100644
index 00000000000..8b9efcc0093
--- /dev/null
+++ b/chromium/third_party/blink/common/privacy_budget/README.md
@@ -0,0 +1,6 @@
+# Privacy Budget: Core Metrics and Aggregation
+
+See [Privacy Budget: Code
+Locations](../../../../docs/privacy_budget_code_locations.md) for
+details.
+
diff --git a/chromium/third_party/blink/common/privacy_budget/identifiability_internal_templates_unittest.cc b/chromium/third_party/blink/common/privacy_budget/identifiability_internal_templates_unittest.cc
new file mode 100644
index 00000000000..048b4586818
--- /dev/null
+++ b/chromium/third_party/blink/common/privacy_budget/identifiability_internal_templates_unittest.cc
@@ -0,0 +1,107 @@
+// Copyright 2020 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/public/common/privacy_budget/identifiability_internal_templates.h"
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+namespace internal {
+namespace {
+
+struct PodType {
+ int x;
+ float y;
+ char c;
+ char g[10];
+};
+
+#if !defined(ARCH_CPU_LITTLE_ENDIAN) && !defined(ARCH_CPU_BIG_ENDIAN)
+#error "What kind of CPU is this?"
+#endif
+
+} // namespace
+
+// remove_cvref_t
+static_assert(std::is_same<int, remove_cvref_t<const int>>::value, "");
+static_assert(std::is_same<int, remove_cvref_t<const volatile int>>::value, "");
+static_assert(std::is_same<int, remove_cvref_t<int&>>::value, "");
+static_assert(std::is_same<int, remove_cvref_t<const int&>>::value, "");
+static_assert(std::is_same<int, remove_cvref_t<const volatile int&>>::value,
+ "");
+static_assert(std::is_same<int, remove_cvref_t<int&&>>::value, "");
+static_assert(std::is_same<PodType, remove_cvref_t<const PodType&>>::value, "");
+static_assert(std::is_same<int*, remove_cvref_t<int*>>::value, "");
+
+// has_unique_object_representations
+static_assert(has_unique_object_representations<int>::value, "");
+static_assert(has_unique_object_representations<float>::value, "");
+static_assert(has_unique_object_representations<double>::value, "");
+
+// long double: check_blink_style doesn't let us use the word 'long' here.
+static_assert(has_unique_object_representations<decltype(1.0l)>::value, "");
+
+// Pointers aren't considered to have a unique representation.
+static_assert(!has_unique_object_representations<int*>::value, "");
+
+// Nor are POD types though they could be if they are dense and don't have any
+// internal padding.
+static_assert(!has_unique_object_representations<PodType>::value, "");
+
+TEST(IdentifiabilityInternalTemplatesTest, DigestOfObjectRepresentation) {
+ const int kV = 5;
+ const int& kRV = kV;
+ const volatile int& kRVV = kV;
+
+ // Note that both little and big endian systems produce the same result from
+ // DigestOfObjectRepresentation();
+
+ // Positive unsigned integers.
+ EXPECT_EQ(INT64_C(5), DigestOfObjectRepresentation(UINT8_C(5)));
+ EXPECT_EQ(INT64_C(5), DigestOfObjectRepresentation(UINT16_C(5)));
+ EXPECT_EQ(INT64_C(5), DigestOfObjectRepresentation(UINT32_C(5)));
+ EXPECT_EQ(INT64_C(5), DigestOfObjectRepresentation(UINT64_C(5)));
+
+ // Positive signed integers.
+ EXPECT_EQ(INT64_C(5), DigestOfObjectRepresentation(INT8_C(5)));
+ EXPECT_EQ(INT64_C(5), DigestOfObjectRepresentation(INT16_C(5)));
+ EXPECT_EQ(INT64_C(5), DigestOfObjectRepresentation(INT32_C(5)));
+ EXPECT_EQ(INT64_C(5), DigestOfObjectRepresentation(INT64_C(5)));
+ // char
+ EXPECT_EQ(INT64_C(65), DigestOfObjectRepresentation('A'));
+
+ // Negative integers.
+ EXPECT_EQ(INT64_C(-5), DigestOfObjectRepresentation(INT8_C(-5)));
+ EXPECT_EQ(INT64_C(-5), DigestOfObjectRepresentation(INT16_C(-5)));
+ EXPECT_EQ(INT64_C(-5), DigestOfObjectRepresentation(INT32_C(-5)));
+ EXPECT_EQ(INT64_C(-5), DigestOfObjectRepresentation(INT64_C(-5)));
+
+ // Large unsigned integer. These wrap around for 2s complement arithmetic.
+ EXPECT_EQ(INT64_C(-1),
+ DigestOfObjectRepresentation(std::numeric_limits<uint64_t>::max()));
+
+ // CV qualified types should be unwrapped.
+ EXPECT_EQ(INT64_C(5), DigestOfObjectRepresentation(kV));
+ EXPECT_EQ(INT64_C(5), DigestOfObjectRepresentation(kRV));
+ EXPECT_EQ(INT64_C(5), DigestOfObjectRepresentation(kRVV));
+}
+
+TEST(IdentifiabilityInternalTemplatesTest,
+ DigestOfObjectRepresentation_Floats) {
+ // IEEE 754 32-bit single precision float.
+ if (sizeof(float) == 4)
+ EXPECT_EQ(INT64_C(1069547520), DigestOfObjectRepresentation(1.5f));
+
+ // IEEE 754 64-bit double precision float.
+ if (sizeof(double) == 8)
+ EXPECT_EQ(INT64_C(4609434218613702656), DigestOfObjectRepresentation(1.5));
+}
+
+} // namespace internal
+} // namespace blink
diff --git a/chromium/third_party/blink/common/privacy_budget/identifiability_metric_builder.cc b/chromium/third_party/blink/common/privacy_budget/identifiability_metric_builder.cc
index 1b6eee8d3f7..45fe183a4c0 100644
--- a/chromium/third_party/blink/common/privacy_budget/identifiability_metric_builder.cc
+++ b/chromium/third_party/blink/common/privacy_budget/identifiability_metric_builder.cc
@@ -18,8 +18,8 @@ IdentifiabilityMetricBuilder::~IdentifiabilityMetricBuilder() = default;
IdentifiabilityMetricBuilder& IdentifiabilityMetricBuilder::Set(
IdentifiableSurface surface,
- int64_t value) {
- SetMetricInternal(surface.ToUkmMetricHash(), value);
+ IdentifiableToken value) {
+ SetMetricInternal(surface.ToUkmMetricHash(), value.value_);
return *this;
}
diff --git a/chromium/third_party/blink/common/privacy_budget/identifiability_metric_builder_unittest.cc b/chromium/third_party/blink/common/privacy_budget/identifiability_metric_builder_unittest.cc
index d923c8040e7..2d206d31d8b 100644
--- a/chromium/third_party/blink/common/privacy_budget/identifiability_metric_builder_unittest.cc
+++ b/chromium/third_party/blink/common/privacy_budget/identifiability_metric_builder_unittest.cc
@@ -4,9 +4,15 @@
#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
+#include <cinttypes>
+#include <limits>
+
#include "base/metrics/ukm_source_id.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom.h"
@@ -74,4 +80,138 @@ TEST(IdentifiabilityMetricBuilderTest, SetWebfeature) {
EXPECT_EQ(entry->metrics, expected_entry->metrics);
}
+namespace {
+
+MATCHER_P(FirstMetricIs,
+ entry,
+ base::StringPrintf("entry is %s0x%" PRIx64,
+ negation ? "not " : "",
+ entry)) {
+ return arg->metrics.begin()->second == entry;
+} // namespace
+
+enum class Never { kGonna, kGive, kYou, kUp };
+
+constexpr IdentifiableSurface kTestSurface =
+ IdentifiableSurface::FromTypeAndInput(
+ IdentifiableSurface::Type::kReservedInternal,
+ 0);
+
+// Sample values
+const char kAbcd[] = "abcd";
+const int64_t kExpectedHashOfAbcd = -0x08a5c475eb66bd73;
+
+// 5.1f
+const int64_t kExpectedHashOfOnePointFive = 0x3ff8000000000000;
+
+} // namespace
+
+TEST(IdentifiabilityMetricBuilderTest, SetChar) {
+ EXPECT_THAT(IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, 'A')
+ .TakeEntry(),
+ FirstMetricIs(INT64_C(65)));
+}
+
+TEST(IdentifiabilityMetricBuilderTest, SetCharArray) {
+ IdentifiableToken sample(kAbcd);
+ EXPECT_THAT(IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, sample)
+ .TakeEntry(),
+ FirstMetricIs(kExpectedHashOfAbcd));
+}
+
+TEST(IdentifiabilityMetricBuilderTest, SetStringPiece) {
+ // StringPiece() needs an explicit constructor invocation.
+ EXPECT_THAT(
+ IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, IdentifiableToken(base::StringPiece(kAbcd)))
+ .TakeEntry(),
+ FirstMetricIs(kExpectedHashOfAbcd));
+}
+
+TEST(IdentifiabilityMetricBuilderTest, SetStdString) {
+ IdentifiableToken sample((std::string(kAbcd)));
+ EXPECT_THAT(IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, sample)
+ .TakeEntry(),
+ FirstMetricIs(kExpectedHashOfAbcd));
+}
+
+TEST(IdentifiabilityMetricBuilderTest, SetInt) {
+ EXPECT_THAT(IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, -5)
+ .TakeEntry(),
+ FirstMetricIs(INT64_C(-5)));
+}
+
+TEST(IdentifiabilityMetricBuilderTest, SetIntRef) {
+ int x = -5;
+ int& xref = x;
+ EXPECT_THAT(IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, xref)
+ .TakeEntry(),
+ FirstMetricIs(INT64_C(-5)));
+}
+
+TEST(IdentifiabilityMetricBuilderTest, SetIntConstRef) {
+ int x = -5;
+ const int& xref = x;
+ EXPECT_THAT(IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, xref)
+ .TakeEntry(),
+ FirstMetricIs(INT64_C(-5)));
+}
+
+TEST(IdentifiabilityMetricBuilderTest, SetUnsigned) {
+ EXPECT_THAT(IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, 5u)
+ .TakeEntry(),
+ FirstMetricIs(INT64_C(5)));
+}
+
+TEST(IdentifiabilityMetricBuilderTest, SetUint64) {
+ EXPECT_THAT(IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, UINT64_C(5))
+ .TakeEntry(),
+ FirstMetricIs(INT64_C(5)));
+}
+
+TEST(IdentifiabilityMetricBuilderTest, SetBigUnsignedInt) {
+ // Slightly different in that this value cannot be converted into the sample
+ // type without loss. Hence it is digested as raw bytes.
+ EXPECT_THAT(IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, std::numeric_limits<uint64_t>::max())
+ .TakeEntry(),
+ FirstMetricIs(INT64_C(-1)));
+}
+
+TEST(IdentifiabilityMetricBuilderTest, SetFloat) {
+ EXPECT_THAT(IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, 1.5f)
+ .TakeEntry(),
+ FirstMetricIs(kExpectedHashOfOnePointFive));
+}
+
+TEST(IdentifiabilityMetricBuilderTest, SetDouble) {
+ EXPECT_THAT(IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, 1.5l)
+ .TakeEntry(),
+ FirstMetricIs(kExpectedHashOfOnePointFive));
+}
+
+TEST(IdentifiabilityMetricBuilderTest, SetEnum) {
+ EXPECT_THAT(IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, Never::kUp)
+ .TakeEntry(),
+ FirstMetricIs(INT64_C(3)));
+}
+
+TEST(IdentifiabilityMetricBuilderTest, SetParameterPack) {
+ EXPECT_THAT(IdentifiabilityMetricBuilder(base::UkmSourceId{})
+ .Set(kTestSurface, IdentifiableToken(1, 2, 3.0, 4, 'a'))
+ .TakeEntry(),
+ FirstMetricIs(INT64_C(0x672cf4c107b5b22)));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/common/privacy_budget/identifiability_metrics.cc b/chromium/third_party/blink/common/privacy_budget/identifiability_metrics.cc
index 4219d1953b6..a0f71fe74ec 100644
--- a/chromium/third_party/blink/common/privacy_budget/identifiability_metrics.cc
+++ b/chromium/third_party/blink/common/privacy_budget/identifiability_metrics.cc
@@ -6,14 +6,66 @@
#include <cstdint>
-#include "base/hash/hash.h"
+#include "base/containers/span.h"
+#include "base/hash/legacy_hash.h"
namespace blink {
uint64_t IdentifiabilityDigestOfBytes(base::span<const uint8_t> in) {
- // NOTE: As documented at the point of declaration, the digest calculated here
- // should be stable once released.
- return base::PersistentHash(in);
+ // The chosen hash function satisfies the following requirements:
+ //
+ // * Fast. These hashes will need to be calculated during performance
+ // critical code.
+ // * Suitable for fingerprinting. I.e. broad domain, good diffusion, low
+ // collision rate.
+ // * Resistant to hash flooding.
+ // * Able to use the entire 64-bit space we have at our disposal.
+ // * Either support iterative operation or be usable as a primitive for
+ // constructing one.
+ // * Remains stable for the duration of the identifiability study O(months).
+ // This one is trivial. It just means that the hash is not in danger of
+ // imminent change.
+ // * Implemented, well tested, and usable by //content, //chrome, as well
+ // as //blink/common.
+ //
+ // It is not a requirement for the digest to be a cryptographic hash. I.e. not
+ // necessary to deter second-preimage construction.
+ //
+ // base::PersistentHash(): (Rejected)
+ // - Based on SuperFastHash() which doesn't meet the fingerprinting
+ // requirement due to a high collision rate.
+ // - Digest is 32-bits.
+ // - No stateful implementation in //base. Blink's StringHasher is
+ // interestingly a stateful implementation of SuperFastHash but is not
+ // available in //blink/public/common.
+ //
+ // base::legacy::CityHash64{WithSeed}(): (Selected)
+ // - Based on Google's CityHash 1.0.3. Some known weaknesses, but still
+ // good enough.
+ // - No ready-to-use chaining implementation.
+ // + Digest is 64-bits.
+ // + Seeded variant is a useful primitive for a chained hash function.
+ // Would be better if it took two seeds, but one is also usable.
+ //
+ // Other hash functions were considered, but were rejected due to one or more
+ // of the following reasons:
+ // - An implementation was not available.
+ // - The version available has significant known weaknesses.
+ //
+ // One in particular that would have been nice to have is FarmHash.
+ //
+ // CityHash is quite efficient for small buffers. Operation counts are
+ // roughly as follows. For small buffers, fetches dominate.:
+ //
+ // Length │ Fetches │ Muls │ Shifts │
+ // ───────┼──────────┼─────────┼─────────┤
+ // 1..16 │ 3 │ 3 │ 4 │
+ // ───────┼──────────┼─────────┼─────────┤
+ // 17..32 │ 4 │ 3 │ 8 │
+ // ───────┼──────────┼─────────┼─────────┤
+ // 33..64 │ 10 │ 4 │ 18 │
+ // ───────┴──────────┴─────────┴─────────┘
+ return base::legacy::CityHash64(in);
}
} // namespace blink
diff --git a/chromium/third_party/blink/common/privacy_budget/identifiability_metrics_unittest.cc b/chromium/third_party/blink/common/privacy_budget/identifiability_metrics_unittest.cc
index 7f60e3be055..167b92ab804 100644
--- a/chromium/third_party/blink/common/privacy_budget/identifiability_metrics_unittest.cc
+++ b/chromium/third_party/blink/common/privacy_budget/identifiability_metrics_unittest.cc
@@ -4,10 +4,10 @@
#include "third_party/blink/public/common/privacy_budget/identifiability_metrics.h"
-#include "stdint.h"
-
+#include <cstdint>
#include <vector>
+#include "base/strings/string_piece_forward.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
@@ -18,7 +18,7 @@ TEST(IdentifiabilityMetricsTest, IdentifiabilityDigestOfBytes_Basic) {
// Due to our requirement that the digest be stable and persistable, this test
// should always pass once the code reaches the stable branch.
- EXPECT_EQ(UINT64_C(238255523), digest);
+ EXPECT_EQ(UINT64_C(0x7cd845f1db5ad659), digest);
}
TEST(IdentifiabilityMetricsTest, IdentifiabilityDigestOfBytes_Padding) {
@@ -26,8 +26,9 @@ TEST(IdentifiabilityMetricsTest, IdentifiabilityDigestOfBytes_Padding) {
const std::vector<uint8_t> kLong(16 * 1024, 'x');
// Ideally we should be using all 64-bits or at least the 56 LSBs.
- EXPECT_EQ(UINT64_C(2790220116), IdentifiabilityDigestOfBytes(kTwoBytes));
- EXPECT_EQ(UINT64_C(2857827930), IdentifiabilityDigestOfBytes(kLong));
+ EXPECT_EQ(UINT64_C(0xb74c74c9fcf0505a),
+ IdentifiabilityDigestOfBytes(kTwoBytes));
+ EXPECT_EQ(UINT64_C(0x76b3567105dc5253), IdentifiabilityDigestOfBytes(kLong));
}
TEST(IdentifiabilityMetricsTest, IdentifiabilityDigestOfBytes_EdgeCases) {
@@ -35,8 +36,9 @@ TEST(IdentifiabilityMetricsTest, IdentifiabilityDigestOfBytes_EdgeCases) {
const uint8_t kOneByte[] = {1};
// As before, these tests should always pass.
- EXPECT_EQ(0x0u, IdentifiabilityDigestOfBytes(kEmpty));
- EXPECT_EQ(UINT64_C(0x9e76b331), IdentifiabilityDigestOfBytes(kOneByte));
+ EXPECT_EQ(UINT64_C(0x9ae16a3b2f90404f), IdentifiabilityDigestOfBytes(kEmpty));
+ EXPECT_EQ(UINT64_C(0x6209312a69a56947),
+ IdentifiabilityDigestOfBytes(kOneByte));
}
TEST(IdentifiabilityMetricsTest, PassInt) {
@@ -59,7 +61,7 @@ TEST(IdentifiabilityMetricsTest, PassUint16) {
EXPECT_EQ(UINT64_C(5), IdentifiabilityDigestHelper(static_cast<uint16_t>(5)));
}
-TEST(IdentifiabilityMetricsTest, PassSizet) {
+TEST(IdentifiabilityMetricsTest, PassSizeT) {
EXPECT_EQ(UINT64_C(1), IdentifiabilityDigestHelper(sizeof(char)));
}
@@ -78,24 +80,30 @@ TEST(IdentifiabilityMetricsTest, PassEnum) {
EXPECT_EQ(UINT64_C(2730421), IdentifiabilityDigestHelper(kSimpleValue));
}
+namespace {
+
// Use an arbitrary, large number to make accidental matches unlikely.
enum Simple64Enum : uint64_t { kSimple64Value = 4983422 };
+// Use an arbitrary, large number to make accidental matches unlikely.
+enum class SimpleEnumClass { kSimpleValue = 3498249 };
+
+// Use an arbitrary, large number to make accidental matches unlikely.
+enum class SimpleEnumClass64 : uint64_t { kSimple64Value = 4398372 };
+
+constexpr uint64_t kExpectedCombinationResult = UINT64_C(0xa5e30a57547cd49b);
+
+} // namespace
+
TEST(IdentifiabilityMetricsTest, PassEnum64) {
EXPECT_EQ(UINT64_C(4983422), IdentifiabilityDigestHelper(kSimple64Value));
}
-// Use an arbitrary, large number to make accidental matches unlikely.
-enum class SimpleEnumClass { kSimpleValue = 3498249 };
-
TEST(IdentifiabilityMetricsTest, PassEnumClass) {
EXPECT_EQ(UINT64_C(3498249),
IdentifiabilityDigestHelper(SimpleEnumClass::kSimpleValue));
}
-// Use an arbitrary, large number to make accidental matches unlikely.
-enum class SimpleEnumClass64 : uint64_t { kSimple64Value = 4398372 };
-
TEST(IdentifiabilityMetricsTest, PassEnumClass64) {
EXPECT_EQ(UINT64_C(4398372),
IdentifiabilityDigestHelper(SimpleEnumClass64::kSimple64Value));
@@ -103,18 +111,16 @@ TEST(IdentifiabilityMetricsTest, PassEnumClass64) {
TEST(IdentifiabilityMetricsTest, PassSpan) {
const int data[] = {1, 2, 3};
- EXPECT_EQ(UINT64_C(825881411),
+ EXPECT_EQ(UINT64_C(0xb0dd8c7041b0a8bb),
IdentifiabilityDigestHelper(base::make_span(data)));
}
TEST(IdentifiabilityMetricsTest, PassSpanDouble) {
const double data[] = {1.0, 2.0, 3.0};
- EXPECT_EQ(UINT64_C(2487485222),
+ EXPECT_EQ(UINT64_C(0x95f52e9784f9582a),
IdentifiabilityDigestHelper(base::make_span(data)));
}
-constexpr uint64_t kExpectedCombinationResult = 2636419788;
-
TEST(IdentifiabilityMetricsTest, Combination) {
const int data[] = {1, 2, 3};
EXPECT_EQ(kExpectedCombinationResult,
diff --git a/chromium/third_party/blink/common/privacy_budget/identifiability_study_participation.cc b/chromium/third_party/blink/common/privacy_budget/identifiability_study_participation.cc
index 713bac426e2..776a3eae04f 100644
--- a/chromium/third_party/blink/common/privacy_budget/identifiability_study_participation.cc
+++ b/chromium/third_party/blink/common/privacy_budget/identifiability_study_participation.cc
@@ -4,11 +4,12 @@
#include "third_party/blink/public/common/privacy_budget/identifiability_study_participation.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
+
namespace blink {
bool IsUserInIdentifiabilityStudy() {
- // TODO(crbug.com/973801): Implement.
- return false;
+ return IdentifiabilityStudySettings::Get()->IsActive();
}
} // namespace blink
diff --git a/chromium/third_party/blink/common/privacy_budget/identifiability_study_settings.cc b/chromium/third_party/blink/common/privacy_budget/identifiability_study_settings.cc
new file mode 100644
index 00000000000..a89af1f0921
--- /dev/null
+++ b/chromium/third_party/blink/common/privacy_budget/identifiability_study_settings.cc
@@ -0,0 +1,139 @@
+// Copyright 2020 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/public/common/privacy_budget/identifiability_study_settings.h"
+
+#include "base/check.h"
+#include "base/compiler_specific.h"
+#include "base/no_destructor.h"
+#include "base/optional.h"
+#include "base/synchronization/atomic_flag.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings_provider.h"
+
+namespace blink {
+
+namespace {
+
+// IdentifiabilityStudySettings is meant to be used as a global singleton. Its
+// use is subject to the following constraints.
+//
+// 1. The embedder should be able to set the
+// IdentifiabilityStudySettingsProvider at any point during execution. This
+// relaxation allows the embedder to perform any required initialization
+// without blocking process startup.
+//
+// 2. Get() and the returned IdentifiabilityStudySettings instance should be
+// usable from any thread. The returned object must always be well
+// formed with an infinite lifetime.
+//
+// 3. Calling Get() "prior" to the embedder calling SetProvider() should be
+// harmless and non-blocking.
+//
+// 4. Be fast.
+class ThreadsafeSettingsWrapper {
+ public:
+ ThreadsafeSettingsWrapper() = default;
+
+ const IdentifiabilityStudySettings* GetSettings() {
+ // Access to initialized_settings_ is behind a memory barrier used for
+ // accessing the atomic flag |initialized_|. The state of
+ // |initialized_settings_| is consistent due to the acquire-release
+ // semantics enforced by |AtomicFlag|. I.e. writes prior to
+ // AtomicFlag::Set() is visible after a AtomicFlag::IsSet() which returns
+ // true.
+ //
+ // If the flag is not set, then |default_settings_| can be used instead.
+ //
+ // In either case, the returned pointer...
+ // 1. ... Points to a well formed IdentifiabilityStudySettings object.
+ // 2. ... Is valid for the remainder of the process lifetime.
+ // 3. ... Is safe to use from any thread.
+ if (!initialized_.IsSet())
+ return &default_settings_;
+ return &initialized_settings_.value();
+ }
+
+ // Same restrictions as IdentifiabilityStudySettings::SetGlobalProvider().
+ void SetProvider(
+ std::unique_ptr<IdentifiabilityStudySettingsProvider> provider) {
+ DCHECK(!initialized_.IsSet());
+ initialized_settings_.emplace(std::move(provider));
+ initialized_.Set();
+ }
+
+ void ResetStateForTesting() {
+ initialized_settings_.reset();
+ initialized_.UnsafeResetForTesting();
+ }
+
+ // Function local static initializer is initialized in a threadsafe manner.
+ // This object itself is cheap to construct.
+ static ThreadsafeSettingsWrapper* GetWrapper() {
+ static base::NoDestructor<ThreadsafeSettingsWrapper> wrapper;
+ return wrapper.get();
+ }
+
+ private:
+ base::Optional<IdentifiabilityStudySettings> initialized_settings_;
+ const IdentifiabilityStudySettings default_settings_;
+ base::AtomicFlag initialized_;
+};
+
+} // namespace
+
+IdentifiabilityStudySettingsProvider::~IdentifiabilityStudySettingsProvider() =
+ default;
+
+IdentifiabilityStudySettings::IdentifiabilityStudySettings() = default;
+
+IdentifiabilityStudySettings::IdentifiabilityStudySettings(
+ std::unique_ptr<IdentifiabilityStudySettingsProvider> provider)
+ : provider_(std::move(provider)),
+ is_enabled_(provider_->IsActive()),
+ is_any_surface_or_type_blocked_(provider_->IsAnyTypeOrSurfaceBlocked()) {}
+
+IdentifiabilityStudySettings::~IdentifiabilityStudySettings() = default;
+
+// static
+const IdentifiabilityStudySettings* IdentifiabilityStudySettings::Get() {
+ return ThreadsafeSettingsWrapper::GetWrapper()->GetSettings();
+}
+
+// static
+void IdentifiabilityStudySettings::SetGlobalProvider(
+ std::unique_ptr<IdentifiabilityStudySettingsProvider> provider) {
+ ThreadsafeSettingsWrapper::GetWrapper()->SetProvider(std::move(provider));
+}
+
+void IdentifiabilityStudySettings::ResetStateForTesting() {
+ ThreadsafeSettingsWrapper::GetWrapper()->ResetStateForTesting();
+}
+
+bool IdentifiabilityStudySettings::IsActive() const {
+ return is_enabled_;
+}
+
+bool IdentifiabilityStudySettings::IsSurfaceAllowed(
+ IdentifiableSurface surface) const {
+ if (LIKELY(!is_enabled_))
+ return false;
+
+ if (LIKELY(!is_any_surface_or_type_blocked_))
+ return true;
+
+ return provider_->IsSurfaceAllowed(surface);
+}
+
+bool IdentifiabilityStudySettings::IsTypeAllowed(
+ IdentifiableSurface::Type type) const {
+ if (LIKELY(!is_enabled_))
+ return false;
+
+ if (LIKELY(!is_any_surface_or_type_blocked_))
+ return true;
+
+ return provider_->IsTypeAllowed(type);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/common/privacy_budget/identifiability_study_settings_unittest.cc b/chromium/third_party/blink/common/privacy_budget/identifiability_study_settings_unittest.cc
new file mode 100644
index 00000000000..e134197c63b
--- /dev/null
+++ b/chromium/third_party/blink/common/privacy_budget/identifiability_study_settings_unittest.cc
@@ -0,0 +1,144 @@
+// Copyright 2020 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/public/common/privacy_budget/identifiability_study_settings.h"
+#include <memory>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings_provider.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
+
+namespace blink {
+
+namespace {
+
+struct CallCounts {
+ bool response_for_is_active = false;
+ bool response_for_is_anything_blocked = false;
+ bool response_for_is_allowed = false;
+
+ int count_of_is_active = 0;
+ int count_of_is_any_type_or_surface_blocked = 0;
+ int count_of_is_surface_allowed = 0;
+ int count_of_is_type_allowed = 0;
+};
+
+class CountingSettingsProvider : public IdentifiabilityStudySettingsProvider {
+ public:
+ explicit CountingSettingsProvider(CallCounts* state) : state_(state) {}
+
+ bool IsActive() const override {
+ ++state_->count_of_is_active;
+ return state_->response_for_is_active;
+ }
+
+ bool IsAnyTypeOrSurfaceBlocked() const override {
+ ++state_->count_of_is_any_type_or_surface_blocked;
+ return state_->response_for_is_anything_blocked;
+ }
+
+ bool IsSurfaceAllowed(IdentifiableSurface surface) const override {
+ ++state_->count_of_is_surface_allowed;
+ return state_->response_for_is_allowed;
+ }
+
+ bool IsTypeAllowed(IdentifiableSurface::Type type) const override {
+ ++state_->count_of_is_type_allowed;
+ return state_->response_for_is_allowed;
+ }
+
+ private:
+ CallCounts* state_ = nullptr;
+};
+
+} // namespace
+
+TEST(IdentifiabilityStudySettingsTest, DisabledProvider) {
+ CallCounts counts{.response_for_is_active = false};
+
+ IdentifiabilityStudySettings settings(
+ std::make_unique<CountingSettingsProvider>(&counts));
+ EXPECT_EQ(1, counts.count_of_is_active);
+ EXPECT_EQ(1, counts.count_of_is_any_type_or_surface_blocked);
+
+ EXPECT_FALSE(settings.IsActive());
+ EXPECT_EQ(1, counts.count_of_is_active);
+ EXPECT_FALSE(settings.IsSurfaceAllowed(IdentifiableSurface()));
+ EXPECT_EQ(1, counts.count_of_is_active);
+ EXPECT_FALSE(
+ settings.IsTypeAllowed(IdentifiableSurface::Type::kCanvasReadback));
+
+ // None of these should have been called.
+ EXPECT_EQ(0, counts.count_of_is_surface_allowed);
+ EXPECT_EQ(0, counts.count_of_is_type_allowed);
+}
+
+TEST(IdentifiabilityStudySettingsTest, IsActiveButNothingIsBlocked) {
+ CallCounts counts{.response_for_is_active = true,
+ .response_for_is_anything_blocked = false,
+
+ // Note that this contradicts the above, but it shouldn't
+ // matter since Is*Blocked() should not be called at all.
+ .response_for_is_allowed = true};
+
+ IdentifiabilityStudySettings settings(
+ std::make_unique<CountingSettingsProvider>(&counts));
+
+ // No other calls should be made.
+ EXPECT_TRUE(settings.IsActive());
+ EXPECT_TRUE(settings.IsSurfaceAllowed(IdentifiableSurface()));
+ EXPECT_TRUE(settings.IsTypeAllowed(IdentifiableSurface::Type::kWebFeature));
+
+ EXPECT_EQ(1, counts.count_of_is_active);
+ EXPECT_EQ(1, counts.count_of_is_any_type_or_surface_blocked);
+ EXPECT_EQ(0, counts.count_of_is_surface_allowed);
+ EXPECT_EQ(0, counts.count_of_is_type_allowed);
+}
+
+TEST(IdentifiabilityStudySettingsTest, IsSurfaceOrTypeBlocked) {
+ CallCounts counts{.response_for_is_active = true,
+ .response_for_is_anything_blocked = true,
+ .response_for_is_allowed = false};
+
+ IdentifiabilityStudySettings settings(
+ std::make_unique<CountingSettingsProvider>(&counts));
+
+ // No other calls should be made.
+ EXPECT_TRUE(settings.IsActive());
+ EXPECT_FALSE(settings.IsSurfaceAllowed(IdentifiableSurface()));
+ EXPECT_FALSE(settings.IsTypeAllowed(IdentifiableSurface::Type::kWebFeature));
+
+ EXPECT_EQ(1, counts.count_of_is_active);
+ EXPECT_EQ(1, counts.count_of_is_any_type_or_surface_blocked);
+ EXPECT_EQ(1, counts.count_of_is_surface_allowed);
+ EXPECT_EQ(1, counts.count_of_is_type_allowed);
+}
+
+TEST(IdentifiabilityStudySettingsTest, DefaultSettings) {
+ auto* default_settings = IdentifiabilityStudySettings::Get();
+ EXPECT_FALSE(default_settings->IsActive());
+ EXPECT_FALSE(default_settings->IsSurfaceAllowed(IdentifiableSurface()));
+ EXPECT_FALSE(
+ default_settings->IsTypeAllowed(IdentifiableSurface::Type::kWebFeature));
+}
+
+TEST(IdentifiabilityStudySettingsTest, StaticSetProvider) {
+ CallCounts counts{.response_for_is_active = true,
+ .response_for_is_anything_blocked = true,
+ .response_for_is_allowed = true};
+
+ IdentifiabilityStudySettings::SetGlobalProvider(
+ std::make_unique<CountingSettingsProvider>(&counts));
+ auto* settings = IdentifiabilityStudySettings::Get();
+ EXPECT_TRUE(settings->IsActive());
+ EXPECT_TRUE(settings->IsSurfaceAllowed(IdentifiableSurface()));
+ EXPECT_EQ(1, counts.count_of_is_surface_allowed);
+
+ IdentifiabilityStudySettings::ResetStateForTesting();
+
+ auto* default_settings = IdentifiabilityStudySettings::Get();
+ EXPECT_FALSE(default_settings->IsActive());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/common/privacy_budget/identifiable_token_builder.cc b/chromium/third_party/blink/common/privacy_budget/identifiable_token_builder.cc
new file mode 100644
index 00000000000..9635c443eb1
--- /dev/null
+++ b/chromium/third_party/blink/common/privacy_budget/identifiable_token_builder.cc
@@ -0,0 +1,139 @@
+// Copyright 2020 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/public/common/privacy_budget/identifiable_token_builder.h"
+#include "base/check.h"
+#include "base/check_op.h"
+#include "base/hash/legacy_hash.h"
+
+namespace blink {
+
+namespace {
+
+// A big random prime. It's also the digest returned for an empty block.
+constexpr uint64_t kChainingValueSeed = UINT64_C(6544625333304541877);
+
+} // namespace
+
+const size_t IdentifiableTokenBuilder::kBlockSizeInBytes;
+
+IdentifiableTokenBuilder::IdentifiableTokenBuilder()
+ : partial_size_(0), chaining_value_(kChainingValueSeed) {}
+
+IdentifiableTokenBuilder::IdentifiableTokenBuilder(
+ const IdentifiableTokenBuilder& other) {
+ partial_size_ = other.partial_size_;
+ chaining_value_ = other.chaining_value_;
+ memcpy(partial_, other.partial_, partial_size_);
+}
+
+IdentifiableTokenBuilder::IdentifiableTokenBuilder(ByteBuffer buffer)
+ : IdentifiableTokenBuilder() {
+ AddBytes(buffer);
+}
+
+IdentifiableTokenBuilder& IdentifiableTokenBuilder::AddBytes(
+ ByteBuffer message) {
+ DCHECK_LE(partial_size_, kBlockSizeInBytes);
+ // Phase 1:
+ // Slurp in as much of the message as necessary if there's a partial block
+ // already assembled. Copying is expensive, so |partial_| is only involved
+ // when there's some left over bytes from a prior round.
+ if (partial_size_ > 0 && !message.empty())
+ message = SkimIntoPartial(message);
+
+ if (message.empty())
+ return *this;
+
+ // Phase 2:
+ // Consume as many full blocks as possible from |message|.
+ DCHECK_EQ(partial_size_, 0u);
+ while (message.size() >= kBlockSizeInBytes) {
+ DigestBlock(message.first<kBlockSizeInBytes>());
+ message = message.subspan(kBlockSizeInBytes);
+ }
+ if (message.empty())
+ return *this;
+
+ // Phase 3:
+ // Whatever remains is stuffed into the partial buffer.
+ message = SkimIntoPartial(message);
+ DCHECK(message.empty());
+ return *this;
+}
+
+IdentifiableTokenBuilder& IdentifiableTokenBuilder::AddAtomic(
+ ByteBuffer buffer) {
+ AlignPartialBuffer();
+ AddValue(buffer.size_bytes());
+ AddBytes(buffer);
+ AlignPartialBuffer();
+ return *this;
+}
+
+IdentifiableTokenBuilder::operator IdentifiableToken() const {
+ return GetToken();
+}
+
+IdentifiableToken IdentifiableTokenBuilder::GetToken() const {
+ if (partial_size_ == 0)
+ return chaining_value_;
+
+ return IdentifiableToken(
+ base::legacy::CityHash64WithSeed(GetPartialBlock(), chaining_value_));
+}
+
+IdentifiableTokenBuilder::ByteBuffer IdentifiableTokenBuilder::SkimIntoPartial(
+ ByteBuffer message) {
+ DCHECK(!message.empty() && partial_size_ < kBlockSizeInBytes);
+ const auto to_copy =
+ std::min(kBlockSizeInBytes - partial_size_, message.size());
+ memcpy(&partial_[partial_size_], message.data(), to_copy);
+ partial_size_ += to_copy;
+ if (partial_size_ == kBlockSizeInBytes)
+ DigestBlock(TakeCompletedBlock());
+ DCHECK_LE(partial_size_, kBlockSizeInBytes);
+ return message.subspan(to_copy);
+}
+
+void IdentifiableTokenBuilder::AlignPartialBuffer() {
+ const auto padding_to_add =
+ kBlockAlignment - (partial_size_ % kBlockAlignment);
+ if (padding_to_add == 0 || padding_to_add == kBlockAlignment)
+ return;
+
+ memset(partial_ + partial_size_, 0, padding_to_add);
+ partial_size_ += padding_to_add;
+
+ if (partial_size_ == kBlockSizeInBytes)
+ DigestBlock(TakeCompletedBlock());
+
+ DCHECK_LT(partial_size_, sizeof(partial_));
+ DCHECK(IsAligned());
+}
+
+void IdentifiableTokenBuilder::DigestBlock(FullBlock block) {
+ // partial_ should've been flushed before calling this.
+ DCHECK_EQ(partial_size_, 0u);
+
+ // The chaining value (initialized with the initialization vector
+ // kChainingValueSeed) is only used for diffusion. There's no length padding
+ // being done here since we aren't interested in second-preimage issues.
+ //
+ // There is a concern over hash flooding, but that's something the entire
+ // study has more-or-less accepted for some metrics and is dealt with during
+ // the analysis phase.
+ chaining_value_ =
+ base::legacy::CityHash64WithSeed(base::make_span(block), chaining_value_);
+}
+
+IdentifiableTokenBuilder::FullBlock
+IdentifiableTokenBuilder::TakeCompletedBlock() {
+ DCHECK_EQ(partial_size_, kBlockSizeInBytes);
+ auto buffer = base::make_span(partial_);
+ partial_size_ = 0;
+ return buffer;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/common/privacy_budget/identifiable_token_builder_atomic_fuzzer.cc b/chromium/third_party/blink/common/privacy_budget/identifiable_token_builder_atomic_fuzzer.cc
new file mode 100644
index 00000000000..0b20fb43719
--- /dev/null
+++ b/chromium/third_party/blink/common/privacy_budget/identifiable_token_builder_atomic_fuzzer.cc
@@ -0,0 +1,27 @@
+// Copyright 2020 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 <fuzzer/FuzzedDataProvider.h>
+
+#include <cstdint>
+#include <string>
+
+#include "base/containers/span.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
+
+// Similar to identifiable_token_builder_fuzzer except uses AddAtomic() instead
+// of AddBytes().
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* fuzz_data,
+ size_t fuzz_data_size) {
+ FuzzedDataProvider fdp(fuzz_data, fuzz_data_size);
+ auto partition_count = fdp.ConsumeIntegralInRange<size_t>(0, fuzz_data_size);
+ blink::IdentifiableTokenBuilder token_builder;
+ for (size_t i = 0; i < partition_count; ++i) {
+ auto partition = fdp.ConsumeRandomLengthString(fuzz_data_size);
+ token_builder.AddAtomic(base::as_bytes(base::make_span(partition)));
+ }
+ auto remainder = fdp.ConsumeRemainingBytes<uint8_t>();
+ token_builder.AddAtomic(base::as_bytes(base::make_span(remainder)));
+ return 0;
+}
diff --git a/chromium/third_party/blink/common/privacy_budget/identifiable_token_builder_fuzzer.cc b/chromium/third_party/blink/common/privacy_budget/identifiable_token_builder_fuzzer.cc
new file mode 100644
index 00000000000..93bb67e6a06
--- /dev/null
+++ b/chromium/third_party/blink/common/privacy_budget/identifiable_token_builder_fuzzer.cc
@@ -0,0 +1,25 @@
+// Copyright 2020 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 <fuzzer/FuzzedDataProvider.h>
+
+#include <cstdint>
+#include <string>
+
+#include "base/containers/span.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* fuzz_data,
+ size_t fuzz_data_size) {
+ FuzzedDataProvider fdp(fuzz_data, fuzz_data_size);
+ auto partition_count = fdp.ConsumeIntegralInRange<size_t>(0, fuzz_data_size);
+ blink::IdentifiableTokenBuilder token_builder;
+ for (size_t i = 0; i < partition_count; ++i) {
+ auto partition = fdp.ConsumeRandomLengthString(fuzz_data_size);
+ token_builder.AddBytes(base::as_bytes(base::make_span(partition)));
+ }
+ auto remainder = fdp.ConsumeRemainingBytes<uint8_t>();
+ token_builder.AddBytes(base::as_bytes(base::make_span(remainder)));
+ return 0;
+}
diff --git a/chromium/third_party/blink/common/privacy_budget/identifiable_token_builder_unittest.cc b/chromium/third_party/blink/common/privacy_budget/identifiable_token_builder_unittest.cc
new file mode 100644
index 00000000000..3754e14699c
--- /dev/null
+++ b/chromium/third_party/blink/common/privacy_budget/identifiable_token_builder_unittest.cc
@@ -0,0 +1,193 @@
+// Copyright 2020 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/public/common/privacy_budget/identifiable_token_builder.h"
+
+#include <cstdint>
+#include <vector>
+
+#include "base/containers/span.h"
+#include "base/rand_util.h"
+#include "base/strings/strcat.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/privacy_budget/identifiable_token.h"
+
+namespace blink {
+
+TEST(IdentifiableTokenBuilderTest, Empty) {
+ IdentifiableTokenBuilder sample;
+ EXPECT_EQ(IdentifiableToken(INT64_C(0x5ad32e10d3a3c2b5)), sample.GetToken());
+}
+
+TEST(IdentifiableTokenBuilderTest, ConstructVsAdd) {
+ const char kOneByte[1] = {'a'};
+ IdentifiableTokenBuilder add_token;
+ add_token.AddBytes(base::as_bytes(base::make_span(kOneByte)));
+
+ IdentifiableTokenBuilder construct_token(
+ base::as_bytes(base::make_span(kOneByte)));
+ EXPECT_EQ(add_token.GetToken(), construct_token.GetToken());
+}
+
+TEST(IdentifiableTokenBuilderTest, OneByte) {
+ const char kOneByte[1] = {'a'};
+ IdentifiableTokenBuilder sample;
+ sample.AddBytes(base::as_bytes(base::make_span(kOneByte)));
+ EXPECT_EQ(IdentifiableToken(INT64_C(0x6de50a5cefa7ba0e)), sample.GetToken());
+}
+
+TEST(IdentifiableTokenBuilderTest, TwoBytesInTwoTakes) {
+ const char kBytes[] = {'a', 'b'};
+ auto bytes_span = base::as_bytes(base::span<const char>(kBytes));
+ IdentifiableTokenBuilder whole_span_token(bytes_span);
+ IdentifiableTokenBuilder two_parts_token;
+ two_parts_token.AddBytes(bytes_span.first(1));
+ two_parts_token.AddBytes(bytes_span.last(1));
+ EXPECT_EQ(whole_span_token.GetToken(), two_parts_token.GetToken());
+}
+
+TEST(IdentifiableTokenBuilderTest, SixtySixBytesInTwoTakes) {
+ constexpr size_t kSize = 66;
+ std::vector<char> big_array(kSize, 'a');
+ auto bytes_span = base::as_bytes(base::span<const char>(big_array));
+ IdentifiableTokenBuilder whole_span_token(bytes_span);
+ IdentifiableTokenBuilder two_parts_token;
+ two_parts_token.AddBytes(bytes_span.first(kSize / 2));
+ two_parts_token.AddBytes(bytes_span.last(kSize / 2));
+ EXPECT_EQ(whole_span_token.GetToken(), two_parts_token.GetToken());
+}
+
+TEST(IdentifiableTokenBuilderTest, AddValue) {
+ const auto kExpectedToken = IdentifiableToken(INT64_C(0xe475af2a732298e2));
+
+ EXPECT_EQ(kExpectedToken,
+ IdentifiableTokenBuilder().AddValue(INT8_C(1)).GetToken());
+ EXPECT_EQ(kExpectedToken,
+ IdentifiableTokenBuilder().AddValue(UINT8_C(1)).GetToken());
+ EXPECT_EQ(kExpectedToken,
+ IdentifiableTokenBuilder().AddValue(INT16_C(1)).GetToken());
+ EXPECT_EQ(kExpectedToken,
+ IdentifiableTokenBuilder().AddValue(UINT16_C(1)).GetToken());
+ EXPECT_EQ(kExpectedToken,
+ IdentifiableTokenBuilder().AddValue(INT32_C(1)).GetToken());
+ EXPECT_EQ(kExpectedToken,
+ IdentifiableTokenBuilder().AddValue(UINT32_C(1)).GetToken());
+ EXPECT_EQ(kExpectedToken,
+ IdentifiableTokenBuilder().AddValue(INT64_C(1)).GetToken());
+ EXPECT_EQ(kExpectedToken,
+ IdentifiableTokenBuilder().AddValue(UINT64_C(1)).GetToken());
+}
+
+TEST(IdentifiableTokenBuilderTest, AddAtomic_AlwaysConstant) {
+ const uint8_t kS1[] = {1, 2, 3, 4, 5};
+ EXPECT_EQ(
+ IdentifiableToken(INT64_C(0xfaeb0b8e769729b9)),
+ IdentifiableTokenBuilder().AddAtomic(base::make_span(kS1)).GetToken());
+}
+
+TEST(IdentifiableTokenBuilderTest, AddAtomic_PadSuffix) {
+ const uint8_t kS1[] = {1, 2, 3, 4, 5};
+ const uint8_t kS1_padded[] = {5, 0, 0, 0, 0, 0, 0, 0, // Little endian 5
+ 1, 2, 3, 4, 5, 0, 0, 0};
+ EXPECT_EQ(
+ IdentifiableTokenBuilder().AddAtomic(base::make_span(kS1)).GetToken(),
+ IdentifiableTokenBuilder()
+ .AddBytes(base::make_span(kS1_padded))
+ .GetToken());
+}
+
+TEST(IdentifiableTokenBuilderTest, AddAtomic_PadPrefix) {
+ const uint8_t kS2_pre[] = {1, 2};
+ const uint8_t kS2[] = {3, 4, 5};
+ const uint8_t kS2_padded[] = {1, 2, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0, // Little endian 3
+ 3, 4, 5, 0, 0, 0, 0, 0};
+ EXPECT_EQ(IdentifiableTokenBuilder()
+ .AddBytes(base::make_span(kS2_pre))
+ .AddAtomic(base::make_span(kS2))
+ .GetToken(),
+ IdentifiableTokenBuilder()
+ .AddBytes(base::make_span(kS2_padded))
+ .GetToken());
+}
+
+TEST(IdentifiableTokenBuilderTest, AddVsAddAtomic) {
+ const uint8_t kA1[] = {'a', 'b', 'c', 'd'};
+ const uint8_t kA2[] = {'e', 'f', 'g', 'h'};
+ const uint8_t kB1[] = {'a'};
+ const uint8_t kB2[] = {'b', 'c', 'd', 'e', 'f', 'g', 'h'};
+
+ // Adding buffers wth AddBytes() doesn't distinguish between the two
+ // partitions, and this is intentional.
+ IdentifiableTokenBuilder builder_A;
+ builder_A.AddBytes(base::make_span(kA1));
+ builder_A.AddBytes(base::make_span(kA2));
+ auto token_for_A = builder_A.GetToken();
+
+ IdentifiableTokenBuilder builder_B;
+ builder_B.AddBytes(base::make_span(kB1));
+ builder_B.AddBytes(base::make_span(kB2));
+ auto token_for_B = builder_B.GetToken();
+
+ EXPECT_EQ(token_for_A, token_for_B);
+
+ // However AtomicAdd distinguishes between the two.
+ IdentifiableTokenBuilder atomic_A;
+ atomic_A.AddAtomic(base::make_span(kA1));
+ atomic_A.AddAtomic(base::make_span(kA2));
+ auto atomic_token_for_A = atomic_A.GetToken();
+
+ IdentifiableTokenBuilder atomic_B;
+ atomic_B.AddAtomic(base::make_span(kB1));
+ atomic_B.AddAtomic(base::make_span(kB2));
+ auto atomic_token_for_B = atomic_B.GetToken();
+
+ EXPECT_NE(atomic_token_for_A, atomic_token_for_B);
+}
+
+TEST(IdentifiableTokenBuilderTest, LotsOfRandomPartitions) {
+ constexpr size_t kLargeBufferSize = 1000 * 1000 * 10;
+ constexpr size_t kCycle = 149; // A prime
+ std::vector<uint8_t> data(kLargeBufferSize);
+ for (size_t i = 0; i < kLargeBufferSize; ++i) {
+ data[i] = i % kCycle;
+ }
+
+ int partition_count = base::RandInt(50, 500);
+
+ // Pick |partition_count| random numbers between 0 and kLargeBufferSize (half
+ // open) that will indicate where the partitions are. In reality there will be
+ // |partition_count + 1| partitions:
+ //
+ // |<--------->:<------------>:<--- .. ...->:<---------------------->|
+ // | : : .. ... : |
+ // 0 partitions[0] partitions[1] .. partitions[n-1] kLargeBufferSize
+ std::vector<int> partitions;
+ for (int i = 0; i < partition_count; ++i)
+ partitions.push_back(base::RandInt(0, kLargeBufferSize));
+ std::sort(partitions.begin(), partitions.end());
+
+ std::string trace;
+ base::StringAppendF(&trace, "Partitions[%d]={0", partition_count + 2);
+ for (auto p : partitions)
+ base::StringAppendF(&trace, ", %d", p);
+ base::StringAppendF(&trace, ", %zu}", kLargeBufferSize);
+ SCOPED_TRACE(trace);
+
+ IdentifiableTokenBuilder partitioned_sample;
+ int low = 0;
+ for (auto high : partitions) {
+ ASSERT_LE(low, high);
+ partitioned_sample.AddBytes(base::make_span(&data[low], high - low));
+ low = high;
+ }
+ partitioned_sample.AddBytes(
+ base::make_span(&data[low], kLargeBufferSize - low));
+
+ IdentifiableTokenBuilder full_buffer_sample(data);
+ EXPECT_EQ(full_buffer_sample.GetToken(), partitioned_sample.GetToken());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/common/privacy_budget/identifiable_token_unittest.cc b/chromium/third_party/blink/common/privacy_budget/identifiable_token_unittest.cc
new file mode 100644
index 00000000000..f59fdc6c2c9
--- /dev/null
+++ b/chromium/third_party/blink/common/privacy_budget/identifiable_token_unittest.cc
@@ -0,0 +1,131 @@
+// Copyright 2020 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/public/common/privacy_budget/identifiable_token.h"
+
+#include "base/strings/string_piece.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+namespace {
+
+// The set of candidate conversion templates depend on whether the conversion is
+// explicit or implicit. This class is used to exercise implicit conversion of
+// IdIdentifiableApiSample.
+struct ImplicitConverter {
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ ImplicitConverter(IdentifiableToken sample) : sample(sample) {}
+
+ IdentifiableToken sample;
+};
+
+} // namespace
+
+TEST(IdentifiableTokenTest, SampleSignedChar) {
+ auto source_value = static_cast<signed char>(-65);
+ auto expected_value = INT64_C(-65);
+ EXPECT_EQ(IdentifiableToken(expected_value), IdentifiableToken(source_value));
+ EXPECT_EQ(IdentifiableToken(expected_value),
+ ImplicitConverter(source_value).sample);
+}
+
+TEST(IdentifiableTokenTest, SampleChar) {
+ auto source_value = 'A';
+ auto expected_value = INT64_C(65);
+ EXPECT_EQ(IdentifiableToken(expected_value), IdentifiableToken(source_value));
+ EXPECT_EQ(IdentifiableToken(expected_value),
+ ImplicitConverter(source_value).sample);
+}
+
+TEST(IdentifiableTokenTest, SampleInt) {
+ auto source_value = 123;
+ auto expected_value = INT64_C(123);
+ EXPECT_EQ(IdentifiableToken(expected_value), IdentifiableToken(source_value));
+ EXPECT_EQ(IdentifiableToken(expected_value),
+ ImplicitConverter(source_value).sample);
+}
+
+TEST(IdentifiableTokenTest, SampleNegativeInt) {
+ auto source_value = -123;
+ auto expected_value = INT64_C(-123);
+ EXPECT_EQ(IdentifiableToken(expected_value), IdentifiableToken(source_value));
+ EXPECT_EQ(IdentifiableToken(expected_value),
+ ImplicitConverter(source_value).sample);
+}
+
+TEST(IdentifiableTokenTest, SampleUnsigned) {
+ auto source_value = UINT64_C(123);
+ auto expected_value = INT64_C(123);
+ EXPECT_EQ(IdentifiableToken(expected_value), IdentifiableToken(source_value));
+ EXPECT_EQ(IdentifiableToken(expected_value),
+ ImplicitConverter(source_value).sample);
+}
+
+TEST(IdentifiableTokenTest, SampleBigUnsignedThatFits) {
+ auto source_value =
+ static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1;
+ auto expected_value = std::numeric_limits<int64_t>::min();
+ EXPECT_EQ(IdentifiableToken(expected_value), IdentifiableToken(source_value));
+ EXPECT_EQ(IdentifiableToken(expected_value),
+ ImplicitConverter(source_value).sample);
+}
+
+TEST(IdentifiableTokenTest, SampleFloat) {
+ auto source_value = 5.1f;
+ auto expected_value = INT64_C(0x4014666660000000);
+ EXPECT_EQ(IdentifiableToken(expected_value), IdentifiableToken(source_value));
+ EXPECT_EQ(IdentifiableToken(expected_value),
+ ImplicitConverter(source_value).sample);
+}
+
+TEST(IdentifiableTokenTest, SampleConstCharArray) {
+ EXPECT_EQ(IdentifiableToken(INT64_C(0xf75a3b8a1499428d)),
+ IdentifiableToken("abcd"));
+ // No implicit converter for const char[].
+}
+
+TEST(IdentifiableTokenTest, SampleStdString) {
+ EXPECT_EQ(IdentifiableToken(INT64_C(0xf75a3b8a1499428d)),
+ IdentifiableToken(std::string("abcd")));
+ // No implicit converter for std::string.
+}
+
+TEST(IdentifiableTokenTest, SampleStringPiece) {
+ auto source_value = base::StringPiece("abcd");
+ auto expected_value = INT64_C(0xf75a3b8a1499428d);
+ EXPECT_EQ(IdentifiableToken(expected_value), IdentifiableToken(source_value));
+ // No implicit converter for StringPiece.
+}
+
+TEST(IdentifiableTokenTest, SampleCharSpan) {
+ auto source_value = base::make_span("abcd", 4);
+ auto expected_value = INT64_C(0xf75a3b8a1499428d);
+ EXPECT_EQ(IdentifiableToken(expected_value), IdentifiableToken(source_value));
+ EXPECT_EQ(IdentifiableToken(expected_value),
+ ImplicitConverter(source_value).sample);
+}
+
+TEST(IdentifiableTokenTest, SampleStringSpan) {
+ std::string strings[] = {"baby", "shark", "du duu du duu du du"};
+ auto source_value = base::make_span(strings);
+ auto expected_value = INT64_C(0xd37aad882e58faa5);
+ EXPECT_EQ(IdentifiableToken(expected_value), IdentifiableToken(source_value));
+ EXPECT_EQ(IdentifiableToken(expected_value),
+ ImplicitConverter(source_value).sample);
+}
+
+TEST(IdentifiableTokenTest, SampleTuple) {
+ EXPECT_EQ(IdentifiableToken(INT64_C(0x5848123245be627a)),
+ IdentifiableToken(1, 2, 3, 4, 5));
+ // No implicit converter for tuples.
+}
+
+TEST(IdentifiableTokenTest, SampleHeterogenousTuple) {
+ EXPECT_EQ(IdentifiableToken(INT64_C(0x672cf4c107b5b22)),
+ IdentifiableToken(1, 2, 3.0, 4, 'a'));
+ // No implicit converter for tuples.
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc b/chromium/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc
index e7979275872..cc9024b8be1 100644
--- a/chromium/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc
+++ b/chromium/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc
@@ -97,6 +97,18 @@ const char* FeatureToString(WebSchedulerTrackedFeature feature) {
return "WebDatabase";
case WebSchedulerTrackedFeature::kPictureInPicture:
return "PictureInPicture";
+ case WebSchedulerTrackedFeature::kPortal:
+ return "Portal";
+ case WebSchedulerTrackedFeature::kSpeechRecognizer:
+ return "SpeechRecognizer";
+ case WebSchedulerTrackedFeature::kIdleManager:
+ return "IdleManager";
+ case WebSchedulerTrackedFeature::kPaymentManager:
+ return "PaymentManager";
+ case WebSchedulerTrackedFeature::kSpeechSynthesis:
+ return "SpeechSynthesis";
+ case WebSchedulerTrackedFeature::kKeyboardLock:
+ return "KeyboardLock";
}
}
diff --git a/chromium/third_party/blink/common/switches.cc b/chromium/third_party/blink/common/switches.cc
index d3803236c5f..31290d0ff88 100644
--- a/chromium/third_party/blink/common/switches.cc
+++ b/chromium/third_party/blink/common/switches.cc
@@ -7,6 +7,78 @@
namespace blink {
namespace switches {
+// Allows processing of input before a frame has been committed.
+// TODO(schenney): crbug.com/987626. Used by headless. Look for a way not
+// involving a command line switch.
+const char kAllowPreCommitInput[] = "allow-pre-commit-input";
+
+// Sets the tile size used by composited layers.
+const char kDefaultTileWidth[] = "default-tile-width";
+const char kDefaultTileHeight[] = "default-tile-height";
+
+// Disallow image animations to be reset to the beginning to avoid skipping
+// many frames. Only effective if compositor image animations are enabled.
+const char kDisableImageAnimationResync[] = "disable-image-animation-resync";
+
+// When using CPU rasterizing disable low resolution tiling. This uses
+// less power, particularly during animations, but more white may be seen
+// during fast scrolling especially on slower devices.
+const char kDisableLowResTiling[] = "disable-low-res-tiling";
+
+// Disable partial raster in the renderer. Disabling this switch also disables
+// the use of persistent gpu memory buffers.
+const char kDisablePartialRaster[] = "disable-partial-raster";
+
+// Disables RGBA_4444 textures.
+const char kDisableRGBA4444Textures[] = "disable-rgba-4444-textures";
+
+// Disable rasterizer that writes directly to GPU memory associated with tiles.
+const char kDisableZeroCopy[] = "disable-zero-copy";
+
+// Specify that all compositor resources should be backed by GPU memory buffers.
+const char kEnableGpuMemoryBufferCompositorResources[] =
+ "enable-gpu-memory-buffer-compositor-resources";
+
+// When using CPU rasterizing generate low resolution tiling. Low res
+// tiles may be displayed during fast scrolls especially on slower devices.
+const char kEnableLowResTiling[] = "enable-low-res-tiling";
+
+// Enables RGBA_4444 textures.
+const char kEnableRGBA4444Textures[] = "enable-rgba-4444-textures";
+
+// Enable rasterizer that writes directly to GPU memory associated with tiles.
+const char kEnableZeroCopy[] = "enable-zero-copy";
+
+// The number of multisample antialiasing samples for GPU rasterization.
+// Requires MSAA support on GPU to have an effect. 0 disables MSAA.
+const char kGpuRasterizationMSAASampleCount[] =
+ "gpu-rasterization-msaa-sample-count";
+
+// Used to communicate managed policy for the IntensiveWakeUpThrottling feature.
+// This feature is typically controlled by base::Feature (see
+// renderer/platform/scheduler/common/features.*) but requires an enterprise
+// policy override. This is implicitly a tri-state, and can be either unset, or
+// set to "1" for force enable, or "0" for force disable.
+extern const char kIntensiveWakeUpThrottlingPolicy[] =
+ "intensive-wake-up-throttling-policy";
+extern const char kIntensiveWakeUpThrottlingPolicy_ForceDisable[] = "0";
+extern const char kIntensiveWakeUpThrottlingPolicy_ForceEnable[] = "1";
+
+// Sets the width and height above which a composited layer will get tiled.
+const char kMaxUntiledLayerHeight[] = "max-untiled-layer-height";
+const char kMaxUntiledLayerWidth[] = "max-untiled-layer-width";
+
+// Sets the min tile height for GPU raster.
+const char kMinHeightForGpuRasterTile[] = "min-height-for-gpu-raster-tile";
+
+// Visibly render a border around layout shift rects in the web page to help
+// debug and study layout shifts.
+const char kShowLayoutShiftRegions[] = "show-layout-shift-regions";
+
+// Visibly render a border around paint rects in the web page to help debug
+// and study painting behavior.
+const char kShowPaintRects[] = "show-paint-rects";
+
// Used to communicate managed policy for the UserAgentClientHint feature.
// This feature is typically controlled by base::Feature (see
// renderer/platform/scheduler/common/features.*) but requires an enterprise
@@ -14,5 +86,6 @@ namespace switches {
extern const char kUserAgentClientHintDisable[] =
"user-agent-client-hint-disable";
+
} // namespace switches
} // namespace blink