diff options
Diffstat (limited to 'chromium/third_party')
110 files changed, 1505 insertions, 525 deletions
diff --git a/chromium/third_party/angle/src/compiler/preprocessor/DiagnosticsBase.cpp b/chromium/third_party/angle/src/compiler/preprocessor/DiagnosticsBase.cpp index 575b151432d..c4832c66d3a 100644 --- a/chromium/third_party/angle/src/compiler/preprocessor/DiagnosticsBase.cpp +++ b/chromium/third_party/angle/src/compiler/preprocessor/DiagnosticsBase.cpp @@ -115,6 +115,8 @@ const char *Diagnostics::message(ID id) return "invalid file number"; case PP_INVALID_LINE_DIRECTIVE: return "invalid line directive"; + case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1: + return "extension directive must occur before any non-preprocessor tokens in ESSL1"; case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3: return "extension directive must occur before any non-preprocessor tokens in ESSL3"; case PP_UNDEFINED_SHIFT: @@ -129,7 +131,7 @@ const char *Diagnostics::message(ID id) return "unexpected token after conditional expression"; case PP_UNRECOGNIZED_PRAGMA: return "unrecognized pragma"; - case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1: + case PP_NON_PP_TOKEN_BEFORE_EXTENSION_WEBGL: return "extension directive should occur before any non-preprocessor tokens"; case PP_WARNING_MACRO_NAME_RESERVED: return "macro name with a double underscore is reserved - unintented behavior is " diff --git a/chromium/third_party/angle/src/compiler/preprocessor/DiagnosticsBase.h b/chromium/third_party/angle/src/compiler/preprocessor/DiagnosticsBase.h index bb90bf08292..6be5c72ddec 100644 --- a/chromium/third_party/angle/src/compiler/preprocessor/DiagnosticsBase.h +++ b/chromium/third_party/angle/src/compiler/preprocessor/DiagnosticsBase.h @@ -73,6 +73,7 @@ class Diagnostics PP_WARNING_BEGIN, PP_EOF_IN_DIRECTIVE, PP_UNRECOGNIZED_PRAGMA, + PP_NON_PP_TOKEN_BEFORE_EXTENSION_WEBGL, PP_WARNING_MACRO_NAME_RESERVED, PP_WARNING_END }; diff --git a/chromium/third_party/angle/src/compiler/preprocessor/DirectiveParser.cpp b/chromium/third_party/angle/src/compiler/preprocessor/DirectiveParser.cpp index e99d843b2d3..b7f8d91ecf5 100644 --- a/chromium/third_party/angle/src/compiler/preprocessor/DirectiveParser.cpp +++ b/chromium/third_party/angle/src/compiler/preprocessor/DirectiveParser.cpp @@ -676,8 +676,16 @@ void DirectiveParser::parseExtension(Token *token) } else { - mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1, - token->location, token->text); + if (mSettings.shaderSpec == SH_WEBGL_SPEC) + { + mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_WEBGL, + token->location, token->text); + } + else + { + mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1, + token->location, token->text); + } } } if (valid) diff --git a/chromium/third_party/blink/common/features.cc b/chromium/third_party/blink/common/features.cc index f5bf253f4a6..6db2247d620 100644 --- a/chromium/third_party/blink/common/features.cc +++ b/chromium/third_party/blink/common/features.cc @@ -132,8 +132,16 @@ const base::Feature kPurgeRendererMemoryWhenBackgrounded { }; // Enable Implicit Root Scroller. https://crbug.com/903260. -const base::Feature kImplicitRootScroller{"ImplicitRootScroller", - base::FEATURE_ENABLED_BY_DEFAULT}; +// TODO(bokan): Temporarily disabled on desktop platforms to address issues +// with non-overlay scrollbars. https://crbug.com/948059. +const base::Feature kImplicitRootScroller { + "ImplicitRootScroller", +#if defined(OS_ANDROID) + base::FEATURE_ENABLED_BY_DEFAULT +#else + base::FEATURE_DISABLED_BY_DEFAULT +#endif +}; // Enables usage of getDisplayMedia() that allows capture of web content, see // https://crbug.com/865060. diff --git a/chromium/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h b/chromium/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h index c88a10c9cd0..25858141012 100644 --- a/chromium/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h +++ b/chromium/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h @@ -44,7 +44,24 @@ enum class WebSchedulerTrackedFeature { // Recorded only for the main frame. kHasScriptableFramesInMultipleTabs = 18, - kMaxValue = kHasScriptableFramesInMultipleTabs + // Whether the page tried to request a permission regardless of the outcome. + // TODO(altimin): Track this more accurately depending on the data. + // See permission.mojom for more details. + kRequestedGeolocationPermission = 19, + kRequestedNotificationsPermission = 20, + kRequestedMIDIPermission = 21, + kRequestedAudioCapturePermission = 22, + kRequestedVideoCapturePermission = 23, + kRequestedSensorsPermission = 24, + // This covers all background-related permissions, including background sync, + // background fetch and others. + kRequestedBackgroundWorkPermission = 26, + + kBroadcastChannel = 27, + + kIndexedDBConnection = 28, + + kMaxValue = kIndexedDBConnection }; } // namespace scheduler diff --git a/chromium/third_party/blink/public/mojom/page/spatial_navigation.mojom b/chromium/third_party/blink/public/mojom/page/spatial_navigation.mojom index 51538fcc766..8358e7ebc0d 100644 --- a/chromium/third_party/blink/public/mojom/page/spatial_navigation.mojom +++ b/chromium/third_party/blink/public/mojom/page/spatial_navigation.mojom @@ -11,6 +11,8 @@ struct SpatialNavigationState { bool can_exit_focus; // True if Spatial Navigation has a target that can be selected. bool can_select_element; + // True if the currently focused element is a form element. + bool is_form_focused; // True if the currently focused element is a form element, and there is a // next form element available to move to. bool has_next_form_element; diff --git a/chromium/third_party/blink/public/platform/web_localized_string.h b/chromium/third_party/blink/public/platform/web_localized_string.h index 7ba33a0c714..51c9a3cdb8b 100644 --- a/chromium/third_party/blink/public/platform/web_localized_string.h +++ b/chromium/third_party/blink/public/platform/web_localized_string.h @@ -73,6 +73,8 @@ struct WebLocalizedString { kAXMediaVolumeSliderHelp, kAXMediaEnterPictureInPictureButton, kAXMediaExitPictureInPictureButton, + kAXMediaTouchLessSeekAction, + kAXMediaTouchLessVolumeAction, kAXMillisecondFieldText, kAXMinuteFieldText, kAXMonthFieldText, diff --git a/chromium/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl b/chromium/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl index a72ca09048d..2598235ff3c 100644 --- a/chromium/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl +++ b/chromium/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl @@ -56,6 +56,11 @@ v8::Context::BackupIncumbentScope backup_incumbent_scope( IncumbentScriptState()->GetContext()); + if (UNLIKELY(ScriptForbiddenScope::IsScriptForbidden())) { + ScriptForbiddenScope::ThrowScriptForbiddenException(GetIsolate()); + return v8::Nothing<{{return_cpp_type}}>(); + } + {% if invoke_or_construct == 'construct' %} // step 3. If ! IsConstructor(F) is false, throw a TypeError exception. // diff --git a/chromium/third_party/blink/renderer/core/dom/element.cc b/chromium/third_party/blink/renderer/core/dom/element.cc index d86329b115a..e5df6bbfc6a 100644 --- a/chromium/third_party/blink/renderer/core/dom/element.cc +++ b/chromium/third_party/blink/renderer/core/dom/element.cc @@ -3491,11 +3491,26 @@ bool Element::SupportsSpatialNavigationFocus() const { // events). if (!IsSpatialNavigationEnabled(GetDocument().GetFrame())) return false; + + if (!GetLayoutObject()) + return false; + if (HasEventListeners(event_type_names::kClick) || HasEventListeners(event_type_names::kKeydown) || HasEventListeners(event_type_names::kKeypress) || HasEventListeners(event_type_names::kKeyup)) return true; + + // Some web apps use click-handlers to react on clicks within rects that are + // styled with {cursor: pointer}. Such rects *look* clickable so they probably + // are. Here we make Hand-trees' tip, the first (biggest) node with {cursor: + // pointer}, navigable because users shouldn't need to navigate through every + // sub element that inherit this CSS. + if (GetComputedStyle()->Cursor() == ECursor::kPointer && + ParentComputedStyle()->Cursor() != ECursor::kPointer) { + return true; + } + if (!IsSVGElement()) return false; return (HasEventListeners(event_type_names::kFocus) || diff --git a/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.cc b/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.cc index 3b6dab593bd..8f3eaf84d00 100644 --- a/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.cc +++ b/chromium/third_party/blink/renderer/core/dom/events/event_dispatcher.cc @@ -36,6 +36,7 @@ #include "third_party/blink/renderer/core/dom/events/event_path.h" #include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h" #include "third_party/blink/renderer/core/dom/events/window_event_context.h" +#include "third_party/blink/renderer/core/events/keyboard_event.h" #include "third_party/blink/renderer/core/events/mouse_event.h" #include "third_party/blink/renderer/core/frame/ad_tracker.h" #include "third_party/blink/renderer/core/frame/deprecation.h" @@ -45,6 +46,8 @@ #include "third_party/blink/renderer/core/frame/use_counter.h" #include "third_party/blink/renderer/core/html/html_element.h" #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h" +#include "third_party/blink/renderer/core/page/page.h" +#include "third_party/blink/renderer/core/page/spatial_navigation_controller.h" #include "third_party/blink/renderer/core/timing/event_timing.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" @@ -370,6 +373,15 @@ inline void EventDispatcher::DispatchEventPostProcess( } } + if (Page* page = node_->GetDocument().GetPage()) { + if (page->GetSettings().GetSpatialNavigationEnabled() && + is_trusted_or_click && event_->IsKeyboardEvent() && + ToKeyboardEvent(*event_).key() == "Enter" && + event_->type() == event_type_names::kKeyup) { + page->GetSpatialNavigationController().ResetEnterKeyState(); + } + } + // Track the usage of sending a mousedown event to a select element to force // it to open. This measures a possible breakage of not allowing untrusted // events to open select boxes. diff --git a/chromium/third_party/blink/renderer/core/editing/frame_selection.h b/chromium/third_party/blink/renderer/core/editing/frame_selection.h index 6dc0e1cf974..1da4b7aad96 100644 --- a/chromium/third_party/blink/renderer/core/editing/frame_selection.h +++ b/chromium/third_party/blink/renderer/core/editing/frame_selection.h @@ -201,6 +201,10 @@ class CORE_EXPORT FrameSelection final // Note: this updates styles and layout, use cautiously. bool ComputeAbsoluteBounds(IntRect& anchor, IntRect& focus) const; + // Computes the rect we should use when scrolling/zooming a selection into + // view. + IntRect ComputeRectToScroll(RevealExtentOption); + void DidChangeFocus(); SelectionInDOMTree GetSelectionInDOMTree() const; @@ -299,8 +303,6 @@ class CORE_EXPORT FrameSelection final GranularityStrategy* GetGranularityStrategy(); - IntRect ComputeRectToScroll(RevealExtentOption); - void MoveRangeSelectionInternal(const SelectionInDOMTree&, TextGranularity); // Implementation of |SynchronousMutationObserver| member functions. diff --git a/chromium/third_party/blink/renderer/core/exported/web_frame_test.cc b/chromium/third_party/blink/renderer/core/exported/web_frame_test.cc index a6969cca501..c45adc0ced8 100644 --- a/chromium/third_party/blink/renderer/core/exported/web_frame_test.cc +++ b/chromium/third_party/blink/renderer/core/exported/web_frame_test.cc @@ -122,6 +122,7 @@ #include "third_party/blink/renderer/core/fullscreen/fullscreen.h" #include "third_party/blink/renderer/core/geometry/dom_rect.h" #include "third_party/blink/renderer/core/html/forms/html_form_element.h" +#include "third_party/blink/renderer/core/html/forms/html_input_element.h" #include "third_party/blink/renderer/core/html/html_body_element.h" #include "third_party/blink/renderer/core/html/html_iframe_element.h" #include "third_party/blink/renderer/core/html/image_document.h" @@ -3390,6 +3391,46 @@ TEST_F(WebFrameTest, CanOverrideScaleLimits) { EXPECT_EQ(2.0f, web_view_helper.GetWebView()->MaximumPageScaleFactor()); } +// Test that setting the "ignore viewport tag scale limits" override remembers +// the current defaults and restores them when the override is removed. +TEST_F(WebFrameTest, RestoreOriginalDefaultScaleLimits) { + RegisterMockedHttpURLLoad("simple_div.html"); + + FixedLayoutTestWebViewClient client; + client.screen_info_.device_scale_factor = 1; + int viewport_width = 640; + int viewport_height = 480; + + frame_test_helpers::WebViewHelper web_view_helper; + web_view_helper.InitializeAndLoad(base_url_ + "simple_div.html", nullptr, + &client, nullptr, ConfigureAndroid); + web_view_helper.Resize(WebSize(viewport_width, viewport_height)); + web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.25f, 5); + + const float minimum_scale_factor = + web_view_helper.GetWebView()->MinimumPageScaleFactor(); + + web_view_helper.GetWebView()->SetInitialPageScaleOverride(2.0f); + + // Removing the override when none is set shouldn't change the initial scale. + web_view_helper.GetWebView()->SetIgnoreViewportTagScaleLimits(false); + UpdateAllLifecyclePhases(web_view_helper.GetWebView()); + EXPECT_EQ(2.0f, web_view_helper.GetWebView()->PageScaleFactor()); + + // Setting the override when will change the initial scale. + web_view_helper.GetWebView()->SetIgnoreViewportTagScaleLimits(true); + web_view_helper.GetWebView()->ResetScaleStateImmediately(); + UpdateAllLifecyclePhases(web_view_helper.GetWebView()); + EXPECT_EQ(minimum_scale_factor, + web_view_helper.GetWebView()->PageScaleFactor()); + + // Disable the override, we should now use the minimum scale factor + web_view_helper.GetWebView()->SetIgnoreViewportTagScaleLimits(false); + web_view_helper.GetWebView()->ResetScaleStateImmediately(); + UpdateAllLifecyclePhases(web_view_helper.GetWebView()); + EXPECT_EQ(2.0f, web_view_helper.GetWebView()->PageScaleFactor()); +} + // Android doesn't have scrollbars on the main LocalFrameView #if defined(OS_ANDROID) TEST_F(WebFrameTest, DISABLED_updateOverlayScrollbarLayers) @@ -11419,6 +11460,40 @@ class WebFrameSimTest : public SimTest { } }; +// This test ensures that setting the "Force Ignore Zoom" accessibility setting +// also causes us to override the initial scale set by the page so that we load +// fully zoomed out. Since we're overriding the minimum-scale, we're making the +// layout viewport larger. Since |position: fixed| elements are sized based on +// the layout viewport size, they may be cut off when the page first loads. +TEST_F(WebFrameSimTest, ForceIgnoreZoomShouldOverrideInitialScale) { + UseAndroidSettings(); + WebView().MainFrameWidget()->Resize(WebSize(500, 300)); + WebView().SetIgnoreViewportTagScaleLimits(true); + + SimRequest r("https://example.com/test.html", "text/html"); + LoadURL("https://example.com/test.html"); + r.Complete(R"HTML( + <!DOCTYPE html> + <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1"> + <style> + body, html { + width: 100%; + height: 100%; + margin: 0; + } + #wide { + width: 1000px; + height: 10px; + } + </style> + <div id="wide"></div> + )HTML"); + + Compositor().BeginFrame(); + + EXPECT_EQ(0.5f, WebView().PageScaleFactor()); +} + TEST_F(WebFrameSimTest, HitTestWithIgnoreClippingAtNegativeOffset) { WebView().MainFrameWidget()->Resize(WebSize(500, 300)); WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false); @@ -11939,6 +12014,58 @@ TEST_F(WebFrameSimTest, ScrollFocusedIntoViewClipped) { EXPECT_GT(clip->scrollTop(), 0); } +// This test ensures that we scroll to the correct scale when the focused +// element has a selection rather than a carret. +TEST_F(WebFrameSimTest, ScrollFocusedSelectionIntoView) { + UseAndroidSettings(); + WebView().MainFrameWidget()->Resize(WebSize(400, 600)); + WebView().EnableFakePageScaleAnimationForTesting(true); + WebView().GetPage()->GetSettings().SetTextAutosizingEnabled(false); + + SimRequest request("https://example.com/test.html", "text/html"); + LoadURL("https://example.com/test.html"); + request.Complete(R"HTML( + <!DOCTYPE html> + <style> + ::-webkit-scrollbar { + width: 0px; + height: 0px; + } + body, html { + margin: 0px; + width: 100%; + height: 100%; + } + input { + padding: 0; + width: 100px; + height: 20px; + } + </style> + <input type="text" id="target" value="test"> + )HTML"); + + Compositor().BeginFrame(); + WebView().AdvanceFocus(false); + + HTMLInputElement* input = + ToHTMLInputElement(GetDocument().getElementById("target")); + input->select(); + + // Simulate the keyboard being shown and resizing the widget. Cause a scroll + // into view after. + ASSERT_EQ(WebView().FakePageScaleAnimationPageScaleForTesting(), 0.f); + WebFrameWidget* widget = WebView().MainFrameImpl()->FrameWidgetImpl(); + widget->ScrollFocusedEditableElementIntoView(); + + // Make sure zoomed in but only up to a legible scale. The bounds are + // arbitrary and fuzzy since we don't specifically care to constrain the + // amount of zooming (that should be tested elsewhere), we just care that it + // zooms but not off to infinity. + EXPECT_GT(WebView().FakePageScaleAnimationPageScaleForTesting(), .75f); + EXPECT_LT(WebView().FakePageScaleAnimationPageScaleForTesting(), 2.f); +} + TEST_F(WebFrameSimTest, DoubleTapZoomWhileScrolled) { UseAndroidSettings(); WebView().MainFrameWidget()->Resize(WebSize(490, 500)); diff --git a/chromium/third_party/blink/renderer/core/exported/web_view_impl.cc b/chromium/third_party/blink/renderer/core/exported/web_view_impl.cc index fa2150289b4..41e11e56e95 100644 --- a/chromium/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/chromium/third_party/blink/renderer/core/exported/web_view_impl.cc @@ -2156,7 +2156,7 @@ bool WebViewImpl::ScrollFocusedEditableElementIntoView() { element->GetDocument() .GetFrame() ->Selection() - .AbsoluteCaretBounds())), + .ComputeRectToScroll(kDoNotRevealExtent))), ShouldZoomToLegibleScale(*element)); return true; @@ -2514,16 +2514,26 @@ void WebViewImpl::SetMaximumLegibleScale(float maximum_legible_scale) { } void WebViewImpl::SetIgnoreViewportTagScaleLimits(bool ignore) { + // This method should be idempotent. + if (ignore == pre_override_default_constraints_.has_value()) + return; + PageScaleConstraints constraints = GetPageScaleConstraintsSet().UserAgentConstraints(); if (ignore) { + DCHECK(!pre_override_default_constraints_); + pre_override_default_constraints_.emplace(constraints); + constraints.minimum_scale = GetPageScaleConstraintsSet().DefaultConstraints().minimum_scale; constraints.maximum_scale = GetPageScaleConstraintsSet().DefaultConstraints().maximum_scale; + constraints.initial_scale = + GetPageScaleConstraintsSet().DefaultConstraints().minimum_scale; } else { - constraints.minimum_scale = -1; - constraints.maximum_scale = -1; + DCHECK(pre_override_default_constraints_); + constraints = pre_override_default_constraints_.value(); + pre_override_default_constraints_.reset(); } GetPage()->SetUserAgentPageScaleConstraints(constraints); } diff --git a/chromium/third_party/blink/renderer/core/exported/web_view_impl.h b/chromium/third_party/blink/renderer/core/exported/web_view_impl.h index aaa17462ee6..64a22db62db 100644 --- a/chromium/third_party/blink/renderer/core/exported/web_view_impl.h +++ b/chromium/third_party/blink/renderer/core/exported/web_view_impl.h @@ -691,6 +691,10 @@ class CORE_EXPORT WebViewImpl final : public WebView, FloatSize elastic_overscroll_; + // When overriding the default page scale constraints, store the original so + // we can revert to them when the override is removed. + base::Optional<PageScaleConstraints> pre_override_default_constraints_; + Persistent<EventListener> popup_mouse_wheel_event_listener_; // The local root whose document has |popup_mouse_wheel_event_listener_| diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame.cc b/chromium/third_party/blink/renderer/core/frame/local_frame.cc index dd0e2f0df7b..c1f7d53655b 100644 --- a/chromium/third_party/blink/renderer/core/frame/local_frame.cc +++ b/chromium/third_party/blink/renderer/core/frame/local_frame.cc @@ -339,7 +339,7 @@ void LocalFrame::Navigate(const FrameLoadRequest& request, WebFrameLoadType frame_load_type) { if (!navigation_rate_limiter().CanProceed()) return; - if (request.ClientRedirect() == ClientRedirectPolicy::kClientRedirect) { + if (request.ClientRedirectReason() != ClientNavigationReason::kNone) { probe::FrameScheduledNavigation(this, request.GetResourceRequest().Url(), 0.0, request.ClientRedirectReason()); if (NavigationScheduler::MustReplaceCurrentItem(this)) @@ -347,7 +347,7 @@ void LocalFrame::Navigate(const FrameLoadRequest& request, } loader_.StartNavigation(request, frame_load_type); - if (request.ClientRedirect() == ClientRedirectPolicy::kClientRedirect) + if (request.ClientRedirectReason() != ClientNavigationReason::kNone) probe::FrameClearedScheduledNavigation(this); } diff --git a/chromium/third_party/blink/renderer/core/frame/remote_frame.cc b/chromium/third_party/blink/renderer/core/frame/remote_frame.cc index 9de006e1b8e..fce85b75bcd 100644 --- a/chromium/third_party/blink/renderer/core/frame/remote_frame.cc +++ b/chromium/third_party/blink/renderer/core/frame/remote_frame.cc @@ -111,8 +111,8 @@ void RemoteFrame::Navigate(const FrameLoadRequest& passed_request, frame->GetSecurityContext() && frame->GetSecurityContext()->IsSandboxed(WebSandboxFlags::kDownloads); initiator_frame_is_ad = frame->IsAdSubframe(); - if (passed_request.ClientRedirect() == - ClientRedirectPolicy::kClientRedirect) { + if (passed_request.ClientRedirectReason() != + ClientNavigationReason::kNone) { probe::FrameRequestedNavigation(frame, this, url, passed_request.ClientRedirectReason()); } diff --git a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc index 98176198d5c..334198dff21 100644 --- a/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/chromium/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc @@ -147,8 +147,6 @@ intptr_t HTMLCanvasElement::global_gpu_memory_usage_ = 0; unsigned HTMLCanvasElement::global_accelerated_context_count_ = 0; HTMLCanvasElement::~HTMLCanvasElement() { - if (surface_layer_bridge_ && surface_layer_bridge_->GetCcLayer()) - GraphicsLayer::UnregisterContentsLayer(surface_layer_bridge_->GetCcLayer()); v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory( -externally_allocated_memory_); } @@ -177,6 +175,19 @@ void HTMLCanvasElement::Dispose() { global_accelerated_context_count_--; } global_gpu_memory_usage_ -= gpu_memory_usage_; + + if (surface_layer_bridge_) { + if (surface_layer_bridge_->GetCcLayer()) { + GraphicsLayer::UnregisterContentsLayer( + surface_layer_bridge_->GetCcLayer()); + } + // Observer has to be cleared out at this point. Otherwise the + // SurfaceLayerBridge may call back into the observer which is undefined + // behavior. In the worst case, the dead canvas element re-adds itself into + // a data structure which may crash at a later point in time. See + // https://crbug.com/976577. + surface_layer_bridge_->ClearObserver(); + } } void HTMLCanvasElement::ParseAttribute( diff --git a/chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc b/chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc index 390b142468a..ac8f7326720 100644 --- a/chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc +++ b/chromium/third_party/blink/renderer/core/html/forms/radio_input_type.cc @@ -155,8 +155,6 @@ void RadioInputType::HandleKeyupEvent(KeyboardEvent& event) { event.key() == "Enter")) { DispatchSimulatedClickIfActive(event); } - - DispatchSimulatedClickIfActive(event); } bool RadioInputType::IsKeyboardFocusable() const { diff --git a/chromium/third_party/blink/renderer/core/html/html_anchor_element.cc b/chromium/third_party/blink/renderer/core/html/html_anchor_element.cc index 94733fedf25..786167ccc30 100644 --- a/chromium/third_party/blink/renderer/core/html/html_anchor_element.cc +++ b/chromium/third_party/blink/renderer/core/html/html_anchor_element.cc @@ -429,8 +429,10 @@ void HTMLAnchorElement::HandleClick(Event& event) { } request.SetRequestContext(mojom::RequestContextType::HYPERLINK); - FrameLoadRequest frame_request(&GetDocument(), request, - getAttribute(kTargetAttr)); + const AtomicString& target = getAttribute(kTargetAttr); + FrameLoadRequest frame_request( + &GetDocument(), request, + target.IsEmpty() ? GetDocument().BaseTarget() : target); frame_request.SetNavigationPolicy(NavigationPolicyFromEvent(&event)); if (HasRel(kRelationNoReferrer)) { frame_request.SetShouldSendReferrer(kNeverSendReferrer); diff --git a/chromium/third_party/blink/renderer/core/html/html_element.cc b/chromium/third_party/blink/renderer/core/html/html_element.cc index 8803bea1c77..8a830c69504 100644 --- a/chromium/third_party/blink/renderer/core/html/html_element.cc +++ b/chromium/third_party/blink/renderer/core/html/html_element.cc @@ -1332,6 +1332,8 @@ bool HTMLElement::MatchesReadWritePseudoClass() const { void HTMLElement::HandleKeypressEvent(KeyboardEvent& event) { if (!IsSpatialNavigationEnabled(GetDocument().GetFrame()) || !SupportsFocus()) return; + if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) + return; GetDocument().UpdateStyleAndLayoutTree(); // if the element is a text form control (like <input type=text> or // <textarea>) or has contentEditable attribute on, we should enter a space or diff --git a/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc b/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc index bfc6b9530d1..9501d2dd946 100644 --- a/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc +++ b/chromium/third_party/blink/renderer/core/html/html_frame_owner_element.cc @@ -25,6 +25,7 @@ #include "third_party/blink/renderer/core/css/style_change_reason.h" #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/dom/node_computed_style.h" +#include "third_party/blink/renderer/core/events/current_input_event.h" #include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h" #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" @@ -403,13 +404,12 @@ bool HTMLFrameOwnerElement::LoadOrRedirectSubframe( KURL url_to_request = url.IsNull() ? BlankURL() : url; if (ContentFrame()) { // TODO(sclittle): Support lazily loading frame navigations. + FrameLoadRequest request(&GetDocument(), ResourceRequest(url_to_request)); + request.SetClientRedirectReason(ClientNavigationReason::kFrameNavigation); WebFrameLoadType frame_load_type = WebFrameLoadType::kStandard; if (replace_current_item) frame_load_type = WebFrameLoadType::kReplaceCurrentItem; - - ContentFrame()->ScheduleNavigation(GetDocument(), url_to_request, - frame_load_type, - UserGestureStatus::kNone); + ContentFrame()->Navigate(request, frame_load_type); return true; } diff --git a/chromium/third_party/blink/renderer/core/html/media/html_video_element.cc b/chromium/third_party/blink/renderer/core/html/media/html_video_element.cc index 07f6c2998fa..723c7faf25b 100644 --- a/chromium/third_party/blink/renderer/core/html/media/html_video_element.cc +++ b/chromium/third_party/blink/renderer/core/html/media/html_video_element.cc @@ -402,6 +402,8 @@ void HTMLVideoElement::OnPlay() { return; } + std::unique_ptr<UserGestureIndicator> gesture = + LocalFrame::NotifyUserActivation(GetDocument().GetFrame()); webkitEnterFullscreen(); } diff --git a/chromium/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc b/chromium/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc index c1a36918ec0..749e6a68982 100644 --- a/chromium/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc +++ b/chromium/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc @@ -157,4 +157,30 @@ TEST_F(VideoAutoFullscreen, ExitFullscreenDoesNotPauseWithPlaysInline) { EXPECT_FALSE(Video()->paused()); } +TEST_F(VideoAutoFullscreen, OnPlayTriggersFullscreenWithoutGesture) { + Video()->SetSrc("http://example.com/foo.mp4"); + { + std::unique_ptr<UserGestureIndicator> user_gesture_scope = + LocalFrame::NotifyUserActivation(GetFrame(), + UserGestureToken::kNewGesture); + Video()->Play(); + } + MakeGarbageCollected<WaitForEvent>(Video(), event_type_names::kPlay); + test::RunPendingTasks(); + + EXPECT_TRUE(Video()->IsFullscreen()); + + GetWebView()->ExitFullscreen(*GetFrame()); + test::RunPendingTasks(); + + EXPECT_TRUE(Video()->paused()); + EXPECT_FALSE(Video()->IsFullscreen()); + + Video()->Play(); + test::RunPendingTasks(); + + EXPECT_FALSE(Video()->paused()); + EXPECT_TRUE(Video()->IsFullscreen()); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/input/event_handler_test.cc b/chromium/third_party/blink/renderer/core/input/event_handler_test.cc index 0cff945a90f..33b3969cbc4 100644 --- a/chromium/third_party/blink/renderer/core/input/event_handler_test.cc +++ b/chromium/third_party/blink/renderer/core/input/event_handler_test.cc @@ -33,6 +33,8 @@ #include "third_party/blink/renderer/core/testing/sim/sim_test.h" #include "third_party/blink/renderer/platform/keyboard_codes.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" +#include "ui/events/keycodes/dom/dom_code.h" +#include "ui/events/keycodes/dom/dom_key.h" namespace blink { @@ -592,6 +594,22 @@ TEST_F(EventHandlerTest, EditableAnchorTextCanStartSelection) { Cursor::Type::kIBeam); // An I-beam signals editability. } +TEST_F(EventHandlerTest, implicitSend) { + SetHtmlInnerHTML("<button>abc</button>"); + GetDocument().GetSettings()->SetSpatialNavigationEnabled(true); + + WebKeyboardEvent e{WebInputEvent::kRawKeyDown, WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests()}; + e.dom_code = static_cast<int>(ui::DomCode::ARROW_DOWN); + e.dom_key = ui::DomKey::ARROW_DOWN; + GetDocument().GetFrame()->GetEventHandler().KeyEvent(e); + + // TODO(crbug.com/949766) Should cleanup these magic numbers. + e.dom_code = 0; + e.dom_key = 0x00200310; + GetDocument().GetFrame()->GetEventHandler().KeyEvent(e); +} + // Regression test for http://crbug.com/641403 to verify we use up-to-date // layout tree for dispatching "contextmenu" event. TEST_F(EventHandlerTest, sendContextMenuEventWithHover) { diff --git a/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc b/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc index aefdaab5a13..d6b65860898 100644 --- a/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc +++ b/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.cc @@ -339,6 +339,9 @@ void KeyboardEventManager::DefaultKeyboardEventHandler( DefaultEscapeEventHandler(event); } else if (event->key() == "Enter") { DefaultEnterEventHandler(event); + } else if (static_cast<int>(event->KeyEvent()->dom_key) == 0x00200310) { + // TODO(bokan): Cleanup magic numbers once https://crbug.com/949766 lands. + DefaultImeSubmitHandler(event); } else { // TODO(bokan): Seems odd to call the default _arrow_ event handler on // events that aren't necessarily arrow keys. @@ -348,16 +351,19 @@ void KeyboardEventManager::DefaultKeyboardEventHandler( frame_->GetEditor().HandleKeyboardEvent(event); if (event->DefaultHandled()) return; - if (event->charCode() == ' ') + if (event->key() == "Enter") { + DefaultEnterEventHandler(event); + } else if (event->charCode() == ' ') { DefaultSpaceEventHandler(event, possible_focused_node); + } } else if (event->type() == event_type_names::kKeyup) { + if (event->DefaultHandled()) + return; if (event->key() == "Enter") { DefaultEnterEventHandler(event); - return; - } - - if (event->keyCode() == kVKeySpatNavBack) + } else if (event->keyCode() == kVKeySpatNavBack) { DefaultSpatNavBackEventHandler(event); + } } } @@ -509,6 +515,17 @@ void KeyboardEventManager::DefaultEnterEventHandler(KeyboardEvent* event) { } } +void KeyboardEventManager::DefaultImeSubmitHandler(KeyboardEvent* event) { + Page* page = frame_->GetPage(); + if (!page) + return; + + if (IsSpatialNavigationEnabled(frame_) && + !frame_->GetDocument()->InDesignMode()) { + page->GetSpatialNavigationController().HandleImeSubmitKeyboardEvent(event); + } +} + static OverrideCapsLockState g_override_caps_lock_state; void KeyboardEventManager::SetCurrentCapsLockState( diff --git a/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h b/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h index 3d9afb6f6fe..3f1b4c4de8d 100644 --- a/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h +++ b/chromium/third_party/blink/renderer/core/input/keyboard_event_manager.h @@ -56,6 +56,7 @@ class CORE_EXPORT KeyboardEventManager void DefaultTabEventHandler(KeyboardEvent*); void DefaultEscapeEventHandler(KeyboardEvent*); void DefaultEnterEventHandler(KeyboardEvent*); + void DefaultImeSubmitHandler(KeyboardEvent*); void DefaultArrowEventHandler(KeyboardEvent*, Node*); bool DefaultSpatNavBackEventHandler(KeyboardEvent*); diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block.cc b/chromium/third_party/blink/renderer/core/layout/layout_block.cc index 481a0be7dc1..cbbd9281df3 100644 --- a/chromium/third_party/blink/renderer/core/layout/layout_block.cc +++ b/chromium/third_party/blink/renderer/core/layout/layout_block.cc @@ -1128,6 +1128,15 @@ void LayoutBlock::RemovePositionedObjects( } void LayoutBlock::AddPercentHeightDescendant(LayoutBox* descendant) { + // A replaced object is incapable of properly acting as a containing block for + // its children (this is an issue with VIDEO elements, for instance, which + // inserts some percentage height flexbox children). Assert that the + // descendant hasn't escaped from within a replaced object. Registering the + // percentage height descendant further up in the tree is only going to cause + // trouble, especially if the replaced object is out-of-flow positioned (and + // we failed to notice). + DCHECK(!descendant->Container()->IsLayoutReplaced()); + if (descendant->PercentHeightContainer()) { if (descendant->PercentHeightContainer() == this) { DCHECK(HasPercentHeightDescendant(descendant)); diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box.cc b/chromium/third_party/blink/renderer/core/layout/layout_box.cc index 5313c3963a3..a28f0ae2be2 100644 --- a/chromium/third_party/blink/renderer/core/layout/layout_box.cc +++ b/chromium/third_party/blink/renderer/core/layout/layout_box.cc @@ -3743,7 +3743,13 @@ LayoutUnit LayoutBox::ComputePercentageLogicalHeight( &cb, &skipped_auto_height_containing_block); DCHECK(cb); - cb->AddPercentHeightDescendant(const_cast<LayoutBox*>(this)); + + // If the container of the descendant is a replaced element (a VIDEO, for + // instance), |cb| (which uses ContainingBlock()) may actually not be in the + // containing block chain for the descendant. + const LayoutObject* container = Container(); + if (!container->IsLayoutReplaced()) + cb->AddPercentHeightDescendant(const_cast<LayoutBox*>(this)); if (available_height == -1) return available_height; diff --git a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc index 230c3830fbc..4cfaf04e392 100644 --- a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc +++ b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc @@ -1393,7 +1393,8 @@ bool LayoutFlexibleBox::ChildHasIntrinsicMainAxisSize( const FlexLayoutAlgorithm& algorithm, const LayoutBox& child) const { bool result = false; - if (!MainAxisIsInlineAxis(child) && !child.ShouldApplySizeContainment()) { + bool main_axis_is_inline = MainAxisIsInlineAxis(child); + if (!main_axis_is_inline && !child.ShouldApplySizeContainment()) { Length child_flex_basis = FlexBasisForChild(child); const Length& child_min_size = IsHorizontalFlow() ? child.StyleRef().MinWidth() @@ -1407,6 +1408,11 @@ bool LayoutFlexibleBox::ChildHasIntrinsicMainAxisSize( } else if (algorithm.ShouldApplyMinSizeAutoForChild(child)) { result = true; } + } else if (main_axis_is_inline && + child.StyleRef().OverflowInlineDirection() == EOverflow::kAuto) { + // Because scrollbars depend on layout, we need to layout before running + // the algorithm to get an up-to-date size. + result = true; } return result; } diff --git a/chromium/third_party/blink/renderer/core/loader/form_submission.cc b/chromium/third_party/blink/renderer/core/loader/form_submission.cc index 020052ff693..1ad45a7cc58 100644 --- a/chromium/third_party/blink/renderer/core/loader/form_submission.cc +++ b/chromium/third_party/blink/renderer/core/loader/form_submission.cc @@ -288,6 +288,8 @@ FrameLoadRequest FormSubmission::CreateFrameLoadRequest( if (!target_.IsEmpty()) frame_request.SetFrameName(target_); + else + frame_request.SetFrameName(origin_document->BaseTarget()); ClientNavigationReason reason = ClientNavigationReason::kFormSubmissionGet; if (method_ == FormSubmission::kPostMethod) { diff --git a/chromium/third_party/blink/renderer/core/loader/frame_load_request.cc b/chromium/third_party/blink/renderer/core/loader/frame_load_request.cc index 78c15ae6085..1bfa77c670a 100644 --- a/chromium/third_party/blink/renderer/core/loader/frame_load_request.cc +++ b/chromium/third_party/blink/renderer/core/loader/frame_load_request.cc @@ -8,6 +8,7 @@ #include "third_party/blink/public/platform/web_url_request.h" #include "third_party/blink/renderer/core/events/current_input_event.h" #include "third_party/blink/renderer/core/fileapi/public_url_manager.h" +#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" @@ -37,7 +38,6 @@ FrameLoadRequest::FrameLoadRequest( : origin_document_(origin_document), resource_request_(resource_request), frame_name_(frame_name), - client_redirect_(ClientRedirectPolicy::kNotClientRedirect), should_send_referrer_(kMaybeSendReferrer), should_check_main_world_content_security_policy_( should_check_main_world_content_security_policy) { @@ -63,7 +63,22 @@ FrameLoadRequest::FrameLoadRequest( origin_document->GetPublicURLManager().Resolve( resource_request.Url(), MakeRequest(&blob_url_token_->data)); } + + if (ContentSecurityPolicy::ShouldBypassMainWorld(origin_document)) { + should_check_main_world_content_security_policy_ = + kDoNotCheckContentSecurityPolicy; + } } } +ClientRedirectPolicy FrameLoadRequest::ClientRedirect() const { + // Form submissions have not historically been reported to the extensions API + // as client redirects. + if (client_navigation_reason_ == ClientNavigationReason::kNone || + client_navigation_reason_ == ClientNavigationReason::kFormSubmissionGet || + client_navigation_reason_ == ClientNavigationReason::kFormSubmissionPost) + return ClientRedirectPolicy::kNotClientRedirect; + return ClientRedirectPolicy::kClientRedirect; +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/loader/frame_load_request.h b/chromium/third_party/blink/renderer/core/loader/frame_load_request.h index 3c4e77dec96..a35c92f0ca9 100644 --- a/chromium/third_party/blink/renderer/core/loader/frame_load_request.h +++ b/chromium/third_party/blink/renderer/core/loader/frame_load_request.h @@ -74,15 +74,15 @@ struct CORE_EXPORT FrameLoadRequest { frame_name_ = frame_name; } - ClientRedirectPolicy ClientRedirect() const { return client_redirect_; } + // TODO(japhet): This is only used from frame_loader.cc, and can probably be + // an implementation detail there. + ClientRedirectPolicy ClientRedirect() const; void SetClientRedirectReason(ClientNavigationReason reason) { - client_redirect_ = ClientRedirectPolicy::kClientRedirect; client_navigation_reason_ = reason; } ClientNavigationReason ClientRedirectReason() const { - DCHECK_EQ(ClientRedirectPolicy::kClientRedirect, client_redirect_); return client_navigation_reason_; } @@ -165,11 +165,8 @@ struct CORE_EXPORT FrameLoadRequest { ResourceRequest resource_request_; AtomicString frame_name_; AtomicString href_translate_; - // TODO(caseq): merge ClientRedirectPolicy and ClientNavigationReason. - // Currently, client_navigation_reason_ is set iff ClientRedirectPolicy - // is set to kClientRedirect. - ClientRedirectPolicy client_redirect_; - ClientNavigationReason client_navigation_reason_; + ClientNavigationReason client_navigation_reason_ = + ClientNavigationReason::kNone; NavigationPolicy navigation_policy_ = kNavigationPolicyCurrentTab; WebTriggeringEventInfo triggering_event_info_ = WebTriggeringEventInfo::kNotFromEvent; diff --git a/chromium/third_party/blink/renderer/core/loader/frame_loader.cc b/chromium/third_party/blink/renderer/core/loader/frame_loader.cc index ebc44803f9a..3f2dad0e9a2 100644 --- a/chromium/third_party/blink/renderer/core/loader/frame_loader.cc +++ b/chromium/third_party/blink/renderer/core/loader/frame_loader.cc @@ -444,7 +444,7 @@ void FrameLoader::DidFinishNavigation() { // progress. DCHECK((document_loader_ && document_loader_->SentDidFinishLoad()) || !HasProvisionalNavigation()); - if (!document_loader_ || !document_loader_->SentDidFinishLoad() || + if ((document_loader_ && !document_loader_->SentDidFinishLoad()) || HasProvisionalNavigation()) { return; } @@ -730,9 +730,6 @@ bool FrameLoader::PrepareRequestForThisFrame(FrameLoadRequest& request) { "Not allowed to load local resource: " + url.ElidedString())); return false; } - - if (request.FrameName().IsEmpty()) - request.SetFrameName(frame_->GetDocument()->BaseTarget()); return true; } @@ -948,7 +945,7 @@ void FrameLoader::StartNavigation(const FrameLoadRequest& passed_request, } } - if (request.ClientRedirect() == ClientRedirectPolicy::kClientRedirect) { + if (request.ClientRedirectReason() != ClientNavigationReason::kNone) { probe::FrameRequestedNavigation(frame_, frame_, url, request.ClientRedirectReason()); } diff --git a/chromium/third_party/blink/renderer/core/loader/frame_loader_types.h b/chromium/third_party/blink/renderer/core/loader/frame_loader_types.h index 4df8bae808c..fa84bd0dfed 100644 --- a/chromium/third_party/blink/renderer/core/loader/frame_loader_types.h +++ b/chromium/third_party/blink/renderer/core/loader/frame_loader_types.h @@ -79,6 +79,7 @@ enum class ClientNavigationReason { kMetaTagRefresh, kPageBlock, kReload, + kNone }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc b/chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc index e60593d480f..c9db8b3291c 100644 --- a/chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc +++ b/chromium/third_party/blink/renderer/core/loader/resource/script_resource.cc @@ -290,6 +290,7 @@ void ScriptResource::OnDataPipeReadable(MojoResult result, // This means the producer finished and streamed to completion. watcher_.reset(); response_body_loader_client_->DidFinishLoadingBody(); + response_body_loader_client_ = nullptr; return; case MOJO_RESULT_SHOULD_WAIT: @@ -300,6 +301,7 @@ void ScriptResource::OnDataPipeReadable(MojoResult result, // Some other error occurred. watcher_.reset(); response_body_loader_client_->DidFailLoadingBody(); + response_body_loader_client_ = nullptr; return; } CHECK(state.readable()); @@ -358,6 +360,7 @@ void ScriptResource::NotifyFinished() { case StreamingState::kStreamingNotAllowed: watcher_.reset(); data_pipe_.reset(); + response_body_loader_client_ = nullptr; AdvanceStreamingState(StreamingState::kFinishedNotificationSent); TextResource::NotifyFinished(); break; @@ -382,6 +385,7 @@ void ScriptResource::StreamingFinished() { // small) and b) an external error triggered the finished notification. watcher_.reset(); data_pipe_.reset(); + response_body_loader_client_ = nullptr; AdvanceStreamingState(StreamingState::kFinishedNotificationSent); TextResource::NotifyFinished(); } @@ -463,6 +467,7 @@ void ScriptResource::SetClientIsWaitingForFinished() { if (IsLoaded()) { watcher_.reset(); data_pipe_.reset(); + response_body_loader_client_ = nullptr; AdvanceStreamingState(StreamingState::kFinishedNotificationSent); TextResource::NotifyFinished(); } @@ -536,6 +541,7 @@ void ScriptResource::CheckStreamingState() const { CHECK(!streamer_ || streamer_->IsFinished()); CHECK(!watcher_ || !watcher_->IsWatching()); CHECK(!data_pipe_); + CHECK(!response_body_loader_client_); CHECK(IsLoaded()); break; } diff --git a/chromium/third_party/blink/renderer/core/page/focus_controller.cc b/chromium/third_party/blink/renderer/core/page/focus_controller.cc index 8e8348de9a5..041804d5ec7 100644 --- a/chromium/third_party/blink/renderer/core/page/focus_controller.cc +++ b/chromium/third_party/blink/renderer/core/page/focus_controller.cc @@ -1158,9 +1158,12 @@ Element* FocusController::NextFocusableElementInForm(Element* element, if (form_element->formOwner() != form_owner || form_element->IsDisabledOrReadOnly()) continue; - // Focusless spatial navigation supports all form types. + // Focusless spatial navigation supports all form types. However, submit + // buttons are explicitly excluded as moving to them isn't necessary - the + // IME should just submit instead. if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled() && - page_->GetSettings().GetSpatialNavigationEnabled()) { + page_->GetSettings().GetSpatialNavigationEnabled() && + !form_element->CanBeSuccessfulSubmitButton()) { return next_element; } LayoutObject* layout = next_element->GetLayoutObject(); diff --git a/chromium/third_party/blink/renderer/core/page/page.cc b/chromium/third_party/blink/renderer/core/page/page.cc index 1c2e3dbbb01..6cc6c5a6f38 100644 --- a/chromium/third_party/blink/renderer/core/page/page.cc +++ b/chromium/third_party/blink/renderer/core/page/page.cc @@ -307,8 +307,6 @@ void Page::DocumentDetached(Document* document) { if (validation_message_client_) validation_message_client_->DocumentDetached(*document); hosts_using_features_.DocumentDetached(*document); - if (spatial_navigation_controller_ && document->GetFrame()->IsMainFrame()) - spatial_navigation_controller_->ResetMojoBindings(); } bool Page::OpenedByDOM() const { diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc b/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc index b443a2d9f4a..b95b34b5118 100644 --- a/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc +++ b/chromium/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc @@ -827,6 +827,10 @@ bool ScrollsWithRootFrame(LayoutObject* object) { DCHECK(object); DCHECK(object->GetFrame()); + // TODO(bokan): Speculative fix for https://crbug.com/964293. + if (!object || !object->GetNode()) + return true; + const LocalFrame& frame = *object->GetFrame(); // If we're in an iframe document, we need to determine if the containing diff --git a/chromium/third_party/blink/renderer/core/page/spatial_navigation.cc b/chromium/third_party/blink/renderer/core/page/spatial_navigation.cc index 04c10fd3910..56a992c588c 100644 --- a/chromium/third_party/blink/renderer/core/page/spatial_navigation.cc +++ b/chromium/third_party/blink/renderer/core/page/spatial_navigation.cc @@ -37,6 +37,7 @@ #include "third_party/blink/renderer/core/html/html_frame_owner_element.h" #include "third_party/blink/renderer/core/html/html_image_element.h" #include "third_party/blink/renderer/core/html_names.h" +#include "third_party/blink/renderer/core/input/event_handler.h" #include "third_party/blink/renderer/core/layout/layout_box.h" #include "third_party/blink/renderer/core/layout/layout_inline.h" #include "third_party/blink/renderer/core/layout/layout_view.h" @@ -47,6 +48,14 @@ namespace blink { +// A small integer that easily fits into a double with a good margin for +// arithmetic. In particular, we don't want to use +// std::numeric_limits<double>::lowest() because, if subtracted, it becomes +// NaN which will make all following arithmetic NaN too (an unusable number). +constexpr double kMinDistance = std::numeric_limits<int>::lowest(); + +constexpr int kFudgeFactor = 2; + static void DeflateIfOverlapped(LayoutRect&, LayoutRect&); FocusCandidate::FocusCandidate(Node* node, SpatialNavigationDirection direction) @@ -185,6 +194,49 @@ ScrollableArea* ScrollableAreaFor(const Node* node) { return ToLayoutBox(object)->GetScrollableArea(); } +bool IsUnobscured(const FocusCandidate& candidate) { + DCHECK(candidate.visible_node); + + const LocalFrame* local_main_frame = DynamicTo<LocalFrame>( + candidate.visible_node->GetDocument().GetPage()->MainFrame()); + if (!local_main_frame) + return false; + + // TODO(crbug.com/955952): We cannot evaluate visibility for media element + // using hit test since attached media controls cover media element. + if (candidate.visible_node->IsMediaElement()) + return true; + + LayoutRect viewport_rect = LayoutRect( + local_main_frame->GetPage()->GetVisualViewport().VisibleContentRect()); + LayoutRect interesting_rect = + Intersection(candidate.rect_in_root_frame, viewport_rect); + + if (interesting_rect.IsEmpty()) + return false; + + HitTestLocation location(interesting_rect); + HitTestResult result = + local_main_frame->GetEventHandler().HitTestResultAtLocation( + location, HitTestRequest::kReadOnly | HitTestRequest::kListBased | + HitTestRequest::kIgnoreZeroOpacityObjects | + HitTestRequest::kAllowChildFrameContent); + + const HitTestResult::NodeSet& nodes = result.ListBasedTestResult(); + for (auto hit_node = nodes.rbegin(); hit_node != nodes.rend(); ++hit_node) { + if (candidate.visible_node->ContainsIncludingHostElements(**hit_node)) + return true; + + if (FrameOwnerElement(candidate) && + FrameOwnerElement(candidate) + ->contentDocument() + ->ContainsIncludingHostElements(**hit_node)) + return true; + } + + return false; +} + bool HasRemoteFrame(const Node* node) { auto* frame_owner_element = DynamicTo<HTMLFrameOwnerElement>(node); if (!frame_owner_element) @@ -237,7 +289,9 @@ bool ScrollInDirection(Node* container, SpatialNavigationDirection direction) { // CanScrollInDirection(). Regular arrow-key scrolling (without // --enable-spatial-navigation) already uses smooth scrolling by default. ScrollableArea* scroller = ScrollableAreaFor(container); - DCHECK(scroller); + if (!scroller) + return false; + scroller->ScrollBy(ScrollOffset(dx, dy), kUserScroll); return true; } @@ -246,7 +300,7 @@ static void DeflateIfOverlapped(LayoutRect& a, LayoutRect& b) { if (!a.Intersects(b) || a.Contains(b) || b.Contains(a)) return; - LayoutUnit deflate_factor = LayoutUnit(-FudgeFactor()); + LayoutUnit deflate_factor = LayoutUnit(-kFudgeFactor); // Avoid negative width or height values. if ((a.Width() + 2 * deflate_factor > 0) && @@ -481,55 +535,42 @@ void EntryAndExitPointsForDirection(SpatialNavigationDirection direction, } } -bool AreElementsOnSameLine(const FocusCandidate& first_candidate, - const FocusCandidate& second_candidate) { - if (first_candidate.IsNull() || second_candidate.IsNull()) - return false; - - if (!first_candidate.visible_node->GetLayoutObject() || - !second_candidate.visible_node->GetLayoutObject()) - return false; - - if (!first_candidate.rect_in_root_frame.Intersects( - second_candidate.rect_in_root_frame)) - return false; - - if (IsHTMLAreaElement(*first_candidate.focusable_node) || - IsHTMLAreaElement(*second_candidate.focusable_node)) - return false; - - if (!first_candidate.visible_node->GetLayoutObject()->IsLayoutInline() || - !second_candidate.visible_node->GetLayoutObject()->IsLayoutInline()) - return false; - - if (first_candidate.visible_node->GetLayoutObject()->ContainingBlock() != - second_candidate.visible_node->GetLayoutObject()->ContainingBlock()) - return false; - - return true; -} - double ComputeDistanceDataForNode(SpatialNavigationDirection direction, const FocusCandidate& current_interest, const FocusCandidate& candidate) { - if (!IsRectInDirection(direction, current_interest.rect_in_root_frame, - candidate.rect_in_root_frame)) - return MaxDistance(); - - if (AreElementsOnSameLine(current_interest, candidate)) { - if ((direction == SpatialNavigationDirection::kUp && - current_interest.rect_in_root_frame.Y() > - candidate.rect_in_root_frame.Y()) || - (direction == SpatialNavigationDirection::kDown && - candidate.rect_in_root_frame.Y() > - current_interest.rect_in_root_frame.Y())) { - return 0.0; - } - } - + double distance = 0.0; + double overlap = 0.0; LayoutRect node_rect = candidate.rect_in_root_frame; LayoutRect current_rect = current_interest.rect_in_root_frame; - DeflateIfOverlapped(current_rect, node_rect); + if (node_rect.Contains(current_rect)) { + // When leaving an "insider", don't focus its underlaying container box. + // Go directly to the outside world. This avoids focus from being trapped + // inside a container. + return kMaxDistance; + } + + if (current_rect.Contains(node_rect)) { + // We give priority to "insiders", candidates that are completely inside the + // current focus rect, by giving them a negative, < 0, distance number. + distance = kMinDistance; + + // For insiders we cannot meassure the distance from the outer box. Instead, + // we meassure distance _from_ the focused container's rect's "opposite + // edge" in the navigated direction, just like we do when we look for + // candidates inside a focused scroll container. + current_rect = OppositeEdge(direction, current_rect); + + // This candidate fully overlaps the current focus rect so we can omit the + // overlap term of the equation. An "insider" will always win against an + // "outsider". + } else if (!IsRectInDirection(direction, current_rect, node_rect)) { + return kMaxDistance; + } else { + DeflateIfOverlapped(current_rect, node_rect); + LayoutRect intersection_rect = Intersection(current_rect, node_rect); + overlap = + (intersection_rect.Width() * intersection_rect.Height()).ToDouble(); + } LayoutPoint exit_point; LayoutPoint entry_point; @@ -538,6 +579,9 @@ double ComputeDistanceDataForNode(SpatialNavigationDirection direction, LayoutUnit x_axis = (exit_point.X() - entry_point.X()).Abs(); LayoutUnit y_axis = (exit_point.Y() - entry_point.Y()).Abs(); + double euclidian_distance = + sqrt((x_axis * x_axis + y_axis * y_axis).ToDouble()); + distance += euclidian_distance; LayoutUnit navigation_axis_distance; LayoutUnit weighted_orthogonal_axis_distance; @@ -572,21 +616,17 @@ double ComputeDistanceDataForNode(SpatialNavigationDirection direction, break; default: NOTREACHED(); - return MaxDistance(); + return kMaxDistance; } - double euclidian_distance_pow2 = - (x_axis * x_axis + y_axis * y_axis).ToDouble(); - LayoutRect intersection_rect = Intersection(current_rect, node_rect); - double overlap = - (intersection_rect.Width() * intersection_rect.Height()).ToDouble(); - // Distance calculation is based on http://www.w3.org/TR/WICD/#focus-handling - return sqrt(euclidian_distance_pow2) + navigation_axis_distance + + return distance + navigation_axis_distance + weighted_orthogonal_axis_distance - sqrt(overlap); } -// Returns a thin rectangle that represents one of box's sides. +// Returns a thin rectangle that represents one of |box|'s edges. +// To not intersect elements that are positioned inside |box|, we add one +// LayoutUnit of margin that puts the returned slice "just outside" |box|. LayoutRect OppositeEdge(SpatialNavigationDirection side, const LayoutRect& box, LayoutUnit thickness) { @@ -595,16 +635,20 @@ LayoutRect OppositeEdge(SpatialNavigationDirection side, case SpatialNavigationDirection::kLeft: thin_rect.SetX(thin_rect.MaxX() - thickness); thin_rect.SetWidth(thickness); + thin_rect.Move(1, 0); break; case SpatialNavigationDirection::kRight: thin_rect.SetWidth(thickness); + thin_rect.Move(-1, 0); break; case SpatialNavigationDirection::kDown: thin_rect.SetHeight(thickness); + thin_rect.Move(0, -1); break; case SpatialNavigationDirection::kUp: thin_rect.SetY(thin_rect.MaxY() - thickness); thin_rect.SetHeight(thickness); + thin_rect.Move(0, 1); break; default: NOTREACHED(); @@ -623,7 +667,7 @@ LayoutRect StartEdgeForAreaElement(const HTMLAreaElement& area, direction, area.GetDocument().GetFrame()->View()->ConvertToRootFrame( area.ComputeAbsoluteRect(area.ImageElement()->GetLayoutObject())), - LayoutUnit(1) /* snav-imagemap-overlapped-areas.html */); + LayoutUnit(kFudgeFactor) /* snav-imagemap-overlapped-areas.html */); return rect; } diff --git a/chromium/third_party/blink/renderer/core/page/spatial_navigation.h b/chromium/third_party/blink/renderer/core/page/spatial_navigation.h index 5a6e2725239..7112a4d3bed 100644 --- a/chromium/third_party/blink/renderer/core/page/spatial_navigation.h +++ b/chromium/third_party/blink/renderer/core/page/spatial_navigation.h @@ -36,13 +36,7 @@ class HTMLFrameOwnerElement; enum class SpatialNavigationDirection { kNone, kUp, kRight, kDown, kLeft }; -inline double MaxDistance() { - return std::numeric_limits<double>::max(); -} - -inline int FudgeFactor() { - return 2; -} +constexpr double kMaxDistance = std::numeric_limits<double>::max(); CORE_EXPORT bool IsSpatialNavigationEnabled(const LocalFrame*); @@ -73,14 +67,13 @@ struct FocusCandidate { CORE_EXPORT bool HasRemoteFrame(const Node*); CORE_EXPORT FloatRect RectInViewport(const Node&); CORE_EXPORT bool IsOffscreen(const Node*); +CORE_EXPORT bool IsUnobscured(const FocusCandidate&); bool ScrollInDirection(Node* container, SpatialNavigationDirection); CORE_EXPORT bool IsScrollableNode(const Node* node); CORE_EXPORT bool IsScrollableAreaOrDocument(const Node*); CORE_EXPORT Node* ScrollableAreaOrDocumentOf(Node*); bool CanScrollInDirection(const Node* container, SpatialNavigationDirection); bool CanScrollInDirection(const LocalFrame*, SpatialNavigationDirection); -bool AreElementsOnSameLine(const FocusCandidate& first_candidate, - const FocusCandidate& second_candidate); double ComputeDistanceDataForNode(SpatialNavigationDirection, const FocusCandidate& current_interest, diff --git a/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.cc b/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.cc index d15a56d90e2..8ba2f2a154f 100644 --- a/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.cc +++ b/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.cc @@ -17,6 +17,8 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/frame/visual_viewport.h" +#include "third_party/blink/renderer/core/html/forms/html_form_control_element.h" +#include "third_party/blink/renderer/core/html/forms/html_form_element.h" #include "third_party/blink/renderer/core/html/html_frame_owner_element.h" #include "third_party/blink/renderer/core/html/media/html_video_element.h" #include "third_party/blink/renderer/core/input/event_handler.h" @@ -90,47 +92,11 @@ static void ConsiderForBestCandidate(SpatialNavigationDirection direction, double distance = ComputeDistanceDataForNode(direction, current_interest, candidate); - if (distance == MaxDistance()) + if (distance == kMaxDistance) return; - if (best_candidate->IsNull()) { - *best_candidate = candidate; - *best_distance = distance; - return; - } - LayoutRect intersection_rect = Intersection( - candidate.rect_in_root_frame, best_candidate->rect_in_root_frame); - if (!intersection_rect.IsEmpty() && - !AreElementsOnSameLine(*best_candidate, candidate) && - intersection_rect == candidate.rect_in_root_frame) { - // If 2 nodes are intersecting, do hit test to find which node in on top. - LayoutUnit x = intersection_rect.X() + intersection_rect.Width() / 2; - LayoutUnit y = intersection_rect.Y() + intersection_rect.Height() / 2; - if (!IsA<LocalFrame>( - candidate.visible_node->GetDocument().GetPage()->MainFrame())) - return; - HitTestLocation location(IntPoint(x.ToInt(), y.ToInt())); - HitTestResult result = - candidate.visible_node->GetDocument() - .GetPage() - ->DeprecatedLocalMainFrame() - ->GetEventHandler() - .HitTestResultAtLocation( - location, HitTestRequest::kReadOnly | HitTestRequest::kActive | - HitTestRequest::kIgnoreClipping); - if (candidate.visible_node->ContainsIncludingHostElements( - *result.InnerNode())) { - *best_candidate = candidate; - *best_distance = distance; - return; - } - if (best_candidate->visible_node->ContainsIncludingHostElements( - *result.InnerNode())) - return; - } - - if (distance < *best_distance) { + if (distance < *best_distance && IsUnobscured(candidate)) { *best_candidate = candidate; *best_distance = distance; } @@ -196,10 +162,18 @@ bool SpatialNavigationController::HandleEnterKeyboardEvent( return false; if (event->type() == event_type_names::kKeydown) { + enter_key_down_seen_ = true; interest_element->SetActive(true); + } else if (event->type() == event_type_names::kKeypress) { + enter_key_press_seen_ = true; } else if (event->type() == event_type_names::kKeyup) { interest_element->SetActive(false); - if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) { + + // Ensure that the enter key has not already been handled by something else, + // or we can end up clicking elements multiple times. Some elements already + // convert the Enter key into click on down and press (and up) events. + if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled() && + enter_key_down_seen_ && enter_key_press_seen_) { interest_element->focus(FocusParams(SelectionBehaviorOnFocus::kReset, kWebFocusTypeSpatialNavigation, nullptr)); @@ -212,6 +186,28 @@ bool SpatialNavigationController::HandleEnterKeyboardEvent( return true; } +void SpatialNavigationController::ResetEnterKeyState() { + enter_key_down_seen_ = false; + enter_key_press_seen_ = false; +} + +bool SpatialNavigationController::HandleImeSubmitKeyboardEvent( + KeyboardEvent* event) { + DCHECK(page_->GetSettings().GetSpatialNavigationEnabled()); + + if (!IsHTMLFormControlElement(GetFocusedElement())) + return false; + + HTMLFormControlElement* element = + ToHTMLFormControlElement(GetFocusedElement()); + + if (!element->formOwner()) + return false; + + element->formOwner()->SubmitImplicitly(*event, true); + return true; +} + bool SpatialNavigationController::HandleEscapeKeyboardEvent( KeyboardEvent* event) { DCHECK(page_->GetSettings().GetSpatialNavigationEnabled()); @@ -248,6 +244,8 @@ void SpatialNavigationController::DidDetachFrameView() { // etc.) then reset navigation. if (interest_element_ && !interest_element_->GetDocument().View()) interest_element_ = nullptr; + // TODO(crbug.com/956209): should be checked via an integration test. + ResetMojoBindings(); } void SpatialNavigationController::Trace(blink::Visitor* visitor) { @@ -317,7 +315,7 @@ FocusCandidate SpatialNavigationController::FindNextCandidateInContainer( current_interest.visible_node = interest_child_in_container; FocusCandidate best_candidate; - double best_distance = MaxDistance(); + double best_distance = kMaxDistance; for (; element; element = IsScrollableAreaOrDocument(element) @@ -550,6 +548,7 @@ void SpatialNavigationController::UpdateSpatialNavigationState( bool change = false; change |= UpdateCanExitFocus(element); change |= UpdateCanSelectInterestedElement(element); + change |= UpdateIsFormFocused(element); change |= UpdateHasNextFormElement(element); change |= UpdateHasDefaultVideoControls(element); if (change) @@ -564,7 +563,7 @@ void SpatialNavigationController::OnSpatialNavigationStateChanged() { } bool SpatialNavigationController::UpdateCanExitFocus(Element* element) { - bool can_exit_focus = IsFocused(element); + bool can_exit_focus = IsFocused(element) && !IsHTMLBodyElement(element); if (can_exit_focus == spatial_navigation_state_->can_exit_focus) return false; spatial_navigation_state_->can_exit_focus = can_exit_focus; @@ -594,6 +593,15 @@ bool SpatialNavigationController::UpdateHasNextFormElement(Element* element) { return true; } +bool SpatialNavigationController::UpdateIsFormFocused(Element* element) { + bool is_form_focused = IsFocused(element) && element->IsFormControlElement(); + + if (is_form_focused == spatial_navigation_state_->is_form_focused) + return false; + spatial_navigation_state_->is_form_focused = is_form_focused; + return true; +} + bool SpatialNavigationController::UpdateHasDefaultVideoControls( Element* element) { bool has_default_video_controls = diff --git a/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.h b/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.h index 05ee39d5615..98b709da93c 100644 --- a/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.h +++ b/chromium/third_party/blink/renderer/core/page/spatial_navigation_controller.h @@ -30,6 +30,11 @@ class CORE_EXPORT SpatialNavigationController bool HandleArrowKeyboardEvent(KeyboardEvent* event); bool HandleEnterKeyboardEvent(KeyboardEvent* event); bool HandleEscapeKeyboardEvent(KeyboardEvent* event); + bool HandleImeSubmitKeyboardEvent(KeyboardEvent* event); + + // Called when the enter key is released to clear local state because we don't + // get a consistent event stream when the Enter key is partially handled. + void ResetEnterKeyState(); // Returns the element that's currently interested. i.e. the Element that's // currently indicated to the user. @@ -40,8 +45,6 @@ class CORE_EXPORT SpatialNavigationController void OnSpatialNavigationSettingChanged(); void FocusedNodeChanged(Document*); - void ResetMojoBindings(); - void Trace(blink::Visitor*); private: @@ -97,15 +100,22 @@ class CORE_EXPORT SpatialNavigationController bool UpdateCanExitFocus(Element* element); bool UpdateCanSelectInterestedElement(Element* element); bool UpdateHasNextFormElement(Element* element); + bool UpdateIsFormFocused(Element* element); bool UpdateHasDefaultVideoControls(Element* element); const mojom::blink::SpatialNavigationHostPtr& GetSpatialNavigationHost(); + void ResetMojoBindings(); // The currently indicated element or nullptr if no node is indicated by // spatial navigation. WeakMember<Element> interest_element_; Member<Page> page_; + // We need to track whether the enter key has been handled in down or press to + // know whether to generate a click on the up. + bool enter_key_down_seen_ = false; + bool enter_key_press_seen_ = false; + mojom::blink::SpatialNavigationStatePtr spatial_navigation_state_; mojom::blink::SpatialNavigationHostPtr spatial_navigation_host_; }; diff --git a/chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc b/chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc index e0716b124bf..a7416224660 100644 --- a/chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc +++ b/chromium/third_party/blink/renderer/core/page/spatial_navigation_test.cc @@ -26,26 +26,28 @@ class SpatialNavigationTest : public RenderingTest { LayoutRect TopOfVisualViewport() { LayoutRect visual_viewport = RootViewport(&GetFrame()); + visual_viewport.SetY(visual_viewport.Y() - 1); visual_viewport.SetHeight(LayoutUnit(0)); return visual_viewport; } LayoutRect BottomOfVisualViewport() { LayoutRect visual_viewport = RootViewport(&GetFrame()); - visual_viewport.SetY(visual_viewport.MaxY()); + visual_viewport.SetY(visual_viewport.MaxY() + 1); visual_viewport.SetHeight(LayoutUnit(0)); return visual_viewport; } LayoutRect LeftSideOfVisualViewport() { LayoutRect visual_viewport = RootViewport(&GetFrame()); + visual_viewport.SetX(visual_viewport.X() - 1); visual_viewport.SetWidth(LayoutUnit(0)); return visual_viewport; } LayoutRect RightSideOfVisualViewport() { LayoutRect visual_viewport = RootViewport(&GetFrame()); - visual_viewport.SetX(visual_viewport.MaxX()); + visual_viewport.SetX(visual_viewport.MaxX() + 1); visual_viewport.SetWidth(LayoutUnit(0)); return visual_viewport; } @@ -245,7 +247,7 @@ TEST_F(SpatialNavigationTest, StartAtVisibleFocusedIframe) { } TEST_F(SpatialNavigationTest, StartAtTopWhenGoingDownwardsWithoutFocus) { - EXPECT_EQ(LayoutRect(0, 0, 111, 0), + EXPECT_EQ(LayoutRect(0, -1, 111, 0), SearchOrigin({0, 0, 111, 222}, nullptr, SpatialNavigationDirection::kDown)); @@ -256,7 +258,7 @@ TEST_F(SpatialNavigationTest, StartAtTopWhenGoingDownwardsWithoutFocus) { TEST_F(SpatialNavigationTest, StartAtBottomWhenGoingUpwardsWithoutFocus) { EXPECT_EQ( - LayoutRect(0, 222, 111, 0), + LayoutRect(0, 222 + 1, 111, 0), SearchOrigin({0, 0, 111, 222}, nullptr, SpatialNavigationDirection::kUp)); EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), nullptr, @@ -265,7 +267,7 @@ TEST_F(SpatialNavigationTest, StartAtBottomWhenGoingUpwardsWithoutFocus) { } TEST_F(SpatialNavigationTest, StartAtLeftSideWhenGoingEastWithoutFocus) { - EXPECT_EQ(LayoutRect(0, 0, 0, 222), + EXPECT_EQ(LayoutRect(-1, 0, 0, 222), SearchOrigin({0, 0, 111, 222}, nullptr, SpatialNavigationDirection::kRight)); @@ -275,7 +277,7 @@ TEST_F(SpatialNavigationTest, StartAtLeftSideWhenGoingEastWithoutFocus) { } TEST_F(SpatialNavigationTest, StartAtRightSideWhenGoingWestWithoutFocus) { - EXPECT_EQ(LayoutRect(111, 0, 0, 222), + EXPECT_EQ(LayoutRect(111 + 1, 0, 0, 222), SearchOrigin({0, 0, 111, 222}, nullptr, SpatialNavigationDirection::kLeft)); @@ -330,14 +332,15 @@ TEST_F(SpatialNavigationTest, StartAtContainersEdge) { // Go down. LayoutRect container_top_edge = container_box; container_top_edge.SetHeight(LayoutUnit(0)); + container_top_edge.SetY(container_top_edge.Y() - 1); EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, SpatialNavigationDirection::kDown), container_top_edge); // Go up. LayoutRect container_bottom_edge = container_box; - container_bottom_edge.SetY(container_bottom_edge.MaxX()); container_bottom_edge.SetHeight(LayoutUnit(0)); + container_bottom_edge.SetY(container_bottom_edge.MaxX() + 1); EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, SpatialNavigationDirection::kUp), container_bottom_edge); @@ -345,13 +348,14 @@ TEST_F(SpatialNavigationTest, StartAtContainersEdge) { // Go right. LayoutRect container_leftmost_edge = container_box; container_leftmost_edge.SetWidth(LayoutUnit(0)); + container_leftmost_edge.SetX(container_leftmost_edge.X() - 1); EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, SpatialNavigationDirection::kRight), container_leftmost_edge); // Go left. LayoutRect container_rightmost_edge = container_box; - container_rightmost_edge.SetX(container_bottom_edge.MaxX()); + container_rightmost_edge.SetX(container_bottom_edge.MaxX() + 1); container_rightmost_edge.SetWidth(LayoutUnit(0)); EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, SpatialNavigationDirection::kLeft), @@ -596,7 +600,7 @@ TEST_F(SpatialNavigationTest, BottomOfPinchedViewport) { EXPECT_EQ(origin.Height(), 0); EXPECT_EQ(origin.Width(), GetFrame().View()->Width()); EXPECT_EQ(origin.X(), 0); - EXPECT_EQ(origin.Y(), GetFrame().View()->Height()); + EXPECT_EQ(origin.Y(), GetFrame().View()->Height() + 1); EXPECT_EQ(origin, BottomOfVisualViewport()); // Now, test SearchOrigin with a pinched viewport. @@ -608,7 +612,7 @@ TEST_F(SpatialNavigationTest, BottomOfPinchedViewport) { EXPECT_EQ(origin.Height(), 0); EXPECT_LT(origin.Width(), GetFrame().View()->Width()); EXPECT_GT(origin.X(), 0); - EXPECT_LT(origin.Y(), GetFrame().View()->Height()); + EXPECT_LT(origin.Y(), GetFrame().View()->Height() + 1); EXPECT_EQ(origin, BottomOfVisualViewport()); } @@ -618,7 +622,7 @@ TEST_F(SpatialNavigationTest, TopOfPinchedViewport) { EXPECT_EQ(origin.Height(), 0); EXPECT_EQ(origin.Width(), GetFrame().View()->Width()); EXPECT_EQ(origin.X(), 0); - EXPECT_EQ(origin.Y(), 0); + EXPECT_EQ(origin.Y(), -1); EXPECT_EQ(origin, TopOfVisualViewport()); // Now, test SearchOrigin with a pinched viewport. @@ -630,7 +634,7 @@ TEST_F(SpatialNavigationTest, TopOfPinchedViewport) { EXPECT_EQ(origin.Height(), 0); EXPECT_LT(origin.Width(), GetFrame().View()->Width()); EXPECT_GT(origin.X(), 0); - EXPECT_GT(origin.Y(), 0); + EXPECT_GT(origin.Y(), -1); EXPECT_EQ(origin, TopOfVisualViewport()); } diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc index aff08d420fe..50e185b0966 100644 --- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc +++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc @@ -172,8 +172,16 @@ void CompositingLayerPropertyUpdater::Update(const LayoutObject& object) { auto* main_graphics_layer = mapping->MainGraphicsLayer(); if (main_graphics_layer->ContentsLayer()) { - main_graphics_layer->SetContentsPropertyTreeState( - fragment_data.ContentsProperties()); + IntPoint offset; + // The offset should be zero when the layer has ReplacedContentTransform, + // because the offset has been baked into ReplacedContentTransform. + if (!fragment_data.PaintProperties() || + !fragment_data.PaintProperties()->ReplacedContentTransform()) { + offset = main_graphics_layer->ContentsRect().Location() + + main_graphics_layer->GetOffsetFromTransformNode(); + } + main_graphics_layer->SetContentsLayerState( + fragment_data.ContentsProperties(), offset); } if (auto* squashing_layer = mapping->SquashingLayer()) { diff --git a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc index 2e93937014a..5a6dee4b34c 100644 --- a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc +++ b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc @@ -69,6 +69,15 @@ namespace blink { static constexpr float kStartOpacity = 1; +namespace { + +float HighlightTargetOpacity() { + // For web tests we don't fade out. + return WebTestSupport::IsRunningWebTest() ? kStartOpacity : 0; +} + +} // namespace + static CompositorElementId NewElementId() { if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() || RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) { @@ -103,7 +112,7 @@ LinkHighlightImpl::LinkHighlightImpl(Node* node) geometry_needs_update_ = true; EffectPaintPropertyNode::State state; - state.opacity = kStartOpacity; + state.opacity = HighlightTargetOpacity(); state.local_transform_space = &TransformPaintPropertyNode::Root(); state.compositor_element_id = element_id_; state.direct_compositing_reasons = CompositingReason::kActiveOpacityAnimation; @@ -354,10 +363,9 @@ void LinkHighlightImpl::StartHighlightAnimationIfNeeded() { curve->AddKeyframe(CompositorFloatKeyframe( extra_duration_required.InSecondsF(), kStartOpacity, timing_function)); } - // For web tests we don't fade out. curve->AddKeyframe(CompositorFloatKeyframe( (kFadeDuration + extra_duration_required).InSecondsF(), - WebTestSupport::IsRunningWebTest() ? kStartOpacity : 0, timing_function)); + HighlightTargetOpacity(), timing_function)); auto keyframe_model = std::make_unique<CompositorKeyframeModel>( *curve, compositor_target_property::OPACITY, 0, 0); diff --git a/chromium/third_party/blink/renderer/core/xml/xpath_grammar.y b/chromium/third_party/blink/renderer/core/xml/xpath_grammar.y index 17d0b89685d..cf0208370a0 100644 --- a/chromium/third_party/blink/renderer/core/xml/xpath_grammar.y +++ b/chromium/third_party/blink/renderer/core/xml/xpath_grammar.y @@ -34,15 +34,14 @@ #include "third_party/blink/renderer/core/xml/xpath_predicate.h" #include "third_party/blink/renderer/core/xml/xpath_step.h" #include "third_party/blink/renderer/core/xml/xpath_variable_reference.h" -#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h" -void* YyFastMalloc(size_t size) -{ - return WTF::Partitions::FastMalloc(size, nullptr); -} - -#define YYMALLOC YyFastMalloc -#define YYFREE WTF::Partitions::FastFree +// The union below must be located on the stack because it contains raw +// pointers to Oilpan objects. crbug.com/961413 +#define YYSTACK_USE_ALLOCA 1 +// Bison's bug? YYSTACK_ALLOC is not defined if _MSC_VER. +#if defined(_MSC_VER) +#define YYSTACK_ALLOC _alloca +#endif #define YYENABLE_NLS 0 #define YYLTYPE_IS_TRIVIAL 1 diff --git a/chromium/third_party/blink/renderer/modules/BUILD.gn b/chromium/third_party/blink/renderer/modules/BUILD.gn index eb6f43aa81f..97a35617a9f 100644 --- a/chromium/third_party/blink/renderer/modules/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/BUILD.gn @@ -393,8 +393,11 @@ jumbo_source_set("unit_tests") { ] if (is_android && notouch_build) { - sources += - [ "media_controls/touchless/media_controls_touchless_impl_test.cc" ] + sources += [ + "media_controls/touchless/media_controls_touchless_impl_test.cc", + "media_controls/touchless/test_media_controls_menu_host.cc", + "media_controls/touchless/test_media_controls_menu_host.h", + ] } configs += [ diff --git a/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc b/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc index 582a091f27b..9d1a1bb6080 100644 --- a/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc +++ b/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc @@ -75,6 +75,7 @@ void BroadcastChannel::close() { remote_client_.reset(); if (binding_.is_bound()) binding_.Close(); + feature_handle_for_scheduler_.reset(); } const AtomicString& BroadcastChannel::InterfaceName() const { @@ -119,7 +120,11 @@ BroadcastChannel::BroadcastChannel(ExecutionContext* execution_context, : ContextLifecycleObserver(execution_context), origin_(execution_context->GetSecurityOrigin()), name_(name), - binding_(this) { + binding_(this), + feature_handle_for_scheduler_( + execution_context->GetScheduler()->RegisterFeature( + SchedulingPolicy::Feature::kBroadcastChannel, + {SchedulingPolicy::RecordMetricsForBackForwardCache()})) { mojom::blink::BroadcastChannelProviderPtr& provider = GetThreadSpecificProvider(); diff --git a/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h b/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h index 62e35c9fc05..6db0dfabbbb 100644 --- a/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h +++ b/chromium/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.h @@ -11,6 +11,7 @@ #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" #include "third_party/blink/renderer/core/dom/events/event_target.h" #include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h" +#include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" namespace blink { @@ -68,6 +69,10 @@ class BroadcastChannel final : public EventTargetWithInlineData, mojo::AssociatedBinding<mojom::blink::BroadcastChannelClient> binding_; mojom::blink::BroadcastChannelClientAssociatedPtr remote_client_; + // Notifies the scheduler that a broadcast channel is active. + FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle + feature_handle_for_scheduler_; + DISALLOW_COPY_AND_ASSIGN(BroadcastChannel); }; diff --git a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc index 06fde4ec2da..16156713451 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc @@ -35,7 +35,7 @@ OffscreenCanvasRenderingContext2D::OffscreenCanvasRenderingContext2D( ExecutionContext* execution_context = canvas->GetTopExecutionContext(); if (auto* document = DynamicTo<Document>(execution_context)) { Settings* settings = document->GetSettings(); - if (settings->GetDisableReadingFromCanvas()) + if (settings && settings->GetDisableReadingFromCanvas()) canvas->SetDisableReadingFromCanvasTrue(); return; } diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc index 3fad0b87279..4f52673d682 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc @@ -101,7 +101,13 @@ IDBDatabase::IDBDatabase(ExecutionContext* context, event_queue_( MakeGarbageCollected<EventQueue>(context, TaskType::kDatabaseAccess)), database_callbacks_(callbacks), - isolate_(isolate) { + isolate_(isolate), + feature_handle_for_scheduler_( + context + ? context->GetScheduler()->RegisterFeature( + SchedulingPolicy::Feature::kIndexedDBConnection, + {SchedulingPolicy::RecordMetricsForBackForwardCache()}) + : FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle()) { database_callbacks_->Connect(this); } @@ -436,6 +442,7 @@ void IDBDatabase::close() { return; close_pending_ = true; + feature_handle_for_scheduler_.reset(); if (transactions_.IsEmpty()) CloseConnection(); diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h index 202056519af..66bcfa78fe5 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.h @@ -46,6 +46,7 @@ #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h" namespace blink { @@ -194,6 +195,9 @@ class MODULES_EXPORT IDBDatabase final // Maintain the isolate so that all externally allocated memory can be // registered against it. v8::Isolate* isolate_; + + FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle + feature_handle_for_scheduler_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.cc index 1f863f883ec..a6b4645ea31 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.cc @@ -6,7 +6,6 @@ #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/renderer/core/dom/events/event.h" -#include "third_party/blink/renderer/core/dom/events/native_event_listener.h" #include "third_party/blink/renderer/core/html/media/html_media_element.h" #include "third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h" #include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h" @@ -21,61 +20,6 @@ const char kTransparentClassName[] = "transparent"; } // anonymous namespace -// Listens for the 'transitionend' event. -class MediaControlPanelElement::TransitionEventListener final - : public NativeEventListener { - public: - using Callback = base::RepeatingCallback<void()>; - - // |element| is the element to listen for the 'transitionend' event on. - // |callback| is the callback to call when the event is handled. - explicit TransitionEventListener(Element* element, Callback callback) - : callback_(callback), element_(element) { - DCHECK(callback_); - DCHECK(element_); - } - - void Attach() { - DCHECK(!attached_); - attached_ = true; - - element_->addEventListener(event_type_names::kTransitionend, this, false); - } - - void Detach() { - DCHECK(attached_); - attached_ = false; - - element_->removeEventListener(event_type_names::kTransitionend, this, - false); - } - - bool IsAttached() const { return attached_; } - - void Invoke(ExecutionContext* context, Event* event) override { - if (event->target() != element_) - return; - - if (event->type() == event_type_names::kTransitionend) { - callback_.Run(); - return; - } - - NOTREACHED(); - } - - void Trace(blink::Visitor* visitor) override { - NativeEventListener::Trace(visitor); - visitor->Trace(element_); - } - - private: - bool attached_ = false; - - Callback callback_; - Member<Element> element_; -}; - MediaControlPanelElement::MediaControlPanelElement( MediaControlsImpl& media_controls) : MediaControlDivElement(media_controls), event_listener_(nullptr) { @@ -148,11 +92,11 @@ bool MediaControlPanelElement::EventListenerIsAttachedForTest() const { void MediaControlPanelElement::EnsureTransitionEventListener() { // Create the event listener if it doesn't exist. if (!event_listener_) { - event_listener_ = - MakeGarbageCollected<MediaControlPanelElement::TransitionEventListener>( - this, WTF::BindRepeating( - &MediaControlPanelElement::HandleTransitionEndEvent, - WrapWeakPersistent(this))); + event_listener_ = MakeGarbageCollected< + MediaControlsSharedHelpers::TransitionEventListener>( + this, + WTF::BindRepeating(&MediaControlPanelElement::HandleTransitionEndEvent, + WrapWeakPersistent(this))); } // Attach the event listener if we are not attached. diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.h index ccb43bbb8fa..a010ba1d627 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.h @@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_PANEL_ELEMENT_H_ #include "third_party/blink/renderer/modules/media_controls/elements/media_control_div_element.h" +#include "third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.h" #include "third_party/blink/renderer/modules/modules_export.h" namespace blink { @@ -40,8 +41,6 @@ class MODULES_EXPORT MediaControlPanelElement final bool EventListenerIsAttachedForTest() const; private: - class TransitionEventListener; - void EnsureTransitionEventListener(); void DetachTransitionEventListener(); @@ -55,7 +54,7 @@ class MODULES_EXPORT MediaControlPanelElement final bool opaque_ = true; bool keep_displayed_for_accessibility_ = false; - Member<TransitionEventListener> event_listener_; + Member<MediaControlsSharedHelpers::TransitionEventListener> event_listener_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc index 0d3796f252d..00b9f48e9c9 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc @@ -87,6 +87,7 @@ #include "third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.h" #include "third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.h" #include "third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.h" +#include "third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.h" #include "third_party/blink/renderer/modules/media_controls/media_controls_text_track_manager.h" #include "third_party/blink/renderer/modules/remoteplayback/remote_playback.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" @@ -154,33 +155,6 @@ constexpr WTF::TimeDelta kTimeToShowVolumeSliderTest = // The number of seconds to jump when double tapping. constexpr int kNumberOfSecondsToJump = 10; -bool ShouldShowFullscreenButton(const HTMLMediaElement& media_element) { - // Unconditionally allow the user to exit fullscreen if we are in it - // now. Especially on android, when we might not yet know if - // fullscreen is supported, we sometimes guess incorrectly and show - // the button earlier, and we don't want to remove it here if the - // user chose to enter fullscreen. crbug.com/500732 . - if (media_element.IsFullscreen()) - return true; - - if (!media_element.IsHTMLVideoElement()) - return false; - - if (!media_element.HasVideo()) - return false; - - if (!Fullscreen::FullscreenEnabled(media_element.GetDocument())) - return false; - - if (media_element.ControlsListInternal()->ShouldHideFullscreen()) { - UseCounter::Count(media_element.GetDocument(), - WebFeature::kHTMLMediaElementControlsListNoFullscreen); - return false; - } - - return true; -} - void MaybeParserAppendChild(Element* parent, Element* child) { DCHECK(parent); if (child) @@ -967,12 +941,14 @@ void MediaControlsImpl::OnControlsListUpdated() { if (IsModern() && ShouldShowVideoControls()) { fullscreen_button_->SetIsWanted(true); - fullscreen_button_->setAttribute(html_names::kDisabledAttr, - ShouldShowFullscreenButton(MediaElement()) - ? AtomicString() - : AtomicString("")); + fullscreen_button_->setAttribute( + html_names::kDisabledAttr, + MediaControlsSharedHelpers::ShouldShowFullscreenButton(MediaElement()) + ? AtomicString() + : AtomicString("")); } else { - fullscreen_button_->SetIsWanted(ShouldShowFullscreenButton(MediaElement())); + fullscreen_button_->SetIsWanted( + MediaControlsSharedHelpers::ShouldShowFullscreenButton(MediaElement())); fullscreen_button_->removeAttribute(html_names::kDisabledAttr); } diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.cc index 33b76717e28..92cc944b9d3 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.cc @@ -5,7 +5,12 @@ #include "third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.h" #include <cmath> +#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-shared.h" +#include "third_party/blink/renderer/core/dom/events/event.h" +#include "third_party/blink/renderer/core/frame/use_counter.h" +#include "third_party/blink/renderer/core/fullscreen/fullscreen.h" #include "third_party/blink/renderer/core/html/media/html_media_element.h" +#include "third_party/blink/renderer/core/html/media/html_media_element_controls_list.h" #include "third_party/blink/renderer/core/html/time_ranges.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" @@ -17,6 +22,54 @@ const double kCurrentTimeBufferedDelta = 1.0; namespace blink { +// |element| is the element to listen for the 'transitionend' event on. +// |callback| is the callback to call when the event is handled. +MediaControlsSharedHelpers::TransitionEventListener::TransitionEventListener( + Element* element, + Callback callback) + : callback_(callback), element_(element) { + DCHECK(callback_); + DCHECK(element_); +} + +void MediaControlsSharedHelpers::TransitionEventListener::Attach() { + DCHECK(!attached_); + attached_ = true; + + element_->addEventListener(event_type_names::kTransitionend, this, false); +} + +void MediaControlsSharedHelpers::TransitionEventListener::Detach() { + DCHECK(attached_); + attached_ = false; + + element_->removeEventListener(event_type_names::kTransitionend, this, false); +} + +bool MediaControlsSharedHelpers::TransitionEventListener::IsAttached() const { + return attached_; +} + +void MediaControlsSharedHelpers::TransitionEventListener::Invoke( + ExecutionContext* context, + Event* event) { + if (event->target() != element_) + return; + + if (event->type() == event_type_names::kTransitionend) { + callback_.Run(); + return; + } + + NOTREACHED(); +} + +void MediaControlsSharedHelpers::TransitionEventListener::Trace( + blink::Visitor* visitor) { + NativeEventListener::Trace(visitor); + visitor->Trace(element_); +} + base::Optional<unsigned> MediaControlsSharedHelpers::GetCurrentBufferedTimeRange( HTMLMediaElement& media_element) { @@ -80,4 +133,32 @@ String MediaControlsSharedHelpers::FormatTime(double time) { return String::Format("%s%d:%02d", negative_sign, minutes, seconds); } +bool MediaControlsSharedHelpers::ShouldShowFullscreenButton( + const HTMLMediaElement& media_element) { + // Unconditionally allow the user to exit fullscreen if we are in it + // now. Especially on android, when we might not yet know if + // fullscreen is supported, we sometimes guess incorrectly and show + // the button earlier, and we don't want to remove it here if the + // user chose to enter fullscreen. crbug.com/500732 . + if (media_element.IsFullscreen()) + return true; + + if (!media_element.IsHTMLVideoElement()) + return false; + + if (!media_element.HasVideo()) + return false; + + if (!Fullscreen::FullscreenEnabled(media_element.GetDocument())) + return false; + + if (media_element.ControlsListInternal()->ShouldHideFullscreen()) { + UseCounter::Count(media_element.GetDocument(), + WebFeature::kHTMLMediaElementControlsListNoFullscreen); + return false; + } + + return true; +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.h b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.h index daf14b42ec2..4920feffe5c 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.h @@ -5,22 +5,43 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_MEDIA_CONTROLS_SHARED_HELPER_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_MEDIA_CONTROLS_SHARED_HELPER_H_ +#include "base/callback.h" #include "base/optional.h" +#include "third_party/blink/renderer/core/dom/events/native_event_listener.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { class HTMLMediaElement; +class Element; class MediaControlsSharedHelpers final { STATIC_ONLY(MediaControlsSharedHelpers); public: + class TransitionEventListener final : public NativeEventListener { + public: + using Callback = base::RepeatingCallback<void()>; + + explicit TransitionEventListener(Element* element, Callback callback); + void Attach(); + void Detach(); + bool IsAttached() const; + void Invoke(ExecutionContext* context, Event* event) override; + void Trace(blink::Visitor* visitor) override; + + private: + bool attached_ = false; + Callback callback_; + Member<Element> element_; + }; + static base::Optional<unsigned> GetCurrentBufferedTimeRange( HTMLMediaElement& media_element); static String FormatTime(double time); + static bool ShouldShowFullscreenButton(const HTMLMediaElement& media_element); }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/resources/legacyMediaControls.css b/chromium/third_party/blink/renderer/modules/media_controls/resources/legacyMediaControls.css index 47780421809..a6ace7d559d 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/resources/legacyMediaControls.css +++ b/chromium/third_party/blink/renderer/modules/media_controls/resources/legacyMediaControls.css @@ -638,6 +638,7 @@ video::cue { display: inline; background-color: rgba(0, 0, 0, 0.8); + padding: 2px 2px; } video::-webkit-media-text-track-region { diff --git a/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css b/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css index 037d667364d..cf64ba3f173 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css +++ b/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css @@ -1169,6 +1169,7 @@ video::cue { display: inline; background-color: rgba(0, 0, 0, 0.8); + padding: 2px 2px; } video::-webkit-media-text-track-region { diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_bottom_container_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_bottom_container_element.cc index 4542382a807..d70899258eb 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_bottom_container_element.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_bottom_container_element.cc @@ -4,8 +4,10 @@ #include "third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_bottom_container_element.h" +#include "third_party/blink/renderer/core/html/media/html_media_element.h" #include "third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_time_display_element.h" #include "third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_timeline_element.h" +#include "third_party/blink/renderer/platform/wtf/functional.h" namespace blink { @@ -25,6 +27,14 @@ MediaControlsTouchlessBottomContainerElement:: ParserAppendChild(time_display_element_); ParserAppendChild(timeline_element_); + + event_listener_ = + MakeGarbageCollected<MediaControlsSharedHelpers::TransitionEventListener>( + this, + WTF::BindRepeating(&MediaControlsTouchlessBottomContainerElement:: + HandleTransitionEndEvent, + WrapWeakPersistent(this))); + event_listener_->Attach(); } LayoutObject* @@ -37,10 +47,30 @@ MediaControlsTouchlessBottomContainerElement::TimeDisplayLayoutObject() { return time_display_element_->GetLayoutObject(); } +void MediaControlsTouchlessBottomContainerElement::MakeOpaque( + bool should_hide) { + SetDisplayed(true); + MediaElement().MediaControlsDidBecomeVisible(); + MediaControlsTouchlessElement::MakeOpaque(should_hide); +} + +void MediaControlsTouchlessBottomContainerElement::HandleTransitionEndEvent() { + SetDisplayed(false); +} + +void MediaControlsTouchlessBottomContainerElement::SetDisplayed( + bool displayed) { + if (displayed) + RemoveInlineStyleProperty(CSSPropertyID::kDisplay); + else + SetInlineStyleProperty(CSSPropertyID::kDisplay, CSSValueID::kNone); +} + void MediaControlsTouchlessBottomContainerElement::Trace( blink::Visitor* visitor) { visitor->Trace(timeline_element_); visitor->Trace(time_display_element_); + visitor->Trace(event_listener_); MediaControlsTouchlessElement::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_bottom_container_element.h b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_bottom_container_element.h index 34d04de3191..e23acc51a24 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_bottom_container_element.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_bottom_container_element.h @@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_TOUCHLESS_ELEMENTS_MEDIA_CONTROLS_TOUCHLESS_BOTTOM_CONTAINER_ELEMENT_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_TOUCHLESS_ELEMENTS_MEDIA_CONTROLS_TOUCHLESS_BOTTOM_CONTAINER_ELEMENT_H_ +#include "third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.h" #include "third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_element.h" namespace blink { @@ -20,11 +21,17 @@ class MediaControlsTouchlessBottomContainerElement MediaControlsTouchlessBottomContainerElement(MediaControlsTouchlessImpl&); LayoutObject* TimelineLayoutObject(); LayoutObject* TimeDisplayLayoutObject(); + + void MakeOpaque(bool); void Trace(blink::Visitor*) override; private: + void HandleTransitionEndEvent(); + void SetDisplayed(bool); + Member<MediaControlsTouchlessTimelineElement> timeline_element_; Member<MediaControlsTouchlessTimeDisplayElement> time_display_element_; + Member<MediaControlsSharedHelpers::TransitionEventListener> event_listener_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_element.cc index cbbac960438..4c2c2137a2d 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_element.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_element.cc @@ -17,6 +17,7 @@ namespace { constexpr WTF::TimeDelta kTimeToHideControl = TimeDelta::FromMilliseconds(3000); const char kTransparentCSSClass[] = "transparent"; +const char kTransparentImmediateCSSClass[] = "transparent-immediate"; } // namespace @@ -34,7 +35,7 @@ HTMLMediaElement& MediaControlsTouchlessElement::MediaElement() const { void MediaControlsTouchlessElement::MakeOpaque(bool should_hide) { EnsureHideControlTimer(); - classList().Remove(kTransparentCSSClass); + removeAttribute("class"); if (hide_control_timer_->IsActive()) StopHideControlTimer(); @@ -43,8 +44,9 @@ void MediaControlsTouchlessElement::MakeOpaque(bool should_hide) { StartHideControlTimer(); } -void MediaControlsTouchlessElement::MakeTransparent() { - classList().Add(kTransparentCSSClass); +void MediaControlsTouchlessElement::MakeTransparent(bool hide_immediate) { + classList().Add(hide_immediate ? kTransparentImmediateCSSClass + : kTransparentCSSClass); } void MediaControlsTouchlessElement::EnsureHideControlTimer() { diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_element.h b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_element.h index b43c44d21db..f5463bbf466 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_element.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_element.h @@ -27,12 +27,13 @@ class MediaControlsTouchlessElement void Trace(blink::Visitor* visitor) override; void MakeOpaque(bool /** True if control should hide after timer fired */); - void MakeTransparent(); + void MakeTransparent(bool = false /** True if hide immediately */); // Non-touch media event listener observer implementation. void OnFocusIn() override {} void OnTimeUpdate() override {} void OnDurationChange() override {} + void OnSeeking() override {} void OnLoadingProgress() override {} void OnPlay() override {} void OnPause() override {} diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_overlay_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_overlay_element.cc index 5e008b0b004..7ac1f447124 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_overlay_element.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_overlay_element.cc @@ -8,6 +8,8 @@ #include "third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_seek_button_element.h" #include "third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_volume_button_element.h" #include "third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl.h" +#include "third_party/blink/renderer/platform/text/platform_locale.h" +#include "third_party/blink/renderer/platform/wtf/text/string_builder.h" namespace blink { @@ -39,6 +41,14 @@ MediaControlsTouchlessOverlayElement::MediaControlsTouchlessOverlayElement( ParserAppendChild(play_button); ParserAppendChild(seek_forward_button); ParserAppendChild(volume_down_button); + + StringBuilder aria_label; + aria_label.Append( + GetLocale().QueryString(WebLocalizedString::kAXMediaTouchLessSeekAction)); + aria_label.Append(" "); + aria_label.Append(GetLocale().QueryString( + WebLocalizedString::kAXMediaTouchLessVolumeAction)); + setAttribute(html_names::kAriaLabelAttr, aria_label.ToAtomicString()); } void MediaControlsTouchlessOverlayElement::Trace(blink::Visitor* visitor) { diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_time_display_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_time_display_element.cc index 261f52bb2d8..5c6db6bfa01 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_time_display_element.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_time_display_element.cc @@ -7,6 +7,7 @@ #include "third_party/blink/renderer/core/html/media/html_media_element.h" #include "third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.h" #include "third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl.h" +#include "third_party/blink/renderer/platform/text/platform_locale.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" namespace blink { @@ -27,6 +28,11 @@ void MediaControlsTouchlessTimeDisplayElement::OnTimeUpdate() { UpdateTimeDisplay(); } +void MediaControlsTouchlessTimeDisplayElement::OnSeeking() { + current_time_ = MediaElement().currentTime(); + UpdateTimeDisplay(); +} + void MediaControlsTouchlessTimeDisplayElement::OnDurationChange() { duration_ = MediaElement().duration(); UpdateTimeDisplay(); @@ -42,6 +48,16 @@ void MediaControlsTouchlessTimeDisplayElement::UpdateTimeDisplay() { builder.Append(" / "); builder.Append(MediaControlsSharedHelpers::FormatTime(duration_)); setInnerText(builder.ToAtomicString(), ASSERT_NO_EXCEPTION); + + StringBuilder aria_label; + aria_label.Append(GetLocale().QueryString( + WebLocalizedString::kAXMediaCurrentTimeDisplay, + MediaControlsSharedHelpers::FormatTime(current_time_))); + aria_label.Append(" "); + aria_label.Append(GetLocale().QueryString( + WebLocalizedString::kAXMediaTimeRemainingDisplay, + MediaControlsSharedHelpers::FormatTime(duration_))); + setAttribute(html_names::kAriaLabelAttr, aria_label.ToAtomicString()); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_time_display_element.h b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_time_display_element.h index 6a8455a559e..0134b091c4c 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_time_display_element.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_time_display_element.h @@ -18,6 +18,7 @@ class MediaControlsTouchlessTimeDisplayElement // MediaControlsTouchlessMediaEventListenerObserver overrides void OnTimeUpdate() override; + void OnSeeking() override; void OnDurationChange() override; void Trace(blink::Visitor* visitor) override; diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_timeline_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_timeline_element.cc index 57bd4a639c8..413ae227057 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_timeline_element.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_timeline_element.cc @@ -34,6 +34,11 @@ void MediaControlsTouchlessTimelineElement::OnTimeUpdate() { UpdateBars(); } +void MediaControlsTouchlessTimelineElement::OnSeeking() { + current_time_ = MediaElement().currentTime(); + UpdateBars(); +} + void MediaControlsTouchlessTimelineElement::OnDurationChange() { duration_ = MediaElement().duration(); UpdateBars(); diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_timeline_element.h b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_timeline_element.h index b1416ce9ae2..c8a17e7ac55 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_timeline_element.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_timeline_element.h @@ -17,6 +17,7 @@ class MediaControlsTouchlessTimelineElement // MediaControlsTouchlessMediaEventListenerObserver overrides void OnTimeUpdate() override; + void OnSeeking() override; void OnDurationChange() override; void OnLoadingProgress() override; diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl.cc b/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl.cc index 7a2c2a8c129..fd6b6b7719a 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl.cc @@ -23,6 +23,7 @@ #include "third_party/blink/renderer/core/page/chrome_client.h" #include "third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h" #include "third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.h" +#include "third_party/blink/renderer/modules/media_controls/media_controls_shared_helper.h" #include "third_party/blink/renderer/modules/media_controls/media_controls_text_track_manager.h" #include "third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_bottom_container_element.h" #include "third_party/blink/renderer/modules/media_controls/touchless/elements/media_controls_touchless_overlay_element.h" @@ -77,24 +78,24 @@ MediaControlsTouchlessImpl* MediaControlsTouchlessImpl::Create( ShadowRoot& shadow_root) { MediaControlsTouchlessImpl* controls = MakeGarbageCollected<MediaControlsTouchlessImpl>(media_element); - controls->overlay_ = - MakeGarbageCollected<MediaControlsTouchlessOverlayElement>(*controls); controls->bottom_container_ = MakeGarbageCollected<MediaControlsTouchlessBottomContainerElement>( *controls); + controls->overlay_ = + MakeGarbageCollected<MediaControlsTouchlessOverlayElement>(*controls); controls->volume_container_ = MakeGarbageCollected<MediaControlsTouchlessVolumeContainerElement>( *controls); - controls->ParserAppendChild(controls->overlay_); controls->ParserAppendChild(controls->bottom_container_); + controls->ParserAppendChild(controls->overlay_); controls->ParserAppendChild(controls->volume_container_); // Controls start hidden. - controls->overlay_->MakeTransparent(); - controls->volume_container_->MakeTransparent(); if (!media_element.paused()) controls->bottom_container_->MakeTransparent(); + controls->overlay_->MakeTransparent(); + controls->volume_container_->MakeTransparent(); if (RuntimeEnabledFeatures::VideoFullscreenOrientationLockEnabled() && media_element.IsHTMLVideoElement()) { @@ -166,8 +167,8 @@ MediaControlsTouchlessImpl::MediaEventListener() const { void MediaControlsTouchlessImpl::OnFocusIn() { if (MediaElement().ShouldShowControls()) { - overlay_->MakeOpaque(true); bottom_container_->MakeOpaque(!MediaElement().paused()); + overlay_->MakeOpaque(true); } } @@ -191,7 +192,7 @@ void MediaControlsTouchlessImpl::OnKeyDown(KeyboardEvent* event) { bool handled = true; switch (event->keyCode()) { case VKEY_RETURN: - volume_container_->MakeTransparent(); + volume_container_->MakeTransparent(true); overlay_->MakeOpaque(true); MediaElement().TogglePlayState(); break; @@ -270,9 +271,8 @@ void MediaControlsTouchlessImpl::ShowContextMenu() { WTF::Vector<mojom::blink::MenuItem> menu_items; - // TODO(jazzhsu, https://crbug.com/942577): Populate fullscreen list entry - // properly. - menu_items.push_back(mojom::blink::MenuItem::FULLSCREEN); + if (MediaControlsSharedHelpers::ShouldShowFullscreenButton(MediaElement())) + menu_items.push_back(mojom::blink::MenuItem::FULLSCREEN); if (MediaElement().HasAudio()) menu_items.push_back(mojom::blink::MenuItem::MUTE); @@ -402,14 +402,14 @@ WebScreenOrientationType MediaControlsTouchlessImpl::GetOrientation() { void MediaControlsTouchlessImpl::HandleTopButtonPress() { MaybeChangeVolume(kVolumeToChangeForTouchless); volume_container_->UpdateVolume(); - overlay_->MakeTransparent(); + overlay_->MakeTransparent(true); volume_container_->MakeOpaque(true); } void MediaControlsTouchlessImpl::HandleBottomButtonPress() { MaybeChangeVolume(kVolumeToChangeForTouchless * -1); volume_container_->UpdateVolume(); - overlay_->MakeTransparent(); + overlay_->MakeTransparent(true); volume_container_->MakeOpaque(true); } @@ -448,9 +448,13 @@ void MediaControlsTouchlessImpl::Trace(blink::Visitor* visitor) { HTMLDivElement::Trace(visitor); } -void MediaControlsTouchlessImpl::OnMediaMenuResultForTest( - mojom::blink::MenuResponsePtr response) { - OnMediaMenuResult(std::move(response)); +void MediaControlsTouchlessImpl::SetMediaControlsMenuHostForTesting( + mojom::blink::MediaControlsMenuHostPtr menu_host) { + media_controls_host_ = std::move(menu_host); +} + +void MediaControlsTouchlessImpl::MenuHostFlushForTesting() { + media_controls_host_.FlushForTesting(); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl.h b/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl.h index 14fc333e7fa..b3d86bd5102 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl.h @@ -56,6 +56,7 @@ class MODULES_EXPORT MediaControlsTouchlessImpl final void OnFocusIn() override; void OnTimeUpdate() override {} void OnDurationChange() override {} + void OnSeeking() override {} void OnLoadingProgress() override {} void OnPlay() override; void OnPause() override; @@ -70,7 +71,9 @@ class MODULES_EXPORT MediaControlsTouchlessImpl final MediaControlsTouchlessMediaEventListener& MediaEventListener() const; // Test functions - void OnMediaMenuResultForTest(mojom::blink::MenuResponsePtr); + void SetMediaControlsMenuHostForTesting( + mojom::blink::MediaControlsMenuHostPtr); + void MenuHostFlushForTesting(); void Trace(blink::Visitor*) override; diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl_test.cc index 9215321dace..01576a0d722 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl_test.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_impl_test.cc @@ -8,21 +8,26 @@ #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/mojom/media_controls/touchless/media_controls.mojom-blink.h" #include "third_party/blink/renderer/core/css/css_property_value_set.h" #include "third_party/blink/renderer/core/dom/dom_token_list.h" #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/dom/element_traversal.h" #include "third_party/blink/renderer/core/events/keyboard_event.h" #include "third_party/blink/renderer/core/frame/settings.h" +#include "third_party/blink/renderer/core/fullscreen/fullscreen.h" #include "third_party/blink/renderer/core/geometry/dom_rect.h" #include "third_party/blink/renderer/core/html/media/html_media_element.h" +#include "third_party/blink/renderer/core/html/media/html_media_element_controls_list.h" #include "third_party/blink/renderer/core/html/media/html_media_test_helper.h" #include "third_party/blink/renderer/core/html/media/html_video_element.h" #include "third_party/blink/renderer/core/html/time_ranges.h" #include "third_party/blink/renderer/core/html/track/text_track.h" #include "third_party/blink/renderer/core/html/track/text_track_list.h" +#include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/loader/empty_clients.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" +#include "third_party/blink/renderer/modules/media_controls/touchless/test_media_controls_menu_host.h" #include "third_party/blink/renderer/platform/keyboard_codes.h" #include "third_party/blink/renderer/platform/testing/empty_web_media_player.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" @@ -31,14 +36,27 @@ namespace blink { namespace { +const char kTextTracksOffString[] = "Off"; + +class LocalePlatformSupport : public TestingPlatformSupport { + public: + WebString QueryLocalizedString(WebLocalizedString::Name name) override { + if (name == WebLocalizedString::kTextTracksOff) + return kTextTracksOffString; + return TestingPlatformSupport::QueryLocalizedString(name); + } +}; + class MockWebMediaPlayerForTouchlessImpl : public EmptyWebMediaPlayer { public: WebTimeRanges Seekable() const override { return seekable_; } bool HasVideo() const override { return true; } + bool HasAudio() const override { return has_audio_; } WebTimeRanges Buffered() const override { return buffered_; } WebTimeRanges buffered_; WebTimeRanges seekable_; + bool has_audio_ = false; }; class MockChromeClientForTouchlessImpl : public EmptyChromeClient { @@ -52,6 +70,14 @@ class MockChromeClientForTouchlessImpl : public EmptyChromeClient { return screen_info; } + void EnterFullscreen(LocalFrame& frame, const FullscreenOptions*) final { + Fullscreen::DidEnterFullscreen(*frame.GetDocument()); + } + + void ExitFullscreen(LocalFrame& frame) final { + Fullscreen::DidExitFullscreen(*frame.GetDocument()); + } + void SetOrientation(WebScreenOrientationType orientation_type) { orientation_ = orientation_type; } @@ -66,6 +92,7 @@ class MediaControlsTouchlessImplTest : public PageTestBase { void InitializePage() { Page::PageClients clients; + FillWithEmptyClients(clients); chrome_client_ = MakeGarbageCollected<MockChromeClientForTouchlessImpl>(); clients.chrome_client = chrome_client_; @@ -78,6 +105,11 @@ class MediaControlsTouchlessImplTest : public PageTestBase { ToHTMLVideoElement(*GetDocument().QuerySelector("video")); media_controls_ = static_cast<MediaControlsTouchlessImpl*>(video.GetMediaControls()); + + test_media_controls_host_ = std::make_unique<TestMediaControlsMenuHost>(); + + media_controls_->SetMediaControlsMenuHostForTesting( + test_media_controls_host_->CreateMediaControlsMenuHostPtr()); } MediaControlsTouchlessImpl& MediaControls() { return *media_controls_; } @@ -88,6 +120,10 @@ class MediaControlsTouchlessImplTest : public PageTestBase { MediaElement().GetWebMediaPlayer()); } + TestMenuHostArgList& GetMenuHostArgList() { + return test_media_controls_host_->GetMenuHostArgList(); + } + void SimulateKeydownEvent(Element& element, int key_code) { KeyboardEventInit* keyboard_event_init = KeyboardEventInit::Create(); keyboard_event_init->setKeyCode(key_code); @@ -111,9 +147,20 @@ class MediaControlsTouchlessImplTest : public PageTestBase { } bool IsControlsVisible(Element* element) { - return !element->classList().contains("transparent"); + return !element->classList().contains("transparent") && + !element->classList().contains("transparent-immediate"); } + bool IsElementDisplayed(Element* element) { + if (!element->InlineStyle()) + return true; + + return element->InlineStyle()->GetPropertyValue(CSSPropertyID::kDisplay) != + "none"; + } + + void SetHasAudio(bool has_audio) { WebMediaPlayer()->has_audio_ = has_audio; } + Element* GetControlByShadowPseudoId(const char* shadow_pseudo_id) { for (Element& element : ElementTraversal::DescendantsOf(MediaControls())) { if (element.ShadowPseudoId() == shadow_pseudo_id) @@ -126,12 +173,15 @@ class MediaControlsTouchlessImplTest : public PageTestBase { chrome_client_->SetOrientation(orientation_type); } - void SimulateClickOnMenuItem(mojom::blink::MenuItem menu_item, - int track_index) { - mojom::blink::MenuResponsePtr response(mojom::blink::MenuResponse::New()); - response->clicked = menu_item; - response->track_index = track_index; - media_controls_->OnMediaMenuResultForTest(std::move(response)); + void SetMenuResponse(mojom::blink::MenuItem menu_item, int track_index = -1) { + test_media_controls_host_->SetMenuResponse(menu_item, track_index); + } + + void SetMenuResponseAndShowMenu(mojom::blink::MenuItem menu_item, + int track_index = -1) { + SetMenuResponse(menu_item, track_index); + MediaControls().ShowContextMenu(); + MediaControls().MenuHostFlushForTesting(); } void CheckControlKeys(int seek_forward_key, @@ -161,6 +211,7 @@ class MediaControlsTouchlessImplTest : public PageTestBase { private: Persistent<MediaControlsTouchlessImpl> media_controls_; Persistent<MockChromeClientForTouchlessImpl> chrome_client_; + std::unique_ptr<TestMediaControlsMenuHost> test_media_controls_host_; }; class MediaControlsTouchlessImplTestWithMockScheduler @@ -283,6 +334,14 @@ TEST_F(MediaControlsTouchlessImplTest, ProgressBar) { EXPECT_DOUBLE_EQ(buffered / duration, loaded_bar_width / timeline_width); EXPECT_DOUBLE_EQ(current_time / buffered, progress_bar_width / loaded_bar_width); + + // Seek event should trigger a UI update as well. + SetBufferedRange(0); + MediaElement().setCurrentTime(0); + MediaElement().DispatchEvent(*Event::Create(event_type_names::kSeeking)); + + EXPECT_DOUBLE_EQ(progress_bar->getBoundingClientRect()->width(), 0); + EXPECT_DOUBLE_EQ(loaded_bar->getBoundingClientRect()->width(), 0); } TEST_F(MediaControlsTouchlessImplTest, TimeDisplay) { @@ -325,47 +384,70 @@ TEST_F(MediaControlsTouchlessImplTest, VolumeDisplayTest) { volume_bar_height / volume_bar_background_height, error); } -/** (jazzhsu@) TODO: Add mojom binding test and fix the following test. -TEST_F(MediaControlsTouchlessImplTest, ContextMenuTest) { - // Fullscreen buttom test. - EXPECT_FALSE(MediaElement().IsFullscreen()); - SimulateClickOnMenuItem(mojom::blink::MenuItem::FULLSCREEN, -1); +TEST_F(MediaControlsTouchlessImplTest, ContextMenuMojomTest) { + ScopedTestingPlatformSupport<LocalePlatformSupport> support; + + MediaControls().MediaElement().SetSrc("https://example.com/foo.mp4"); + std::unique_ptr<UserGestureIndicator> user_gesture_scope = + LocalFrame::NotifyUserActivation(GetDocument().GetFrame(), + UserGestureToken::kNewGesture); test::RunPendingTasks(); + + KeyboardEventInit* keyboard_event_init = KeyboardEventInit::Create(); + keyboard_event_init->setKey("SoftRight"); + Event* keyboard_event = + MakeGarbageCollected<KeyboardEvent>("keydown", keyboard_event_init); + + // Test fullscreen function. + SetMenuResponse(mojom::blink::MenuItem::FULLSCREEN); + MediaElement().DispatchEvent(*keyboard_event); + MediaControls().MenuHostFlushForTesting(); + test::RunPendingTasks(); + + TestMenuHostArgList& arg_list = GetMenuHostArgList(); + EXPECT_EQ((int)arg_list.menu_items.size(), 2); + EXPECT_EQ(arg_list.menu_items[0], mojom::blink::MenuItem::FULLSCREEN); + EXPECT_EQ(arg_list.menu_items[1], mojom::blink::MenuItem::DOWNLOAD); + EXPECT_FALSE(arg_list.video_state->is_fullscreen); EXPECT_TRUE(MediaElement().IsFullscreen()); - SimulateClickOnMenuItem(mojom::blink::MenuItem::FULLSCREEN, -1); + + SetMenuResponseAndShowMenu(mojom::blink::MenuItem::FULLSCREEN); test::RunPendingTasks(); + + EXPECT_TRUE(arg_list.video_state->is_fullscreen); EXPECT_FALSE(MediaElement().IsFullscreen()); - // Mute buttom test. - EXPECT_FALSE(MediaElement().muted()); - SimulateClickOnMenuItem(mojom::blink::MenuItem::MUTE, -1); + // Disable download and fullscreen, and show mute option. + MediaElement().ControlsListInternal()->Add("nofullscreen"); + MediaElement().GetDocument().GetSettings()->SetHideDownloadUI(true); + SetHasAudio(true); + + SetMenuResponseAndShowMenu(mojom::blink::MenuItem::MUTE); + + EXPECT_EQ((int)arg_list.menu_items.size(), 1); + EXPECT_EQ(arg_list.menu_items[0], mojom::blink::MenuItem::MUTE); + EXPECT_FALSE(arg_list.video_state->is_muted); EXPECT_TRUE(MediaElement().muted()); - SimulateClickOnMenuItem(mojom::blink::MenuItem::MUTE, -1); + + SetMenuResponseAndShowMenu(mojom::blink::MenuItem::MUTE); + + EXPECT_TRUE(arg_list.video_state->is_muted); EXPECT_FALSE(MediaElement().muted()); - // Text track test. - TextTrack* track1 = MediaElement().addTextTrack("subtitle", "english", - "en", NASSERT_NO_EXCEPTION); - TextTrack* track2 = MediaElement().addTextTrack("subtitle", "english2", - "en", ASSERT_NO_EXCEPTION); - EXPECT_NE(track1->mode(), TextTrack::ShowingKeyword()); - EXPECT_NE(track2->mode(), TextTrack::ShowingKeyword()); - - // Select first track. - SimulateClickOnMenuItem(mojom::blink::MenuItem::CAPTIONS, 0); - EXPECT_EQ(track1->mode(), TextTrack::ShowingKeyword()); - - // Select second track. - SimulateClickOnMenuItem(mojom::blink::MenuItem::CAPTIONS, 1); - EXPECT_NE(track1->mode(), TextTrack::ShowingKeyword()); - EXPECT_EQ(track2->mode(), TextTrack::ShowingKeyword()); - - // Turn all tracks off. - SimulateClickOnMenuItem(mojom::blink::MenuItem::CAPTIONS, -1); - EXPECT_NE(track1->mode(), TextTrack::ShowingKeyword()); - EXPECT_NE(track2->mode(), TextTrack::ShowingKeyword()); + // Disable mute option and show text track option. + SetHasAudio(false); + TextTrack* track = MediaElement().addTextTrack("subtitles", "english", "en", + ASSERT_NO_EXCEPTION); + SetMenuResponseAndShowMenu(mojom::blink::MenuItem::CAPTIONS, 0); + + EXPECT_EQ((int)arg_list.menu_items.size(), 1); + EXPECT_EQ(arg_list.menu_items[0], mojom::blink::MenuItem::CAPTIONS); + EXPECT_EQ(arg_list.text_tracks[1]->label, "english"); + EXPECT_EQ(track->mode(), TextTrack::ShowingKeyword()); + + SetMenuResponseAndShowMenu(mojom::blink::MenuItem::CAPTIONS, -1); + EXPECT_NE(track->mode(), TextTrack::ShowingKeyword()); } -*/ TEST_F(MediaControlsTouchlessImplTestWithMockScheduler, MidOverlayHideTimerTest) { @@ -408,6 +490,7 @@ TEST_F(MediaControlsTouchlessImplTestWithMockScheduler, // Bottom container starts opaque since video is paused. EXPECT_TRUE(IsControlsVisible(bottom_container)); + EXPECT_TRUE(IsElementDisplayed(bottom_container)); MediaElement().Play(); platform()->RunForPeriodSeconds(3); @@ -434,6 +517,11 @@ TEST_F(MediaControlsTouchlessImplTestWithMockScheduler, platform()->RunForPeriodSeconds(3); EXPECT_FALSE(IsControlsVisible(bottom_container)); + // Display should be none after hide transition ends. + bottom_container->DispatchEvent( + *Event::Create(event_type_names::kTransitionend)); + EXPECT_FALSE(IsElementDisplayed(bottom_container)); + // Bottom container should show after pressing right/left arrow. SimulateKeydownEvent(MediaElement(), VK_RIGHT); EXPECT_TRUE(IsControlsVisible(bottom_container)); diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_media_event_listener.cc b/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_media_event_listener.cc index 315164554be..17fc5f17796 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_media_event_listener.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_media_event_listener.cc @@ -35,6 +35,7 @@ void MediaControlsTouchlessMediaEventListener::Attach() { media_element_->addEventListener(event_type_names::kTimeupdate, this, false); media_element_->addEventListener(event_type_names::kDurationchange, this, false); + media_element_->addEventListener(event_type_names::kSeeking, this, false); media_element_->addEventListener(event_type_names::kProgress, this, false); media_element_->addEventListener(event_type_names::kPlay, this, false); @@ -76,6 +77,11 @@ void MediaControlsTouchlessMediaEventListener::Invoke( observer->OnDurationChange(); return; } + if (event->type() == event_type_names::kSeeking) { + for (auto& observer : observers_) + observer->OnSeeking(); + return; + } if (event->type() == event_type_names::kProgress) { for (auto& observer : observers_) observer->OnLoadingProgress(); diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_media_event_listener_observer.h b/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_media_event_listener_observer.h index 1c297a9e47c..cf07510f775 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_media_event_listener_observer.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/media_controls_touchless_media_event_listener_observer.h @@ -17,6 +17,7 @@ class MediaControlsTouchlessMediaEventListenerObserver virtual void OnFocusIn() = 0; virtual void OnTimeUpdate() = 0; virtual void OnDurationChange() = 0; + virtual void OnSeeking() = 0; virtual void OnLoadingProgress() = 0; virtual void OnPlay() = 0; virtual void OnPause() = 0; diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/resources/mediaControlsTouchless.css b/chromium/third_party/blink/renderer/modules/media_controls/touchless/resources/mediaControlsTouchless.css index 1ef89f2a909..98516f3aa39 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/touchless/resources/mediaControlsTouchless.css +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/resources/mediaControlsTouchless.css @@ -40,6 +40,10 @@ video::-internal-media-controls-touchless-overlay.transparent { transition: opacity .5s; } +video::-internal-media-controls-touchless-overlay.transparent-immediate { + opacity: 0; +} + video::-internal-media-controls-touchless-volume-up-button { width: 30px; height: 30px; @@ -175,6 +179,10 @@ video::-internal-media-controls-touchless-volume-container.transparent { transition: opacity .5s; } +video::-internal-media-controls-touchless-volume-container.transparent-immediate { + opacity: 0; +} + video::-internal-media-controls-touchless-volume-bar-background { width: 4px; margin-left: 20px; diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/test_media_controls_menu_host.cc b/chromium/third_party/blink/renderer/modules/media_controls/touchless/test_media_controls_menu_host.cc new file mode 100644 index 00000000000..d8780771ab3 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/test_media_controls_menu_host.cc @@ -0,0 +1,47 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/media_controls/touchless/test_media_controls_menu_host.h" + +namespace blink { + +mojom::blink::MediaControlsMenuHostPtr +TestMediaControlsMenuHost::CreateMediaControlsMenuHostPtr() { + mojom::blink::MediaControlsMenuHostPtr ptr; + binding_.Bind(mojo::MakeRequest(&ptr)); + return ptr; +} + +void TestMediaControlsMenuHost::ShowMediaMenu( + const WTF::Vector<mojom::MenuItem>& menu_items, + mojom::blink::VideoStatePtr video_state, + base::Optional<WTF::Vector<mojom::blink::TextTrackMetadataPtr>> text_tracks, + ShowMediaMenuCallback callback) { + arg_list_.menu_items = WTF::Vector<mojom::MenuItem>(menu_items); + + arg_list_.video_state = mojom::blink::VideoState::New(); + arg_list_.video_state->is_fullscreen = video_state->is_fullscreen; + arg_list_.video_state->is_muted = video_state->is_muted; + + arg_list_.text_tracks = WTF::Vector<mojom::blink::TextTrackMetadataPtr>( + std::move(text_tracks.value())); + + std::move(callback).Run(std::move(response_)); +} + +TestMenuHostArgList& TestMediaControlsMenuHost::GetMenuHostArgList() { + return arg_list_; +} + +void TestMediaControlsMenuHost::SetMenuResponse( + mojom::blink::MenuItem menu_item, + int track_index) { + if (response_.is_null()) + response_ = mojom::blink::MenuResponse::New(); + + response_->clicked = menu_item; + response_->track_index = track_index; +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/touchless/test_media_controls_menu_host.h b/chromium/third_party/blink/renderer/modules/media_controls/touchless/test_media_controls_menu_host.h new file mode 100644 index 00000000000..4378945032f --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/media_controls/touchless/test_media_controls_menu_host.h @@ -0,0 +1,40 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_TOUCHLESS_TEST_MEDIA_CONTROLS_MENU_HOST_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_TOUCHLESS_TEST_MEDIA_CONTROLS_MENU_HOST_H_ + +#include "mojo/public/cpp/bindings/binding.h" +#include "third_party/blink/public/mojom/media_controls/touchless/media_controls.mojom-blink.h" + +namespace blink { + +struct TestMenuHostArgList { + WTF::Vector<mojom::MenuItem> menu_items; + mojom::blink::VideoStatePtr video_state; + WTF::Vector<mojom::blink::TextTrackMetadataPtr> text_tracks; +}; + +class TestMediaControlsMenuHost : public mojom::blink::MediaControlsMenuHost { + public: + mojom::blink::MediaControlsMenuHostPtr CreateMediaControlsMenuHostPtr(); + void ShowMediaMenu( + const WTF::Vector<mojom::MenuItem>& menu_items, + mojom::blink::VideoStatePtr video_state, + base::Optional<WTF::Vector<mojom::blink::TextTrackMetadataPtr>> + text_tracks, + ShowMediaMenuCallback callback) override; + + TestMenuHostArgList& GetMenuHostArgList(); + void SetMenuResponse(mojom::blink::MenuItem menu_item, int track_index); + + private: + mojo::Binding<mojom::blink::MediaControlsMenuHost> binding_{this}; + TestMenuHostArgList arg_list_; + mojom::blink::MenuResponsePtr response_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_TOUCHLESS_TEST_MEDIA_CONTROLS_MENU_HOST_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc index a84a1980eaa..9f3885137c6 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc @@ -2883,6 +2883,15 @@ void RTCPeerConnection::DidModifyTransceivers( transceiver->receiver()->track()->Component()->Source()->SetReadyState( MediaStreamSource::kReadyStateLive); } + + // Transceiver modifications can cause changes in the set of ICE + // transports, which may affect ICE transport state. + // Note - this must be done every time the set of ICE transports happens. + // At the moment this only happens in SLD/SRD, and this function is called + // whenever these functions complete. + if (sdp_semantics_ == webrtc::SdpSemantics::kUnifiedPlan) { + UpdateIceConnectionState(); + } } void RTCPeerConnection::SetAssociatedMediaStreams( diff --git a/chromium/third_party/blink/renderer/modules/permissions/permissions.cc b/chromium/third_party/blink/renderer/modules/permissions/permissions.cc index 461d120524d..bee801ccead 100644 --- a/chromium/third_party/blink/renderer/modules/permissions/permissions.cc +++ b/chromium/third_party/blink/renderer/modules/permissions/permissions.cc @@ -25,6 +25,7 @@ #include "third_party/blink/renderer/modules/permissions/permission_status.h" #include "third_party/blink/renderer/modules/permissions/permission_utils.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" +#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/vector.h" #include "third_party/blink/renderer/platform/wtf/wtf_size_t.h" @@ -148,6 +149,44 @@ PermissionDescriptorPtr ParsePermission(ScriptState* script_state, return nullptr; } +base::Optional<SchedulingPolicy::Feature> PermissionToSchedulingFeature( + PermissionName permission) { + switch (permission) { + case PermissionName::GEOLOCATION: + return SchedulingPolicy::Feature::kRequestedGeolocationPermission; + case PermissionName::NOTIFICATIONS: + return SchedulingPolicy::Feature::kRequestedNotificationsPermission; + case PermissionName::MIDI: + return SchedulingPolicy::Feature::kRequestedMIDIPermission; + case PermissionName::AUDIO_CAPTURE: + return SchedulingPolicy::Feature::kRequestedAudioCapturePermission; + case PermissionName::VIDEO_CAPTURE: + return SchedulingPolicy::Feature::kRequestedVideoCapturePermission; + case PermissionName::SENSORS: + return SchedulingPolicy::Feature::kRequestedSensorsPermission; + case PermissionName::BACKGROUND_SYNC: + case PermissionName::BACKGROUND_FETCH: + return SchedulingPolicy::Feature::kRequestedBackgroundWorkPermission; + default: + return base::nullopt; + } +} + +void NotifySchedulerAboutPermissionRequest(ExecutionContext* context, + PermissionName permission) { + if (!context) + return; + + base::Optional<SchedulingPolicy::Feature> feature = + PermissionToSchedulingFeature(permission); + + if (!feature) + return; + + context->GetScheduler()->RegisterStickyFeature( + feature.value(), {SchedulingPolicy::RecordMetricsForBackForwardCache()}); +} + } // anonymous namespace ScriptPromise Permissions::query(ScriptState* script_state, @@ -184,6 +223,8 @@ ScriptPromise Permissions::request(ScriptState* script_state, ExecutionContext* context = ExecutionContext::From(script_state); + NotifySchedulerAboutPermissionRequest(context, descriptor->name); + auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); ScriptPromise promise = resolver->Promise(); @@ -229,6 +270,9 @@ ScriptPromise Permissions::requestAll( Vector<PermissionDescriptorPtr> internal_permissions; Vector<int> caller_index_to_internal_index; caller_index_to_internal_index.resize(raw_permissions.size()); + + ExecutionContext* context = ExecutionContext::From(script_state); + for (wtf_size_t i = 0; i < raw_permissions.size(); ++i) { const ScriptValue& raw_permission = raw_permissions[i]; @@ -237,6 +281,8 @@ ScriptPromise Permissions::requestAll( if (exception_state.HadException()) return ScriptPromise(); + NotifySchedulerAboutPermissionRequest(context, descriptor->name); + // Only append permissions types that are not already present in the vector. wtf_size_t internal_index = kNotFound; for (wtf_size_t j = 0; j < internal_permissions.size(); ++j) { @@ -252,8 +298,6 @@ ScriptPromise Permissions::requestAll( caller_index_to_internal_index[i] = internal_index; } - ExecutionContext* context = ExecutionContext::From(script_state); - auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); ScriptPromise promise = resolver->Promise(); diff --git a/chromium/third_party/blink/renderer/platform/bindings/script_forbidden_scope.h b/chromium/third_party/blink/renderer/platform/bindings/script_forbidden_scope.h index 656083c7377..ae44c6d23d8 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/script_forbidden_scope.h +++ b/chromium/third_party/blink/renderer/platform/bindings/script_forbidden_scope.h @@ -7,6 +7,7 @@ #include "base/auto_reset.h" #include "base/macros.h" +#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/stack_util.h" @@ -41,7 +42,11 @@ class PLATFORM_EXPORT ScriptForbiddenScope final { return GetMutableCounter() > 0; } - // DO NOT USE THESE FUNCTIONS FROM OUTSIDE OF THIS CLASS. + static void ThrowScriptForbiddenException(v8::Isolate* isolate) { + V8ThrowException::ThrowError(isolate, "Script execution is forbidden."); + } + + private: static void Enter() { if (LIKELY(!WTF::MayNotBeMainThread())) { ++g_main_thread_counter_; @@ -58,9 +63,11 @@ class PLATFORM_EXPORT ScriptForbiddenScope final { } } - private: static unsigned& GetMutableCounter(); static unsigned g_main_thread_counter_; + + // V8GCController is exceptionally allowed to call Enter/Exit. + friend class V8GCController; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc index 48cf52efb0f..e4a7c0c96d1 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc @@ -1058,16 +1058,23 @@ void GraphicsLayer::SetLayerState(const PropertyTreeState& layer_state, SetPaintArtifactCompositorNeedsUpdate(); } -void GraphicsLayer::SetContentsPropertyTreeState( - const PropertyTreeState& layer_state) { +void GraphicsLayer::SetContentsLayerState(const PropertyTreeState& layer_state, + const IntPoint& layer_offset) { DCHECK(ContentsLayer()); - if (contents_property_tree_state_) { - *contents_property_tree_state_ = layer_state; + if (contents_layer_state_) { + if (contents_layer_state_->state == layer_state && + contents_layer_state_->offset == layer_offset) + return; + contents_layer_state_->state = layer_state; + contents_layer_state_->offset = layer_offset; } else { - contents_property_tree_state_ = - std::make_unique<PropertyTreeState>(layer_state); + contents_layer_state_ = + std::make_unique<LayerState>(LayerState{layer_state, layer_offset}); } + + if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) + SetPaintArtifactCompositorNeedsUpdate(); } scoped_refptr<cc::DisplayItemList> GraphicsLayer::PaintContentsToDisplayList( diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h index ced1a78d816..1c7f75af559 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h +++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h @@ -232,6 +232,8 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, return const_cast<GraphicsLayer*>(this)->ContentsLayerIfRegistered(); } + const IntRect& ContentsRect() const { return contents_rect_; } + // For hosting this GraphicsLayer in a native layer hierarchy. cc::PictureLayer* CcLayer() const; @@ -294,16 +296,15 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, } IntPoint GetOffsetFromTransformNode() const { return layer_state_->offset; } - void SetContentsPropertyTreeState(const PropertyTreeState&); + void SetContentsLayerState(const PropertyTreeState&, + const IntPoint& layer_offset); const PropertyTreeState& GetContentsPropertyTreeState() const { - return contents_property_tree_state_ ? *contents_property_tree_state_ - : GetPropertyTreeState(); + return contents_layer_state_ ? contents_layer_state_->state + : GetPropertyTreeState(); } IntPoint GetContentsOffsetFromTransformNode() const { - auto offset = contents_rect_.Location(); - if (layer_state_) - offset = offset + GetOffsetFromTransformNode(); - return offset; + return contents_layer_state_ ? contents_layer_state_->offset + : GetOffsetFromTransformNode(); } // Capture the last painted result into a PaintRecord. This GraphicsLayer @@ -423,7 +424,7 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, IntPoint offset; }; std::unique_ptr<LayerState> layer_state_; - std::unique_ptr<PropertyTreeState> contents_property_tree_state_; + std::unique_ptr<LayerState> contents_layer_state_; std::unique_ptr<RasterInvalidator> raster_invalidator_; diff --git a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc index 17c24ba6149..c3d0a529526 100644 --- a/chromium/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc +++ b/chromium/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc @@ -16,6 +16,8 @@ bool SchedulingPolicy::IsFeatureSticky(SchedulingPolicy::Feature feature) { case Feature::kOutstandingNetworkRequest: case Feature::kOutstandingIndexedDBTransaction: case Feature::kHasScriptableFramesInMultipleTabs: + case Feature::kBroadcastChannel: + case Feature::kIndexedDBConnection: return false; case Feature::kMainResourceHasCacheControlNoStore: case Feature::kMainResourceHasCacheControlNoCache: @@ -30,6 +32,13 @@ bool SchedulingPolicy::IsFeatureSticky(SchedulingPolicy::Feature feature) { case Feature::kContainsPlugins: case Feature::kDocumentLoaded: case Feature::kServiceWorkerControlledPage: + case Feature::kRequestedGeolocationPermission: + case Feature::kRequestedNotificationsPermission: + case Feature::kRequestedMIDIPermission: + case Feature::kRequestedAudioCapturePermission: + case Feature::kRequestedVideoCapturePermission: + case Feature::kRequestedSensorsPermission: + case Feature::kRequestedBackgroundWorkPermission: return true; } } diff --git a/chromium/third_party/icu/README.chromium b/chromium/third_party/icu/README.chromium index 4c8e9b0fb58..c75f49a1ed5 100644 --- a/chromium/third_party/icu/README.chromium +++ b/chromium/third_party/icu/README.chromium @@ -205,7 +205,7 @@ D. Local Modifications windowsZones.txt zoneinfo64.txt - As of Dec 31, 2018, the latest version is 2018i and the above files + As of May 7, 2019, the latest version is 2019a and the above files are available at the ICU github repos. 4. Build-related changes @@ -258,3 +258,10 @@ D. Local Modifications https://unicode-org.atlassian.net/browse/ICU-20391 - upstream PR: https://github.com/unicode-org/icu/pull/628 + +9. Timezone breakage patch + - patches/timezone.patch + - upstream bug: + https://unicode-org.atlassian.net/browse/ICU-20595 + - upstream PR: + https://github.com/unicode-org/icu/pull/649 diff --git a/chromium/third_party/icu/cast/icudtl.dat b/chromium/third_party/icu/cast/icudtl.dat Binary files differindex 6b72db42cc1..7d493f69cad 100644 --- a/chromium/third_party/icu/cast/icudtl.dat +++ b/chromium/third_party/icu/cast/icudtl.dat diff --git a/chromium/third_party/icu/chromeos/icudtl.dat b/chromium/third_party/icu/chromeos/icudtl.dat Binary files differindex 20d9a305662..f0d4aca98c9 100644 --- a/chromium/third_party/icu/chromeos/icudtl.dat +++ b/chromium/third_party/icu/chromeos/icudtl.dat diff --git a/chromium/third_party/icu/common/icudtb.dat b/chromium/third_party/icu/common/icudtb.dat Binary files differindex 00aab097946..9429366ec85 100644 --- a/chromium/third_party/icu/common/icudtb.dat +++ b/chromium/third_party/icu/common/icudtb.dat diff --git a/chromium/third_party/icu/common/icudtl.dat b/chromium/third_party/icu/common/icudtl.dat Binary files differindex 195f6f8ed7f..0a6596ae65c 100644 --- a/chromium/third_party/icu/common/icudtl.dat +++ b/chromium/third_party/icu/common/icudtl.dat diff --git a/chromium/third_party/icu/filters/android.json b/chromium/third_party/icu/filters/android.json index 1ee8f13242f..38be85f6393 100644 --- a/chromium/third_party/icu/filters/android.json +++ b/chromium/third_party/icu/filters/android.json @@ -756,11 +756,6 @@ // https://cs.chromium.org/chromium/src/third_party/icu/patches/data.build.patch?rcl=797b7c "unames": { "filterType": "exclude" - }, -// Based on the --disable-layout mentioned in -// https://cs.chromium.org/chromium/src/third_party/icu/README.chromium?rcl=797b7c - "ulayout": { - "filterType": "exclude" } }, // Based on the ICU63 version of diff --git a/chromium/third_party/icu/filters/android_small.json b/chromium/third_party/icu/filters/android_small.json index 68a19c8df8d..e002a075575 100644 --- a/chromium/third_party/icu/filters/android_small.json +++ b/chromium/third_party/icu/filters/android_small.json @@ -739,11 +739,6 @@ // https://cs.chromium.org/chromium/src/third_party/icu/patches/data.build.patch?rcl=797b7c "unames": { "filterType": "exclude" - }, -// Based on the --disable-layout mentioned in -// https://cs.chromium.org/chromium/src/third_party/icu/README.chromium?rcl=797b7c - "ulayout": { - "filterType": "exclude" } }, // Based on the ICU63 version of diff --git a/chromium/third_party/icu/filters/cast.json b/chromium/third_party/icu/filters/cast.json index a1709eab4d1..7a1e8251811 100644 --- a/chromium/third_party/icu/filters/cast.json +++ b/chromium/third_party/icu/filters/cast.json @@ -796,11 +796,6 @@ // https://cs.chromium.org/chromium/src/third_party/icu/patches/data.build.patch?rcl=797b7c "unames": { "filterType": "exclude" - }, -// Based on the --disable-layout mentioned in -// https://cs.chromium.org/chromium/src/third_party/icu/README.chromium?rcl=797b7c - "ulayout": { - "filterType": "exclude" } }, // Based on the ICU63 version of diff --git a/chromium/third_party/icu/filters/chromeos.json b/chromium/third_party/icu/filters/chromeos.json index 5e28c076f83..d3de23c5bbc 100644 --- a/chromium/third_party/icu/filters/chromeos.json +++ b/chromium/third_party/icu/filters/chromeos.json @@ -784,11 +784,6 @@ // https://cs.chromium.org/chromium/src/third_party/icu/patches/data.build.patch?rcl=797b7c "unames": { "filterType": "exclude" - }, -// Based on the --disable-layout mentioned in -// https://cs.chromium.org/chromium/src/third_party/icu/README.chromium?rcl=797b7c - "ulayout": { - "filterType": "exclude" } }, // Based on the ICU63 version of diff --git a/chromium/third_party/icu/filters/common.json b/chromium/third_party/icu/filters/common.json index 3219e8ad064..9750dcf2be8 100644 --- a/chromium/third_party/icu/filters/common.json +++ b/chromium/third_party/icu/filters/common.json @@ -784,11 +784,6 @@ // https://cs.chromium.org/chromium/src/third_party/icu/patches/data.build.patch?rcl=797b7c "unames": { "filterType": "exclude" - }, -// Based on the --disable-layout mentioned in -// https://cs.chromium.org/chromium/src/third_party/icu/README.chromium?rcl=797b7c - "ulayout": { - "filterType": "exclude" } }, // Based on the ICU63 version of diff --git a/chromium/third_party/icu/filters/flutter.json b/chromium/third_party/icu/filters/flutter.json index bda4b98bbee..91ea4fde4a9 100644 --- a/chromium/third_party/icu/filters/flutter.json +++ b/chromium/third_party/icu/filters/flutter.json @@ -722,11 +722,6 @@ // https://cs.chromium.org/chromium/src/third_party/icu/patches/data.build.patch?rcl=797b7c "unames": { "filterType": "exclude" - }, -// Based on the --disable-layout mentioned in -// https://cs.chromium.org/chromium/src/third_party/icu/README.chromium?rcl=797b7c - "ulayout": { - "filterType": "exclude" } }, // Based on the ICU63 version of diff --git a/chromium/third_party/icu/flutter/icudtl.dat b/chromium/third_party/icu/flutter/icudtl.dat Binary files differindex c501eb4fc86..3606735a793 100644 --- a/chromium/third_party/icu/flutter/icudtl.dat +++ b/chromium/third_party/icu/flutter/icudtl.dat diff --git a/chromium/third_party/icu/patches/timezone.patch b/chromium/third_party/icu/patches/timezone.patch new file mode 100644 index 00000000000..bf7e1729aef --- /dev/null +++ b/chromium/third_party/icu/patches/timezone.patch @@ -0,0 +1,52 @@ +diff --git a/source/i18n/timezone.cpp b/source/i18n/timezone.cpp +index f129d8b6..32214d72 100644 +--- a/source/i18n/timezone.cpp ++++ b/source/i18n/timezone.cpp +@@ -527,6 +527,11 @@ TimeZone::detectHostTimeZone() + + // ------------------------------------- + ++static UMutex *gDefaultZoneMutex() { ++ static UMutex* m = new UMutex(); ++ return m; ++} ++ + /** + * Initialize DEFAULT_ZONE from the system default time zone. + * Upon return, DEFAULT_ZONE will not be NULL, unless operator new() +@@ -536,6 +541,7 @@ static void U_CALLCONV initDefault() + { + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); + ++ Mutex lock(gDefaultZoneMutex()); + // If setDefault() has already been called we can skip getting the + // default zone information from the system. + if (DEFAULT_ZONE != NULL) { +@@ -571,7 +577,10 @@ TimeZone* U_EXPORT2 + TimeZone::createDefault() + { + umtx_initOnce(gDefaultZoneInitOnce, initDefault); +- return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL; ++ { ++ Mutex lock(gDefaultZoneMutex()); ++ return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL; ++ } + } + + // ------------------------------------- +@@ -581,9 +590,12 @@ TimeZone::adoptDefault(TimeZone* zone) + { + if (zone != NULL) + { +- TimeZone *old = DEFAULT_ZONE; +- DEFAULT_ZONE = zone; +- delete old; ++ { ++ Mutex lock(gDefaultZoneMutex()); ++ TimeZone *old = DEFAULT_ZONE; ++ DEFAULT_ZONE = zone; ++ delete old; ++ } + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); + } + } diff --git a/chromium/third_party/icu/scripts/copy_data.sh b/chromium/third_party/icu/scripts/copy_data.sh index edc16771c42..16820e4a7b9 100755 --- a/chromium/third_party/icu/scripts/copy_data.sh +++ b/chromium/third_party/icu/scripts/copy_data.sh @@ -19,6 +19,7 @@ source "${TOPSRC}/scripts/data_common.sh" function copy_common { DATA_PREFIX="data/out/tmp/icudt${VERSION}" + TZRES_PREFIX="data/out/build/icudt${VERSION}l" echo "Generating the big endian data bundle" LD_LIBRARY_PATH=lib bin/icupkg -tb "${DATA_PREFIX}l.dat" "${DATA_PREFIX}b.dat" @@ -29,6 +30,12 @@ function copy_common { cp "${DATA_PREFIX}${endian}.dat" "${TOPSRC}/common/icudt${endian}.dat" done + echo "Copying metaZones.res, timezoneTypes.res, zoneinfo64.res" + for tzfile in metaZones timezoneTypes zoneinfo64 + do + cp "${TZRES_PREFIX}/${tzfile}.res" "${TOPSRC}/tzres/${tzfile}.res" + done + echo "Done with copying pre-built ICU data files." } diff --git a/chromium/third_party/icu/source/i18n/timezone.cpp b/chromium/third_party/icu/source/i18n/timezone.cpp index f129d8b6076..129e6a5f27d 100644 --- a/chromium/third_party/icu/source/i18n/timezone.cpp +++ b/chromium/third_party/icu/source/i18n/timezone.cpp @@ -527,6 +527,11 @@ TimeZone::detectHostTimeZone() // ------------------------------------- +static UMutex *gDefaultZoneMutex() { + static UMutex* m = new UMutex(); + return m; +} + /** * Initialize DEFAULT_ZONE from the system default time zone. * Upon return, DEFAULT_ZONE will not be NULL, unless operator new() @@ -536,6 +541,7 @@ static void U_CALLCONV initDefault() { ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); + Mutex lock(gDefaultZoneMutex()); // If setDefault() has already been called we can skip getting the // default zone information from the system. if (DEFAULT_ZONE != NULL) { @@ -571,7 +577,10 @@ TimeZone* U_EXPORT2 TimeZone::createDefault() { umtx_initOnce(gDefaultZoneInitOnce, initDefault); - return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL; + { + Mutex lock(gDefaultZoneMutex()); + return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL; + } } // ------------------------------------- @@ -581,9 +590,12 @@ TimeZone::adoptDefault(TimeZone* zone) { if (zone != NULL) { - TimeZone *old = DEFAULT_ZONE; - DEFAULT_ZONE = zone; - delete old; + { + Mutex lock(gDefaultZoneMutex()); + TimeZone *old = DEFAULT_ZONE; + DEFAULT_ZONE = zone; + delete old; + } ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); } } diff --git a/chromium/third_party/icu/tzres/metaZones.res b/chromium/third_party/icu/tzres/metaZones.res Binary files differnew file mode 100644 index 00000000000..a39c3ff8e2f --- /dev/null +++ b/chromium/third_party/icu/tzres/metaZones.res diff --git a/chromium/third_party/icu/tzres/timezoneTypes.res b/chromium/third_party/icu/tzres/timezoneTypes.res Binary files differnew file mode 100644 index 00000000000..68cc6204260 --- /dev/null +++ b/chromium/third_party/icu/tzres/timezoneTypes.res diff --git a/chromium/third_party/icu/tzres/zoneinfo64.res b/chromium/third_party/icu/tzres/zoneinfo64.res Binary files differnew file mode 100644 index 00000000000..7e0afd40558 --- /dev/null +++ b/chromium/third_party/icu/tzres/zoneinfo64.res diff --git a/chromium/third_party/skia/src/core/SkRemoteGlyphCache.cpp b/chromium/third_party/skia/src/core/SkRemoteGlyphCache.cpp index 7bcb29a35e9..b12e52058a2 100644 --- a/chromium/third_party/skia/src/core/SkRemoteGlyphCache.cpp +++ b/chromium/third_party/skia/src/core/SkRemoteGlyphCache.cpp @@ -169,7 +169,10 @@ bool read_path(Deserializer* deserializer, SkGlyph* glyph, SkStrike* cache) { uint64_t pathSize = 0u; if (!deserializer->read<uint64_t>(&pathSize)) return false; - if (pathSize == 0u) return true; + if (pathSize == 0u) { + cache->initializePath(glyph, nullptr, 0u); + return true; + } auto* path = deserializer->read(pathSize, kPathAlignment); if (!path) return false; @@ -605,16 +608,14 @@ void SkStrikeServer::SkGlyphCacheState::writeGlyphPath(const SkPackedGlyphID& gl } -// This version of glyphMetrics only adds entries to result if their data need to be sent to the -// GPU process. As a result, empty glyphs will be sent so that the GPU code can lookup the glyph -// and detect that it is empty. +// Be sure to read and understand the comment for prepareForDrawing in SkStrikeInterface.h before +// working on this code. SkSpan<const SkGlyphPos> SkStrikeServer::SkGlyphCacheState::prepareForDrawing( const SkGlyphID glyphIDs[], const SkPoint positions[], size_t n, int maxDimension, SkGlyphPos results[]) { - size_t glyphsToSendCount = 0; for (size_t i = 0; i < n; i++) { SkPoint glyphPos = positions[i]; SkGlyphID glyphID = glyphIDs[i]; @@ -635,10 +636,7 @@ SkSpan<const SkGlyphPos> SkStrikeServer::SkGlyphCacheState::prepareForDrawing( fContext->getMetrics(glyphPtr); if (glyphPtr->maxDimension() <= maxDimension) { - // The mask/SDF will fit in the cache. - // TODO: no need to do this once code base converted over to bulk. - results[glyphsToSendCount++] = {i, glyphPtr, glyphPos}; } else if (glyphPtr->fMaskFormat != SkMask::kARGB32_Format) { // The glyph is too big for the atlas, but it is not color, so it is handled with a @@ -646,13 +644,12 @@ SkSpan<const SkGlyphPos> SkStrikeServer::SkGlyphCacheState::prepareForDrawing( if (glyphPtr->fPathData == nullptr) { // Never checked for a path before. Add the path now. - auto path = const_cast<SkGlyph&>(*glyphPtr).addPath(fContext.get(), &fAlloc); - if (path != nullptr) { + const_cast<SkGlyph&>(*glyphPtr).addPath(fContext.get(), &fAlloc); - // A path was added make sure to send it to the GPU. - fCachedGlyphPaths.add(glyphPtr->getPackedID()); - fPendingGlyphPaths.push_back(glyphPtr->getPackedID()); - } + // Always send the path data, even if its not available, to make sure empty + // paths are not incorrectly assumed to be cache misses. + fCachedGlyphPaths.add(glyphPtr->getPackedID()); + fPendingGlyphPaths.push_back(glyphPtr->getPackedID()); } } else { @@ -666,8 +663,13 @@ SkSpan<const SkGlyphPos> SkStrikeServer::SkGlyphCacheState::prepareForDrawing( fPendingGlyphImages.push_back(packedGlyphID); } + // Each glyph needs to be added as per the contract for prepareForDrawing. + // TODO(herb): check if the empty glyphs need to be added here. They certainly need to be + // sent, but do the need to be processed by the painter? + results[i] = {i, glyphPtr, glyphPos}; } - return SkSpan<const SkGlyphPos>(results, glyphsToSendCount); + + return SkSpan<const SkGlyphPos>{results, n}; } // SkStrikeClient ----------------------------------------- @@ -694,10 +696,10 @@ SkStrikeClient::SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManage SkStrikeClient::~SkStrikeClient() = default; -#define READ_FAILURE \ - { \ - SkDebugf("Bad font data serialization"); \ - return false; \ +#define READ_FAILURE \ + { \ + SkDebugf("Bad font data serialization line: %d", __LINE__); \ + return false; \ } static bool readGlyph(SkTLazy<SkGlyph>& glyph, Deserializer* deserializer) { diff --git a/chromium/third_party/skia/src/core/SkStrike.cpp b/chromium/third_party/skia/src/core/SkStrike.cpp index e248e6f52c7..09ab883dedd 100644 --- a/chromium/third_party/skia/src/core/SkStrike.cpp +++ b/chromium/third_party/skia/src/core/SkStrike.cpp @@ -183,6 +183,8 @@ bool SkStrike::initializePath(SkGlyph* glyph, const volatile void* data, size_t if (glyph->fWidth) { SkGlyph::PathData* pathData = fAlloc.make<SkGlyph::PathData>(); glyph->fPathData = pathData; + if (size == 0u) return true; + auto path = skstd::make_unique<SkPath>(); if (!pathData->fPath.readFromMemory(const_cast<const void*>(data), size)) { return false; @@ -254,7 +256,6 @@ SkSpan<const SkGlyphPos> SkStrike::prepareForDrawing(const SkGlyphID glyphIDs[], // The out of atlas glyph is not color so we can draw it using paths. this->findPath(glyph); } else { - // This will be handled by the fallback strike. SkASSERT(glyph.maxDimension() > maxDimension && glyph.fMaskFormat == SkMask::kARGB32_Format); diff --git a/chromium/third_party/webrtc/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc b/chromium/third_party/webrtc/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc index 95ba2660a14..5f2f15aa385 100644 --- a/chromium/third_party/webrtc/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc +++ b/chromium/third_party/webrtc/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc @@ -804,7 +804,7 @@ TEST_F(TestVp9Impl, EnablingNewLayerIsDelayedInScreenshareAndAddsSsInfo) { codec_settings_.maxFramerate = 30; ConfigureSvc(num_spatial_layers); codec_settings_.spatialLayers[0].maxFramerate = 5.0; - // use 30 for the SL 1 instead of 5, so even if SL 0 frame is dropped due to + // use 30 for the SL 1 instead of 10, so even if SL 0 frame is dropped due to // framerate capping we would still get back at least a middle layer. It // simplifies the test. codec_settings_.spatialLayers[1].maxFramerate = 30.0; @@ -868,6 +868,93 @@ TEST_F(TestVp9Impl, EnablingNewLayerIsDelayedInScreenshareAndAddsSsInfo) { EXPECT_TRUE(codec_specific_info[0].codecSpecific.VP9.ss_data_available); } +TEST_F(TestVp9Impl, ScreenshareFrameDropping) { + const int num_spatial_layers = 3; + const int num_frames_to_detect_drops = 2; + + codec_settings_.maxFramerate = 30; + ConfigureSvc(num_spatial_layers); + // use 30 for the SL0 and SL1 because it simplifies the test. + codec_settings_.spatialLayers[0].maxFramerate = 30.0; + codec_settings_.spatialLayers[1].maxFramerate = 30.0; + codec_settings_.spatialLayers[2].maxFramerate = 30.0; + codec_settings_.VP9()->frameDroppingOn = true; + codec_settings_.mode = VideoCodecMode::kScreensharing; + codec_settings_.VP9()->interLayerPred = InterLayerPredMode::kOn; + codec_settings_.VP9()->flexibleMode = true; + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->InitEncode(&codec_settings_, 1 /* number of cores */, + 0 /* max payload size (unused) */)); + + // Enable all but the last layer. + VideoBitrateAllocation bitrate_allocation; + // Very low bitrate for the lowest spatial layer to ensure rate-control drops. + bitrate_allocation.SetBitrate(0, 0, 1000); + bitrate_allocation.SetBitrate( + 1, 0, codec_settings_.spatialLayers[1].targetBitrate * 1000); + // Disable highest layer. + bitrate_allocation.SetBitrate(2, 0, 0); + + encoder_->SetRates(VideoEncoder::RateControlParameters( + bitrate_allocation, codec_settings_.maxFramerate)); + + bool frame_dropped = false; + // Encode enough frames to force drop due to rate-control. + for (size_t frame_num = 0; frame_num < num_frames_to_detect_drops; + ++frame_num) { + SetWaitForEncodedFramesThreshold(1); + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->Encode(*NextInputFrame(), nullptr)); + std::vector<EncodedImage> encoded_frames; + std::vector<CodecSpecificInfo> codec_specific_info; + ASSERT_TRUE(WaitForEncodedFrames(&encoded_frames, &codec_specific_info)); + EXPECT_LE(encoded_frames.size(), 2u); + EXPECT_GE(encoded_frames.size(), 1u); + if (encoded_frames.size() == 1) { + frame_dropped = true; + // Dropped frame is on the SL0. + EXPECT_EQ(encoded_frames[0].SpatialIndex(), 1); + } + } + EXPECT_TRUE(frame_dropped); + + // Enable the last layer. + bitrate_allocation.SetBitrate( + 2, 0, codec_settings_.spatialLayers[2].targetBitrate * 1000); + encoder_->SetRates(VideoEncoder::RateControlParameters( + bitrate_allocation, codec_settings_.maxFramerate)); + SetWaitForEncodedFramesThreshold(1); + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->Encode(*NextInputFrame(), nullptr)); + std::vector<EncodedImage> encoded_frames; + std::vector<CodecSpecificInfo> codec_specific_info; + ASSERT_TRUE(WaitForEncodedFrames(&encoded_frames, &codec_specific_info)); + // No drop allowed. + EXPECT_EQ(encoded_frames.size(), 3u); + + // Verify that frame-dropping is re-enabled back. + frame_dropped = false; + // Encode enough frames to force drop due to rate-control. + for (size_t frame_num = 0; frame_num < num_frames_to_detect_drops; + ++frame_num) { + SetWaitForEncodedFramesThreshold(1); + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->Encode(*NextInputFrame(), nullptr)); + std::vector<EncodedImage> encoded_frames; + std::vector<CodecSpecificInfo> codec_specific_info; + ASSERT_TRUE(WaitForEncodedFrames(&encoded_frames, &codec_specific_info)); + EXPECT_LE(encoded_frames.size(), 3u); + EXPECT_GE(encoded_frames.size(), 2u); + if (encoded_frames.size() == 2) { + frame_dropped = true; + // Dropped frame is on the SL0. + EXPECT_EQ(encoded_frames[0].SpatialIndex(), 1); + EXPECT_EQ(encoded_frames[1].SpatialIndex(), 2); + } + } + EXPECT_TRUE(frame_dropped); +} + TEST_F(TestVp9Impl, RemovingLayerIsNotDelayedInScreenshareAndAddsSsInfo) { const size_t num_spatial_layers = 3; // Chosen by hand, the 2nd frame is dropped with configured per-layer max @@ -1341,47 +1428,6 @@ TEST_F(TestVp9ImplFrameDropping, DifferentFrameratePerSpatialLayer) { } } -TEST_F(TestVp9ImplFrameDropping, LayerMaxFramerateIsCappedByCodecMaxFramerate) { - const float input_framerate_fps = 30.0; - const float layer_max_framerate_fps = 30.0; - const uint32_t codec_max_framerate_fps = layer_max_framerate_fps / 3; - const size_t video_duration_secs = 3; - const size_t num_input_frames = video_duration_secs * input_framerate_fps; - - VideoBitrateAllocation bitrate_allocation; - codec_settings_.spatialLayers[0].width = codec_settings_.width; - codec_settings_.spatialLayers[0].height = codec_settings_.height; - codec_settings_.spatialLayers[0].maxFramerate = layer_max_framerate_fps; - codec_settings_.spatialLayers[0].minBitrate = codec_settings_.startBitrate; - codec_settings_.spatialLayers[0].maxBitrate = codec_settings_.startBitrate; - codec_settings_.spatialLayers[0].targetBitrate = codec_settings_.startBitrate; - codec_settings_.spatialLayers[0].active = true; - - bitrate_allocation.SetBitrate( - 0, 0, codec_settings_.spatialLayers[0].targetBitrate * 1000); - - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, - encoder_->InitEncode(&codec_settings_, 1 /* number of cores */, - 0 /* max payload size (unused) */)); - - encoder_->SetRates(VideoEncoder::RateControlParameters( - bitrate_allocation, codec_max_framerate_fps)); - - VideoFrame* input_frame = NextInputFrame(); - for (size_t frame_num = 0; frame_num < num_input_frames; ++frame_num) { - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Encode(*input_frame, nullptr)); - const size_t timestamp = input_frame->timestamp() + - kVideoPayloadTypeFrequency / input_framerate_fps; - input_frame->set_timestamp(static_cast<uint32_t>(timestamp)); - } - - const size_t num_encoded_frames = GetNumEncodedFrames(); - const float encoded_framerate_fps = num_encoded_frames / video_duration_secs; - const float max_framerate_error_fps = codec_max_framerate_fps * 0.1f; - EXPECT_NEAR(encoded_framerate_fps, codec_max_framerate_fps, - max_framerate_error_fps); -} - class TestVp9ImplProfile2 : public TestVp9Impl { protected: void SetUp() override { diff --git a/chromium/third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc b/chromium/third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc index abb54b6b932..a09a7d944b3 100644 --- a/chromium/third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc +++ b/chromium/third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc @@ -54,7 +54,7 @@ constexpr double kLowRateFactor = 1.0; constexpr double kHighRateFactor = 2.0; // These settings correspond to the settings in vpx_codec_enc_cfg. -struct Vp8RateSettings { +struct Vp9RateSettings { uint32_t rc_undershoot_pct; uint32_t rc_overshoot_pct; uint32_t rc_buf_sz; @@ -161,9 +161,9 @@ uint32_t Interpolate(uint32_t low, return static_cast<uint32_t>(((1.0 - factor) * low) + (factor * high) + 0.5); } -Vp8RateSettings GetRateSettings(double bandwidth_headroom_factor) { - static const Vp8RateSettings low_settings{1000u, 0u, 100u, 30u, 40u}; - static const Vp8RateSettings high_settings{100u, 15u, 1000u, 600u, 5u}; +Vp9RateSettings GetRateSettings(double bandwidth_headroom_factor) { + static const Vp9RateSettings low_settings{100u, 0u, 100u, 33u, 40u}; + static const Vp9RateSettings high_settings{50u, 50u, 1000u, 700u, 5u}; if (bandwidth_headroom_factor <= kLowRateFactor) { return low_settings; @@ -171,7 +171,7 @@ Vp8RateSettings GetRateSettings(double bandwidth_headroom_factor) { return high_settings; } - Vp8RateSettings settings; + Vp9RateSettings settings; settings.rc_undershoot_pct = Interpolate(low_settings.rc_undershoot_pct, high_settings.rc_undershoot_pct, bandwidth_headroom_factor); @@ -191,7 +191,7 @@ Vp8RateSettings GetRateSettings(double bandwidth_headroom_factor) { } void UpdateRateSettings(vpx_codec_enc_cfg_t* config, - const Vp8RateSettings& new_settings) { + const Vp9RateSettings& new_settings) { config->rc_undershoot_pct = new_settings.rc_undershoot_pct; config->rc_overshoot_pct = new_settings.rc_overshoot_pct; config->rc_buf_sz = new_settings.rc_buf_sz; @@ -316,8 +316,7 @@ bool VP9EncoderImpl::SetSvcRates( } framerate_controller_[sl_idx].SetTargetRate( - std::min(static_cast<float>(codec_.maxFramerate), - codec_.spatialLayers[sl_idx].maxFramerate)); + codec_.spatialLayers[sl_idx].maxFramerate); } } else { float rate_ratio[VPX_MAX_LAYERS] = {0}; @@ -535,24 +534,18 @@ int VP9EncoderImpl::InitEncode(const VideoCodec* inst, inter_layer_pred_ = inst->VP9().interLayerPred; - different_framerates_used_ = false; - for (size_t sl_idx = 1; sl_idx < num_spatial_layers_; ++sl_idx) { - if (std::abs(codec_.spatialLayers[sl_idx].maxFramerate - - codec_.spatialLayers[0].maxFramerate) > 1e-9) { - different_framerates_used_ = true; - } - } - - if (different_framerates_used_ && !is_flexible_mode_) { - RTC_LOG(LS_ERROR) << "Flexible mode required for different framerates on " - "different spatial layers"; + if (num_spatial_layers_ > 1 && + codec_.mode == VideoCodecMode::kScreensharing && !is_flexible_mode_) { + RTC_LOG(LS_ERROR) << "Flexible mode is required for screenshare with " + "several spatial layers"; return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; } // External reference control is required for different frame rate on spatial // layers because libvpx generates rtp incompatible references in this case. external_ref_control_ = field_trial::IsEnabled("WebRTC-Vp9ExternalRefCtrl") || - different_framerates_used_ || + (num_spatial_layers_ > 1 && + codec_.mode == VideoCodecMode::kScreensharing) || inter_layer_pred_ == InterLayerPredMode::kOn; if (num_temporal_layers_ == 1) { @@ -589,7 +582,8 @@ int VP9EncoderImpl::InitEncode(const VideoCodec* inst, if (external_ref_control_) { config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS; - if (num_temporal_layers_ > 1 && different_framerates_used_) { + if (num_temporal_layers_ > 1 && num_spatial_layers_ > 1 && + codec_.mode == VideoCodecMode::kScreensharing) { // External reference control for several temporal layers with different // frame rates on spatial layers is not implemented yet. return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; @@ -717,18 +711,35 @@ int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) { RTC_NOTREACHED(); } - // Configure encoder to drop entire superframe whenever it needs to drop - // a layer. This mode is prefered over per-layer dropping which causes - // quality flickering and is not compatible with RTP non-flexible mode. - vpx_svc_frame_drop_t svc_drop_frame; - memset(&svc_drop_frame, 0, sizeof(svc_drop_frame)); - svc_drop_frame.framedrop_mode = - full_superframe_drop_ ? FULL_SUPERFRAME_DROP : CONSTRAINED_LAYER_DROP; - svc_drop_frame.max_consec_drop = std::numeric_limits<int>::max(); - for (size_t i = 0; i < num_spatial_layers_; ++i) { - svc_drop_frame.framedrop_thresh[i] = config_->rc_dropframe_thresh; + memset(&svc_drop_frame_, 0, sizeof(svc_drop_frame_)); + dropping_only_base_layer_ = inter_layer_pred_ == InterLayerPredMode::kOn && + codec_.mode == VideoCodecMode::kScreensharing && + num_spatial_layers_ > 1; + if (dropping_only_base_layer_) { + // Screenshare dropping mode: only the base spatial layer + // can be dropped and it doesn't affect other spatial layers. + // This mode is preferable because base layer has low bitrate targets + // and more likely to drop frames. It shouldn't reduce framerate on other + // layers. + svc_drop_frame_.framedrop_mode = LAYER_DROP; + svc_drop_frame_.max_consec_drop = 5; + svc_drop_frame_.framedrop_thresh[0] = config_->rc_dropframe_thresh; + for (size_t i = 1; i < num_spatial_layers_; ++i) { + svc_drop_frame_.framedrop_thresh[i] = 0; + } + } else { + // Configure encoder to drop entire superframe whenever it needs to drop + // a layer. This mode is preferred over per-layer dropping which causes + // quality flickering and is not compatible with RTP non-flexible mode. + svc_drop_frame_.framedrop_mode = + full_superframe_drop_ ? FULL_SUPERFRAME_DROP : CONSTRAINED_LAYER_DROP; + svc_drop_frame_.max_consec_drop = std::numeric_limits<int>::max(); + for (size_t i = 0; i < num_spatial_layers_; ++i) { + svc_drop_frame_.framedrop_thresh[i] = config_->rc_dropframe_thresh; + } } - vpx_codec_control(encoder_, VP9E_SET_SVC_FRAME_DROP_LAYER, &svc_drop_frame); + vpx_codec_control(encoder_, VP9E_SET_SVC_FRAME_DROP_LAYER, + &svc_drop_frame_); } // Register callback for getting each spatial layer. @@ -894,9 +905,22 @@ int VP9EncoderImpl::Encode(const VideoFrame& input_image, if (less_layers_requested || more_layers_requested) { ss_info_needed_ = true; } + if (more_layers_requested && !force_key_frame_) { + // Prohibit drop of all layers for the next frame, so newly enabled + // layer would have a valid spatial reference. + for (size_t i = 0; i < num_spatial_layers_; ++i) { + svc_drop_frame_.framedrop_thresh[i] = 0; + } + } } } + if (num_spatial_layers_ > 1) { + // Update frame dropping settings as they may change on per-frame basis. + vpx_codec_control(encoder_, VP9E_SET_SVC_FRAME_DROP_LAYER, + &svc_drop_frame_); + } + if (vpx_codec_enc_config_set(encoder_, config_)) { return WEBRTC_VIDEO_CODEC_ERROR; } @@ -964,7 +988,8 @@ int VP9EncoderImpl::Encode(const VideoFrame& input_image, if (VideoCodecMode::kScreensharing == codec_.mode) { for (uint8_t sl_idx = 0; sl_idx < num_active_spatial_layers_; ++sl_idx) { ref_config.duration[sl_idx] = static_cast<int64_t>( - 90000 / framerate_controller_[sl_idx].GetTargetRate()); + 90000 / (std::min(static_cast<float>(codec_.maxFramerate), + framerate_controller_[sl_idx].GetTargetRate()))); } } @@ -983,8 +1008,9 @@ int VP9EncoderImpl::Encode(const VideoFrame& input_image, RTC_DCHECK_GE(framerate_controller_.size(), num_active_spatial_layers_); float target_framerate_fps = (codec_.mode == VideoCodecMode::kScreensharing) - ? framerate_controller_[num_active_spatial_layers_ - 1] - .GetTargetRate() + ? std::min(static_cast<float>(codec_.maxFramerate), + framerate_controller_[num_active_spatial_layers_ - 1] + .GetTargetRate()) : codec_.maxFramerate; uint32_t duration = static_cast<uint32_t>(90000 / target_framerate_fps); const vpx_codec_err_t rv = vpx_codec_encode(encoder_, raw_, timestamp_, @@ -1199,6 +1225,8 @@ void VP9EncoderImpl::FillReferenceIndices(const vpx_codec_cx_pkt& pkt, // It is safe to ignore this requirement if inter-layer prediction is // enabled for all frames when all base frames are relayed to receiver. RTC_DCHECK_EQ(ref_buf.spatial_layer_id, layer_id.spatial_layer_id); + } else { + RTC_DCHECK_LE(ref_buf.spatial_layer_id, layer_id.spatial_layer_id); } RTC_DCHECK_LE(ref_buf.temporal_layer_id, layer_id.temporal_layer_id); @@ -1318,7 +1346,7 @@ vpx_svc_ref_frame_config_t VP9EncoderImpl::SetReferences( const bool same_spatial_layer = ref_buf_[buf_idx].spatial_layer_id == sl_idx; bool correct_pid = false; - if (different_framerates_used_) { + if (is_flexible_mode_) { correct_pid = pid_diff < kMaxAllowedPidDIff; } else { // Below code assumes single temporal referecence. @@ -1442,6 +1470,16 @@ int VP9EncoderImpl::GetEncodedLayerFrame(const vpx_codec_cx_pkt* pkt) { void VP9EncoderImpl::DeliverBufferedFrame(bool end_of_picture) { if (encoded_image_.size() > 0) { + if (num_spatial_layers_ > 1) { + // Restore frame dropping settings, as dropping may be temporary forbidden + // due to dynamically enabled layers. + svc_drop_frame_.framedrop_thresh[0] = config_->rc_dropframe_thresh; + for (size_t i = 1; i < num_spatial_layers_; ++i) { + svc_drop_frame_.framedrop_thresh[i] = + dropping_only_base_layer_ ? 0 : config_->rc_dropframe_thresh; + } + } + codec_specific_.codecSpecific.VP9.end_of_picture = end_of_picture; // No data partitioning in VP9, so 1 partition only. @@ -1519,7 +1557,8 @@ size_t VP9EncoderImpl::SteadyStateSize(int sid, int tid) { const size_t bitrate_bps = current_bitrate_allocation_.GetBitrate( sid, tid == kNoTemporalIdx ? 0 : tid); const float fps = (codec_.mode == VideoCodecMode::kScreensharing) - ? framerate_controller_[sid].GetTargetRate() + ? std::min(static_cast<float>(codec_.maxFramerate), + framerate_controller_[sid].GetTargetRate()) : codec_.maxFramerate; return static_cast<size_t>( bitrate_bps / (8 * fps) * diff --git a/chromium/third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h b/chromium/third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h index acc03bff5c9..fb195a7c001 100644 --- a/chromium/third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h +++ b/chromium/third_party/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h @@ -113,7 +113,6 @@ class VP9EncoderImpl : public VP9Encoder { GofInfoVP9 gof_; // Contains each frame's temporal information for // non-flexible mode. bool force_key_frame_; - bool different_framerates_used_; size_t pics_since_key_; uint8_t num_temporal_layers_; uint8_t num_spatial_layers_; // Number of configured SLs @@ -125,6 +124,8 @@ class VP9EncoderImpl : public VP9Encoder { const bool trusted_rate_controller_; const bool dynamic_rate_settings_; const bool full_superframe_drop_; + bool dropping_only_base_layer_; + vpx_svc_frame_drop_t svc_drop_frame_; bool first_frame_in_picture_; VideoBitrateAllocation current_bitrate_allocation_; absl::optional<RateControlParameters> requested_rate_settings_; diff --git a/chromium/third_party/webrtc/pc/jsep_session_description.cc b/chromium/third_party/webrtc/pc/jsep_session_description.cc index 90b12a4125b..d9c1fad94d1 100644 --- a/chromium/third_party/webrtc/pc/jsep_session_description.cc +++ b/chromium/third_party/webrtc/pc/jsep_session_description.cc @@ -207,7 +207,7 @@ bool JsepSessionDescription::Initialize( bool JsepSessionDescription::AddCandidate( const IceCandidateInterface* candidate) { - if (!candidate || candidate->sdp_mline_index() < 0) + if (!candidate) return false; size_t mediasection_index = 0; if (!GetMediasectionIndex(candidate, &mediasection_index)) { @@ -291,7 +291,18 @@ bool JsepSessionDescription::GetMediasectionIndex( if (!candidate || !index) { return false; } - *index = static_cast<size_t>(candidate->sdp_mline_index()); + + // If the candidate has no valid mline index or sdp_mid, it is impossible + // to find a match. + if (candidate->sdp_mid().empty() && + (candidate->sdp_mline_index() < 0 || + static_cast<size_t>(candidate->sdp_mline_index()) >= + description_->contents().size())) { + return false; + } + + if (candidate->sdp_mline_index() >= 0) + *index = static_cast<size_t>(candidate->sdp_mline_index()); if (description_ && !candidate->sdp_mid().empty()) { bool found = false; // Try to match the sdp_mid with content name. diff --git a/chromium/third_party/webrtc/pc/peer_connection.cc b/chromium/third_party/webrtc/pc/peer_connection.cc index 30fbf5c11ca..81034b91fc3 100644 --- a/chromium/third_party/webrtc/pc/peer_connection.cc +++ b/chromium/third_party/webrtc/pc/peer_connection.cc @@ -6185,21 +6185,18 @@ bool PeerConnection::UseCandidatesInSessionDescription( } bool PeerConnection::UseCandidate(const IceCandidateInterface* candidate) { - size_t mediacontent_index = static_cast<size_t>(candidate->sdp_mline_index()); - size_t remote_content_size = - remote_description()->description()->contents().size(); - if (mediacontent_index >= remote_content_size) { - RTC_LOG(LS_ERROR) << "UseCandidate: Invalid candidate media index."; + RTCErrorOr<const cricket::ContentInfo*> result = + FindContentInfo(remote_description(), candidate); + if (!result.ok()) { + RTC_LOG(LS_ERROR) << "UseCandidate: Invalid candidate. " + << result.error().message(); return false; } - - cricket::ContentInfo content = - remote_description()->description()->contents()[mediacontent_index]; std::vector<cricket::Candidate> candidates; candidates.push_back(candidate->candidate()); // Invoking BaseSession method to handle remote candidates. - RTCError error = - transport_controller_->AddRemoteCandidates(content.name, candidates); + RTCError error = transport_controller_->AddRemoteCandidates( + result.value()->name, candidates); if (error.ok()) { // Candidates successfully submitted for checking. if (ice_connection_state_ == PeerConnectionInterface::kIceConnectionNew || @@ -6222,6 +6219,42 @@ bool PeerConnection::UseCandidate(const IceCandidateInterface* candidate) { return true; } +RTCErrorOr<const cricket::ContentInfo*> PeerConnection::FindContentInfo( + const SessionDescriptionInterface* description, + const IceCandidateInterface* candidate) { + if (candidate->sdp_mline_index() >= 0) { + size_t mediacontent_index = + static_cast<size_t>(candidate->sdp_mline_index()); + size_t content_size = description->description()->contents().size(); + if (mediacontent_index < content_size) { + return &description->description()->contents()[mediacontent_index]; + } else { + return RTCError(RTCErrorType::INVALID_RANGE, + "Media line index (" + + rtc::ToString(candidate->sdp_mline_index()) + + ") out of range (number of mlines: " + + rtc::ToString(content_size) + ")."); + } + } else if (!candidate->sdp_mid().empty()) { + auto& contents = description->description()->contents(); + auto it = absl::c_find_if( + contents, [candidate](const cricket::ContentInfo& content_info) { + return content_info.mid() == candidate->sdp_mid(); + }); + if (it == contents.end()) { + return RTCError( + RTCErrorType::INVALID_PARAMETER, + "Mid " + candidate->sdp_mid() + + " specified but no media section with that mid found."); + } else { + return &*it; + } + } + + return RTCError(RTCErrorType::INVALID_PARAMETER, + "Neither sdp_mline_index nor sdp_mid specified."); +} + void PeerConnection::RemoveUnusedChannels(const SessionDescription* desc) { // Destroy video channel first since it may have a pointer to the // voice channel. @@ -6850,26 +6883,18 @@ bool PeerConnection::ReadyToUseRemoteCandidate( return false; } - size_t mediacontent_index = static_cast<size_t>(candidate->sdp_mline_index()); - size_t remote_content_size = - current_remote_desc->description()->contents().size(); - if (mediacontent_index >= remote_content_size) { - RTC_LOG(LS_ERROR) - << "ReadyToUseRemoteCandidate: Invalid candidate media index " - << mediacontent_index; + RTCErrorOr<const cricket::ContentInfo*> result = + FindContentInfo(current_remote_desc, candidate); + if (!result.ok()) { + RTC_LOG(LS_ERROR) << "ReadyToUseRemoteCandidate: Invalid candidate. " + << result.error().message(); *valid = false; return false; } - cricket::ContentInfo content = - current_remote_desc->description()->contents()[mediacontent_index]; - - const std::string transport_name = GetTransportName(content.name); - if (transport_name.empty()) { - return false; - } - return true; + std::string transport_name = GetTransportName(result.value()->name); + return !transport_name.empty(); } bool PeerConnection::SrtpRequired() const { diff --git a/chromium/third_party/webrtc/pc/peer_connection.h b/chromium/third_party/webrtc/pc/peer_connection.h index 39cb8674061..79408d4c0fd 100644 --- a/chromium/third_party/webrtc/pc/peer_connection.h +++ b/chromium/third_party/webrtc/pc/peer_connection.h @@ -911,6 +911,9 @@ class PeerConnection : public PeerConnectionInternal, // Uses |candidate| in this session. bool UseCandidate(const IceCandidateInterface* candidate) RTC_RUN_ON(signaling_thread()); + RTCErrorOr<const cricket::ContentInfo*> FindContentInfo( + const SessionDescriptionInterface* description, + const IceCandidateInterface* candidate) RTC_RUN_ON(signaling_thread()); // Deletes the corresponding channel of contents that don't exist in |desc|. // |desc| can be null. This means that all channels are deleted. void RemoveUnusedChannels(const cricket::SessionDescription* desc) diff --git a/chromium/third_party/webrtc/pc/peer_connection_ice_unittest.cc b/chromium/third_party/webrtc/pc/peer_connection_ice_unittest.cc index 03c11283bbc..afc859434f1 100644 --- a/chromium/third_party/webrtc/pc/peer_connection_ice_unittest.cc +++ b/chromium/third_party/webrtc/pc/peer_connection_ice_unittest.cc @@ -58,7 +58,7 @@ class PeerConnectionWrapperForIceTest : public PeerConnectionWrapper { const auto& first_content = desc->contents()[0]; candidate->set_transport_name(first_content.name); std::unique_ptr<IceCandidateInterface> jsep_candidate = - CreateIceCandidate(first_content.name, 0, *candidate); + CreateIceCandidate(first_content.name, -1, *candidate); return pc()->AddIceCandidate(jsep_candidate.get()); } diff --git a/chromium/third_party/webrtc/video/video_quality_test.cc b/chromium/third_party/webrtc/video/video_quality_test.cc index 10f96996011..00a1ff3e4cf 100644 --- a/chromium/third_party/webrtc/video/video_quality_test.cc +++ b/chromium/third_party/webrtc/video/video_quality_test.cc @@ -822,7 +822,7 @@ void VideoQualityTest::SetupVideo(Transport* send_transport, params_.ss[video_idx].num_spatial_layers); vp9_settings.interLayerPred = params_.ss[video_idx].inter_layer_pred; // High FPS vp9 screenshare requires flexible mode. - if (params_.video[video_idx].fps > 5) { + if (params_.ss[video_idx].num_spatial_layers > 1) { vp9_settings.flexibleMode = true; } video_encoder_configs_[video_idx].encoder_specific_settings = |