diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/third_party/blink/common | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/blink/common')
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(×tamp)) + 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 |