diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-12-10 16:19:40 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-12-10 16:01:50 +0000 |
commit | 51f6c2793adab2d864b3d2b360000ef8db1d3e92 (patch) | |
tree | 835b3b4446b012c75e80177cef9fbe6972cc7dbe /chromium/third_party/blink/renderer/modules | |
parent | 6036726eb981b6c4b42047513b9d3f4ac865daac (diff) | |
download | qtwebengine-chromium-51f6c2793adab2d864b3d2b360000ef8db1d3e92.tar.gz |
BASELINE: Update Chromium to 71.0.3578.93
Change-Id: I6a32086c33670e1b033f8b10e6bf1fd4da1d105d
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/modules')
691 files changed, 20251 insertions, 7577 deletions
diff --git a/chromium/third_party/blink/renderer/modules/BUILD.gn b/chromium/third_party/blink/renderer/modules/BUILD.gn index 6f94a382cec..7af1d24e4be 100644 --- a/chromium/third_party/blink/renderer/modules/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/BUILD.gn @@ -83,6 +83,7 @@ target("jumbo_" + modules_target_type, "modules") { deps = [ ":make_modules_generated", ":module_names", + "//net:net", "//third_party/blink/renderer/bindings/modules:generated", "//third_party/blink/renderer/bindings/modules/v8:bindings_modules_impl", "//third_party/blink/renderer/bindings/modules/v8:bindings_modules_origin_trial_features", @@ -93,6 +94,7 @@ target("jumbo_" + modules_target_type, "modules") { "//third_party/blink/renderer/modules/audio_output_devices", "//third_party/blink/renderer/modules/background_fetch", "//third_party/blink/renderer/modules/background_sync", + "//third_party/blink/renderer/modules/badging", "//third_party/blink/renderer/modules/battery", "//third_party/blink/renderer/modules/beacon", "//third_party/blink/renderer/modules/bluetooth", @@ -143,6 +145,7 @@ target("jumbo_" + modules_target_type, "modules") { "//third_party/blink/renderer/modules/remoteplayback", "//third_party/blink/renderer/modules/screen_orientation", "//third_party/blink/renderer/modules/sensor", + "//third_party/blink/renderer/modules/serial", "//third_party/blink/renderer/modules/service_worker", "//third_party/blink/renderer/modules/shapedetection", "//third_party/blink/renderer/modules/speech", @@ -163,6 +166,7 @@ target("jumbo_" + modules_target_type, "modules") { "//third_party/blink/renderer/modules/xr", "//third_party/icu", "//third_party/webrtc/pc:libjingle_peerconnection", + "//third_party/webrtc/rtc_base:rtc_base", "//third_party/webrtc_overrides:init_webrtc", "//third_party/zlib", ] @@ -187,6 +191,11 @@ jumbo_source_set("modules_testing") { "navigatorcontentutils/testing/internals_navigator_content_utils.h", "navigatorcontentutils/testing/navigator_content_utils_client_mock.cc", "navigatorcontentutils/testing/navigator_content_utils_client_mock.h", + "peerconnection/adapters/test/mock_ice_transport_adapter.h", + "peerconnection/adapters/test/mock_ice_transport_adapter_cross_thread_factory.h", + "peerconnection/adapters/test/mock_p2p_quic_packet_transport.h", + "peerconnection/adapters/test/mock_p2p_quic_transport.h", + "peerconnection/adapters/test/mock_p2p_quic_transport_factory.h", "peerconnection/testing/internals_rtc_certificate.cc", "peerconnection/testing/internals_rtc_certificate.h", "peerconnection/testing/internals_rtc_peer_connection.cc", @@ -256,6 +265,7 @@ jumbo_source_set("unit_tests") { "document_metadata/copyless_paste_extractor_test.cc", "eventsource/event_source_parser_test.cc", "filesystem/dom_file_system_base_test.cc", + "filesystem/file_writer_test.cc", "indexeddb/idb_key_path_test.cc", "indexeddb/idb_request_test.cc", "indexeddb/idb_test_helper.cc", @@ -264,10 +274,10 @@ jumbo_source_set("unit_tests") { "indexeddb/mock_web_idb_database.cc", "indexeddb/mock_web_idb_database.h", "manifest/image_resource_type_converters_test.cc", + "media_controls/elements/media_control_animated_arrow_container_element_test.cc", "media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc", "media_controls/elements/media_control_input_element_test.cc", "media_controls/elements/media_control_loading_panel_element_test.cc", - "media_controls/elements/media_control_overlay_play_button_element_test.cc", "media_controls/elements/media_control_panel_element_test.cc", "media_controls/elements/media_control_scrubbing_message_element_test.cc", "media_controls/elements/media_control_timeline_element_test.cc", @@ -294,8 +304,13 @@ jumbo_source_set("unit_tests") { "payments/payment_test_helper.cc", "payments/payment_test_helper.h", "payments/payments_validators_test.cc", + "peerconnection/adapters/p2p_quic_transport_test.cc", "peerconnection/rtc_data_channel_test.cc", + "peerconnection/rtc_ice_transport_test.cc", + "peerconnection/rtc_ice_transport_test.h", "peerconnection/rtc_peer_connection_test.cc", + "peerconnection/rtc_quic_transport_test.cc", + "peerconnection/rtc_quic_transport_test.h", "picture_in_picture/html_video_element_picture_in_picture_test.cc", "presentation/mock_presentation_service.h", "presentation/presentation_availability_state_test.cc", @@ -308,6 +323,8 @@ jumbo_source_set("unit_tests") { "remoteplayback/remote_playback_test.cc", "screen_orientation/screen_orientation_controller_impl_test.cc", "service_worker/service_worker_container_test.cc", + "service_worker/service_worker_installed_scripts_manager_test.cc", + "service_worker/thread_safe_script_container_test.cc", "service_worker/web_embedded_worker_impl_test.cc", "wake_lock/screen_wake_lock_test.cc", "webaudio/audio_basic_processor_handler_test.cc", @@ -333,7 +350,9 @@ jumbo_source_set("unit_tests") { deps = [ ":modules", ":modules_testing", + "//net:quic_test_tools", "//services/device/public/cpp/test:test_support", + "//services/viz/public/interfaces:interfaces_blink", "//skia", "//testing/gmock", "//testing/gtest", @@ -342,6 +361,7 @@ jumbo_source_set("unit_tests") { "//third_party/blink/renderer/modules/storage:unit_tests", "//third_party/blink/renderer/platform", "//third_party/blink/renderer/platform/wtf", + "//third_party/webrtc/rtc_base:rtc_base", "//v8", ] } diff --git a/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn b/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn index 3aadcb08e2c..c4478a9d087 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/accessibility/BUILD.gn @@ -62,6 +62,10 @@ blink_modules_sources("accessibility") { "inspector_type_builder_helper.h", ] + deps = [ + "//ui/accessibility:ax_enums_mojo_blink", + ] + # The modules/accessibility/ depends closely on core/ -- # include the core pch for faster Windows compilation times. configs += [ "//third_party/blink/renderer/core:blink_core_pch" ] diff --git a/chromium/third_party/blink/renderer/modules/accessibility/DEPS b/chromium/third_party/blink/renderer/modules/accessibility/DEPS index ec3df5f6ed4..44011c4a0c6 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/DEPS +++ b/chromium/third_party/blink/renderer/modules/accessibility/DEPS @@ -1,5 +1,6 @@ include_rules = [ "+mojo/public/cpp/bindings/binding.h", + "+ui/accessibility/ax_enums.mojom-blink.h", "-third_party/blink/renderer/modules", "+third_party/blink/renderer/modules/accessibility", "+third_party/blink/renderer/modules/media_controls", diff --git a/chromium/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc index cac291e66d8..b5cbf790b05 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/accessibility_object_model_test.cc @@ -55,13 +55,13 @@ TEST_F(AccessibilityObjectModelTest, SetAccessibleNodeRole) { ASSERT_NE(nullptr, button); auto* axButton = cache->GetOrCreate(button); - EXPECT_EQ(kButtonRole, axButton->RoleValue()); + EXPECT_EQ(ax::mojom::Role::kButton, axButton->RoleValue()); button->accessibleNode()->setRole("slider"); EXPECT_EQ("slider", button->accessibleNode()->role()); axButton = cache->GetOrCreate(button); - EXPECT_EQ(kSliderRole, axButton->RoleValue()); + EXPECT_EQ(ax::mojom::Role::kSlider, axButton->RoleValue()); } TEST_F(AccessibilityObjectModelTest, AOMDoesNotReflectARIA) { @@ -81,8 +81,8 @@ TEST_F(AccessibilityObjectModelTest, AOMDoesNotReflectARIA) { auto* cache = AXObjectCache(); ASSERT_NE(nullptr, cache); auto* axTextBox = cache->GetOrCreate(textbox); - EXPECT_EQ(kTextFieldWithComboBoxRole, axTextBox->RoleValue()); - AXNameFrom name_from; + EXPECT_EQ(ax::mojom::Role::kTextFieldWithComboBox, axTextBox->RoleValue()); + ax::mojom::NameFrom name_from; AXObject::AXObjectVector name_objects; EXPECT_EQ("Combo", axTextBox->GetName(name_from, &name_objects)); EXPECT_EQ(axTextBox->Restriction(), kDisabled); @@ -112,8 +112,8 @@ TEST_F(AccessibilityObjectModelTest, AOMPropertiesCanBeCleared) { auto* cache = AXObjectCache(); ASSERT_NE(nullptr, cache); auto* axButton = cache->GetOrCreate(button); - EXPECT_EQ(kCheckBoxRole, axButton->RoleValue()); - AXNameFrom name_from; + EXPECT_EQ(ax::mojom::Role::kCheckBox, axButton->RoleValue()); + ax::mojom::NameFrom name_from; AXObject::AXObjectVector name_objects; EXPECT_EQ("Check", axButton->GetName(name_from, &name_objects)); EXPECT_EQ(axButton->Restriction(), kDisabled); @@ -125,7 +125,7 @@ TEST_F(AccessibilityObjectModelTest, AOMPropertiesCanBeCleared) { // Assert that the AX object was affected by AOM properties. axButton = cache->GetOrCreate(button); - EXPECT_EQ(kRadioButtonRole, axButton->RoleValue()); + EXPECT_EQ(ax::mojom::Role::kRadioButton, axButton->RoleValue()); EXPECT_EQ("Radio", axButton->GetName(name_from, &name_objects)); EXPECT_EQ(axButton->Restriction(), kNone); @@ -136,7 +136,7 @@ TEST_F(AccessibilityObjectModelTest, AOMPropertiesCanBeCleared) { // The AX Object should now revert to ARIA. axButton = cache->GetOrCreate(button); - EXPECT_EQ(kCheckBoxRole, axButton->RoleValue()); + EXPECT_EQ(ax::mojom::Role::kCheckBox, axButton->RoleValue()); EXPECT_EQ("Check", axButton->GetName(name_from, &name_objects)); EXPECT_EQ(axButton->Restriction(), kDisabled); } @@ -316,16 +316,16 @@ TEST_F(AccessibilityObjectModelTest, SparseAttributes) { ASSERT_EQ("Widget", sparse_attributes .string_attributes[AXStringAttribute::kAriaRoleDescription]); - ASSERT_EQ(kListBoxOptionRole, + ASSERT_EQ(ax::mojom::Role::kListBoxOption, sparse_attributes .object_attributes[AXObjectAttribute::kAriaActiveDescendant] ->RoleValue()); ASSERT_EQ( - kContentInfoRole, + ax::mojom::Role::kContentInfo, sparse_attributes.object_attributes[AXObjectAttribute::kAriaDetails] ->RoleValue()); ASSERT_EQ( - kArticleRole, + ax::mojom::Role::kArticle, sparse_attributes.object_attributes[AXObjectAttribute::kAriaErrorMessage] ->RoleValue()); @@ -347,14 +347,15 @@ TEST_F(AccessibilityObjectModelTest, SparseAttributes) { ASSERT_EQ("Object", sparse_attributes2 .string_attributes[AXStringAttribute::kAriaRoleDescription]); - ASSERT_EQ(kCellRole, + ASSERT_EQ(ax::mojom::Role::kCell, sparse_attributes2 .object_attributes[AXObjectAttribute::kAriaActiveDescendant] ->RoleValue()); - ASSERT_EQ(kFormRole, sparse_attributes2 - .object_attributes[AXObjectAttribute::kAriaDetails] - ->RoleValue()); - ASSERT_EQ(kBannerRole, + ASSERT_EQ( + ax::mojom::Role::kForm, + sparse_attributes2.object_attributes[AXObjectAttribute::kAriaDetails] + ->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kBanner, sparse_attributes2 .object_attributes[AXObjectAttribute::kAriaErrorMessage] ->RoleValue()); diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_enums.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_enums.cc index a674868b4d7..7b1d31b4173 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_enums.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_enums.cc @@ -12,201 +12,6 @@ namespace blink { -STATIC_ASSERT_ENUM(kWebAXRoleAbbr, kAbbrRole); -STATIC_ASSERT_ENUM(kWebAXRoleAlertDialog, kAlertDialogRole); -STATIC_ASSERT_ENUM(kWebAXRoleAlert, kAlertRole); -STATIC_ASSERT_ENUM(kWebAXRoleAnchor, kAnchorRole); -STATIC_ASSERT_ENUM(kWebAXRoleAnnotation, kAnnotationRole); -STATIC_ASSERT_ENUM(kWebAXRoleApplication, kApplicationRole); -STATIC_ASSERT_ENUM(kWebAXRoleArticle, kArticleRole); -STATIC_ASSERT_ENUM(kWebAXRoleAudio, kAudioRole); -STATIC_ASSERT_ENUM(kWebAXRoleBanner, kBannerRole); -STATIC_ASSERT_ENUM(kWebAXRoleBlockquote, kBlockquoteRole); -STATIC_ASSERT_ENUM(kWebAXRoleButton, kButtonRole); -STATIC_ASSERT_ENUM(kWebAXRoleCanvas, kCanvasRole); -STATIC_ASSERT_ENUM(kWebAXRoleCaption, kCaptionRole); -STATIC_ASSERT_ENUM(kWebAXRoleCell, kCellRole); -STATIC_ASSERT_ENUM(kWebAXRoleCheckBox, kCheckBoxRole); -STATIC_ASSERT_ENUM(kWebAXRoleColorWell, kColorWellRole); -STATIC_ASSERT_ENUM(kWebAXRoleColumnHeader, kColumnHeaderRole); -STATIC_ASSERT_ENUM(kWebAXRoleColumn, kColumnRole); -STATIC_ASSERT_ENUM(kWebAXRoleComboBoxGrouping, kComboBoxGroupingRole); -STATIC_ASSERT_ENUM(kWebAXRoleComboBoxMenuButton, kComboBoxMenuButtonRole); -STATIC_ASSERT_ENUM(kWebAXRoleComplementary, kComplementaryRole); -STATIC_ASSERT_ENUM(kWebAXRoleContentDeletion, kContentDeletionRole); -STATIC_ASSERT_ENUM(kWebAXRoleContentInsertion, kContentInsertionRole); -STATIC_ASSERT_ENUM(kWebAXRoleContentInfo, kContentInfoRole); -STATIC_ASSERT_ENUM(kWebAXRoleDate, kDateRole); -STATIC_ASSERT_ENUM(kWebAXRoleDateTime, kDateTimeRole); -STATIC_ASSERT_ENUM(kWebAXRoleDefinition, kDefinitionRole); -STATIC_ASSERT_ENUM(kWebAXRoleDescriptionListDetail, kDescriptionListDetailRole); -STATIC_ASSERT_ENUM(kWebAXRoleDescriptionList, kDescriptionListRole); -STATIC_ASSERT_ENUM(kWebAXRoleDescriptionListTerm, kDescriptionListTermRole); -STATIC_ASSERT_ENUM(kWebAXRoleDetails, kDetailsRole); -STATIC_ASSERT_ENUM(kWebAXRoleDialog, kDialogRole); -STATIC_ASSERT_ENUM(kWebAXRoleDirectory, kDirectoryRole); -STATIC_ASSERT_ENUM(kWebAXRoleDisclosureTriangle, kDisclosureTriangleRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocAbstract, kDocAbstractRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocAcknowledgments, kDocAcknowledgmentsRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocAfterword, kDocAfterwordRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocAppendix, kDocAppendixRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocBackLink, kDocBackLinkRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocBiblioEntry, kDocBiblioEntryRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocBibliography, kDocBibliographyRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocBiblioRef, kDocBiblioRefRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocChapter, kDocChapterRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocColophon, kDocColophonRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocConclusion, kDocConclusionRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocCover, kDocCoverRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocCredit, kDocCreditRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocCredits, kDocCreditsRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocDedication, kDocDedicationRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocEndnote, kDocEndnoteRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocEndnotes, kDocEndnotesRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocEpigraph, kDocEpigraphRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocEpilogue, kDocEpilogueRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocErrata, kDocErrataRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocExample, kDocExampleRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocFootnote, kDocFootnoteRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocForeword, kDocForewordRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocGlossary, kDocGlossaryRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocGlossRef, kDocGlossRefRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocIndex, kDocIndexRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocIntroduction, kDocIntroductionRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocNoteRef, kDocNoteRefRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocNotice, kDocNoticeRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocPageBreak, kDocPageBreakRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocPageList, kDocPageListRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocPart, kDocPartRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocPreface, kDocPrefaceRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocPrologue, kDocPrologueRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocPullquote, kDocPullquoteRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocQna, kDocQnaRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocSubtitle, kDocSubtitleRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocTip, kDocTipRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocToc, kDocTocRole); -STATIC_ASSERT_ENUM(kWebAXRoleDocument, kDocumentRole); -STATIC_ASSERT_ENUM(kWebAXRoleEmbeddedObject, kEmbeddedObjectRole); -STATIC_ASSERT_ENUM(kWebAXRoleFeed, kFeedRole); -STATIC_ASSERT_ENUM(kWebAXRoleFigcaption, kFigcaptionRole); -STATIC_ASSERT_ENUM(kWebAXRoleFigure, kFigureRole); -STATIC_ASSERT_ENUM(kWebAXRoleFooter, kFooterRole); -STATIC_ASSERT_ENUM(kWebAXRoleForm, kFormRole); -STATIC_ASSERT_ENUM(kWebAXRoleGenericContainer, kGenericContainerRole); -STATIC_ASSERT_ENUM(kWebAXRoleGraphicsDocument, kGraphicsDocumentRole); -STATIC_ASSERT_ENUM(kWebAXRoleGraphicsObject, kGraphicsObjectRole); -STATIC_ASSERT_ENUM(kWebAXRoleGraphicsSymbol, kGraphicsSymbolRole); -STATIC_ASSERT_ENUM(kWebAXRoleGrid, kGridRole); -STATIC_ASSERT_ENUM(kWebAXRoleGroup, kGroupRole); -STATIC_ASSERT_ENUM(kWebAXRoleHeading, kHeadingRole); -STATIC_ASSERT_ENUM(kWebAXRoleIframe, kIframeRole); -STATIC_ASSERT_ENUM(kWebAXRoleIframePresentational, kIframePresentationalRole); -STATIC_ASSERT_ENUM(kWebAXRoleIgnored, kIgnoredRole); -STATIC_ASSERT_ENUM(kWebAXRoleImageMap, kImageMapRole); -STATIC_ASSERT_ENUM(kWebAXRoleImage, kImageRole); -STATIC_ASSERT_ENUM(kWebAXRoleInlineTextBox, kInlineTextBoxRole); -STATIC_ASSERT_ENUM(kWebAXRoleInputTime, kInputTimeRole); -STATIC_ASSERT_ENUM(kWebAXRoleLabel, kLabelRole); -STATIC_ASSERT_ENUM(kWebAXRoleLayoutTable, kLayoutTableRole); -STATIC_ASSERT_ENUM(kWebAXRoleLayoutTableCell, kLayoutTableCellRole); -STATIC_ASSERT_ENUM(kWebAXRoleLayoutTableColumn, kLayoutTableColumnRole); -STATIC_ASSERT_ENUM(kWebAXRoleLayoutTableRow, kLayoutTableRowRole); -STATIC_ASSERT_ENUM(kWebAXRoleLegend, kLegendRole); -STATIC_ASSERT_ENUM(kWebAXRoleLineBreak, kLineBreakRole); -STATIC_ASSERT_ENUM(kWebAXRoleLink, kLinkRole); -STATIC_ASSERT_ENUM(kWebAXRoleListBoxOption, kListBoxOptionRole); -STATIC_ASSERT_ENUM(kWebAXRoleListBox, kListBoxRole); -STATIC_ASSERT_ENUM(kWebAXRoleListItem, kListItemRole); -STATIC_ASSERT_ENUM(kWebAXRoleListMarker, kListMarkerRole); -STATIC_ASSERT_ENUM(kWebAXRoleList, kListRole); -STATIC_ASSERT_ENUM(kWebAXRoleLog, kLogRole); -STATIC_ASSERT_ENUM(kWebAXRoleMain, kMainRole); -STATIC_ASSERT_ENUM(kWebAXRoleMark, kMarkRole); -STATIC_ASSERT_ENUM(kWebAXRoleMarquee, kMarqueeRole); -STATIC_ASSERT_ENUM(kWebAXRoleMath, kMathRole); -STATIC_ASSERT_ENUM(kWebAXRoleMenuBar, kMenuBarRole); -STATIC_ASSERT_ENUM(kWebAXRoleMenuButton, kMenuButtonRole); -STATIC_ASSERT_ENUM(kWebAXRoleMenuItem, kMenuItemRole); -STATIC_ASSERT_ENUM(kWebAXRoleMenuItemCheckBox, kMenuItemCheckBoxRole); -STATIC_ASSERT_ENUM(kWebAXRoleMenuItemRadio, kMenuItemRadioRole); -STATIC_ASSERT_ENUM(kWebAXRoleMenuListOption, kMenuListOptionRole); -STATIC_ASSERT_ENUM(kWebAXRoleMenuListPopup, kMenuListPopupRole); -STATIC_ASSERT_ENUM(kWebAXRoleMenu, kMenuRole); -STATIC_ASSERT_ENUM(kWebAXRoleMeter, kMeterRole); -STATIC_ASSERT_ENUM(kWebAXRoleNavigation, kNavigationRole); -STATIC_ASSERT_ENUM(kWebAXRoleNone, kNoneRole); -STATIC_ASSERT_ENUM(kWebAXRoleNote, kNoteRole); -STATIC_ASSERT_ENUM(kWebAXRoleParagraph, kParagraphRole); -STATIC_ASSERT_ENUM(kWebAXRolePopUpButton, kPopUpButtonRole); -STATIC_ASSERT_ENUM(kWebAXRolePre, kPreRole); -STATIC_ASSERT_ENUM(kWebAXRolePresentational, kPresentationalRole); -STATIC_ASSERT_ENUM(kWebAXRoleProgressIndicator, kProgressIndicatorRole); -STATIC_ASSERT_ENUM(kWebAXRoleRadioButton, kRadioButtonRole); -STATIC_ASSERT_ENUM(kWebAXRoleRadioGroup, kRadioGroupRole); -STATIC_ASSERT_ENUM(kWebAXRoleRegion, kRegionRole); -STATIC_ASSERT_ENUM(kWebAXRoleRowHeader, kRowHeaderRole); -STATIC_ASSERT_ENUM(kWebAXRoleRow, kRowRole); -STATIC_ASSERT_ENUM(kWebAXRoleRuby, kRubyRole); -STATIC_ASSERT_ENUM(kWebAXRoleSVGRoot, kSVGRootRole); -STATIC_ASSERT_ENUM(kWebAXRoleScrollBar, kScrollBarRole); -STATIC_ASSERT_ENUM(kWebAXRoleSearch, kSearchRole); -STATIC_ASSERT_ENUM(kWebAXRoleSearchBox, kSearchBoxRole); -STATIC_ASSERT_ENUM(kWebAXRoleSlider, kSliderRole); -STATIC_ASSERT_ENUM(kWebAXRoleSliderThumb, kSliderThumbRole); -STATIC_ASSERT_ENUM(kWebAXRoleSpinButton, kSpinButtonRole); -STATIC_ASSERT_ENUM(kWebAXRoleSplitter, kSplitterRole); -STATIC_ASSERT_ENUM(kWebAXRoleStaticText, kStaticTextRole); -STATIC_ASSERT_ENUM(kWebAXRoleStatus, kStatusRole); -STATIC_ASSERT_ENUM(kWebAXRoleSwitch, kSwitchRole); -STATIC_ASSERT_ENUM(kWebAXRoleTabList, kTabListRole); -STATIC_ASSERT_ENUM(kWebAXRoleTabPanel, kTabPanelRole); -STATIC_ASSERT_ENUM(kWebAXRoleTab, kTabRole); -STATIC_ASSERT_ENUM(kWebAXRoleTableHeaderContainer, kTableHeaderContainerRole); -STATIC_ASSERT_ENUM(kWebAXRoleTable, kTableRole); -STATIC_ASSERT_ENUM(kWebAXRoleTerm, kTermRole); -STATIC_ASSERT_ENUM(kWebAXRoleTextField, kTextFieldRole); -STATIC_ASSERT_ENUM(kWebAXRoleTextFieldWithComboBox, kTextFieldWithComboBoxRole); -STATIC_ASSERT_ENUM(kWebAXRoleTime, kTimeRole); -STATIC_ASSERT_ENUM(kWebAXRoleTimer, kTimerRole); -STATIC_ASSERT_ENUM(kWebAXRoleToggleButton, kToggleButtonRole); -STATIC_ASSERT_ENUM(kWebAXRoleToolbar, kToolbarRole); -STATIC_ASSERT_ENUM(kWebAXRoleTreeGrid, kTreeGridRole); -STATIC_ASSERT_ENUM(kWebAXRoleTreeItem, kTreeItemRole); -STATIC_ASSERT_ENUM(kWebAXRoleTree, kTreeRole); -STATIC_ASSERT_ENUM(kWebAXRoleUnknown, kUnknownRole); -STATIC_ASSERT_ENUM(kWebAXRoleUserInterfaceTooltip, kUserInterfaceTooltipRole); -STATIC_ASSERT_ENUM(kWebAXRoleVideo, kVideoRole); -STATIC_ASSERT_ENUM(kWebAXRoleWebArea, kWebAreaRole); - -STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kActivate, - AXDefaultActionVerb::kActivate); -STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kCheck, AXDefaultActionVerb::kCheck); -STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kClick, AXDefaultActionVerb::kClick); -STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kClickAncestor, - AXDefaultActionVerb::kClickAncestor); -STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kJump, AXDefaultActionVerb::kJump); -STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kOpen, AXDefaultActionVerb::kOpen); -STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kPress, AXDefaultActionVerb::kPress); -STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kSelect, - AXDefaultActionVerb::kSelect); -STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kUncheck, - AXDefaultActionVerb::kUncheck); - -STATIC_ASSERT_ENUM(kWebAXTextDirectionLR, kAccessibilityTextDirectionLTR); -STATIC_ASSERT_ENUM(kWebAXTextDirectionRL, kAccessibilityTextDirectionRTL); -STATIC_ASSERT_ENUM(kWebAXTextDirectionTB, kAccessibilityTextDirectionTTB); -STATIC_ASSERT_ENUM(kWebAXTextDirectionBT, kAccessibilityTextDirectionBTT); - -STATIC_ASSERT_ENUM(kWebAXTextPositionNone, kAXTextPositionNone); -STATIC_ASSERT_ENUM(kWebAXTextPositionSubscript, kAXTextPositionSubscript); -STATIC_ASSERT_ENUM(kWebAXTextPositionSuperscript, kAXTextPositionSuperscript); - -STATIC_ASSERT_ENUM(kWebAXSortDirectionUndefined, kSortDirectionUndefined); -STATIC_ASSERT_ENUM(kWebAXSortDirectionNone, kSortDirectionNone); -STATIC_ASSERT_ENUM(kWebAXSortDirectionAscending, kSortDirectionAscending); -STATIC_ASSERT_ENUM(kWebAXSortDirectionDescending, kSortDirectionDescending); -STATIC_ASSERT_ENUM(kWebAXSortDirectionOther, kSortDirectionOther); - STATIC_ASSERT_ENUM(kWebAXExpandedUndefined, kExpandedUndefined); STATIC_ASSERT_ENUM(kWebAXExpandedCollapsed, kExpandedCollapsed); STATIC_ASSERT_ENUM(kWebAXExpandedExpanded, kExpandedExpanded); @@ -218,54 +23,12 @@ STATIC_ASSERT_ENUM(kWebAXOrientationVertical, STATIC_ASSERT_ENUM(kWebAXOrientationHorizontal, kAccessibilityOrientationHorizontal); -STATIC_ASSERT_ENUM(kWebAXAriaCurrentStateUndefined, kAriaCurrentStateUndefined); -STATIC_ASSERT_ENUM(kWebAXAriaCurrentStateFalse, kAriaCurrentStateFalse); -STATIC_ASSERT_ENUM(kWebAXAriaCurrentStateTrue, kAriaCurrentStateTrue); -STATIC_ASSERT_ENUM(kWebAXAriaCurrentStatePage, kAriaCurrentStatePage); -STATIC_ASSERT_ENUM(kWebAXAriaCurrentStateStep, kAriaCurrentStateStep); -STATIC_ASSERT_ENUM(kWebAXAriaCurrentStateLocation, kAriaCurrentStateLocation); -STATIC_ASSERT_ENUM(kWebAXAriaCurrentStateDate, kAriaCurrentStateDate); -STATIC_ASSERT_ENUM(kWebAXAriaCurrentStateTime, kAriaCurrentStateTime); - -STATIC_ASSERT_ENUM(kWebAXHasPopupFalse, kAXHasPopupFalse); -STATIC_ASSERT_ENUM(kWebAXHasPopupTrue, kAXHasPopupTrue); -STATIC_ASSERT_ENUM(kWebAXHasPopupMenu, kAXHasPopupMenu); -STATIC_ASSERT_ENUM(kWebAXHasPopupListbox, kAXHasPopupListbox); -STATIC_ASSERT_ENUM(kWebAXHasPopupTree, kAXHasPopupTree); -STATIC_ASSERT_ENUM(kWebAXHasPopupGrid, kAXHasPopupGrid); -STATIC_ASSERT_ENUM(kWebAXHasPopupDialog, kAXHasPopupDialog); - -STATIC_ASSERT_ENUM(kWebAXInvalidStateUndefined, kInvalidStateUndefined); -STATIC_ASSERT_ENUM(kWebAXInvalidStateFalse, kInvalidStateFalse); -STATIC_ASSERT_ENUM(kWebAXInvalidStateTrue, kInvalidStateTrue); -STATIC_ASSERT_ENUM(kWebAXInvalidStateSpelling, kInvalidStateSpelling); -STATIC_ASSERT_ENUM(kWebAXInvalidStateGrammar, kInvalidStateGrammar); -STATIC_ASSERT_ENUM(kWebAXInvalidStateOther, kInvalidStateOther); - STATIC_ASSERT_ENUM(kWebAXTextStyleNone, kTextStyleNone); STATIC_ASSERT_ENUM(kWebAXTextStyleBold, kTextStyleBold); STATIC_ASSERT_ENUM(kWebAXTextStyleItalic, kTextStyleItalic); STATIC_ASSERT_ENUM(kWebAXTextStyleUnderline, kTextStyleUnderline); STATIC_ASSERT_ENUM(kWebAXTextStyleLineThrough, kTextStyleLineThrough); -STATIC_ASSERT_ENUM(kWebAXNameFromUninitialized, kAXNameFromUninitialized); -STATIC_ASSERT_ENUM(kWebAXNameFromAttribute, kAXNameFromAttribute); -STATIC_ASSERT_ENUM(kWebAXNameFromAttributeExplicitlyEmpty, - kAXNameFromAttributeExplicitlyEmpty); -STATIC_ASSERT_ENUM(kWebAXNameFromCaption, kAXNameFromCaption); -STATIC_ASSERT_ENUM(kWebAXNameFromContents, kAXNameFromContents); -STATIC_ASSERT_ENUM(kWebAXNameFromPlaceholder, kAXNameFromPlaceholder); -STATIC_ASSERT_ENUM(kWebAXNameFromRelatedElement, kAXNameFromRelatedElement); -STATIC_ASSERT_ENUM(kWebAXNameFromValue, kAXNameFromValue); -STATIC_ASSERT_ENUM(kWebAXNameFromTitle, kAXNameFromTitle); - -STATIC_ASSERT_ENUM(kWebAXDescriptionFromUninitialized, - kAXDescriptionFromUninitialized); -STATIC_ASSERT_ENUM(kWebAXDescriptionFromAttribute, kAXDescriptionFromAttribute); -STATIC_ASSERT_ENUM(kWebAXDescriptionFromContents, kAXDescriptionFromContents); -STATIC_ASSERT_ENUM(kWebAXDescriptionFromRelatedElement, - kAXDescriptionFromRelatedElement); - STATIC_ASSERT_ENUM(WebAXStringAttribute::kAriaKeyShortcuts, AXStringAttribute::kAriaKeyShortcuts); STATIC_ASSERT_ENUM(WebAXStringAttribute::kAriaRoleDescription, diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_enums.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_enums.h index 9bee8cacfae..1619d789722 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_enums.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_enums.h @@ -9,210 +9,12 @@ namespace blink { -enum AccessibilityRole { - kUnknownRole = 0, // Not mapped in platform APIs, generally indicates a bug - kAbbrRole, // No mapping to ARIA role. - kAlertDialogRole, - kAlertRole, - kAnchorRole, // No mapping to ARIA role. - kAnnotationRole, // No mapping to ARIA role. - kApplicationRole, - kArticleRole, - kAudioRole, // No mapping to ARIA role. - kBannerRole, - kBlockquoteRole, // No mapping to ARIA role. - kButtonRole, - kCanvasRole, // No mapping to ARIA role. - kCaptionRole, // No mapping to ARIA role. - kCellRole, - kCheckBoxRole, - kColorWellRole, // No mapping to ARIA role. - kColumnHeaderRole, - kColumnRole, // No mapping to ARIA role. - kComboBoxGroupingRole, - kComboBoxMenuButtonRole, - kComplementaryRole, - kContentDeletionRole, // ARIA role mapping expected in ARIA v1.2. - kContentInsertionRole, // ARIA role mapping expected in ARIA v1.2. - kContentInfoRole, - kDateRole, // No mapping to ARIA role. - kDateTimeRole, // No mapping to ARIA role. - kDefinitionRole, - kDescriptionListDetailRole, // No mapping to ARIA role. - kDescriptionListRole, // No mapping to ARIA role. - kDescriptionListTermRole, // No mapping to ARIA role. - kDetailsRole, // No mapping to ARIA role. - kDialogRole, - kDirectoryRole, - kDisclosureTriangleRole, // No mapping to ARIA role. - kDocAbstractRole, - kDocAcknowledgmentsRole, - kDocAfterwordRole, - kDocAppendixRole, - // -------------------------------------------------------------- - // DPub Roles: - // https://www.w3.org/TR/dpub-aam-1.0/#mapping_role_table - kDocBackLinkRole, - kDocBiblioEntryRole, - kDocBibliographyRole, - kDocBiblioRefRole, - kDocChapterRole, - kDocColophonRole, - kDocConclusionRole, - kDocCoverRole, - kDocCreditRole, - kDocCreditsRole, - kDocDedicationRole, - kDocEndnoteRole, - kDocEndnotesRole, - kDocEpigraphRole, - kDocEpilogueRole, - kDocErrataRole, - kDocExampleRole, - kDocFootnoteRole, - kDocForewordRole, - kDocGlossaryRole, - kDocGlossRefRole, - kDocIndexRole, - kDocIntroductionRole, - kDocNoteRefRole, - kDocNoticeRole, - kDocPageBreakRole, - kDocPageListRole, - kDocPartRole, - kDocPrefaceRole, - kDocPrologueRole, - kDocPullquoteRole, - kDocQnaRole, - kDocSubtitleRole, - kDocTipRole, - kDocTocRole, - // End DPub roles. - // -------------------------------------------------------------- - kDocumentRole, - kEmbeddedObjectRole, // No mapping to ARIA role. - kFeedRole, - kFigcaptionRole, // No mapping to ARIA role. - kFigureRole, - kFooterRole, - kFormRole, - kGenericContainerRole, // No role was defined for this container - // -------------------------------------------------------------- - // ARIA Graphics module roles: - // https://rawgit.com/w3c/graphics-aam/master/#mapping_role_table - kGraphicsDocumentRole, - kGraphicsObjectRole, - kGraphicsSymbolRole, - // End ARIA Graphics module roles. - // -------------------------------------------------------------- - kGridRole, - kGroupRole, - kHeadingRole, - kIframePresentationalRole, // No mapping to ARIA role. - kIframeRole, // No mapping to ARIA role. - kIgnoredRole, // No mapping to ARIA role. - kImageMapRole, // No mapping to ARIA role. - kImageRole, - kInlineTextBoxRole, // No mapping to ARIA role. - kInputTimeRole, // No mapping to ARIA role. - kLabelRole, - kLayoutTableRole, - kLayoutTableCellRole, - kLayoutTableColumnRole, - kLayoutTableRowRole, - kLegendRole, // No mapping to ARIA role. - kLineBreakRole, // No mapping to ARIA role. - kLinkRole, - kListBoxOptionRole, - kListBoxRole, - kListItemRole, - kListMarkerRole, // No mapping to ARIA role. - kListRole, - kLogRole, - kMainRole, - kMarkRole, // No mapping to ARIA role. - kMarqueeRole, - kMathRole, - kMenuBarRole, - kMenuButtonRole, - kMenuItemRole, - kMenuItemCheckBoxRole, - kMenuItemRadioRole, - kMenuListOptionRole, - kMenuListPopupRole, - kMenuRole, - kMeterRole, - kNavigationRole, - kNoneRole, // ARIA role of "none" - kNoteRole, - kParagraphRole, // No mapping to ARIA role. - kPopUpButtonRole, - kPreRole, // No mapping to ARIA role. - kPresentationalRole, - kProgressIndicatorRole, - kRadioButtonRole, - kRadioGroupRole, - kRegionRole, - kRowHeaderRole, - kRowRole, - kRubyRole, // No mapping to ARIA role. - kSVGRootRole, // No mapping to ARIA role. - kScrollBarRole, - kSearchRole, - kSearchBoxRole, - kSliderRole, - kSliderThumbRole, // No mapping to ARIA role. - kSpinButtonRole, - kSplitterRole, - kStaticTextRole, // No mapping to ARIA role. - kStatusRole, - kSwitchRole, - kTabListRole, - kTabPanelRole, - kTabRole, - kTableHeaderContainerRole, // No mapping to ARIA role. - kTableRole, - kTermRole, - kTextFieldRole, - kTextFieldWithComboBoxRole, - kTimeRole, // No mapping to ARIA role. - kTimerRole, - kToggleButtonRole, - kToolbarRole, - kTreeGridRole, - kTreeItemRole, - kTreeRole, - kUserInterfaceTooltipRole, - kVideoRole, // No mapping to ARIA role. - kWebAreaRole, // No mapping to ARIA role. - kNumRoles -}; - enum AccessibilityOrientation { kAccessibilityOrientationUndefined = 0, kAccessibilityOrientationVertical, kAccessibilityOrientationHorizontal, }; -enum class AXDefaultActionVerb { - kNone = 0, - kActivate, - kCheck, - kClick, - - // A click will be performed on one of the object's ancestors. - // This happens when the object itself is not clickable, but one of its - // ancestors has click handlers attached which are able to capture the click - // as it bubbles up. - kClickAncestor, - - kJump, - kOpen, - kPress, - kSelect, - kUncheck -}; - // The input restriction on an object. enum AXRestriction { kNone = 0, // An object that is not disabled. @@ -220,39 +22,6 @@ enum AXRestriction { kDisabled, }; -enum class AXSupportedAction { - kNone = 0, - kActivate, - kCheck, - kClick, - kJump, - kOpen, - kPress, - kSelect, - kUncheck -}; - -enum AccessibilityTextDirection { - kAccessibilityTextDirectionLTR, - kAccessibilityTextDirectionRTL, - kAccessibilityTextDirectionTTB, - kAccessibilityTextDirectionBTT -}; - -enum AXTextPosition { - kAXTextPositionNone = 0, - kAXTextPositionSubscript, - kAXTextPositionSuperscript -}; - -enum SortDirection { - kSortDirectionUndefined = 0, - kSortDirectionNone, - kSortDirectionAscending, - kSortDirectionDescending, - kSortDirectionOther -}; - enum AccessibilityExpanded { kExpandedUndefined = 0, kExpandedCollapsed, @@ -265,36 +34,6 @@ enum AccessibilitySelectedState { kSelectedStateTrue, }; -enum AriaCurrentState { - kAriaCurrentStateUndefined = 0, - kAriaCurrentStateFalse, - kAriaCurrentStateTrue, - kAriaCurrentStatePage, - kAriaCurrentStateStep, - kAriaCurrentStateLocation, - kAriaCurrentStateDate, - kAriaCurrentStateTime -}; - -enum AXHasPopup { - kAXHasPopupFalse = 0, - kAXHasPopupTrue, - kAXHasPopupMenu, - kAXHasPopupListbox, - kAXHasPopupTree, - kAXHasPopupGrid, - kAXHasPopupDialog -}; - -enum InvalidState { - kInvalidStateUndefined = 0, - kInvalidStateFalse, - kInvalidStateTrue, - kInvalidStateSpelling, - kInvalidStateGrammar, - kInvalidStateOther -}; - enum TextStyle { kTextStyleNone = 0, kTextStyleBold = 1 << 0, @@ -323,44 +62,12 @@ enum class AXObjectVectorAttribute { kAriaFlowTo, }; -// The source of the accessible name of an element. This is needed -// because on some platforms this determines how the accessible name -// is exposed. -enum AXNameFrom { - kAXNameFromUninitialized = -1, - kAXNameFromAttribute = 0, - kAXNameFromAttributeExplicitlyEmpty, - kAXNameFromCaption, - kAXNameFromContents, - kAXNameFromPlaceholder, - kAXNameFromRelatedElement, - kAXNameFromValue, - kAXNameFromTitle, -}; - -// The source of the accessible description of an element. This is needed -// because on some platforms this determines how the accessible description -// is exposed. -enum AXDescriptionFrom { - kAXDescriptionFromUninitialized = -1, - kAXDescriptionFromAttribute = 0, - kAXDescriptionFromContents, - kAXDescriptionFromRelatedElement, -}; - enum AXObjectInclusion { kIncludeObject, kIgnoreObject, kDefaultBehavior, }; -enum AccessibilityCheckedState { - kCheckedStateUndefined = 0, - kCheckedStateFalse, - kCheckedStateTrue, - kCheckedStateMixed -}; - enum AccessibilityOptionalBool { kOptionalBoolUndefined = 0, kOptionalBoolTrue, @@ -395,7 +102,7 @@ enum AXIgnoredReason { kAXLabelFor, kAXNotRendered, kAXNotVisible, - kAXPresentationalRole, + kAXPresentational, kAXProbablyPresentational, kAXStaticTextUsedAsNameFor, kAXUninteresting diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc index a3025d4e553..3a1dde79006 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc @@ -68,13 +68,13 @@ AXObject* AXImageMapLink::ComputeParent() const { return AXObjectCache().GetOrCreate(MapElement()->GetLayoutObject()); } -AccessibilityRole AXImageMapLink::RoleValue() const { +ax::mojom::Role AXImageMapLink::RoleValue() const { const AtomicString& aria_role = GetAOMPropertyOrARIAAttribute(AOMStringProperty::kRole); if (!aria_role.IsEmpty()) return AXObject::AriaRoleToWebCoreRole(aria_role); - return kLinkRole; + return ax::mojom::Role::kLink; } bool AXImageMapLink::ComputeAccessibilityIsIgnored( diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.h index 75084f36967..0f6fe6d99b6 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_image_map_link.h @@ -51,7 +51,7 @@ class AXImageMapLink final : public AXNodeObject { HTMLMapElement* MapElement() const; - AccessibilityRole RoleValue() const override; + ax::mojom::Role RoleValue() const override; bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override; Element* AnchorElement() const override; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc index 2a3837fb577..cc2f3aaa45f 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc @@ -128,12 +128,12 @@ void AXInlineTextBox::GetWordBoundaries(Vector<AXRange>& words) const { } } -String AXInlineTextBox::GetName(AXNameFrom& name_from, +String AXInlineTextBox::GetName(ax::mojom::NameFrom& name_from, AXObject::AXObjectVector* name_objects) const { if (!inline_text_box_) return String(); - name_from = kAXNameFromContents; + name_from = ax::mojom::NameFrom::kContents; return inline_text_box_->GetText(); } @@ -149,19 +149,19 @@ AXObject* AXInlineTextBox::ComputeParent() const { // In addition to LTR and RTL direction, edit fields also support // top to bottom and bottom to top via the CSS writing-mode property. -AccessibilityTextDirection AXInlineTextBox::GetTextDirection() const { +ax::mojom::TextDirection AXInlineTextBox::GetTextDirection() const { if (!inline_text_box_) return AXObject::GetTextDirection(); switch (inline_text_box_->GetDirection()) { case AbstractInlineTextBox::kLeftToRight: - return kAccessibilityTextDirectionLTR; + return ax::mojom::TextDirection::kLtr; case AbstractInlineTextBox::kRightToLeft: - return kAccessibilityTextDirectionRTL; + return ax::mojom::TextDirection::kRtl; case AbstractInlineTextBox::kTopToBottom: - return kAccessibilityTextDirectionTTB; + return ax::mojom::TextDirection::kTtb; case AbstractInlineTextBox::kBottomToTop: - return kAccessibilityTextDirectionBTT; + return ax::mojom::TextDirection::kBtt; } return AXObject::GetTextDirection(); diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h index 7e39dc6ffb9..8d0dfdb5c68 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h @@ -53,8 +53,10 @@ class AXInlineTextBox final : public AXObject { bool IsAXInlineTextBox() const override { return true; } public: - AccessibilityRole RoleValue() const override { return kInlineTextBoxRole; } - String GetName(AXNameFrom&, + ax::mojom::Role RoleValue() const override { + return ax::mojom::Role::kInlineTextBox; + } + String GetName(ax::mojom::NameFrom&, AXObject::AXObjectVector* name_objects) const override; void TextCharacterOffsets(Vector<int>&) const override; void GetWordBoundaries(Vector<AXRange>&) const override; @@ -63,7 +65,7 @@ class AXInlineTextBox final : public AXObject { SkMatrix44& out_container_transform, bool* clips_children = nullptr) const override; AXObject* ComputeParent() const override; - AccessibilityTextDirection GetTextDirection() const override; + ax::mojom::TextDirection GetTextDirection() const override; Node* GetNode() const override; AXObject* NextOnLine() const override; AXObject* PreviousOnLine() const override; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc index 83d3bc2792d..c61588ea1d9 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc @@ -284,70 +284,74 @@ static bool IsImageOrAltText(LayoutBoxModelObject* box, Node* node) { return false; } -AccessibilityRole AXLayoutObject::NativeAccessibilityRoleIgnoringAria() const { +ax::mojom::Role AXLayoutObject::NativeRoleIgnoringAria() const { Node* node = layout_object_->GetNode(); LayoutBoxModelObject* css_box = GetLayoutBoxModelObject(); if ((css_box && css_box->IsListItem()) || IsHTMLLIElement(node)) - return kListItemRole; + return ax::mojom::Role::kListItem; if (layout_object_->IsListMarkerIncludingNG()) - return kListMarkerRole; + return ax::mojom::Role::kListMarker; if (layout_object_->IsBR()) - return kLineBreakRole; + return ax::mojom::Role::kLineBreak; if (layout_object_->IsText()) - return kStaticTextRole; - if (layout_object_->IsTable() && node) - return IsDataTable() ? kTableRole : kLayoutTableRole; + return ax::mojom::Role::kStaticText; + if (layout_object_->IsTable() && node) { + return IsDataTable() ? ax::mojom::Role::kTable + : ax::mojom::Role::kLayoutTable; + } if (layout_object_->IsTableRow() && node) return DetermineTableRowRole(); if (layout_object_->IsTableCell() && node) return DetermineTableCellRole(); if (css_box && IsImageOrAltText(css_box, node)) { if (node && node->IsLink()) - return kImageMapRole; + return ax::mojom::Role::kImageMap; if (IsHTMLInputElement(node)) return ButtonRoleType(); if (IsSVGImage()) - return kSVGRootRole; + return ax::mojom::Role::kSvgRoot; - return kImageRole; + return ax::mojom::Role::kImage; } if (IsHTMLCanvasElement(node)) - return kCanvasRole; + return ax::mojom::Role::kCanvas; if (css_box && css_box->IsLayoutView()) - return kWebAreaRole; + return ax::mojom::Role::kRootWebArea; if (layout_object_->IsSVGImage()) - return kImageRole; + return ax::mojom::Role::kImage; if (layout_object_->IsSVGRoot()) - return kSVGRootRole; + return ax::mojom::Role::kSvgRoot; // Table sections should be ignored. if (layout_object_->IsTableSection()) - return kIgnoredRole; + return ax::mojom::Role::kIgnored; if (layout_object_->IsHR()) - return kSplitterRole; + return ax::mojom::Role::kSplitter; - return AXNodeObject::NativeAccessibilityRoleIgnoringAria(); + return AXNodeObject::NativeRoleIgnoringAria(); } -AccessibilityRole AXLayoutObject::DetermineAccessibilityRole() { +ax::mojom::Role AXLayoutObject::DetermineAccessibilityRole() { if (!layout_object_) - return kUnknownRole; + return ax::mojom::Role::kUnknown; - native_role_ = NativeAccessibilityRoleIgnoringAria(); + native_role_ = NativeRoleIgnoringAria(); - if ((aria_role_ = DetermineAriaRoleAttribute()) != kUnknownRole) + if ((aria_role_ = DetermineAriaRoleAttribute()) != ax::mojom::Role::kUnknown) return aria_role_; // Anything that needs to still be exposed but doesn't have a more specific // role should be considered a generic container. Examples are // layout blocks with no node, in-page link targets, and plain elements // such as a <span> with ARIA markup. - return native_role_ == kUnknownRole ? kGenericContainerRole : native_role_; + return native_role_ == ax::mojom::Role::kUnknown + ? ax::mojom::Role::kGenericContainer + : native_role_; } Node* AXLayoutObject::GetNodeOrContainingBlockNode() const { @@ -396,13 +400,28 @@ bool AXLayoutObject::IsEditable() const { if (IsDetached()) return false; - if (GetLayoutObject()->IsTextControl()) - return true; - const Node* node = GetNodeOrContainingBlockNode(); if (!node) return false; + // TODO(accessibility) pursue standards track so that aria-goog-editable + // becomes aria-editable. At that time, create ariaEditableAttr in + // html_element.cc. The current version of the editable attribute does not + // inherit, in order to match the automatic Gecko implementation, but + // hopefully the standardized version will, in which case a more performant + // implementation will be required, e.g. cache it or only expose on ancestor, + // having browser-side propagate it. + const Element* elem = node->IsElementNode() + ? ToElement(node) + : FlatTreeTraversal::ParentElement(*node); + if (elem && elem->hasAttribute("aria-goog-editable")) { + auto editable = elem->getAttribute("aria-goog-editable"); + return !EqualIgnoringASCIICase("false", editable); + } + + if (GetLayoutObject()->IsTextControl()) + return true; + if (HasEditableStyle(*node)) return true; @@ -430,6 +449,21 @@ bool AXLayoutObject::IsRichlyEditable() const { if (!node) return false; + // TODO(accessibility) pursue standards track so that aria-goog-editable + // becomes aria-editable. At that time, create ariaEditableAttr in + // html_element.cc. The current version of the editable attribute does not + // inherit, in order to match the automatic Gecko implementation, but + // hopefully the standardized version will, in which case a more performant + // implementation will be required, e.g. cache it or only expose on ancestor, + // having browser-side propagate it. + const Element* elem = node->IsElementNode() + ? ToElement(node) + : FlatTreeTraversal::ParentElement(*node); + if (elem && elem->hasAttribute("aria-goog-editable")) { + auto editable = elem->getAttribute("aria-goog-editable"); + return !EqualIgnoringASCIICase("false", editable); + } + if (HasRichlyEditableStyle(*node)) return true; @@ -463,7 +497,7 @@ bool AXLayoutObject::IsLoaded() const { bool AXLayoutObject::IsOffScreen() const { DCHECK(layout_object_); IntRect content_rect = - PixelSnappedIntRect(layout_object_->AbsoluteVisualRect()); + PixelSnappedIntRect(layout_object_->VisualRectInDocument()); LocalFrameView* view = layout_object_->GetFrame()->View(); IntRect view_rect(IntPoint(), view->Size()); view_rect.Intersect(content_rect); @@ -496,7 +530,7 @@ bool AXLayoutObject::IsFocused() const { // A web area is represented by the Document node in the DOM tree, which isn't // focusable. Check instead if the frame's selection controller is focused if (focused_object == this || - (RoleValue() == kWebAreaRole && + (RoleValue() == ax::mojom::Role::kRootWebArea && GetDocument()->GetFrame()->Selection().FrameIsFocusedAndActive())) return true; @@ -595,6 +629,30 @@ static bool HasLineBox(const LayoutBlockFlow& block_flow) { return false; } +// Is this the anonymous placeholder for a text control? +bool AXLayoutObject::IsPlaceholder() const { + AXObject* parent_object = ParentObject(); + if (!parent_object) + return false; + + LayoutObject* parent_layout_object = parent_object->GetLayoutObject(); + if (!parent_layout_object || !parent_layout_object->IsTextControl()) + return false; + + LayoutTextControl* layout_text_control = + ToLayoutTextControl(parent_layout_object); + DCHECK(layout_text_control); + + TextControlElement* text_control_element = + layout_text_control->GetTextControlElement(); + if (!text_control_element) + return false; + + HTMLElement* placeholder_element = text_control_element->PlaceholderElement(); + + return GetElement() == static_cast<Element*>(placeholder_element); +} + bool AXLayoutObject::ComputeAccessibilityIsIgnored( IgnoredReasons* ignored_reasons) const { #if DCHECK_IS_ON() @@ -625,7 +683,7 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored( return true; } - if (RoleValue() == kIgnoredRole) { + if (RoleValue() == ax::mojom::Role::kIgnored) { if (ignored_reasons) ignored_reasons->push_back(IgnoredReason(kAXUninteresting)); return true; @@ -635,7 +693,7 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored( if (ignored_reasons) { const AXObject* inherits_from = InheritsPresentationalRoleFrom(); if (inherits_from == this) - ignored_reasons->push_back(IgnoredReason(kAXPresentationalRole)); + ignored_reasons->push_back(IgnoredReason(kAXPresentational)); else ignored_reasons->push_back( IgnoredReason(kAXInheritsPresentation, inherits_from)); @@ -653,8 +711,18 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored( // Make sure renderers with layers stay in the tree. if (GetLayoutObject() && GetLayoutObject()->HasLayer() && GetNode() && - GetNode()->hasChildren()) + GetNode()->hasChildren()) { + if (IsPlaceholder()) { + // Placeholder is already exposed via AX attributes, do not expose as + // child of text input. Therefore, if there is a child of a text input, + // it will contain the value. + if (ignored_reasons) + ignored_reasons->push_back(IgnoredReason(kAXPresentational)); + return true; + } + return false; + } // Find out if this element is inside of a label element. If so, it may be // ignored because it's the label for a checkbox or radio button. @@ -688,8 +756,8 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored( // A click handler might be placed on an otherwise ignored non-empty block // element, e.g. a div. We shouldn't ignore such elements because if an AT - // sees the |AXDefaultActionVerb::kClickAncestor|, it will look for the - // clickable ancestor and it expects to find one. + // sees the |ax::mojom::DefaultActionVerb::kClickAncestor|, it will look for + // the clickable ancestor and it expects to find one. if (IsClickable()) return false; @@ -718,7 +786,7 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored( if (IsControl()) return false; - if (AriaRoleAttribute() != kUnknownRole) + if (AriaRoleAttribute() != ax::mojom::Role::kUnknown) return false; // don't ignore labels, because they serve as TitleUIElements @@ -733,58 +801,58 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored( if (HasContentEditableAttributeSet()) return false; - if (RoleValue() == kAbbrRole) + if (RoleValue() == ax::mojom::Role::kAbbr) return false; // List items play an important role in defining the structure of lists. They // should not be ignored. - if (RoleValue() == kListItemRole) + if (RoleValue() == ax::mojom::Role::kListItem) return false; - if (RoleValue() == kBlockquoteRole) + if (RoleValue() == ax::mojom::Role::kBlockquote) return false; - if (RoleValue() == kDialogRole) + if (RoleValue() == ax::mojom::Role::kDialog) return false; - if (RoleValue() == kFigcaptionRole) + if (RoleValue() == ax::mojom::Role::kFigcaption) return false; - if (RoleValue() == kFigureRole) + if (RoleValue() == ax::mojom::Role::kFigure) return false; - if (RoleValue() == kContentDeletionRole) + if (RoleValue() == ax::mojom::Role::kContentDeletion) return false; - if (RoleValue() == kContentInsertionRole) + if (RoleValue() == ax::mojom::Role::kContentInsertion) return false; - if (RoleValue() == kDetailsRole) + if (RoleValue() == ax::mojom::Role::kDetails) return false; - if (RoleValue() == kMarkRole) + if (RoleValue() == ax::mojom::Role::kMark) return false; - if (RoleValue() == kMathRole) + if (RoleValue() == ax::mojom::Role::kMath) return false; - if (RoleValue() == kMeterRole) + if (RoleValue() == ax::mojom::Role::kMeter) return false; - if (RoleValue() == kRubyRole) + if (RoleValue() == ax::mojom::Role::kRuby) return false; - if (RoleValue() == kSplitterRole) + if (RoleValue() == ax::mojom::Role::kSplitter) return false; - if (RoleValue() == kTimeRole) + if (RoleValue() == ax::mojom::Role::kTime) return false; - if (RoleValue() == kProgressIndicatorRole) + if (RoleValue() == ax::mojom::Role::kProgressIndicator) return false; // if this element has aria attributes on it, it should not be ignored. - if (SupportsARIAAttributes()) + if (HasGlobalARIAAttribute()) return false; if (IsImage()) @@ -837,6 +905,14 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored( if (layout_object_->IsPositioned()) return false; + // Inner editor element of editable area with empty text provides bounds + // used to compute the character extent for index 0. This is the same as + // what the caret's bounds would be if the editable area is focused. + if (ParentObject() && ParentObject()->GetLayoutObject() && + ParentObject()->GetLayoutObject()->IsTextControl()) { + return false; + } + // Ignore layout objects that are block flows with inline children. These // are usually dummy layout objects that pad out the tree, but there are // some exceptions below. @@ -868,9 +944,10 @@ bool AXLayoutObject::HasAriaCellRole(Element* elem) const { if (aria_role_str.IsEmpty()) return false; - AccessibilityRole aria_role = AriaRoleToWebCoreRole(aria_role_str); - return aria_role == kCellRole || aria_role == kColumnHeaderRole || - aria_role == kRowHeaderRole; + ax::mojom::Role aria_role = AriaRoleToWebCoreRole(aria_role_str); + return aria_role == ax::mojom::Role::kCell || + aria_role == ax::mojom::Role::kColumnHeader || + aria_role == ax::mojom::Role::kRowHeader; } // Return true if whitespace is not necessary to keep adjacent_node separate @@ -1118,7 +1195,8 @@ String AXLayoutObject::ImageDataUrl(const IntSize& max_size) const { SkImageInfo info = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType); size_t row_bytes = info.minRowBytes(); - Vector<char> pixel_storage(info.computeByteSize(row_bytes)); + Vector<char> pixel_storage( + SafeCast<wtf_size_t>(info.computeByteSize(row_bytes))); SkPixmap pixmap(info, pixel_storage.data(), row_bytes); if (!SkImage::MakeFromBitmap(bitmap)->readPixels(pixmap, 0, 0)) return String(); @@ -1171,7 +1249,7 @@ String AXLayoutObject::GetText() const { return AXNodeObject::GetText(); } -AccessibilityTextDirection AXLayoutObject::GetTextDirection() const { +ax::mojom::TextDirection AXLayoutObject::GetTextDirection() const { if (!GetLayoutObject()) return AXNodeObject::GetTextDirection(); @@ -1182,23 +1260,23 @@ AccessibilityTextDirection AXLayoutObject::GetTextDirection() const { if (style->IsHorizontalWritingMode()) { switch (style->Direction()) { case TextDirection::kLtr: - return kAccessibilityTextDirectionLTR; + return ax::mojom::TextDirection::kLtr; case TextDirection::kRtl: - return kAccessibilityTextDirectionRTL; + return ax::mojom::TextDirection::kRtl; } } else { switch (style->Direction()) { case TextDirection::kLtr: - return kAccessibilityTextDirectionTTB; + return ax::mojom::TextDirection::kTtb; case TextDirection::kRtl: - return kAccessibilityTextDirectionBTT; + return ax::mojom::TextDirection::kBtt; } } return AXNodeObject::GetTextDirection(); } -AXTextPosition AXLayoutObject::GetTextPosition() const { +ax::mojom::TextPosition AXLayoutObject::GetTextPosition() const { if (!GetLayoutObject()) return AXNodeObject::GetTextPosition(); @@ -1217,9 +1295,9 @@ AXTextPosition AXLayoutObject::GetTextPosition() const { case EVerticalAlign::kLength: return AXNodeObject::GetTextPosition(); case EVerticalAlign::kSub: - return kAXTextPositionSubscript; + return ax::mojom::TextPosition::kSubscript; case EVerticalAlign::kSuper: - return kAXTextPositionSuperscript; + return ax::mojom::TextPosition::kSuperscript; } } @@ -1505,7 +1583,7 @@ String AXLayoutObject::StringValue() const { String AXLayoutObject::TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom& name_from, + ax::mojom::NameFrom& name_from, AXRelatedObjectVector* related_objects, NameSources* name_sources) const { if (layout_object_) { @@ -1546,7 +1624,7 @@ String AXLayoutObject::TextAlternative(bool recursive, } if (found_text_alternative) { - name_from = kAXNameFromContents; + name_from = ax::mojom::NameFrom::kContents; if (name_sources) { name_sources->push_back(NameSource(false)); name_sources->back().type = name_from; @@ -1575,24 +1653,24 @@ void AXLayoutObject::AriaDescribedbyElements( describedby); } -AXHasPopup AXLayoutObject::HasPopup() const { +ax::mojom::HasPopup AXLayoutObject::HasPopup() const { const AtomicString& has_popup = GetAOMPropertyOrARIAAttribute(AOMStringProperty::kHasPopUp); if (!has_popup.IsNull()) { if (EqualIgnoringASCIICase(has_popup, "false")) - return kAXHasPopupFalse; + return ax::mojom::HasPopup::kFalse; if (EqualIgnoringASCIICase(has_popup, "listbox")) - return kAXHasPopupListbox; + return ax::mojom::HasPopup::kListbox; if (EqualIgnoringASCIICase(has_popup, "tree")) - return kAXHasPopupTree; + return ax::mojom::HasPopup::kTree; if (EqualIgnoringASCIICase(has_popup, "grid")) - return kAXHasPopupGrid; + return ax::mojom::HasPopup::kGrid; if (EqualIgnoringASCIICase(has_popup, "dialog")) - return kAXHasPopupDialog; + return ax::mojom::HasPopup::kDialog; // To provide backward compatibility with ARIA 1.0 content, // user agents MUST treat an aria-haspopup value of true @@ -1600,13 +1678,13 @@ AXHasPopup AXLayoutObject::HasPopup() const { // And unknown value also return menu too. if (EqualIgnoringASCIICase(has_popup, "true") || EqualIgnoringASCIICase(has_popup, "menu") || !has_popup.IsEmpty()) - return kAXHasPopupMenu; + return ax::mojom::HasPopup::kMenu; } // ARIA 1.1 default value of haspopup for combobox is "listbox". - if (RoleValue() == kComboBoxMenuButtonRole || - RoleValue() == kTextFieldWithComboBoxRole) - return kAXHasPopupListbox; + if (RoleValue() == ax::mojom::Role::kComboBoxMenuButton || + RoleValue() == ax::mojom::Role::kTextFieldWithComboBox) + return ax::mojom::HasPopup::kListbox; return AXObject::HasPopup(); } @@ -1654,13 +1732,13 @@ const AtomicString& AXLayoutObject::LiveRegionStatus() const { // These roles have implicit live region status. if (live_region_status.IsEmpty()) { switch (RoleValue()) { - case kAlertRole: + case ax::mojom::Role::kAlert: return live_region_status_assertive; - case kLogRole: - case kStatusRole: + case ax::mojom::Role::kLog: + case ax::mojom::Role::kStatus: return live_region_status_polite; - case kTimerRole: - case kMarqueeRole: + case ax::mojom::Role::kTimer: + case ax::mojom::Role::kMarquee: return live_region_status_off; default: break; @@ -1760,12 +1838,12 @@ AXObject* AXLayoutObject::ComputeParent() const { if (!layout_object_) return nullptr; - if (AriaRoleAttribute() == kMenuBarRole) + if (AriaRoleAttribute() == ax::mojom::Role::kMenuBar) return AXObjectCache().GetOrCreate(layout_object_->Parent()); // menuButton and its corresponding menu are DOM siblings, but Accessibility // needs them to be parent/child. - if (AriaRoleAttribute() == kMenuRole) { + if (AriaRoleAttribute() == ax::mojom::Role::kMenu) { AXObject* parent = MenuButtonForMenu(); if (parent) return parent; @@ -1788,12 +1866,12 @@ AXObject* AXLayoutObject::ComputeParentIfExists() const { if (!layout_object_) return nullptr; - if (AriaRoleAttribute() == kMenuBarRole) + if (AriaRoleAttribute() == ax::mojom::Role::kMenuBar) return AXObjectCache().Get(layout_object_->Parent()); // menuButton and its corresponding menu are DOM siblings, but Accessibility // needs them to be parent/child. - if (AriaRoleAttribute() == kMenuRole) { + if (AriaRoleAttribute() == ax::mojom::Role::kMenu) { AXObject* parent = MenuButtonForMenuIfExists(); if (parent) return parent; @@ -2414,7 +2492,7 @@ void AXLayoutObject::HandleActiveDescendantChanged() { return; AXObject* focused_object = AXObjectCache().FocusedObject(); - if (focused_object == this && SupportsARIAActiveDescendant()) { + if (focused_object == this) { AXObject* active_descendant = ActiveDescendant(); if (active_descendant && active_descendant->IsSelectedFromFocus()) { // In single selection containers, selection follows focus, so a selection @@ -2423,8 +2501,10 @@ void AXLayoutObject::HandleActiveDescendantChanged() { // the user navigates through the items. AXObjectCache().HandleAriaSelectedChanged(active_descendant->GetNode()); } - AXObjectCache().PostNotification( - GetLayoutObject(), AXObjectCacheImpl::kAXActiveDescendantChanged); + + // Mark this node dirty. AXEventGenerator will automatically infer + // that the active descendant changed. + AXObjectCache().MarkAXObjectDirty(this, false); } } @@ -2435,11 +2515,11 @@ void AXLayoutObject::HandleAriaExpandedChanged() { bool found_parent = false; switch (container_parent->RoleValue()) { - case kLayoutTableRole: - case kTreeRole: - case kTreeGridRole: - case kGridRole: - case kTableRole: + case ax::mojom::Role::kLayoutTable: + case ax::mojom::Role::kTree: + case ax::mojom::Role::kTreeGrid: + case ax::mojom::Role::kGrid: + case ax::mojom::Role::kTable: found_parent = true; break; default: @@ -2453,25 +2533,25 @@ void AXLayoutObject::HandleAriaExpandedChanged() { } // Post that the row count changed. - if (container_parent) + if (container_parent) { AXObjectCache().PostNotification(container_parent, - AXObjectCacheImpl::kAXRowCountChanged); + ax::mojom::Event::kRowCountChanged); + } // Post that the specific row either collapsed or expanded. AccessibilityExpanded expanded = IsExpanded(); if (!expanded) return; - if (RoleValue() == kRowRole || RoleValue() == kTreeItemRole) { - AXObjectCacheImpl::AXNotification notification = - AXObjectCacheImpl::kAXRowExpanded; + if (RoleValue() == ax::mojom::Role::kRow || + RoleValue() == ax::mojom::Role::kTreeItem) { + ax::mojom::Event notification = ax::mojom::Event::kRowExpanded; if (expanded == kExpandedCollapsed) - notification = AXObjectCacheImpl::kAXRowCollapsed; + notification = ax::mojom::Event::kRowCollapsed; AXObjectCache().PostNotification(this, notification); } else { - AXObjectCache().PostNotification(this, - AXObjectCacheImpl::kAXExpandedChanged); + AXObjectCache().PostNotification(this, ax::mojom::Event::kExpandedChanged); } } @@ -2481,7 +2561,7 @@ void AXLayoutObject::HandleAutofillStateChanged(bool is_available) { // Reusing the value change event in order to invalidate, even though the // value did not necessarily change. // TODO(dmazzoni) change to using a MarkDirty() API. - AXObjectCache().PostNotification(this, AXObjectCacheImpl::kAXValueChanged); + AXObjectCache().PostNotification(this, ax::mojom::Event::kValueChanged); } } @@ -2491,7 +2571,7 @@ void AXLayoutObject::TextChanged() { Settings* settings = GetDocument()->GetSettings(); if (settings && settings->GetInlineTextBoxAccessibilityEnabled() && - RoleValue() == kStaticTextRole) + RoleValue() == ax::mojom::Role::kStaticText) ChildrenChanged(); // Do this last - AXNodeObject::textChanged posts live region announcements, @@ -2632,7 +2712,8 @@ void AXLayoutObject::LineBreaks(Vector<int>& line_breaks) const { } // The following is a heuristic used to determine if a -// <table> should be with kTableRole or kLayoutTableRole. +// <table> should be with ax::mojom::Role::kTable or +// ax::mojom::Role::kLayoutTable. bool AXLayoutObject::IsDataTable() const { if (!layout_object_ || !GetNode()) return false; @@ -2840,7 +2921,7 @@ bool AXLayoutObject::IsDataTable() const { } unsigned AXLayoutObject::ColumnCount() const { - if (AriaRoleAttribute() != kUnknownRole) + if (AriaRoleAttribute() != ax::mojom::Role::kUnknown) return AXNodeObject::ColumnCount(); LayoutObject* layout_object = GetLayoutObject(); @@ -2857,7 +2938,7 @@ unsigned AXLayoutObject::ColumnCount() const { } unsigned AXLayoutObject::RowCount() const { - if (AriaRoleAttribute() != kUnknownRole) + if (AriaRoleAttribute() != ax::mojom::Role::kUnknown) return AXNodeObject::RowCount(); LayoutObject* layout_object = GetLayoutObject(); @@ -2954,99 +3035,100 @@ unsigned AXLayoutObject::RowSpan() const { return cell->ResolvedRowSpan(); } -SortDirection AXLayoutObject::GetSortDirection() const { - if (RoleValue() != kRowHeaderRole && RoleValue() != kColumnHeaderRole) - return kSortDirectionUndefined; +ax::mojom::SortDirection AXLayoutObject::GetSortDirection() const { + if (RoleValue() != ax::mojom::Role::kRowHeader && + RoleValue() != ax::mojom::Role::kColumnHeader) + return ax::mojom::SortDirection::kNone; const AtomicString& aria_sort = GetAOMPropertyOrARIAAttribute(AOMStringProperty::kSort); if (aria_sort.IsEmpty()) - return kSortDirectionUndefined; + return ax::mojom::SortDirection::kNone; if (EqualIgnoringASCIICase(aria_sort, "none")) - return kSortDirectionNone; + return ax::mojom::SortDirection::kNone; if (EqualIgnoringASCIICase(aria_sort, "ascending")) - return kSortDirectionAscending; + return ax::mojom::SortDirection::kAscending; if (EqualIgnoringASCIICase(aria_sort, "descending")) - return kSortDirectionDescending; + return ax::mojom::SortDirection::kDescending; // Technically, illegal values should be exposed as is, but this does // not seem to be worth the implementation effort at this time. - return kSortDirectionOther; + return ax::mojom::SortDirection::kOther; } -static AccessibilityRole DecideRoleFromSibling(LayoutTableCell* sibling_cell) { +static ax::mojom::Role DecideRoleFromSibling(LayoutTableCell* sibling_cell) { if (!sibling_cell) - return kCellRole; + return ax::mojom::Role::kCell; if (Node* sibling_node = sibling_cell->GetNode()) { if (sibling_node->HasTagName(thTag)) - return kColumnHeaderRole; + return ax::mojom::Role::kColumnHeader; if (sibling_node->HasTagName(tdTag)) - return kRowHeaderRole; + return ax::mojom::Role::kRowHeader; } - return kCellRole; + return ax::mojom::Role::kCell; } -AccessibilityRole AXLayoutObject::DetermineTableRowRole() const { +ax::mojom::Role AXLayoutObject::DetermineTableRowRole() const { AXObject* parent = ParentObjectUnignored(); if (!parent) - return kGenericContainerRole; + return ax::mojom::Role::kGenericContainer; - if (parent->RoleValue() == kLayoutTableRole) - return kLayoutTableRowRole; + if (parent->RoleValue() == ax::mojom::Role::kLayoutTable) + return ax::mojom::Role::kLayoutTableRow; if (parent->IsTableLikeRole()) - return kRowRole; + return ax::mojom::Role::kRow; - return kGenericContainerRole; + return ax::mojom::Role::kGenericContainer; } -AccessibilityRole AXLayoutObject::DetermineTableCellRole() const { +ax::mojom::Role AXLayoutObject::DetermineTableCellRole() const { DCHECK(layout_object_); AXObject* parent = ParentObjectUnignored(); if (!parent || !parent->IsTableRowLikeRole()) - return kGenericContainerRole; + return ax::mojom::Role::kGenericContainer; AXObject* grandparent = parent->ParentObjectUnignored(); if (!grandparent || !grandparent->IsTableLikeRole()) - return kGenericContainerRole; + return ax::mojom::Role::kGenericContainer; - if (parent->RoleValue() == kLayoutTableRowRole) - return kLayoutTableCellRole; + if (parent->RoleValue() == ax::mojom::Role::kLayoutTableRow) + return ax::mojom::Role::kLayoutTableCell; if (!parent->IsTableRowLikeRole()) - return kGenericContainerRole; + return ax::mojom::Role::kGenericContainer; if (!GetNode() || !GetNode()->HasTagName(thTag)) - return kCellRole; + return ax::mojom::Role::kCell; const AtomicString& scope = GetAttribute(scopeAttr); if (EqualIgnoringASCIICase(scope, "row") || EqualIgnoringASCIICase(scope, "rowgroup")) - return kRowHeaderRole; + return ax::mojom::Role::kRowHeader; if (EqualIgnoringASCIICase(scope, "col") || EqualIgnoringASCIICase(scope, "colgroup")) - return kColumnHeaderRole; + return ax::mojom::Role::kColumnHeader; // Check the previous cell and the next cell on the same row. LayoutTableCell* layout_cell = ToLayoutTableCell(layout_object_); - AccessibilityRole header_role = kCellRole; + ax::mojom::Role header_role = ax::mojom::Role::kCell; // if header is preceded by header cells on the same row, then it is a // column header. If it is preceded by other cells then it's a row header. if ((header_role = DecideRoleFromSibling(layout_cell->PreviousCell())) != - kCellRole) + ax::mojom::Role::kCell) return header_role; // if header is followed by header cells on the same row, then it is a // column header. If it is followed by other cells then it's a row header. if ((header_role = DecideRoleFromSibling(layout_cell->NextCell())) != - kCellRole) + ax::mojom::Role::kCell) return header_role; // If there are no other cells on that row, then it is a column header. - return kColumnHeaderRole; + return ax::mojom::Role::kColumnHeader; } AXObject* AXLayoutObject::CellForColumnAndRow(unsigned target_column_index, @@ -3098,7 +3180,7 @@ AXObject* AXLayoutObject::CellForColumnAndRow(unsigned target_column_index, return nullptr; } -bool AXLayoutObject::FindAllTableCellsWithRole(AccessibilityRole role, +bool AXLayoutObject::FindAllTableCellsWithRole(ax::mojom::Role role, AXObjectVector& cells) const { LayoutObject* layout_object = GetLayoutObject(); if (!layout_object || !layout_object->IsTable()) @@ -3129,12 +3211,12 @@ bool AXLayoutObject::FindAllTableCellsWithRole(AccessibilityRole role, } void AXLayoutObject::ColumnHeaders(AXObjectVector& headers) const { - if (!FindAllTableCellsWithRole(kColumnHeaderRole, headers)) + if (!FindAllTableCellsWithRole(ax::mojom::Role::kColumnHeader, headers)) AXNodeObject::ColumnHeaders(headers); } void AXLayoutObject::RowHeaders(AXObjectVector& headers) const { - if (!FindAllTableCellsWithRole(kRowHeaderRole, headers)) + if (!FindAllTableCellsWithRole(ax::mojom::Role::kRowHeader, headers)) AXNodeObject::RowHeaders(headers); } @@ -3147,7 +3229,7 @@ AXObject* AXLayoutObject::HeaderObject() const { for (LayoutTableCell* cell = row->FirstCell(); cell; cell = cell->NextCell()) { AXObject* ax_cell = AXObjectCache().GetOrCreate(cell); - if (ax_cell && ax_cell->RoleValue() == kRowHeaderRole) + if (ax_cell && ax_cell->RoleValue() == ax::mojom::Role::kRowHeader) return ax_cell; } @@ -3182,7 +3264,7 @@ bool AXLayoutObject::IsTabItemSelected() const { AXObject* tab_panel = AXObjectCache().GetOrCreate(element); // A tab item should only control tab panels. - if (!tab_panel || tab_panel->RoleValue() != kTabPanelRole) + if (!tab_panel || tab_panel->RoleValue() != ax::mojom::Role::kTabPanel) continue; AXObject* check_focus_element = focused_element; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.h index f7b2597c2ee..45384248ffa 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.h @@ -56,8 +56,8 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { LayoutObject* GetLayoutObject() const final { return layout_object_; } LayoutBoxModelObject* GetLayoutBoxModelObject() const; ScrollableArea* GetScrollableAreaIfScrollable() const final; - AccessibilityRole DetermineAccessibilityRole() override; - AccessibilityRole NativeAccessibilityRoleIgnoringAria() const override; + ax::mojom::Role DetermineAccessibilityRole() override; + ax::mojom::Role NativeRoleIgnoringAria() const override; // If this is an anonymous block, returns the node of its containing layout // block, otherwise returns the node of this layout object. @@ -107,8 +107,8 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { float FontSize() const final; String ImageDataUrl(const IntSize& max_size) const final; String GetText() const override; - AccessibilityTextDirection GetTextDirection() const final; - AXTextPosition GetTextPosition() const final; + ax::mojom::TextDirection GetTextDirection() const final; + ax::mojom::TextPosition GetTextPosition() const final; int TextLength() const override; TextStyle GetTextStyle() const final; KURL Url() const override; @@ -125,7 +125,7 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { void AriaDescribedbyElements(AXObjectVector&) const override; void AriaOwnsElements(AXObjectVector&) const override; - AXHasPopup HasPopup() const override; + ax::mojom::HasPopup HasPopup() const override; bool SupportsARIADragging() const override; bool SupportsARIADropping() const override; bool SupportsARIAFlowTo() const override; @@ -139,7 +139,7 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { String TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom&, + ax::mojom::NameFrom&, AXRelatedObjectVector*, NameSources*) const override; @@ -202,7 +202,7 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { unsigned RowIndex() const override; // Also for a table row. unsigned ColumnSpan() const override; unsigned RowSpan() const override; - SortDirection GetSortDirection() const override; + ax::mojom::SortDirection GetSortDirection() const override; // For a table row or column. AXObject* HeaderObject() const override; @@ -224,9 +224,9 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { void AddRemoteSVGChildren(); void AddTableChildren(); void AddInlineTextBoxChildren(bool force); - AccessibilityRole DetermineTableCellRole() const; - AccessibilityRole DetermineTableRowRole() const; - bool FindAllTableCellsWithRole(AccessibilityRole, AXObjectVector&) const; + ax::mojom::Role DetermineTableCellRole() const; + ax::mojom::Role DetermineTableRowRole() const; + bool FindAllTableCellsWithRole(ax::mojom::Role, AXObjectVector&) const; LayoutRect ComputeElementRect() const; AXSelection TextControlSelection() const; @@ -236,6 +236,7 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { bool CanIgnoreTextAsEmpty() const; bool CanIgnoreSpaceNextTo(LayoutObject*, bool is_after) const; bool HasAriaCellRole(Element*) const; + bool IsPlaceholder() const; bool is_autofill_available_; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_list.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_list.cc index 59f9b75a3a8..98d081036a6 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_list.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_list.cc @@ -59,10 +59,10 @@ bool AXList::IsDescriptionList() const { return node && node->HasTagName(dlTag); } -AccessibilityRole AXList::RoleValue() const { +ax::mojom::Role AXList::RoleValue() const { if (IsDescriptionList()) - return kDescriptionListRole; + return ax::mojom::Role::kDescriptionList; - return kListRole; + return ax::mojom::Role::kList; } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_list.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_list.h index b07f0712680..f2211e18772 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_list.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_list.h @@ -46,7 +46,7 @@ class AXList final : public AXLayoutObject { bool IsList() const override { return true; } - AccessibilityRole RoleValue() const final; + ax::mojom::Role RoleValue() const final; private: bool IsDescriptionList() const; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box.cc index c34efafd2c6..083bad904a2 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box.cc @@ -50,11 +50,11 @@ AXListBox* AXListBox::Create(LayoutObject* layout_object, return new AXListBox(layout_object, ax_object_cache); } -AccessibilityRole AXListBox::DetermineAccessibilityRole() { - if ((aria_role_ = DetermineAriaRoleAttribute()) != kUnknownRole) +ax::mojom::Role AXListBox::DetermineAccessibilityRole() { + if ((aria_role_ = DetermineAriaRoleAttribute()) != ax::mojom::Role::kUnknown) return aria_role_; - return kListBoxRole; + return ax::mojom::Role::kListBox; } AXObject* AXListBox::ActiveDescendant() { @@ -84,8 +84,8 @@ void AXListBox::ActiveIndexChanged() { if (!select->IsFocused()) return; - AXObjectCache().PostNotification( - this, AXObjectCacheImpl::kAXActiveDescendantChanged); + AXObjectCache().PostNotification(this, + ax::mojom::Event::kActiveDescendantChanged); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box.h index e79171d3b6b..c4ddb67784e 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box.h @@ -44,7 +44,7 @@ class AXListBox final : public AXLayoutObject { static AXListBox* Create(LayoutObject*, AXObjectCacheImpl&); ~AXListBox() override; - AccessibilityRole DetermineAccessibilityRole() final; + ax::mojom::Role DetermineAccessibilityRole() final; bool IsAXListBox() const override { return true; } AXObject* ActiveDescendant() final; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box_option.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box_option.cc index c0ce1e480e3..de06a56fd1c 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box_option.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box_option.cc @@ -49,8 +49,8 @@ AXListBoxOption* AXListBoxOption::Create(LayoutObject* layout_object, return new AXListBoxOption(layout_object, ax_object_cache); } -AccessibilityRole AXListBoxOption::DetermineAccessibilityRole() { - if ((aria_role_ = DetermineAriaRoleAttribute()) != kUnknownRole) +ax::mojom::Role AXListBoxOption::DetermineAccessibilityRole() { + if ((aria_role_ = DetermineAriaRoleAttribute()) != ax::mojom::Role::kUnknown) return aria_role_; // http://www.w3.org/TR/wai-aria/complete#presentation @@ -59,9 +59,9 @@ AccessibilityRole AXListBoxOption::DetermineAccessibilityRole() { // does not cause the content contained within the element to be removed from // the accessibility tree. if (IsParentPresentationalRole()) - return kStaticTextRole; + return ax::mojom::Role::kStaticText; - return kListBoxOptionRole; + return ax::mojom::Role::kListBoxOption; } bool AXListBoxOption::IsParentPresentationalRole() const { @@ -111,7 +111,7 @@ bool AXListBoxOption::ComputeAccessibilityIsIgnored( String AXListBoxOption::TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom& name_from, + ax::mojom::NameFrom& name_from, AXRelatedObjectVector* related_objects, NameSources* name_sources) const { // If nameSources is non-null, relatedObjects is used in filling it in, so it @@ -129,7 +129,7 @@ String AXListBoxOption::TextAlternative(bool recursive, if (found_text_alternative && !name_sources) return text_alternative; - name_from = kAXNameFromContents; + name_from = ax::mojom::NameFrom::kContents; text_alternative = ToHTMLOptionElement(GetNode())->DisplayLabel(); if (name_sources) { name_sources->push_back(NameSource(found_text_alternative)); diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box_option.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box_option.h index ef2129317de..07ed3c8f526 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box_option.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_list_box_option.h @@ -47,7 +47,7 @@ class AXListBoxOption final : public AXLayoutObject { ~AXListBoxOption() override; bool IsAXListBoxOption() const override { return true; } - AccessibilityRole DetermineAccessibilityRole() final; + ax::mojom::Role DetermineAccessibilityRole() final; AccessibilitySelectedState IsSelected() const override; bool IsSelectedOptionActive() const override; bool OnNativeSetSelectedAction(bool) override; @@ -55,7 +55,7 @@ class AXListBoxOption final : public AXLayoutObject { String TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom&, + ax::mojom::NameFrom&, AXRelatedObjectVector*, NameSources*) const override; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc index 66bef28d1da..4bc852fd8ee 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc @@ -59,6 +59,10 @@ AXObject* AccessibilityMediaControl::Create( case kMediaSlider: return AccessibilityMediaTimeline::Create(layout_object, ax_object_cache); + case kMediaVolumeSlider: + return AccessibilityMediaVolumeSlider::Create(layout_object, + ax_object_cache); + case kMediaCurrentTimeDisplay: case kMediaTimeRemainingDisplay: return AccessibilityMediaTimeDisplay::Create(layout_object, @@ -79,7 +83,6 @@ AXObject* AccessibilityMediaControl::Create( case kMediaTimelineContainer: case kMediaTrackSelectionCheckmark: case kMediaVolumeSliderContainer: - case kMediaVolumeSlider: case kMediaVolumeSliderThumb: case kMediaExitFullscreenButton: case kMediaCastOffButton: @@ -93,6 +96,7 @@ AXObject* AccessibilityMediaControl::Create( case kMediaEnterPictureInPictureButton: case kMediaExitPictureInPictureButton: case kMediaDisplayCutoutFullscreenButton: + case kMediaAnimatedArrowContainer: return new AccessibilityMediaControl(layout_object, ax_object_cache); } @@ -108,28 +112,21 @@ MediaControlElementType AccessibilityMediaControl::ControlType() const { GetLayoutObject()->GetNode()); } -bool AccessibilityMediaControl::OnNativeScrollToGlobalPointAction( - const IntPoint& point) const { +bool AccessibilityMediaControl::InternalSetAccessibilityFocusAction() { MediaControlElementsHelper::NotifyMediaControlAccessibleFocus(GetElement()); - return AXLayoutObject::OnNativeScrollToGlobalPointAction(point); + return AXLayoutObject::InternalSetAccessibilityFocusAction(); } -bool AccessibilityMediaControl::OnNativeScrollToMakeVisibleAction() const { - MediaControlElementsHelper::NotifyMediaControlAccessibleFocus(GetElement()); - return AXLayoutObject::OnNativeScrollToMakeVisibleAction(); -} - -bool AccessibilityMediaControl::OnNativeScrollToMakeVisibleWithSubFocusAction( - const IntRect& rect) const { - MediaControlElementsHelper::NotifyMediaControlAccessibleFocus(GetElement()); - return AXLayoutObject::OnNativeScrollToMakeVisibleWithSubFocusAction(rect); +bool AccessibilityMediaControl::InternalClearAccessibilityFocusAction() { + MediaControlElementsHelper::NotifyMediaControlAccessibleBlur(GetElement()); + return AXLayoutObject::InternalClearAccessibilityFocusAction(); } String AccessibilityMediaControl::TextAlternative( bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom& name_from, + ax::mojom::NameFrom& name_from, AXRelatedObjectVector* related_objects, NameSources* name_sources) const { switch (ControlType()) { @@ -169,10 +166,10 @@ String AccessibilityMediaControl::TextAlternative( case kMediaTrackSelectionCheckmark: case kMediaControlsPanel: case kMediaVolumeSliderContainer: - case kMediaVolumeSlider: case kMediaVolumeSliderThumb: case kMediaOverflowList: case kMediaScrubbingMessage: + case kMediaAnimatedArrowContainer: return QueryString(WebLocalizedString::kAXMediaDefault); case kMediaEnterPictureInPictureButton: return QueryString( @@ -184,6 +181,7 @@ String AccessibilityMediaControl::TextAlternative( return QueryString( WebLocalizedString::kAXMediaDisplayCutoutFullscreenButton); case kMediaSlider: + case kMediaVolumeSlider: NOTREACHED(); return QueryString(WebLocalizedString::kAXMediaDefault); } @@ -193,62 +191,49 @@ String AccessibilityMediaControl::TextAlternative( } String AccessibilityMediaControl::Description( - AXNameFrom name_from, - AXDescriptionFrom& description_from, + ax::mojom::NameFrom name_from, + ax::mojom::DescriptionFrom& description_from, AXObjectVector* description_objects) const { switch (ControlType()) { + case kMediaCurrentTimeDisplay: + return QueryString(WebLocalizedString::kAXMediaCurrentTimeDisplayHelp); + case kMediaTimeRemainingDisplay: + return QueryString(WebLocalizedString::kAXMediaTimeRemainingDisplayHelp); + case kMediaOverflowButton: + return QueryString(WebLocalizedString::kAXMediaOverflowButtonHelp); + // The following descriptions are repeats of their respective titles. When + // read by accessibility, we get the same thing said twice, with no value + // added. So instead, we just return an empty string. case kMediaEnterFullscreenButton: - return QueryString(WebLocalizedString::kAXMediaEnterFullscreenButtonHelp); case kMediaExitFullscreenButton: - return QueryString(WebLocalizedString::kAXMediaExitFullscreenButtonHelp); + case kMediaDisplayCutoutFullscreenButton: case kMediaMuteButton: - return QueryString(WebLocalizedString::kAXMediaMuteButtonHelp); - case kMediaPlayButton: - return QueryString(WebLocalizedString::kAXMediaPlayButtonHelp); case kMediaUnMuteButton: - return QueryString(WebLocalizedString::kAXMediaUnMuteButtonHelp); + case kMediaPlayButton: case kMediaPauseButton: - return QueryString(WebLocalizedString::kAXMediaPauseButtonHelp); - case kMediaCurrentTimeDisplay: - return QueryString(WebLocalizedString::kAXMediaCurrentTimeDisplayHelp); - case kMediaTimeRemainingDisplay: - return QueryString(WebLocalizedString::kAXMediaTimeRemainingDisplayHelp); case kMediaShowClosedCaptionsButton: - return QueryString( - WebLocalizedString::kAXMediaShowClosedCaptionsButtonHelp); case kMediaHideClosedCaptionsButton: - return QueryString( - WebLocalizedString::kAXMediaHideClosedCaptionsButtonHelp); case kMediaCastOffButton: case kMediaOverlayCastOffButton: - return QueryString(WebLocalizedString::kAXMediaCastOffButtonHelp); case kMediaCastOnButton: case kMediaOverlayCastOnButton: - return QueryString(WebLocalizedString::kAXMediaCastOnButtonHelp); - case kMediaOverflowButton: - return QueryString(WebLocalizedString::kAXMediaOverflowButtonHelp); case kMediaEnterPictureInPictureButton: - return QueryString( - WebLocalizedString::kAXMediaEnterPictureInPictureButtonHelp); case kMediaExitPictureInPictureButton: - return QueryString( - WebLocalizedString::kAXMediaExitPictureInPictureButtonHelp); - case kMediaDisplayCutoutFullscreenButton: - return QueryString( - WebLocalizedString::kAXMediaDisplayCutoutFullscreenButtonHelp); + return ""; case kMediaSliderThumb: case kMediaTextTrackList: case kMediaTimelineContainer: case kMediaTrackSelectionCheckmark: case kMediaControlsPanel: case kMediaVolumeSliderContainer: - case kMediaVolumeSlider: case kMediaVolumeSliderThumb: case kMediaOverflowList: case kMediaDownloadButton: case kMediaScrubbingMessage: + case kMediaAnimatedArrowContainer: return QueryString(WebLocalizedString::kAXMediaDefault); case kMediaSlider: + case kMediaVolumeSlider: NOTREACHED(); return QueryString(WebLocalizedString::kAXMediaDefault); } @@ -267,7 +252,7 @@ bool AccessibilityMediaControl::ComputeAccessibilityIsIgnored( return AccessibilityIsIgnoredByDefault(ignored_reasons); } -AccessibilityRole AccessibilityMediaControl::RoleValue() const { +ax::mojom::Role AccessibilityMediaControl::RoleValue() const { switch (ControlType()) { case kMediaEnterFullscreenButton: case kMediaExitFullscreenButton: @@ -286,32 +271,33 @@ AccessibilityRole AccessibilityMediaControl::RoleValue() const { case kMediaEnterPictureInPictureButton: case kMediaExitPictureInPictureButton: case kMediaDisplayCutoutFullscreenButton: - return kButtonRole; + return ax::mojom::Role::kButton; case kMediaTimelineContainer: case kMediaVolumeSliderContainer: case kMediaTextTrackList: case kMediaOverflowList: - return kGroupRole; + return ax::mojom::Role::kGroup; case kMediaControlsPanel: case kMediaCurrentTimeDisplay: case kMediaTimeRemainingDisplay: case kMediaSliderThumb: case kMediaTrackSelectionCheckmark: - case kMediaVolumeSlider: case kMediaVolumeSliderThumb: case kMediaScrubbingMessage: - return kUnknownRole; + case kMediaAnimatedArrowContainer: + return ax::mojom::Role::kUnknown; case kMediaSlider: + case kMediaVolumeSlider: // Not using AccessibilityMediaControl. NOTREACHED(); - return kUnknownRole; + return ax::mojom::Role::kUnknown; } NOTREACHED(); - return kUnknownRole; + return ax::mojom::Role::kUnknown; } // @@ -331,7 +317,7 @@ String AXMediaControlsContainer::TextAlternative( bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom& name_from, + ax::mojom::NameFrom& name_from, AXRelatedObjectVector* related_objects, NameSources* name_sources) const { return QueryString(IsControllingVideoElement() @@ -340,8 +326,8 @@ String AXMediaControlsContainer::TextAlternative( } String AXMediaControlsContainer::Description( - AXNameFrom name_from, - AXDescriptionFrom& description_from, + ax::mojom::NameFrom name_from, + ax::mojom::DescriptionFrom& description_from, AXObjectVector* description_objects) const { return QueryString(IsControllingVideoElement() ? WebLocalizedString::kAXMediaVideoElementHelp @@ -374,8 +360,8 @@ AXObject* AccessibilityMediaTimeline::Create( } String AccessibilityMediaTimeline::Description( - AXNameFrom name_from, - AXDescriptionFrom& description_from, + ax::mojom::NameFrom name_from, + ax::mojom::DescriptionFrom& description_from, AXObjectVector* description_objects) const { return QueryString(IsControllingVideoElement() ? WebLocalizedString::kAXMediaVideoSliderHelp @@ -383,6 +369,37 @@ String AccessibilityMediaTimeline::Description( } // +// AccessibilityMediaVolumeSlider + +AccessibilityMediaVolumeSlider::AccessibilityMediaVolumeSlider( + LayoutObject* layout_object, + AXObjectCacheImpl& ax_object_cache) + : AXSlider(layout_object, ax_object_cache) {} + +AXObject* AccessibilityMediaVolumeSlider::Create( + LayoutObject* layout_object, + AXObjectCacheImpl& ax_object_cache) { + return new AccessibilityMediaVolumeSlider(layout_object, ax_object_cache); +} + +String AccessibilityMediaVolumeSlider::Description( + ax::mojom::NameFrom name_from, + ax::mojom::DescriptionFrom& description_from, + AXObjectVector* description_objects) const { + return QueryString(WebLocalizedString::kAXMediaVolumeSliderHelp); +} + +bool AccessibilityMediaVolumeSlider::InternalSetAccessibilityFocusAction() { + MediaControlElementsHelper::NotifyMediaControlAccessibleFocus(GetElement()); + return AXSlider::InternalSetAccessibilityFocusAction(); +} + +bool AccessibilityMediaVolumeSlider::InternalClearAccessibilityFocusAction() { + MediaControlElementsHelper::NotifyMediaControlAccessibleBlur(GetElement()); + return AXSlider::InternalClearAccessibilityFocusAction(); +} + +// // AccessibilityMediaTimeDisplay AccessibilityMediaTimeDisplay::AccessibilityMediaTimeDisplay( @@ -412,7 +429,7 @@ String AccessibilityMediaTimeDisplay::TextAlternative( bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom& name_from, + ax::mojom::NameFrom& name_from, AXRelatedObjectVector* related_objects, NameSources* name_sources) const { if (ControlType() == kMediaCurrentTimeDisplay) diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.h index 17f1913e57f..fc7c71c0424 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_media_controls.h @@ -42,22 +42,20 @@ class AccessibilityMediaControl : public AXLayoutObject { static AXObject* Create(LayoutObject*, AXObjectCacheImpl&); ~AccessibilityMediaControl() override = default; - AccessibilityRole RoleValue() const override; + ax::mojom::Role RoleValue() const override; String TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom&, + ax::mojom::NameFrom&, AXRelatedObjectVector*, NameSources*) const override; - String Description(AXNameFrom, - AXDescriptionFrom&, + String Description(ax::mojom::NameFrom, + ax::mojom::DescriptionFrom&, AXObjectVector* description_objects) const override; - bool OnNativeScrollToGlobalPointAction(const IntPoint&) const override; - bool OnNativeScrollToMakeVisibleAction() const override; - bool OnNativeScrollToMakeVisibleWithSubFocusAction( - const IntRect&) const override; + bool InternalSetAccessibilityFocusAction() override; + bool InternalClearAccessibilityFocusAction() override; protected: AccessibilityMediaControl(LayoutObject*, AXObjectCacheImpl&); @@ -72,8 +70,8 @@ class AccessibilityMediaTimeline final : public AXSlider { static AXObject* Create(LayoutObject*, AXObjectCacheImpl&); ~AccessibilityMediaTimeline() override = default; - String Description(AXNameFrom, - AXDescriptionFrom&, + String Description(ax::mojom::NameFrom, + ax::mojom::DescriptionFrom&, AXObjectVector* description_objects) const override; private: @@ -82,21 +80,41 @@ class AccessibilityMediaTimeline final : public AXSlider { DISALLOW_COPY_AND_ASSIGN(AccessibilityMediaTimeline); }; +class AccessibilityMediaVolumeSlider final : public AXSlider { + public: + static AXObject* Create(LayoutObject*, AXObjectCacheImpl&); + ~AccessibilityMediaVolumeSlider() override = default; + + String Description(ax::mojom::NameFrom, + ax::mojom::DescriptionFrom&, + AXObjectVector* description_objects) const override; + + bool InternalSetAccessibilityFocusAction() override; + bool InternalClearAccessibilityFocusAction() override; + + private: + AccessibilityMediaVolumeSlider(LayoutObject*, AXObjectCacheImpl&); + + DISALLOW_COPY_AND_ASSIGN(AccessibilityMediaVolumeSlider); +}; + class AXMediaControlsContainer final : public AccessibilityMediaControl { public: static AXObject* Create(LayoutObject*, AXObjectCacheImpl&); ~AXMediaControlsContainer() override = default; - AccessibilityRole RoleValue() const override { return kToolbarRole; } + ax::mojom::Role RoleValue() const override { + return ax::mojom::Role::kToolbar; + } String TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom&, + ax::mojom::NameFrom&, AXRelatedObjectVector*, NameSources*) const override; - String Description(AXNameFrom, - AXDescriptionFrom&, + String Description(ax::mojom::NameFrom, + ax::mojom::DescriptionFrom&, AXObjectVector* description_objects) const override; private: @@ -111,13 +129,15 @@ class AccessibilityMediaTimeDisplay final : public AccessibilityMediaControl { static AXObject* Create(LayoutObject*, AXObjectCacheImpl&); ~AccessibilityMediaTimeDisplay() override = default; - AccessibilityRole RoleValue() const override { return kStaticTextRole; } + ax::mojom::Role RoleValue() const override { + return ax::mojom::Role::kStaticText; + } String StringValue() const override; String TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom&, + ax::mojom::NameFrom&, AXRelatedObjectVector*, NameSources*) const override; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc index 85ee9f64206..1f294af0880 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc @@ -41,11 +41,11 @@ AXMenuList* AXMenuList::Create(LayoutMenuList* layout_object, return new AXMenuList(layout_object, ax_object_cache); } -AccessibilityRole AXMenuList::DetermineAccessibilityRole() { - if ((aria_role_ = DetermineAriaRoleAttribute()) != kUnknownRole) +ax::mojom::Role AXMenuList::DetermineAccessibilityRole() { + if ((aria_role_ = DetermineAriaRoleAttribute()) != ax::mojom::Role::kUnknown) return aria_role_; - return kPopUpButtonRole; + return ax::mojom::Role::kPopUpButton; } bool AXMenuList::OnNativeClickAction() { @@ -78,7 +78,7 @@ void AXMenuList::AddChildren() { AXObjectCacheImpl& cache = AXObjectCache(); - AXObject* list = cache.GetOrCreate(kMenuListPopupRole); + AXObject* list = cache.GetOrCreate(ax::mojom::Role::kMenuListPopup); if (!list) return; @@ -127,7 +127,7 @@ void AXMenuList::DidUpdateActiveOption(int option_index) { } AXObjectCache().PostNotification(this, - AXObjectCacheImpl::kAXMenuListValueChanged); + ax::mojom::Event::kMenuListValueChanged); } void AXMenuList::DidShowPopup() { @@ -146,8 +146,7 @@ void AXMenuList::DidHidePopup() { popup->DidHide(); if (GetNode() && GetNode()->IsFocused()) - AXObjectCache().PostNotification( - this, AXObjectCacheImpl::kAXFocusedUIElementChanged); + AXObjectCache().PostNotification(this, ax::mojom::Event::kFocus); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.h index bafcc00afa5..a54dc3177da 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list.h @@ -38,7 +38,6 @@ class AXMenuList final : public AXLayoutObject { public: static AXMenuList* Create(LayoutMenuList* layout_object, AXObjectCacheImpl&); - bool IsCollapsed() const override; AccessibilityExpanded IsExpanded() const final; bool OnNativeClickAction() override; void ClearChildren() override; @@ -53,10 +52,12 @@ class AXMenuList final : public AXLayoutObject { AXMenuList(LayoutMenuList*, AXObjectCacheImpl&); bool IsMenuList() const override { return true; } - AccessibilityRole DetermineAccessibilityRole() final; + ax::mojom::Role DetermineAccessibilityRole() final; void AddChildren() override; + bool IsCollapsed() const; + DISALLOW_COPY_AND_ASSIGN(AXMenuList); }; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc index a6b3ae05669..57b987bbdcd 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.cc @@ -55,16 +55,16 @@ LocalFrameView* AXMenuListOption::DocumentFrameView() const { return element_->GetDocument().View(); } -AccessibilityRole AXMenuListOption::RoleValue() const { +ax::mojom::Role AXMenuListOption::RoleValue() const { const AtomicString& aria_role = GetAOMPropertyOrARIAAttribute(AOMStringProperty::kRole); if (aria_role.IsEmpty()) - return kMenuListOptionRole; + return ax::mojom::Role::kMenuListOption; - AccessibilityRole role = AriaRoleToWebCoreRole(aria_role); - if (role) + ax::mojom::Role role = AriaRoleToWebCoreRole(aria_role); + if (role != ax::mojom::Role::kUnknown) return role; - return kMenuListOptionRole; + return ax::mojom::Role::kMenuListOption; } Element* AXMenuListOption::ActionElement() const { @@ -79,6 +79,8 @@ AXObject* AXMenuListOption::ComputeParent() const { if (!select) return nullptr; AXObject* select_ax_object = AXObjectCache().GetOrCreate(select); + if (!select_ax_object) + return nullptr; // This happens if the <select> is not rendered. Return it and move on. if (!select_ax_object->IsMenuList()) @@ -178,7 +180,7 @@ void AXMenuListOption::GetRelativeBounds(AXObject** out_container, String AXMenuListOption::TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom& name_from, + ax::mojom::NameFrom& name_from, AXRelatedObjectVector* related_objects, NameSources* name_sources) const { // If nameSources is non-null, relatedObjects is used in filling it in, so it @@ -196,7 +198,7 @@ String AXMenuListOption::TextAlternative(bool recursive, if (found_text_alternative && !name_sources) return text_alternative; - name_from = kAXNameFromContents; + name_from = ax::mojom::NameFrom::kContents; text_alternative = element_->DisplayLabel(); if (name_sources) { name_sources->push_back(NameSource(found_text_alternative)); diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h index 8d60d311093..cfb60cb8751 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_option.h @@ -55,7 +55,7 @@ class AXMenuListOption final : public AXMockObject { void Detach() override; bool IsDetached() const override { return !element_; } LocalFrameView* DocumentFrameView() const override; - AccessibilityRole RoleValue() const override; + ax::mojom::Role RoleValue() const override; bool CanHaveChildren() const override { return false; } AXObject* ComputeParent() const override; @@ -72,7 +72,7 @@ class AXMenuListOption final : public AXMockObject { String TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom&, + ax::mojom::NameFrom&, AXRelatedObjectVector*, NameSources*) const override; bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc index bfb71651b0e..a1bf9c85429 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc @@ -44,7 +44,7 @@ bool AXMenuListPopup::IsOffScreen() const { if (!parent_) return true; - return parent_->IsCollapsed(); + return parent_->IsExpanded() == kExpandedCollapsed; } AXRestriction AXMenuListPopup::Restriction() const { @@ -135,25 +135,24 @@ void AXMenuListPopup::DidUpdateActiveOption(int option_index, old_index < static_cast<int>(children_.size())) { AXObject* previous_child = children_[old_index].Get(); cache.PostNotification(previous_child, - AXObjectCacheImpl::kAXMenuListItemUnselected); + ax::mojom::Event::kMenuListItemSelected); } if (option_index >= 0 && option_index < static_cast<int>(children_.size())) { AXObject* child = children_[option_index].Get(); - cache.PostNotification(this, AXObjectCacheImpl::kAXChildrenChanged); - cache.PostNotification(this, AXObjectCacheImpl::kAXActiveDescendantChanged); - cache.PostNotification(child, AXObjectCacheImpl::kAXMenuListItemSelected); + cache.PostNotification(this, ax::mojom::Event::kChildrenChanged); + cache.PostNotification(this, ax::mojom::Event::kActiveDescendantChanged); + cache.PostNotification(child, ax::mojom::Event::kMenuListItemSelected); } } void AXMenuListPopup::DidHide() { AXObjectCacheImpl& cache = AXObjectCache(); AXObject* descendant = ActiveDescendant(); - cache.PostNotification(this, AXObjectCacheImpl::kAXHide); + cache.PostNotification(this, ax::mojom::Event::kHide); if (descendant) { - cache.PostNotification(this, AXObjectCacheImpl::kAXChildrenChanged); - cache.PostNotification(descendant, - AXObjectCacheImpl::kAXMenuListItemUnselected); + cache.PostNotification(this, ax::mojom::Event::kChildrenChanged); + cache.PostNotification(descendant, ax::mojom::Event::kMenuListItemSelected); } } @@ -162,14 +161,13 @@ void AXMenuListPopup::DidShow() { AddChildren(); AXObjectCacheImpl& cache = AXObjectCache(); - cache.PostNotification(this, AXObjectCacheImpl::kAXShow); + cache.PostNotification(this, ax::mojom::Event::kShow); int selected_index = GetSelectedIndex(); if (selected_index >= 0 && selected_index < static_cast<int>(children_.size())) { DidUpdateActiveOption(selected_index); } else { - cache.PostNotification(parent_, - AXObjectCacheImpl::kAXFocusedUIElementChanged); + cache.PostNotification(parent_, ax::mojom::Event::kFocus); } } diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h index 5c88b4143da..2625784fa6c 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h @@ -55,7 +55,9 @@ class AXMenuListPopup final : public AXMockObject { bool IsMenuListPopup() const override { return true; } - AccessibilityRole RoleValue() const override { return kMenuListPopupRole; } + ax::mojom::Role RoleValue() const override { + return ax::mojom::Role::kMenuListPopup; + } bool IsVisible() const override; bool OnNativeClickAction() override; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc index 40cae4314eb..a73d98400e9 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc @@ -40,6 +40,7 @@ #include "third_party/blink/renderer/core/dom/user_gesture_indicator.h" #include "third_party/blink/renderer/core/editing/editing_utilities.h" #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h" +#include "third_party/blink/renderer/core/editing/position.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" #include "third_party/blink/renderer/core/html/forms/html_field_set_element.h" @@ -87,7 +88,7 @@ const int kDefaultHeadingLevel = 2; AXNodeObject::AXNodeObject(Node* node, AXObjectCacheImpl& ax_object_cache) : AXObject(ax_object_cache), children_dirty_(false), - native_role_(kUnknownRole), + native_role_(ax::mojom::Role::kUnknown), node_(node) {} AXNodeObject* AXNodeObject::Create(Node* node, @@ -113,8 +114,7 @@ void AXNodeObject::AlterSliderOrSpinButtonValue(bool increase) { value += increase ? step : -step; OnNativeSetValueAction(String::Number(value)); - AXObjectCache().PostNotification(GetNode(), - AXObjectCacheImpl::kAXValueChanged); + AXObjectCache().PostNotification(GetNode(), ax::mojom::Event::kValueChanged); } AXObject* AXNodeObject::ActiveDescendant() { @@ -174,7 +174,7 @@ bool AXNodeObject::ComputeAccessibilityIsIgnored( return true; } - if (role_ == kUnknownRole) { + if (role_ == ax::mojom::Role::kUnknown) { if (ignored_reasons) ignored_reasons->push_back(IgnoredReason(kAXUninteresting)); return true; @@ -188,18 +188,19 @@ static bool IsListElement(Node* node) { } static bool IsRequiredOwnedElement(AXObject* parent, - AccessibilityRole current_role, + ax::mojom::Role current_role, HTMLElement* current_element) { Node* parent_node = parent->GetNode(); if (!parent_node || !parent_node->IsHTMLElement()) return false; - if (current_role == kListItemRole) + if (current_role == ax::mojom::Role::kListItem) return IsListElement(parent_node); - if (current_role == kListMarkerRole) + if (current_role == ax::mojom::Role::kListMarker) return IsHTMLLIElement(*parent_node); - if (current_role == kMenuItemCheckBoxRole || current_role == kMenuItemRole || - current_role == kMenuItemRadioRole) + if (current_role == ax::mojom::Role::kMenuItemCheckBox || + current_role == ax::mojom::Role::kMenuItem || + current_role == ax::mojom::Role::kMenuItemRadio) return IsHTMLMenuElement(*parent_node); if (!current_element) @@ -229,7 +230,7 @@ const AXObject* AXNodeObject::InheritsPresentationalRoleFrom() const { // ARIA spec says that the user agent MUST apply an inherited role of // presentation // to any owned elements that do not have an explicit role defined. - if (AriaRoleAttribute() != kUnknownRole) + if (AriaRoleAttribute() != ax::mojom::Role::kUnknown) return nullptr; AXObject* parent = ParentObject(); @@ -290,195 +291,200 @@ bool AXNodeObject::IsDescendantOfElementType( // TODO(accessibility) This value is cached in native_role_ so it needs to // be recached if anything it depends on change, such as IsClickable(), // DataList(), aria-pressed, the parent's tag, role on an iframe, etc. -AccessibilityRole AXNodeObject::NativeAccessibilityRoleIgnoringAria() const { +ax::mojom::Role AXNodeObject::NativeRoleIgnoringAria() const { if (!GetNode()) - return kUnknownRole; + return ax::mojom::Role::kUnknown; // |HTMLAnchorElement| sets isLink only when it has hrefAttr. if (GetNode()->IsLink()) - return kLinkRole; + return ax::mojom::Role::kLink; if (IsHTMLAnchorElement(*GetNode())) { // We assume that an anchor element is LinkRole if it has event listners // even though it doesn't have hrefAttr. if (IsClickable()) - return kLinkRole; - return kAnchorRole; + return ax::mojom::Role::kLink; + return ax::mojom::Role::kAnchor; } if (IsHTMLButtonElement(*GetNode())) return ButtonRoleType(); if (IsHTMLDetailsElement(*GetNode())) - return kDetailsRole; + return ax::mojom::Role::kDetails; if (IsHTMLSummaryElement(*GetNode())) { ContainerNode* parent = FlatTreeTraversal::Parent(*GetNode()); if (parent && IsHTMLSlotElement(parent)) parent = FlatTreeTraversal::Parent(*parent); if (parent && IsHTMLDetailsElement(parent)) - return kDisclosureTriangleRole; - return kUnknownRole; + return ax::mojom::Role::kDisclosureTriangle; + return ax::mojom::Role::kUnknown; } if (const auto* input = ToHTMLInputElementOrNull(*GetNode())) { const AtomicString& type = input->type(); if (input->DataList()) - return kTextFieldWithComboBoxRole; + return ax::mojom::Role::kTextFieldWithComboBox; if (type == InputTypeNames::button) { if ((GetNode()->parentNode() && IsHTMLMenuElement(GetNode()->parentNode())) || - (ParentObject() && ParentObject()->RoleValue() == kMenuRole)) - return kMenuItemRole; + (ParentObject() && + ParentObject()->RoleValue() == ax::mojom::Role::kMenu)) + return ax::mojom::Role::kMenuItem; return ButtonRoleType(); } if (type == InputTypeNames::checkbox) { if ((GetNode()->parentNode() && IsHTMLMenuElement(GetNode()->parentNode())) || - (ParentObject() && ParentObject()->RoleValue() == kMenuRole)) - return kMenuItemCheckBoxRole; - return kCheckBoxRole; + (ParentObject() && + ParentObject()->RoleValue() == ax::mojom::Role::kMenu)) + return ax::mojom::Role::kMenuItemCheckBox; + return ax::mojom::Role::kCheckBox; } if (type == InputTypeNames::date) - return kDateRole; + return ax::mojom::Role::kDate; if (type == InputTypeNames::datetime || type == InputTypeNames::datetime_local || type == InputTypeNames::month || type == InputTypeNames::week) - return kDateTimeRole; + return ax::mojom::Role::kDateTime; if (type == InputTypeNames::file) - return kButtonRole; + return ax::mojom::Role::kButton; if (type == InputTypeNames::radio) { if ((GetNode()->parentNode() && IsHTMLMenuElement(GetNode()->parentNode())) || - (ParentObject() && ParentObject()->RoleValue() == kMenuRole)) - return kMenuItemRadioRole; - return kRadioButtonRole; + (ParentObject() && + ParentObject()->RoleValue() == ax::mojom::Role::kMenu)) + return ax::mojom::Role::kMenuItemRadio; + return ax::mojom::Role::kRadioButton; } if (type == InputTypeNames::number) - return kSpinButtonRole; + return ax::mojom::Role::kSpinButton; if (input->IsTextButton()) return ButtonRoleType(); if (type == InputTypeNames::range) - return kSliderRole; + return ax::mojom::Role::kSlider; if (type == InputTypeNames::color) - return kColorWellRole; + return ax::mojom::Role::kColorWell; if (type == InputTypeNames::time) - return kInputTimeRole; - return kTextFieldRole; + return ax::mojom::Role::kInputTime; + return ax::mojom::Role::kTextField; } - if (auto* select_element = ToHTMLSelectElementOrNull(*GetNode())) - return select_element->IsMultiple() ? kListBoxRole : kPopUpButtonRole; + if (auto* select_element = ToHTMLSelectElementOrNull(*GetNode())) { + return select_element->IsMultiple() ? ax::mojom::Role::kListBox + : ax::mojom::Role::kPopUpButton; + } if (auto* option = ToHTMLOptionElementOrNull(*GetNode())) { HTMLSelectElement* select_element = option->OwnerSelectElement(); return !select_element || select_element->IsMultiple() - ? kListBoxOptionRole - : kMenuListOptionRole; + ? ax::mojom::Role::kListBoxOption + : ax::mojom::Role::kMenuListOption; } if (IsHTMLTextAreaElement(*GetNode())) - return kTextFieldRole; + return ax::mojom::Role::kTextField; if (HeadingLevel()) - return kHeadingRole; + return ax::mojom::Role::kHeading; if (IsHTMLDivElement(*GetNode())) - return kGenericContainerRole; + return ax::mojom::Role::kGenericContainer; if (IsHTMLMeterElement(*GetNode())) - return kMeterRole; + return ax::mojom::Role::kMeter; if (IsHTMLProgressElement(*GetNode())) - return kProgressIndicatorRole; + return ax::mojom::Role::kProgressIndicator; if (IsHTMLOutputElement(*GetNode())) - return kStatusRole; + return ax::mojom::Role::kStatus; if (IsHTMLParagraphElement(*GetNode())) - return kParagraphRole; + return ax::mojom::Role::kParagraph; if (IsHTMLLabelElement(*GetNode())) - return kLabelRole; + return ax::mojom::Role::kLabelText; if (IsHTMLLegendElement(*GetNode())) - return kLegendRole; + return ax::mojom::Role::kLegend; if (IsHTMLRubyElement(*GetNode())) - return kRubyRole; + return ax::mojom::Role::kRuby; if (IsHTMLDListElement(*GetNode())) - return kDescriptionListRole; + return ax::mojom::Role::kDescriptionList; if (IsHTMLAudioElement(*GetNode())) - return kAudioRole; + return ax::mojom::Role::kAudio; if (IsHTMLVideoElement(*GetNode())) - return kVideoRole; + return ax::mojom::Role::kVideo; if (GetNode()->HasTagName(ddTag)) - return kDescriptionListDetailRole; + return ax::mojom::Role::kDescriptionListDetail; if (GetNode()->HasTagName(dtTag)) - return kDescriptionListTermRole; + return ax::mojom::Role::kDescriptionListTerm; if (GetNode()->nodeName() == "math") - return kMathRole; + return ax::mojom::Role::kMath; if (GetNode()->HasTagName(rpTag) || GetNode()->HasTagName(rtTag)) - return kAnnotationRole; + return ax::mojom::Role::kAnnotation; if (IsHTMLFormElement(*GetNode())) - return kFormRole; + return ax::mojom::Role::kForm; if (GetNode()->HasTagName(abbrTag)) - return kAbbrRole; + return ax::mojom::Role::kAbbr; if (GetNode()->HasTagName(articleTag)) - return kArticleRole; + return ax::mojom::Role::kArticle; if (GetNode()->HasTagName(delTag)) - return kContentDeletionRole; + return ax::mojom::Role::kContentDeletion; if (GetNode()->HasTagName(insTag)) - return kContentInsertionRole; + return ax::mojom::Role::kContentInsertion; if (GetNode()->HasTagName(mainTag)) - return kMainRole; + return ax::mojom::Role::kMain; if (GetNode()->HasTagName(markTag)) - return kMarkRole; + return ax::mojom::Role::kMark; if (GetNode()->HasTagName(navTag)) - return kNavigationRole; + return ax::mojom::Role::kNavigation; if (GetNode()->HasTagName(asideTag)) - return kComplementaryRole; + return ax::mojom::Role::kComplementary; if (GetNode()->HasTagName(preTag)) - return kPreRole; + return ax::mojom::Role::kPre; if (GetNode()->HasTagName(sectionTag)) - return kRegionRole; + return ax::mojom::Role::kRegion; // TODO(accessibility): http://crbug.com/873118 if (GetNode()->HasTagName(addressTag)) - return kContentInfoRole; + return ax::mojom::Role::kContentInfo; if (IsHTMLDialogElement(*GetNode())) - return kDialogRole; + return ax::mojom::Role::kDialog; // The HTML element should not be exposed as an element. That's what the // LayoutView element does. if (IsHTMLHtmlElement(*GetNode())) - return kIgnoredRole; + return ax::mojom::Role::kIgnored; // Treat <iframe> and <frame> the same. if (IsHTMLIFrameElement(*GetNode()) || IsHTMLFrameElement(*GetNode())) { const AtomicString& aria_role = GetAOMPropertyOrARIAAttribute(AOMStringProperty::kRole); if (aria_role == "none" || aria_role == "presentation") - return kIframePresentationalRole; - return kIframeRole; + return ax::mojom::Role::kIframePresentational; + return ax::mojom::Role::kIframe; } // There should only be one banner/contentInfo per page. If header/footer are @@ -486,55 +492,57 @@ AccessibilityRole AXNodeObject::NativeAccessibilityRoleIgnoringAria() const { // whole page's banner/contentInfo but as a generic container role. if (GetNode()->HasTagName(headerTag)) { if (IsDescendantOfElementType(GetLandmarkRolesNotAllowed())) - return kGenericContainerRole; - return kBannerRole; + return ax::mojom::Role::kGenericContainer; + return ax::mojom::Role::kBanner; } if (GetNode()->HasTagName(footerTag)) { if (IsDescendantOfElementType(GetLandmarkRolesNotAllowed())) - return kGenericContainerRole; - return kFooterRole; + return ax::mojom::Role::kGenericContainer; + return ax::mojom::Role::kFooter; } if (GetNode()->HasTagName(blockquoteTag)) - return kBlockquoteRole; + return ax::mojom::Role::kBlockquote; if (GetNode()->HasTagName(captionTag)) - return kCaptionRole; + return ax::mojom::Role::kCaption; if (GetNode()->HasTagName(figcaptionTag)) - return kFigcaptionRole; + return ax::mojom::Role::kFigcaption; if (GetNode()->HasTagName(figureTag)) - return kFigureRole; + return ax::mojom::Role::kFigure; if (GetNode()->nodeName() == "TIME") - return kTimeRole; + return ax::mojom::Role::kTime; if (IsEmbeddedObject()) - return kEmbeddedObjectRole; + return ax::mojom::Role::kEmbeddedObject; if (IsHTMLHRElement(*GetNode())) - return kSplitterRole; + return ax::mojom::Role::kSplitter; if (IsFieldset()) - return kGroupRole; + return ax::mojom::Role::kGroup; - return kUnknownRole; + return ax::mojom::Role::kUnknown; } -AccessibilityRole AXNodeObject::DetermineAccessibilityRole() { +ax::mojom::Role AXNodeObject::DetermineAccessibilityRole() { if (!GetNode()) - return kUnknownRole; + return ax::mojom::Role::kUnknown; - native_role_ = NativeAccessibilityRoleIgnoringAria(); + native_role_ = NativeRoleIgnoringAria(); - if ((aria_role_ = DetermineAriaRoleAttribute()) != kUnknownRole) + if ((aria_role_ = DetermineAriaRoleAttribute()) != ax::mojom::Role::kUnknown) return aria_role_; if (GetNode()->IsTextNode()) - return kStaticTextRole; + return ax::mojom::Role::kStaticText; - return native_role_ == kUnknownRole ? kGenericContainerRole : native_role_; + return native_role_ == ax::mojom::Role::kUnknown + ? ax::mojom::Role::kGenericContainer + : native_role_; } void AXNodeObject::AccessibilityChildrenFromAOMProperty( @@ -563,8 +571,9 @@ bool AXNodeObject::IsMultiline() const { if (!node) return false; - const AccessibilityRole role = RoleValue(); - const bool is_edit_box = role == kSearchBoxRole || role == kTextFieldRole; + const ax::mojom::Role role = RoleValue(); + const bool is_edit_box = role == ax::mojom::Role::kSearchBox || + role == ax::mojom::Role::kTextField; if (!IsEditable() && !is_edit_box) return false; // Doesn't support multiline. @@ -609,11 +618,11 @@ bool AXNodeObject::IsTextControl() const { return true; switch (RoleValue()) { - case kTextFieldRole: - case kTextFieldWithComboBoxRole: - case kSearchBoxRole: + case ax::mojom::Role::kTextField: + case ax::mojom::Role::kTextFieldWithComboBox: + case ax::mojom::Role::kSearchBox: return true; - case kSpinButtonRole: + case ax::mojom::Role::kSpinButton: // When it's a native spin button, it behaves like a text box, i.e. users // can type in it and navigate around using cursors. if (const auto* input = ToHTMLInputElementOrNull(*GetNode())) { @@ -669,7 +678,7 @@ static Element* SiblingWithAriaRole(String role, Node* node) { } Element* AXNodeObject::MenuItemElementForMenu() const { - if (AriaRoleAttribute() != kMenuRole) + if (AriaRoleAttribute() != ax::mojom::Role::kMenu) return nullptr; return SiblingWithAriaRole("menuitem", GetNode()); @@ -757,7 +766,7 @@ bool AXNodeObject::IsFieldset() const { } bool AXNodeObject::IsHeading() const { - return RoleValue() == kHeadingRole; + return RoleValue() == ax::mojom::Role::kHeading; } bool AXNodeObject::IsHovered() const { @@ -767,7 +776,7 @@ bool AXNodeObject::IsHovered() const { } bool AXNodeObject::IsImage() const { - return RoleValue() == kImageRole; + return RoleValue() == ax::mojom::Role::kImage; } bool AXNodeObject::IsImageButton() const { @@ -776,14 +785,14 @@ bool AXNodeObject::IsImageButton() const { bool AXNodeObject::IsInputImage() const { Node* node = this->GetNode(); - if (RoleValue() == kButtonRole && IsHTMLInputElement(node)) + if (RoleValue() == ax::mojom::Role::kButton && IsHTMLInputElement(node)) return ToHTMLInputElement(*node).type() == InputTypeNames::image; return false; } bool AXNodeObject::IsLink() const { - return RoleValue() == kLinkRole; + return RoleValue() == ax::mojom::Role::kLink; } // It is not easily possible to find out if an element is the target of an @@ -810,24 +819,24 @@ bool AXNodeObject::IsInPageLinkTarget() const { } bool AXNodeObject::IsMenu() const { - return RoleValue() == kMenuRole; + return RoleValue() == ax::mojom::Role::kMenu; } bool AXNodeObject::IsMenuButton() const { - return RoleValue() == kMenuButtonRole; + return RoleValue() == ax::mojom::Role::kMenuButton; } bool AXNodeObject::IsMeter() const { - return RoleValue() == kMeterRole; + return RoleValue() == ax::mojom::Role::kMeter; } bool AXNodeObject::IsMultiSelectable() const { switch (RoleValue()) { - case kGridRole: - case kTreeGridRole: - case kTreeRole: - case kListBoxRole: - case kTabListRole: { + case ax::mojom::Role::kGrid: + case ax::mojom::Role::kTreeGrid: + case ax::mojom::Role::kTree: + case ax::mojom::Role::kListBox: + case ax::mojom::Role::kTabList: { bool multiselectable = false; if (HasAOMPropertyOrARIAAttribute(AOMBooleanProperty::kMultiselectable, multiselectable)) { @@ -900,15 +909,16 @@ bool AXNodeObject::IsPasswordField() const { if (!IsHTMLInputElement(node)) return false; - AccessibilityRole aria_role = AriaRoleAttribute(); - if (aria_role != kTextFieldRole && aria_role != kUnknownRole) + ax::mojom::Role aria_role = AriaRoleAttribute(); + if (aria_role != ax::mojom::Role::kTextField && + aria_role != ax::mojom::Role::kUnknown) return false; return ToHTMLInputElement(node)->type() == InputTypeNames::password; } bool AXNodeObject::IsProgressIndicator() const { - return RoleValue() == kProgressIndicatorRole; + return RoleValue() == ax::mojom::Role::kProgressIndicator; } bool AXNodeObject::IsRichlyEditable() const { @@ -916,11 +926,11 @@ bool AXNodeObject::IsRichlyEditable() const { } bool AXNodeObject::IsSlider() const { - return RoleValue() == kSliderRole; + return RoleValue() == ax::mojom::Role::kSlider; } bool AXNodeObject::IsSpinButton() const { - return RoleValue() == kSpinButtonRole; + return RoleValue() == ax::mojom::Role::kSpinButton; } bool AXNodeObject::IsNativeSlider() const { @@ -936,7 +946,7 @@ bool AXNodeObject::IsNativeSpinButton() const { } bool AXNodeObject::IsMoveableSplitter() const { - return RoleValue() == kSplitterRole && CanSetFocusAttribute(); + return RoleValue() == ax::mojom::Role::kSplitter && CanSetFocusAttribute(); } bool AXNodeObject::IsClickable() const { @@ -1007,8 +1017,9 @@ AXRestriction AXNodeObject::Restriction() const { AXObject* row = ParentObjectUnignored(); if (row->IsTableRowLikeRole()) { AXObject* table = row->ParentObjectUnignored(); - if (table->IsTableLikeRole() && (table->RoleValue() == kGridRole || - table->RoleValue() == kTreeGridRole)) { + if (table->IsTableLikeRole() && + (table->RoleValue() == ax::mojom::Role::kGrid || + table->RoleValue() == ax::mojom::Role::kTreeGrid)) { if (table->Restriction() == kReadOnly) return kReadOnly; } @@ -1040,7 +1051,8 @@ AccessibilityExpanded AXNodeObject::IsExpanded() const { } bool AXNodeObject::IsModal() const { - if (RoleValue() != kDialogRole && RoleValue() != kAlertDialogRole) + if (RoleValue() != ax::mojom::Role::kDialog && + RoleValue() != ax::mojom::Role::kAlertDialog) return false; bool modal = false; @@ -1078,7 +1090,7 @@ int AXNodeObject::HeadingLevel() const { if (!node) return 0; - if (RoleValue() == kHeadingRole) { + if (RoleValue() == ax::mojom::Role::kHeading) { uint32_t level; if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kLevel, level)) { if (level >= 1 && level <= 9) @@ -1108,7 +1120,7 @@ int AXNodeObject::HeadingLevel() const { if (element.HasTagName(h6Tag)) return 6; - if (RoleValue() == kHeadingRole) + if (RoleValue() == ax::mojom::Role::kHeading) return kDefaultHeadingLevel; return 0; @@ -1126,7 +1138,7 @@ unsigned AXNodeObject::HierarchicalLevel() const { } // Only tree item will calculate its level through the DOM currently. - if (RoleValue() != kTreeItemRole) + if (RoleValue() != ax::mojom::Role::kTreeItem) return 0; // Hierarchy leveling starts at 1, to match the aria-level spec. @@ -1134,10 +1146,10 @@ unsigned AXNodeObject::HierarchicalLevel() const { level = 1; for (AXObject* parent = ParentObject(); parent; parent = parent->ParentObject()) { - AccessibilityRole parent_role = parent->RoleValue(); - if (parent_role == kGroupRole) + ax::mojom::Role parent_role = parent->RoleValue(); + if (parent_role == ax::mojom::Role::kGroup) level++; - else if (parent_role == kTreeRole) + else if (parent_role == ax::mojom::Role::kTree) break; } @@ -1187,14 +1199,23 @@ void AXNodeObject::Markers(Vector<DocumentMarker::MarkerType>& marker_types, DocumentMarkerController& marker_controller = GetDocument()->Markers(); DocumentMarkerVector markers = marker_controller.MarkersFor(ToText(*GetNode())); - for (size_t i = 0; i < markers.size(); ++i) { - DocumentMarker* marker = markers[i]; - if (MarkerTypeIsUsedForAccessibility(marker->GetType())) { - marker_types.push_back(marker->GetType()); - marker_ranges.emplace_back( - AXPosition::CreatePositionInTextObject(*this, marker->StartOffset()), - AXPosition::CreatePositionInTextObject(*this, marker->EndOffset())); + for (DocumentMarker* marker : markers) { + if (!MarkerTypeIsUsedForAccessibility(marker->GetType())) + continue; + + const Position start_position(*GetNode(), marker->StartOffset()); + const Position end_position(*GetNode(), marker->EndOffset()); + if (!start_position.IsValidFor(*GetDocument()) || + !end_position.IsValidFor(*GetDocument())) { + continue; } + + marker_types.push_back(marker->GetType()); + marker_ranges.emplace_back( + AXPosition::FromPosition(start_position, TextAffinity::kDownstream, + AXPositionAdjustmentBehavior::kMoveLeft), + AXPosition::FromPosition(end_position, TextAffinity::kDownstream, + AXPositionAdjustmentBehavior::kMoveRight)); } } @@ -1236,27 +1257,27 @@ AccessibilityOrientation AXNodeObject::Orientation() const { orientation = kAccessibilityOrientationVertical; switch (RoleValue()) { - case kListBoxRole: - case kMenuRole: - case kScrollBarRole: - case kTreeRole: + case ax::mojom::Role::kListBox: + case ax::mojom::Role::kMenu: + case ax::mojom::Role::kScrollBar: + case ax::mojom::Role::kTree: if (orientation == kAccessibilityOrientationUndefined) orientation = kAccessibilityOrientationVertical; return orientation; - case kMenuBarRole: - case kSliderRole: - case kSplitterRole: - case kTabListRole: - case kToolbarRole: + case ax::mojom::Role::kMenuBar: + case ax::mojom::Role::kSlider: + case ax::mojom::Role::kSplitter: + case ax::mojom::Role::kTabList: + case ax::mojom::Role::kToolbar: if (orientation == kAccessibilityOrientationUndefined) orientation = kAccessibilityOrientationHorizontal; return orientation; - case kComboBoxGroupingRole: - case kComboBoxMenuButtonRole: - case kRadioGroupRole: - case kTreeGridRole: + case ax::mojom::Role::kComboBoxGrouping: + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kRadioGroup: + case ax::mojom::Role::kTreeGrid: return orientation; default: return AXObject::Orientation(); @@ -1265,15 +1286,14 @@ AccessibilityOrientation AXNodeObject::Orientation() const { AXObject::AXObjectVector AXNodeObject::RadioButtonsInGroup() const { AXObjectVector radio_buttons; - if (!node_ || RoleValue() != kRadioButtonRole) + if (!node_ || RoleValue() != ax::mojom::Role::kRadioButton) return radio_buttons; if (auto* radio_button = ToHTMLInputElementOrNull(node_)) { HeapVector<Member<HTMLInputElement>> html_radio_buttons = FindAllRadioButtonsWithSameName(radio_button); - for (size_t i = 0; i < html_radio_buttons.size(); ++i) { - AXObject* ax_radio_button = - AXObjectCache().GetOrCreate(html_radio_buttons[i]); + for (HTMLInputElement* radio_button : html_radio_buttons) { + AXObject* ax_radio_button = AXObjectCache().GetOrCreate(radio_button); if (ax_radio_button) radio_buttons.push_back(ax_radio_button); } @@ -1283,11 +1303,10 @@ AXObject::AXObjectVector AXNodeObject::RadioButtonsInGroup() const { // If the immediate parent is a radio group, return all its children that are // radio buttons. AXObject* parent = ParentObject(); - if (parent && parent->RoleValue() == kRadioGroupRole) { - for (size_t i = 0; i < parent->Children().size(); ++i) { - AXObject* child = parent->Children()[i]; + if (parent && parent->RoleValue() == ax::mojom::Role::kRadioGroup) { + for (AXObject* child : parent->Children()) { DCHECK(child); - if (child->RoleValue() == kRadioButtonRole && + if (child->RoleValue() == ax::mojom::Role::kRadioButton && !child->AccessibilityIsIgnored()) { radio_buttons.push_back(child); } @@ -1358,47 +1377,47 @@ RGBA32 AXNodeObject::ColorValue() const { return color.Rgb(); } -AriaCurrentState AXNodeObject::GetAriaCurrentState() const { +ax::mojom::AriaCurrentState AXNodeObject::GetAriaCurrentState() const { const AtomicString& attribute_value = GetAOMPropertyOrARIAAttribute(AOMStringProperty::kCurrent); if (attribute_value.IsNull()) - return kAriaCurrentStateUndefined; + return ax::mojom::AriaCurrentState::kNone; if (attribute_value.IsEmpty() || EqualIgnoringASCIICase(attribute_value, "false")) - return kAriaCurrentStateFalse; + return ax::mojom::AriaCurrentState::kFalse; if (EqualIgnoringASCIICase(attribute_value, "true")) - return kAriaCurrentStateTrue; + return ax::mojom::AriaCurrentState::kTrue; if (EqualIgnoringASCIICase(attribute_value, "page")) - return kAriaCurrentStatePage; + return ax::mojom::AriaCurrentState::kPage; if (EqualIgnoringASCIICase(attribute_value, "step")) - return kAriaCurrentStateStep; + return ax::mojom::AriaCurrentState::kStep; if (EqualIgnoringASCIICase(attribute_value, "location")) - return kAriaCurrentStateLocation; + return ax::mojom::AriaCurrentState::kLocation; if (EqualIgnoringASCIICase(attribute_value, "date")) - return kAriaCurrentStateDate; + return ax::mojom::AriaCurrentState::kDate; if (EqualIgnoringASCIICase(attribute_value, "time")) - return kAriaCurrentStateTime; + return ax::mojom::AriaCurrentState::kTime; // An unknown value should return true. if (!attribute_value.IsEmpty()) - return kAriaCurrentStateTrue; + return ax::mojom::AriaCurrentState::kTrue; return AXObject::GetAriaCurrentState(); } -InvalidState AXNodeObject::GetInvalidState() const { +ax::mojom::InvalidState AXNodeObject::GetInvalidState() const { const AtomicString& attribute_value = GetAOMPropertyOrARIAAttribute(AOMStringProperty::kInvalid); if (EqualIgnoringASCIICase(attribute_value, "false")) - return kInvalidStateFalse; + return ax::mojom::InvalidState::kFalse; if (EqualIgnoringASCIICase(attribute_value, "true")) - return kInvalidStateTrue; + return ax::mojom::InvalidState::kTrue; if (EqualIgnoringASCIICase(attribute_value, "spelling")) - return kInvalidStateSpelling; + return ax::mojom::InvalidState::kSpelling; if (EqualIgnoringASCIICase(attribute_value, "grammar")) - return kInvalidStateGrammar; + return ax::mojom::InvalidState::kGrammar; // A yet unknown value. if (!attribute_value.IsEmpty()) - return kInvalidStateOther; + return ax::mojom::InvalidState::kOther; if (GetNode() && GetNode()->IsElementNode() && ToElement(GetNode())->IsFormControlElement()) { @@ -1406,7 +1425,8 @@ InvalidState AXNodeObject::GetInvalidState() const { HeapVector<Member<HTMLFormControlElement>> invalid_controls; bool is_invalid = !element->checkValidity(&invalid_controls, kCheckValidityDispatchNoEvent); - return is_invalid ? kInvalidStateTrue : kInvalidStateFalse; + return is_invalid ? ax::mojom::InvalidState::kTrue + : ax::mojom::InvalidState::kFalse; } return AXObject::GetInvalidState(); @@ -1447,14 +1467,15 @@ int AXNodeObject::AutoPosInSet() const { int pos_in_set = 1; const AXObject::AXObjectVector siblings = parent->Children(); - AccessibilityRole role = RoleValue(); + ax::mojom::Role role = RoleValue(); int level = HierarchicalLevel(); int index_in_parent = IndexInParent(); for (int index = index_in_parent - 1; index >= 0; index--) { const AXObject* sibling = siblings[index]; - AccessibilityRole sibling_role = sibling->RoleValue(); - if (sibling_role == kSplitterRole || sibling_role == kGroupRole) + ax::mojom::Role sibling_role = sibling->RoleValue(); + if (sibling_role == ax::mojom::Role::kSplitter || + sibling_role == ax::mojom::Role::kGroup) break; // Set stops at a separator or an optgroup. if (sibling_role != role || sibling->AccessibilityIsIgnored()) continue; @@ -1483,15 +1504,16 @@ int AXNodeObject::AutoSetSize() const { int set_size = AutoPosInSet(); auto siblings = parent->Children(); - AccessibilityRole role = RoleValue(); + ax::mojom::Role role = RoleValue(); int level = HierarchicalLevel(); int index_in_parent = IndexInParent(); int sibling_count = siblings.size(); for (int index = index_in_parent + 1; index < sibling_count; index++) { const auto sibling = siblings[index]; - AccessibilityRole sibling_role = sibling->RoleValue(); - if (sibling_role == kSplitterRole || sibling_role == kGroupRole) + ax::mojom::Role sibling_role = sibling->RoleValue(); + if (sibling_role == ax::mojom::Role::kSplitter || + sibling_role == ax::mojom::Role::kGroup) break; // Set stops at a separator or an optgroup. if (sibling_role != role || sibling->AccessibilityIsIgnored()) continue; @@ -1510,7 +1532,7 @@ int AXNodeObject::AutoSetSize() const { } String AXNodeObject::AriaInvalidValue() const { - if (GetInvalidState() == kInvalidStateOther) + if (GetInvalidState() == ax::mojom::InvalidState::kOther) return GetAOMPropertyOrARIAAttribute(AOMStringProperty::kInvalid); return String(); @@ -1546,8 +1568,8 @@ bool AXNodeObject::ValueForRange(float* out_value) const { // - separator : 50 // - spinbutton : 0 switch (AriaRoleAttribute()) { - case kScrollBarRole: - case kSliderRole: { + case ax::mojom::Role::kScrollBar: + case ax::mojom::Role::kSlider: { float min_value, max_value; if (MinValueForRange(&min_value) && MaxValueForRange(&max_value)) { *out_value = (min_value + max_value) / 2.0f; @@ -1555,11 +1577,11 @@ bool AXNodeObject::ValueForRange(float* out_value) const { } FALLTHROUGH; } - case kSplitterRole: { + case ax::mojom::Role::kSplitter: { *out_value = 50.0f; return true; } - case kSpinButtonRole: { + case ax::mojom::Role::kSpinButton: { *out_value = 0.0f; return true; } @@ -1590,9 +1612,9 @@ bool AXNodeObject::MaxValueForRange(float* out_value) const { // In ARIA 1.1, default value of scrollbar, separator and slider // for aria-valuemax were changed to 100. switch (AriaRoleAttribute()) { - case kScrollBarRole: - case kSplitterRole: - case kSliderRole: { + case ax::mojom::Role::kScrollBar: + case ax::mojom::Role::kSplitter: + case ax::mojom::Role::kSlider: { *out_value = 100.0f; return true; } @@ -1623,9 +1645,9 @@ bool AXNodeObject::MinValueForRange(float* out_value) const { // In ARIA 1.1, default value of scrollbar, separator and slider // for aria-valuemin were changed to 0. switch (AriaRoleAttribute()) { - case kScrollBarRole: - case kSplitterRole: - case kSliderRole: { + case ax::mojom::Role::kScrollBar: + case ax::mojom::Role::kSplitter: + case ax::mojom::Role::kSlider: { *out_value = 0.0f; return true; } @@ -1645,9 +1667,9 @@ bool AXNodeObject::StepValueForRange(float* out_value) const { } switch (AriaRoleAttribute()) { - case kScrollBarRole: - case kSplitterRole: - case kSliderRole: { + case ax::mojom::Role::kScrollBar: + case ax::mojom::Role::kSplitter: + case ax::mojom::Role::kSlider: { *out_value = 0.0f; return true; } @@ -1668,7 +1690,7 @@ String AXNodeObject::StringValue() const { const HeapVector<Member<HTMLElement>>& list_items = select_element->GetListItems(); if (selected_index >= 0 && - static_cast<size_t>(selected_index) < list_items.size()) { + static_cast<wtf_size_t>(selected_index) < list_items.size()) { const AtomicString& overridden_description = list_items[selected_index]->FastGetAttribute(aria_labelAttr); if (!overridden_description.IsNull()) @@ -1701,7 +1723,7 @@ String AXNodeObject::StringValue() const { return String(); } -AccessibilityRole AXNodeObject::AriaRoleAttribute() const { +ax::mojom::Role AXNodeObject::AriaRoleAttribute() const { return aria_role_; } @@ -1737,10 +1759,10 @@ static bool IsInSameNonInlineBlockFlow(LayoutObject* r1, LayoutObject* r2) { // New AX name calculation. // -String AXNodeObject::GetName(AXNameFrom& name_from, +String AXNodeObject::GetName(ax::mojom::NameFrom& name_from, AXObjectVector* name_objects) const { String name = AXObject::GetName(name_from, name_objects); - if (RoleValue() == kSpinButtonRole && DatetimeAncestor()) { + if (RoleValue() == ax::mojom::Role::kSpinButton && DatetimeAncestor()) { // Fields inside a datetime control need to merge the field name with // the name of the <input> element. name_objects->clear(); @@ -1755,7 +1777,7 @@ String AXNodeObject::GetName(AXNameFrom& name_from, String AXNodeObject::TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom& name_from, + ax::mojom::NameFrom& name_from, AXRelatedObjectVector* related_objects, NameSources* name_sources) const { // If nameSources is non-null, relatedObjects is used in filling it in, so it @@ -1793,13 +1815,28 @@ String AXNodeObject::TextAlternative(bool recursive, return StringValue(); } + // Step 2E from: http://www.w3.org/TR/accname-aam-1.1 + // "If the embedded control has role combobox or listbox, return the text + // alternative of the chosen option." + if (NameFromSelectedOption(recursive)) { + StringBuilder accumulated_text; + AXObjectVector selected_options; + SelectedOptions(selected_options); + for (const auto& child : selected_options) { + if (accumulated_text.length()) + accumulated_text.Append(" "); + accumulated_text.Append(child->ComputedName()); + } + return accumulated_text.ToString(); + } + // Step 2D from: http://www.w3.org/TR/accname-aam-1.1 text_alternative = NativeTextAlternative(visited, name_from, related_objects, name_sources, &found_text_alternative); const bool has_text_alternative = !text_alternative.IsEmpty() || - name_from == kAXNameFromAttributeExplicitlyEmpty; + name_from == ax::mojom::NameFrom::kAttributeExplicitlyEmpty; if (has_text_alternative && !name_sources) return text_alternative; @@ -1807,7 +1844,7 @@ String AXNodeObject::TextAlternative(bool recursive, if (in_aria_labelled_by_traversal || NameFromContents(recursive)) { Node* node = GetNode(); if (!IsHTMLSelectElement(node)) { // Avoid option descendant text - name_from = kAXNameFromContents; + name_from = ax::mojom::NameFrom::kContents; if (name_sources) { name_sources->push_back(NameSource(found_text_alternative)); name_sources->back().type = name_from; @@ -1832,7 +1869,7 @@ String AXNodeObject::TextAlternative(bool recursive, } // Step 2H from: http://www.w3.org/TR/accname-aam-1.1 - name_from = kAXNameFromTitle; + name_from = ax::mojom::NameFrom::kTitle; if (name_sources) { name_sources->push_back(NameSource(found_text_alternative, titleAttr)); name_sources->back().type = name_from; @@ -1840,6 +1877,7 @@ String AXNodeObject::TextAlternative(bool recursive, const AtomicString& title = GetAttribute(titleAttr); if (!title.IsEmpty()) { text_alternative = title; + name_from = ax::mojom::NameFrom::kTitle; if (name_sources) { found_text_alternative = true; name_sources->back().text = text_alternative; @@ -1848,12 +1886,11 @@ String AXNodeObject::TextAlternative(bool recursive, } } - name_from = kAXNameFromUninitialized; + name_from = ax::mojom::NameFrom::kUninitialized; if (name_sources && found_text_alternative) { - for (size_t i = 0; i < name_sources->size(); ++i) { - if (!(*name_sources)[i].text.IsNull() && !(*name_sources)[i].superseded) { - NameSource& name_source = (*name_sources)[i]; + for (NameSource& name_source : *name_sources) { + if (!name_source.text.IsNull() && !name_source.superseded) { name_from = name_source.type; if (!name_source.related_objects.IsEmpty()) *related_objects = name_source.related_objects; @@ -1865,6 +1902,59 @@ String AXNodeObject::TextAlternative(bool recursive, return String(); } +static bool ShouldInsertSpaceBetweenObjectsIfNeeded( + AXObject* previous, + AXObject* next, + ax::mojom::NameFrom last_used_name_from, + ax::mojom::NameFrom name_from) { + // If we're going between two layoutObjects that are in separate + // LayoutBoxes, add whitespace if it wasn't there already. Intuitively if + // you have <span>Hello</span><span>World</span>, those are part of the same + // LayoutBox so we should return "HelloWorld", but given + // <div>Hello</div><div>World</div> the strings are in separate boxes so we + // should return "Hello World". + if (!IsInSameNonInlineBlockFlow(next->GetLayoutObject(), + previous->GetLayoutObject())) + return true; + + // Even if it is in the same inline block flow, if we are using a text + // alternative such as an ARIA label or HTML title, we should separate + // the strings. Doing so is consistent with what is stated in the AccName + // spec and with what is done in other user agents. + switch (last_used_name_from) { + case ax::mojom::NameFrom::kNone: + case ax::mojom::NameFrom::kUninitialized: + case ax::mojom::NameFrom::kAttributeExplicitlyEmpty: + case ax::mojom::NameFrom::kContents: + break; + case ax::mojom::NameFrom::kAttribute: + case ax::mojom::NameFrom::kCaption: + case ax::mojom::NameFrom::kPlaceholder: + case ax::mojom::NameFrom::kRelatedElement: + case ax::mojom::NameFrom::kTitle: + case ax::mojom::NameFrom::kValue: + return true; + } + switch (name_from) { + case ax::mojom::NameFrom::kNone: + case ax::mojom::NameFrom::kUninitialized: + case ax::mojom::NameFrom::kAttributeExplicitlyEmpty: + case ax::mojom::NameFrom::kContents: + break; + case ax::mojom::NameFrom::kAttribute: + case ax::mojom::NameFrom::kCaption: + case ax::mojom::NameFrom::kPlaceholder: + case ax::mojom::NameFrom::kRelatedElement: + case ax::mojom::NameFrom::kTitle: + case ax::mojom::NameFrom::kValue: + return true; + } + + // According to the AccName spec, we need to separate controls from text nodes + // using a space. + return previous->IsControl() || next->IsControl(); +} + String AXNodeObject::TextFromDescendants(AXObjectSet& visited, bool recursive) const { if (!CanHaveChildren() && recursive) @@ -1872,6 +1962,7 @@ String AXNodeObject::TextFromDescendants(AXObjectSet& visited, StringBuilder accumulated_text; AXObject* previous = nullptr; + ax::mojom::NameFrom last_used_name_from = ax::mojom::NameFrom::kUninitialized; AXObjectVector children; @@ -1893,26 +1984,39 @@ String AXNodeObject::TextFromDescendants(AXObjectSet& visited, if (child->AOMPropertyOrARIAAttributeIsTrue(AOMBooleanProperty::kHidden)) continue; - // If we're going between two layoutObjects that are in separate - // LayoutBoxes, add whitespace if it wasn't there already. Intuitively if - // you have <span>Hello</span><span>World</span>, those are part of the same - // LayoutBox so we should return "HelloWorld", but given - // <div>Hello</div><div>World</div> the strings are in separate boxes so we - // should return "Hello World". - if (previous && accumulated_text.length() && - !IsHTMLSpace(accumulated_text[accumulated_text.length() - 1])) { - if (!IsInSameNonInlineBlockFlow(child->GetLayoutObject(), - previous->GetLayoutObject())) + ax::mojom::NameFrom child_name_from = ax::mojom::NameFrom::kUninitialized; + String result; + if (child->IsPresentational()) { + result = child->TextFromDescendants(visited, true); + } else { + result = + RecursiveTextAlternative(*child, false, visited, child_name_from); + } + + if (!result.IsEmpty() && previous && accumulated_text.length() && + !IsHTMLSpace(accumulated_text[accumulated_text.length() - 1]) && + !IsHTMLSpace(result[0])) { + if (ShouldInsertSpaceBetweenObjectsIfNeeded( + previous, child, last_used_name_from, child_name_from)) { accumulated_text.Append(' '); + } } - String result; - if (child->IsPresentational()) - result = child->TextFromDescendants(visited, true); - else - result = RecursiveTextAlternative(*child, false, visited); accumulated_text.Append(result); + + // We keep track of all non-hidden children, even those whose content is + // not included, because all rendered children impact whether or not a + // space should be inserted between objects. Example: A label which has + // a single, nameless input surrounded by CSS-generated content should + // have a space separating the before and after content. previous = child; + + // We only keep track of the source of children whose content is included. + // Example: Three spans, the first with an aria-label, the second with no + // content, and the third whose name comes from content. There should be a + // space between the first and third because of the aria-label in the first. + if (!result.IsEmpty()) + last_used_name_from = child_name_from; } return accumulated_text.ToString(); @@ -2134,8 +2238,8 @@ void AXNodeObject::InsertChild(AXObject* child, unsigned index) { if (child->AccessibilityIsIgnored()) { const auto& children = child->Children(); - size_t length = children.size(); - for (size_t i = 0; i < length; ++i) + wtf_size_t length = children.size(); + for (wtf_size_t i = 0; i < length; ++i) children_.insert(index + i, children[i]); } else { DCHECK_EQ(child->ParentObject(), this); @@ -2166,55 +2270,55 @@ bool AXNodeObject::CanHaveChildren() const { } switch (native_role_) { - case kButtonRole: - case kCheckBoxRole: - case kImageRole: - case kListBoxOptionRole: - case kMenuButtonRole: - case kMenuListOptionRole: - case kMenuItemRole: - case kMenuItemCheckBoxRole: - case kMenuItemRadioRole: - case kProgressIndicatorRole: - case kRadioButtonRole: - case kScrollBarRole: - // case kSearchBoxRole: - case kSliderRole: - case kSplitterRole: - case kSwitchRole: - case kTabRole: - // case kTextFieldRole: - case kToggleButtonRole: + case ax::mojom::Role::kButton: + case ax::mojom::Role::kCheckBox: + case ax::mojom::Role::kImage: + case ax::mojom::Role::kListBoxOption: + case ax::mojom::Role::kMenuButton: + case ax::mojom::Role::kMenuListOption: + case ax::mojom::Role::kMenuItem: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kProgressIndicator: + case ax::mojom::Role::kRadioButton: + case ax::mojom::Role::kScrollBar: + // case ax::mojom::Role::kSearchBox: + case ax::mojom::Role::kSlider: + case ax::mojom::Role::kSplitter: + case ax::mojom::Role::kSwitch: + case ax::mojom::Role::kTab: + // case ax::mojom::Role::kTextField: + case ax::mojom::Role::kToggleButton: return false; - case kPopUpButtonRole: + case ax::mojom::Role::kPopUpButton: return true; - case kStaticTextRole: + case ax::mojom::Role::kStaticText: return AXObjectCache().InlineTextBoxAccessibilityEnabled(); default: break; } switch (AriaRoleAttribute()) { - case kImageRole: + case ax::mojom::Role::kImage: return false; - case kButtonRole: - case kCheckBoxRole: - case kListBoxOptionRole: - case kMathRole: // role="math" is flat, unlike <math> - case kMenuButtonRole: - case kMenuListOptionRole: - case kMenuItemRole: - case kMenuItemCheckBoxRole: - case kMenuItemRadioRole: - case kPopUpButtonRole: - case kProgressIndicatorRole: - case kRadioButtonRole: - case kScrollBarRole: - case kSliderRole: - case kSplitterRole: - case kSwitchRole: - case kTabRole: - case kToggleButtonRole: { + case ax::mojom::Role::kButton: + case ax::mojom::Role::kCheckBox: + case ax::mojom::Role::kListBoxOption: + case ax::mojom::Role::kMath: // role="math" is flat, unlike <math> + case ax::mojom::Role::kMenuButton: + case ax::mojom::Role::kMenuListOption: + case ax::mojom::Role::kMenuItem: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kPopUpButton: + case ax::mojom::Role::kProgressIndicator: + case ax::mojom::Role::kRadioButton: + case ax::mojom::Role::kScrollBar: + case ax::mojom::Role::kSlider: + case ax::mojom::Role::kSplitter: + case ax::mojom::Role::kSwitch: + case ax::mojom::Role::kTab: + case ax::mojom::Role::kToggleButton: { // These roles have ChildrenPresentational: true in the ARIA spec. // We used to remove/prune all descendants of them, but that removed // useful content if the author didn't follow the spec perfectly, for @@ -2354,7 +2458,7 @@ bool AXNodeObject::OnNativeFocusAction() { bool AXNodeObject::OnNativeIncrementAction() { LocalFrame* frame = GetDocument() ? GetDocument()->GetFrame() : nullptr; std::unique_ptr<UserGestureIndicator> gesture_indicator = - Frame::NotifyUserActivation(frame, UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(frame, UserGestureToken::kNewGesture); AlterSliderOrSpinButtonValue(true); return true; } @@ -2362,7 +2466,7 @@ bool AXNodeObject::OnNativeIncrementAction() { bool AXNodeObject::OnNativeDecrementAction() { LocalFrame* frame = GetDocument() ? GetDocument()->GetFrame() : nullptr; std::unique_ptr<UserGestureIndicator> gesture_indicator = - Frame::NotifyUserActivation(frame, UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(frame, UserGestureToken::kNewGesture); AlterSliderOrSpinButtonValue(false); return true; } @@ -2408,7 +2512,7 @@ void AXNodeObject::ChildrenChanged() { if (IsDetached()) return; - AXObjectCache().PostNotification(this, AXObjectCacheImpl::kAXChildrenChanged); + AXObjectCache().PostNotification(this, ax::mojom::Event::kChildrenChanged); // Go up the accessibility parent chain, but only if the element already // exists. This method is called during layout, minimal work should be done. @@ -2424,16 +2528,16 @@ void AXNodeObject::ChildrenChanged() { // If this element supports ARIA live regions, then notify the AT of // changes. - if (parent->IsLiveRegion()) + if (parent->IsLiveRegion()) { AXObjectCache().PostNotification(parent, - AXObjectCacheImpl::kAXLiveRegionChanged); + ax::mojom::Event::kLiveRegionChanged); + } // If this element is an ARIA text box or content editable, post a "value // changed" notification on it so that it behaves just like a native input // element or textarea. if (IsNonNativeTextControl()) - AXObjectCache().PostNotification(parent, - AXObjectCacheImpl::kAXValueChanged); + AXObjectCache().PostNotification(parent, ax::mojom::Event::kValueChanged); } } @@ -2444,17 +2548,47 @@ void AXNodeObject::UpdateChildrenIfNecessary() { AXObject::UpdateChildrenIfNecessary(); } +void AXNodeObject::SelectedOptions(AXObjectVector& options) const { + if (IsHTMLSelectElement(GetNode())) { + HTMLSelectElement* select = ToHTMLSelectElement(GetNode()); + for (auto* const option : *select->selectedOptions()) { + options.push_back(AXObjectCache().GetOrCreate(option)); + } + return; + } + + // If the combobox or listbox is a descendant of a label element for another + // widget, it may be ignored and Children() won't return all its children. + // As a result, we need to use RawFirstChild and RawNextSibling to iterate + // over the children in search of the selected option(s). + + if (RoleValue() == ax::mojom::Role::kComboBoxGrouping || + RoleValue() == ax::mojom::Role::kComboBoxMenuButton) { + for (AXObject* obj = RawFirstChild(); obj; obj = obj->RawNextSibling()) { + if (obj->RoleValue() == ax::mojom::Role::kListBox) { + obj->SelectedOptions(options); + return; + } + } + } + + for (AXObject* obj = RawFirstChild(); obj; obj = obj->RawNextSibling()) { + if (obj->IsSelected() == kSelectedStateTrue) + options.push_back(obj); + } +} + void AXNodeObject::SelectionChanged() { // Post the selected text changed event on the first ancestor that's // focused (to handle form controls, ARIA text boxes and contentEditable), // or the web area if the selection is just in the document somewhere. if (IsFocused() || IsWebArea()) { AXObjectCache().PostNotification(this, - AXObjectCacheImpl::kAXSelectedTextChanged); + ax::mojom::Event::kTextSelectionChanged); if (GetDocument()) { AXObject* document_object = AXObjectCache().GetOrCreate(GetDocument()); AXObjectCache().PostNotification( - document_object, AXObjectCacheImpl::kAXDocumentSelectionChanged); + document_object, ax::mojom::Event::kDocumentSelectionChanged); } } else { AXObject::SelectionChanged(); // Calls selectionChanged on parent. @@ -2472,14 +2606,13 @@ void AXNodeObject::TextChanged() { continue; if (parent->IsLiveRegion()) - cache.PostNotification(parent_node, - AXObjectCacheImpl::kAXLiveRegionChanged); + cache.PostNotification(parent_node, ax::mojom::Event::kLiveRegionChanged); // If this element is an ARIA text box or content editable, post a "value // changed" notification on it so that it behaves just like a native input // element or textarea. if (parent->IsNonNativeTextControl()) - cache.PostNotification(parent_node, AXObjectCacheImpl::kAXValueChanged); + cache.PostNotification(parent_node, ax::mojom::Event::kValueChanged); } } @@ -2520,7 +2653,7 @@ void AXNodeObject::ComputeAriaOwnsChildren( // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible-name-and-description-calculation String AXNodeObject::NativeTextAlternative( AXObjectSet& visited, - AXNameFrom& name_from, + ax::mojom::NameFrom& name_from, AXRelatedObjectVector* related_objects, NameSources* name_sources, bool* found_text_alternative) const { @@ -2544,7 +2677,7 @@ String AXNodeObject::NativeTextAlternative( html_element = ToHTMLElement(GetNode()); if (html_element && html_element->IsLabelable()) { - name_from = kAXNameFromRelatedElement; + name_from = ax::mojom::NameFrom::kRelatedElement; if (name_sources) { name_sources->push_back(NameSource(*found_text_alternative)); name_sources->back().type = name_from; @@ -2578,7 +2711,7 @@ String AXNodeObject::NativeTextAlternative( source.related_objects = *related_objects; source.text = text_alternative; } else { - return text_alternative; + return text_alternative.StripWhiteSpace(); } } else if (name_sources) { name_sources->back().invalid = true; @@ -2589,7 +2722,7 @@ String AXNodeObject::NativeTextAlternative( // 5.2 input type="button", input type="submit" and input type="reset" if (input_element && input_element->IsTextButton()) { // value attribue - name_from = kAXNameFromValue; + name_from = ax::mojom::NameFrom::kValue; if (name_sources) { name_sources->push_back(NameSource(*found_text_alternative, valueAttr)); name_sources->back().type = name_from; @@ -2612,7 +2745,7 @@ String AXNodeObject::NativeTextAlternative( String default_label = input_element->ValueOrDefaultLabel(); if (value.IsNull() && !default_label.IsNull()) { // default label - name_from = kAXNameFromContents; + name_from = ax::mojom::NameFrom::kContents; if (name_sources) { name_sources->push_back(NameSource(*found_text_alternative)); name_sources->back().type = name_from; @@ -2636,8 +2769,8 @@ String AXNodeObject::NativeTextAlternative( // alt attr const AtomicString& alt = input_element->getAttribute(altAttr); const bool is_empty = alt.IsEmpty() && !alt.IsNull(); - name_from = - is_empty ? kAXNameFromAttributeExplicitlyEmpty : kAXNameFromAttribute; + name_from = is_empty ? ax::mojom::NameFrom::kAttributeExplicitlyEmpty + : ax::mojom::NameFrom::kAttribute; if (name_sources) { name_sources->push_back(NameSource(*found_text_alternative, altAttr)); name_sources->back().type = name_from; @@ -2659,7 +2792,7 @@ String AXNodeObject::NativeTextAlternative( name_sources->push_back(NameSource(*found_text_alternative, valueAttr)); name_sources->back().type = name_from; } - name_from = kAXNameFromAttribute; + name_from = ax::mojom::NameFrom::kAttribute; String value = input_element->value(); if (!value.IsNull()) { text_alternative = value; @@ -2672,8 +2805,27 @@ String AXNodeObject::NativeTextAlternative( } } + // title attr + if (name_sources) { + name_sources->push_back(NameSource(*found_text_alternative, titleAttr)); + name_sources->back().type = name_from; + } + name_from = ax::mojom::NameFrom::kTitle; + const AtomicString& title = input_element->getAttribute(titleAttr); + if (!title.IsNull()) { + text_alternative = title; + if (name_sources) { + NameSource& source = name_sources->back(); + source.attribute_value = title; + source.text = text_alternative; + *found_text_alternative = true; + } else { + return text_alternative; + } + } + // localised default value ("Submit") - name_from = kAXNameFromValue; + name_from = ax::mojom::NameFrom::kValue; text_alternative = input_element->GetLocale().QueryString( WebLocalizedString::kSubmitButtonDefaultLabel); if (name_sources) { @@ -2691,7 +2843,7 @@ String AXNodeObject::NativeTextAlternative( // 5.1 Text inputs - step 3 (placeholder attribute) if (html_element && html_element->IsTextControl()) { - name_from = kAXNameFromPlaceholder; + name_from = ax::mojom::NameFrom::kPlaceholder; if (name_sources) { name_sources->push_back( NameSource(*found_text_alternative, placeholderAttr)); @@ -2711,9 +2863,11 @@ String AXNodeObject::NativeTextAlternative( return text_alternative; } } + } - // Also check for aria-placeholder. - name_from = kAXNameFromPlaceholder; + // Also check for aria-placeholder. + if (IsTextControl()) { + name_from = ax::mojom::NameFrom::kPlaceholder; if (name_sources) { name_sources->push_back( NameSource(*found_text_alternative, aria_placeholderAttr)); @@ -2740,7 +2894,7 @@ String AXNodeObject::NativeTextAlternative( // 5.7 figure and figcaption Elements if (GetNode()->HasTagName(figureTag)) { // figcaption - name_from = kAXNameFromRelatedElement; + name_from = ax::mojom::NameFrom::kRelatedElement; if (name_sources) { name_sources->push_back(NameSource(*found_text_alternative)); name_sources->back().type = name_from; @@ -2785,8 +2939,8 @@ String AXNodeObject::NativeTextAlternative( // alt const AtomicString& alt = GetAttribute(altAttr); const bool is_empty = alt.IsEmpty() && !alt.IsNull(); - name_from = - is_empty ? kAXNameFromAttributeExplicitlyEmpty : kAXNameFromAttribute; + name_from = is_empty ? ax::mojom::NameFrom::kAttributeExplicitlyEmpty + : ax::mojom::NameFrom::kAttribute; if (name_sources) { name_sources->push_back(NameSource(*found_text_alternative, altAttr)); name_sources->back().type = name_from; @@ -2808,7 +2962,7 @@ String AXNodeObject::NativeTextAlternative( // 5.9 table Element if (auto* table_element = ToHTMLTableElementOrNull(GetNode())) { // caption - name_from = kAXNameFromCaption; + name_from = ax::mojom::NameFrom::kCaption; if (name_sources) { name_sources->push_back(NameSource(*found_text_alternative)); name_sources->back().type = name_from; @@ -2839,7 +2993,7 @@ String AXNodeObject::NativeTextAlternative( } // summary - name_from = kAXNameFromAttribute; + name_from = ax::mojom::NameFrom::kAttribute; if (name_sources) { name_sources->push_back(NameSource(*found_text_alternative, summaryAttr)); name_sources->back().type = name_from; @@ -2862,7 +3016,7 @@ String AXNodeObject::NativeTextAlternative( // Per SVG AAM 1.0's modifications to 2D of this algorithm. if (GetNode()->IsSVGElement()) { - name_from = kAXNameFromRelatedElement; + name_from = ax::mojom::NameFrom::kRelatedElement; if (name_sources) { name_sources->push_back(NameSource(*found_text_alternative)); name_sources->back().type = name_from; @@ -2897,7 +3051,7 @@ String AXNodeObject::NativeTextAlternative( // Fieldset / legend. if (IsHTMLFieldSetElement(GetNode())) { - name_from = kAXNameFromRelatedElement; + name_from = ax::mojom::NameFrom::kRelatedElement; if (name_sources) { name_sources->push_back(NameSource(*found_text_alternative)); name_sources->back().type = name_from; @@ -2934,7 +3088,7 @@ String AXNodeObject::NativeTextAlternative( if (IsWebArea()) { Document* document = this->GetDocument(); if (document) { - name_from = kAXNameFromAttribute; + name_from = ax::mojom::NameFrom::kAttribute; if (name_sources) { name_sources->push_back( NameSource(found_text_alternative, aria_labelAttr)); @@ -2958,7 +3112,7 @@ String AXNodeObject::NativeTextAlternative( } } - name_from = kAXNameFromRelatedElement; + name_from = ax::mojom::NameFrom::kRelatedElement; if (name_sources) { name_sources->push_back(NameSource(*found_text_alternative)); name_sources->back().type = name_from; @@ -2992,25 +3146,25 @@ String AXNodeObject::NativeTextAlternative( return text_alternative; } -String AXNodeObject::Description(AXNameFrom name_from, - AXDescriptionFrom& description_from, +String AXNodeObject::Description(ax::mojom::NameFrom name_from, + ax::mojom::DescriptionFrom& description_from, AXObjectVector* description_objects) const { AXRelatedObjectVector related_objects; String result = Description(name_from, description_from, nullptr, &related_objects); if (description_objects) { description_objects->clear(); - for (size_t i = 0; i < related_objects.size(); i++) - description_objects->push_back(related_objects[i]->object); + for (NameSourceRelatedObject* related_object : related_objects) + description_objects->push_back(related_object->object); } result = CollapseWhitespace(result); - if (RoleValue() == kSpinButtonRole && DatetimeAncestor()) { + if (RoleValue() == ax::mojom::Role::kSpinButton && DatetimeAncestor()) { // Fields inside a datetime control need to merge the field description // with the description of the <input> element. const AXObject* datetime_ancestor = DatetimeAncestor(); - AXNameFrom name_from; + ax::mojom::NameFrom name_from; datetime_ancestor->GetName(name_from, nullptr); description_objects->clear(); String ancestor_description = DatetimeAncestor()->Description( @@ -3026,8 +3180,8 @@ String AXNodeObject::Description(AXNameFrom name_from, // Based on // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible-name-and-description-calculation -String AXNodeObject::Description(AXNameFrom name_from, - AXDescriptionFrom& description_from, +String AXNodeObject::Description(ax::mojom::NameFrom name_from, + ax::mojom::DescriptionFrom& description_from, DescriptionSources* description_sources, AXRelatedObjectVector* related_objects) const { // If descriptionSources is non-null, relatedObjects is used in filling it in, @@ -3041,7 +3195,7 @@ String AXNodeObject::Description(AXNameFrom name_from, String description; bool found_description = false; - description_from = kAXDescriptionFromRelatedElement; + description_from = ax::mojom::DescriptionFrom::kRelatedElement; if (description_sources) { description_sources->push_back( DescriptionSource(found_description, aria_describedbyAttr)); @@ -3099,9 +3253,9 @@ String AXNodeObject::Description(AXNameFrom name_from, const HTMLInputElement* input_element = ToHTMLInputElementOrNull(GetNode()); // value, 5.2.2 from: http://rawgit.com/w3c/aria/master/html-aam/html-aam.html - if (name_from != kAXNameFromValue && input_element && + if (name_from != ax::mojom::NameFrom::kValue && input_element && input_element->IsTextButton()) { - description_from = kAXDescriptionFromAttribute; + description_from = ax::mojom::DescriptionFrom::kAttribute; if (description_sources) { description_sources->push_back( DescriptionSource(found_description, valueAttr)); @@ -3122,10 +3276,11 @@ String AXNodeObject::Description(AXNameFrom name_from, // table caption, 5.9.2 from: // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html - if (name_from != kAXNameFromCaption && IsHTMLTableElement(GetNode())) { + if (name_from != ax::mojom::NameFrom::kCaption && + IsHTMLTableElement(GetNode())) { HTMLTableElement* table_element = ToHTMLTableElement(GetNode()); - description_from = kAXDescriptionFromRelatedElement; + description_from = ax::mojom::DescriptionFrom::kRelatedElement; if (description_sources) { description_sources->push_back(DescriptionSource(found_description)); description_sources->back().type = description_from; @@ -3157,8 +3312,9 @@ String AXNodeObject::Description(AXNameFrom name_from, // summary, 5.6.2 from: // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html - if (name_from != kAXNameFromContents && IsHTMLSummaryElement(GetNode())) { - description_from = kAXDescriptionFromContents; + if (name_from != ax::mojom::NameFrom::kContents && + IsHTMLSummaryElement(GetNode())) { + description_from = ax::mojom::DescriptionFrom::kContents; if (description_sources) { description_sources->push_back(DescriptionSource(found_description)); description_sources->back().type = description_from; @@ -3179,8 +3335,8 @@ String AXNodeObject::Description(AXNameFrom name_from, // title attribute, from: // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html - if (name_from != kAXNameFromTitle) { - description_from = kAXDescriptionFromAttribute; + if (name_from != ax::mojom::NameFrom::kTitle) { + description_from = ax::mojom::DescriptionFrom::kAttribute; if (description_sources) { description_sources->push_back( DescriptionSource(found_description, titleAttr)); @@ -3201,7 +3357,7 @@ String AXNodeObject::Description(AXNameFrom name_from, // aria-help. // FIXME: this is not part of the official standard, but it's needed because // the built-in date/time controls use it. - description_from = kAXDescriptionFromAttribute; + description_from = ax::mojom::DescriptionFrom::kAttribute; if (description_sources) { description_sources->push_back( DescriptionSource(found_description, aria_helpAttr)); @@ -3218,13 +3374,11 @@ String AXNodeObject::Description(AXNameFrom name_from, } } - description_from = kAXDescriptionFromUninitialized; + description_from = ax::mojom::DescriptionFrom::kUninitialized; if (found_description) { - for (size_t i = 0; i < description_sources->size(); ++i) { - if (!(*description_sources)[i].text.IsNull() && - !(*description_sources)[i].superseded) { - DescriptionSource& description_source = (*description_sources)[i]; + for (DescriptionSource& description_source : *description_sources) { + if (!description_source.text.IsNull() && !description_source.superseded) { description_from = description_source.type; if (!description_source.related_objects.IsEmpty()) *related_objects = description_source.related_objects; @@ -3236,8 +3390,8 @@ String AXNodeObject::Description(AXNameFrom name_from, return String(); } -String AXNodeObject::Placeholder(AXNameFrom name_from) const { - if (name_from == kAXNameFromPlaceholder) +String AXNodeObject::Placeholder(ax::mojom::NameFrom name_from) const { + if (name_from == ax::mojom::NameFrom::kPlaceholder) return String(); Node* node = GetNode(); diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.h index a36cf324253..400c2b91aa1 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.h @@ -55,14 +55,12 @@ class MODULES_EXPORT AXNodeObject : public AXObject { bool initialized_ = false; #endif // The accessibility role, not taking ARIA into account. - AccessibilityRole native_role_; + ax::mojom::Role native_role_; bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override; const AXObject* InheritsPresentationalRoleFrom() const override; - AccessibilityRole DetermineAccessibilityRole() override; - virtual AccessibilityRole NativeAccessibilityRoleIgnoringAria() const; - String AccessibilityDescriptionForElements( - HeapVector<Member<Element>>& elements) const; + ax::mojom::Role DetermineAccessibilityRole() override; + virtual ax::mojom::Role NativeRoleIgnoringAria() const; void AlterSliderOrSpinButtonValue(bool increase); AXObject* ActiveDescendant() override; String AriaAccessibilityDescription() const; @@ -144,8 +142,8 @@ class MODULES_EXPORT AXNodeObject : public AXObject { String GetText() const override; // Properties of interactive elements. - AriaCurrentState GetAriaCurrentState() const final; - InvalidState GetInvalidState() const final; + ax::mojom::AriaCurrentState GetAriaCurrentState() const final; + ax::mojom::InvalidState GetInvalidState() const final; // Only used when invalidState() returns InvalidStateOther. String AriaInvalidValue() const final; String ValueDescription() const override; @@ -156,24 +154,25 @@ class MODULES_EXPORT AXNodeObject : public AXObject { String StringValue() const override; // ARIA attributes. - AccessibilityRole AriaRoleAttribute() const final; + ax::mojom::Role AriaRoleAttribute() const final; // AX name calculation. - String GetName(AXNameFrom&, AXObjectVector* name_objects) const override; + String GetName(ax::mojom::NameFrom&, + AXObjectVector* name_objects) const override; String TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom&, + ax::mojom::NameFrom&, AXRelatedObjectVector*, NameSources*) const override; - String Description(AXNameFrom, - AXDescriptionFrom&, + String Description(ax::mojom::NameFrom, + ax::mojom::DescriptionFrom&, AXObjectVector* description_objects) const override; - String Description(AXNameFrom, - AXDescriptionFrom&, + String Description(ax::mojom::NameFrom, + ax::mojom::DescriptionFrom&, DescriptionSources*, AXRelatedObjectVector*) const override; - String Placeholder(AXNameFrom) const override; + String Placeholder(ax::mojom::NameFrom) const override; bool NameFromLabelElement() const override; // Location @@ -197,6 +196,7 @@ class MODULES_EXPORT AXNodeObject : public AXObject { bool NeedsToUpdateChildren() const override { return children_dirty_; } void SetNeedsToUpdateChildren() override { children_dirty_ = true; } void UpdateChildrenIfNecessary() override; + void SelectedOptions(AXObjectVector&) const override; // DOM and Render tree access. Element* ActionElement() const override; @@ -235,7 +235,7 @@ class MODULES_EXPORT AXNodeObject : public AXObject { String TextFromDescendants(AXObjectSet& visited, bool recursive) const override; String NativeTextAlternative(AXObjectSet& visited, - AXNameFrom&, + ax::mojom::NameFrom&, AXRelatedObjectVector*, NameSources*, bool* found_text_alternative) const; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc index dcc25560fb0..25aaa69a578 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object.cc @@ -72,372 +72,384 @@ using namespace HTMLNames; namespace { -struct AccessibilityRoleHashTraits : HashTraits<AccessibilityRole> { +struct RoleHashTraits : HashTraits<ax::mojom::Role> { static const bool kEmptyValueIsZero = true; - static AccessibilityRole EmptyValue() { - return AccessibilityRole::kUnknownRole; - } + static ax::mojom::Role EmptyValue() { return ax::mojom::Role::kUnknown; } }; using ARIARoleMap = HashMap<String, - AccessibilityRole, + ax::mojom::Role, CaseFoldingHash, HashTraits<String>, - AccessibilityRoleHashTraits>; + RoleHashTraits>; struct RoleEntry { const char* aria_role; - AccessibilityRole webcore_role; + ax::mojom::Role webcore_role; }; // Mapping of ARIA role name to internal role name. -const RoleEntry kRoles[] = {{"alert", kAlertRole}, - {"alertdialog", kAlertDialogRole}, - {"application", kApplicationRole}, - {"article", kArticleRole}, - {"banner", kBannerRole}, - {"blockquote", kBlockquoteRole}, - {"button", kButtonRole}, - {"caption", kCaptionRole}, - {"cell", kCellRole}, - {"checkbox", kCheckBoxRole}, - {"columnheader", kColumnHeaderRole}, - {"combobox", kComboBoxGroupingRole}, - {"complementary", kComplementaryRole}, - {"contentinfo", kContentInfoRole}, - {"definition", kDefinitionRole}, - {"dialog", kDialogRole}, - {"directory", kDirectoryRole}, - // ------------------------------------------------- - // DPub Roles: - // www.w3.org/TR/dpub-aam-1.0/#mapping_role_table - {"doc-abstract", kDocAbstractRole}, - {"doc-acknowledgments", kDocAcknowledgmentsRole}, - {"doc-afterword", kDocAfterwordRole}, - {"doc-appendix", kDocAppendixRole}, - {"doc-backlink", kDocBackLinkRole}, - {"doc-biblioentry", kDocBiblioEntryRole}, - {"doc-bibliography", kDocBibliographyRole}, - {"doc-biblioref", kDocBiblioRefRole}, - {"doc-chapter", kDocChapterRole}, - {"doc-colophon", kDocColophonRole}, - {"doc-conclusion", kDocConclusionRole}, - {"doc-cover", kDocCoverRole}, - {"doc-credit", kDocCreditRole}, - {"doc-credits", kDocCreditsRole}, - {"doc-dedication", kDocDedicationRole}, - {"doc-endnote", kDocEndnoteRole}, - {"doc-endnotes", kDocEndnotesRole}, - {"doc-epigraph", kDocEpigraphRole}, - {"doc-epilogue", kDocEpilogueRole}, - {"doc-errata", kDocErrataRole}, - {"doc-example", kDocExampleRole}, - {"doc-footnote", kDocFootnoteRole}, - {"doc-foreword", kDocForewordRole}, - {"doc-glossary", kDocGlossaryRole}, - {"doc-glossref", kDocGlossRefRole}, - {"doc-index", kDocIndexRole}, - {"doc-introduction", kDocIntroductionRole}, - {"doc-noteref", kDocNoteRefRole}, - {"doc-notice", kDocNoticeRole}, - {"doc-pagebreak", kDocPageBreakRole}, - {"doc-pagelist", kDocPageListRole}, - {"doc-part", kDocPartRole}, - {"doc-preface", kDocPrefaceRole}, - {"doc-prologue", kDocPrologueRole}, - {"doc-pullquote", kDocPullquoteRole}, - {"doc-qna", kDocQnaRole}, - {"doc-subtitle", kDocSubtitleRole}, - {"doc-tip", kDocTipRole}, - {"doc-toc", kDocTocRole}, - // End DPub roles. - // ------------------------------------------------- - {"document", kDocumentRole}, - {"feed", kFeedRole}, - {"figure", kFigureRole}, - {"form", kFormRole}, - // ------------------------------------------------- - // ARIA Graphics module roles: - // https://rawgit.com/w3c/graphics-aam/master/ - {"graphics-document", kGraphicsDocumentRole}, - {"graphics-object", kGraphicsObjectRole}, - {"graphics-symbol", kGraphicsSymbolRole}, - // End ARIA Graphics module roles. - // ------------------------------------------------- - {"grid", kGridRole}, - {"gridcell", kCellRole}, - {"group", kGroupRole}, - {"heading", kHeadingRole}, - {"img", kImageRole}, - {"link", kLinkRole}, - {"list", kListRole}, - {"listbox", kListBoxRole}, - {"listitem", kListItemRole}, - {"log", kLogRole}, - {"main", kMainRole}, - {"marquee", kMarqueeRole}, - {"math", kMathRole}, - {"menu", kMenuRole}, - {"menubar", kMenuBarRole}, - {"menuitem", kMenuItemRole}, - {"menuitemcheckbox", kMenuItemCheckBoxRole}, - {"menuitemradio", kMenuItemRadioRole}, - {"navigation", kNavigationRole}, - {"none", kNoneRole}, - {"note", kNoteRole}, - {"option", kListBoxOptionRole}, - {"paragraph", kParagraphRole}, - {"presentation", kPresentationalRole}, - {"progressbar", kProgressIndicatorRole}, - {"radio", kRadioButtonRole}, - {"radiogroup", kRadioGroupRole}, - // TODO(accessibility) region should only be mapped - // if name present. See http://crbug.com/840819. - {"region", kRegionRole}, - {"row", kRowRole}, - {"rowheader", kRowHeaderRole}, - {"scrollbar", kScrollBarRole}, - {"search", kSearchRole}, - {"searchbox", kSearchBoxRole}, - {"separator", kSplitterRole}, - {"slider", kSliderRole}, - {"spinbutton", kSpinButtonRole}, - {"status", kStatusRole}, - {"switch", kSwitchRole}, - {"tab", kTabRole}, - {"table", kTableRole}, - {"tablist", kTabListRole}, - {"tabpanel", kTabPanelRole}, - {"term", kTermRole}, - {"text", kStaticTextRole}, - {"textbox", kTextFieldRole}, - {"timer", kTimerRole}, - {"toolbar", kToolbarRole}, - {"tooltip", kUserInterfaceTooltipRole}, - {"tree", kTreeRole}, - {"treegrid", kTreeGridRole}, - {"treeitem", kTreeItemRole}}; +const RoleEntry kRoles[] = { + {"alert", ax::mojom::Role::kAlert}, + {"alertdialog", ax::mojom::Role::kAlertDialog}, + {"application", ax::mojom::Role::kApplication}, + {"article", ax::mojom::Role::kArticle}, + {"banner", ax::mojom::Role::kBanner}, + {"blockquote", ax::mojom::Role::kBlockquote}, + {"button", ax::mojom::Role::kButton}, + {"caption", ax::mojom::Role::kCaption}, + {"cell", ax::mojom::Role::kCell}, + {"checkbox", ax::mojom::Role::kCheckBox}, + {"columnheader", ax::mojom::Role::kColumnHeader}, + {"combobox", ax::mojom::Role::kComboBoxGrouping}, + {"complementary", ax::mojom::Role::kComplementary}, + {"contentinfo", ax::mojom::Role::kContentInfo}, + {"definition", ax::mojom::Role::kDefinition}, + {"dialog", ax::mojom::Role::kDialog}, + {"directory", ax::mojom::Role::kDirectory}, + // ------------------------------------------------- + // DPub Roles: + // www.w3.org/TR/dpub-aam-1.0/#mapping_role_table + {"doc-abstract", ax::mojom::Role::kDocAbstract}, + {"doc-acknowledgments", ax::mojom::Role::kDocAcknowledgments}, + {"doc-afterword", ax::mojom::Role::kDocAfterword}, + {"doc-appendix", ax::mojom::Role::kDocAppendix}, + {"doc-backlink", ax::mojom::Role::kDocBackLink}, + {"doc-biblioentry", ax::mojom::Role::kDocBiblioEntry}, + {"doc-bibliography", ax::mojom::Role::kDocBibliography}, + {"doc-biblioref", ax::mojom::Role::kDocBiblioRef}, + {"doc-chapter", ax::mojom::Role::kDocChapter}, + {"doc-colophon", ax::mojom::Role::kDocColophon}, + {"doc-conclusion", ax::mojom::Role::kDocConclusion}, + {"doc-cover", ax::mojom::Role::kDocCover}, + {"doc-credit", ax::mojom::Role::kDocCredit}, + {"doc-credits", ax::mojom::Role::kDocCredits}, + {"doc-dedication", ax::mojom::Role::kDocDedication}, + {"doc-endnote", ax::mojom::Role::kDocEndnote}, + {"doc-endnotes", ax::mojom::Role::kDocEndnotes}, + {"doc-epigraph", ax::mojom::Role::kDocEpigraph}, + {"doc-epilogue", ax::mojom::Role::kDocEpilogue}, + {"doc-errata", ax::mojom::Role::kDocErrata}, + {"doc-example", ax::mojom::Role::kDocExample}, + {"doc-footnote", ax::mojom::Role::kDocFootnote}, + {"doc-foreword", ax::mojom::Role::kDocForeword}, + {"doc-glossary", ax::mojom::Role::kDocGlossary}, + {"doc-glossref", ax::mojom::Role::kDocGlossRef}, + {"doc-index", ax::mojom::Role::kDocIndex}, + {"doc-introduction", ax::mojom::Role::kDocIntroduction}, + {"doc-noteref", ax::mojom::Role::kDocNoteRef}, + {"doc-notice", ax::mojom::Role::kDocNotice}, + {"doc-pagebreak", ax::mojom::Role::kDocPageBreak}, + {"doc-pagelist", ax::mojom::Role::kDocPageList}, + {"doc-part", ax::mojom::Role::kDocPart}, + {"doc-preface", ax::mojom::Role::kDocPreface}, + {"doc-prologue", ax::mojom::Role::kDocPrologue}, + {"doc-pullquote", ax::mojom::Role::kDocPullquote}, + {"doc-qna", ax::mojom::Role::kDocQna}, + {"doc-subtitle", ax::mojom::Role::kDocSubtitle}, + {"doc-tip", ax::mojom::Role::kDocTip}, + {"doc-toc", ax::mojom::Role::kDocToc}, + // End DPub roles. + // ------------------------------------------------- + {"document", ax::mojom::Role::kDocument}, + {"feed", ax::mojom::Role::kFeed}, + {"figure", ax::mojom::Role::kFigure}, + {"form", ax::mojom::Role::kForm}, + // ------------------------------------------------- + // ARIA Graphics module roles: + // https://rawgit.com/w3c/graphics-aam/master/ + {"graphics-document", ax::mojom::Role::kGraphicsDocument}, + {"graphics-object", ax::mojom::Role::kGraphicsObject}, + {"graphics-symbol", ax::mojom::Role::kGraphicsSymbol}, + // End ARIA Graphics module roles. + // ------------------------------------------------- + {"grid", ax::mojom::Role::kGrid}, + {"gridcell", ax::mojom::Role::kCell}, + {"group", ax::mojom::Role::kGroup}, + {"heading", ax::mojom::Role::kHeading}, + {"img", ax::mojom::Role::kImage}, + {"link", ax::mojom::Role::kLink}, + {"list", ax::mojom::Role::kList}, + {"listbox", ax::mojom::Role::kListBox}, + {"listitem", ax::mojom::Role::kListItem}, + {"log", ax::mojom::Role::kLog}, + {"main", ax::mojom::Role::kMain}, + {"marquee", ax::mojom::Role::kMarquee}, + {"math", ax::mojom::Role::kMath}, + {"menu", ax::mojom::Role::kMenu}, + {"menubar", ax::mojom::Role::kMenuBar}, + {"menuitem", ax::mojom::Role::kMenuItem}, + {"menuitemcheckbox", ax::mojom::Role::kMenuItemCheckBox}, + {"menuitemradio", ax::mojom::Role::kMenuItemRadio}, + {"navigation", ax::mojom::Role::kNavigation}, + {"none", ax::mojom::Role::kNone}, + {"note", ax::mojom::Role::kNote}, + {"option", ax::mojom::Role::kListBoxOption}, + {"paragraph", ax::mojom::Role::kParagraph}, + {"presentation", ax::mojom::Role::kPresentational}, + {"progressbar", ax::mojom::Role::kProgressIndicator}, + {"radio", ax::mojom::Role::kRadioButton}, + {"radiogroup", ax::mojom::Role::kRadioGroup}, + // TODO(accessibility) region should only be mapped + // if name present. See http://crbug.com/840819. + {"region", ax::mojom::Role::kRegion}, + {"row", ax::mojom::Role::kRow}, + {"rowheader", ax::mojom::Role::kRowHeader}, + {"scrollbar", ax::mojom::Role::kScrollBar}, + {"search", ax::mojom::Role::kSearch}, + {"searchbox", ax::mojom::Role::kSearchBox}, + {"separator", ax::mojom::Role::kSplitter}, + {"slider", ax::mojom::Role::kSlider}, + {"spinbutton", ax::mojom::Role::kSpinButton}, + {"status", ax::mojom::Role::kStatus}, + {"switch", ax::mojom::Role::kSwitch}, + {"tab", ax::mojom::Role::kTab}, + {"table", ax::mojom::Role::kTable}, + {"tablist", ax::mojom::Role::kTabList}, + {"tabpanel", ax::mojom::Role::kTabPanel}, + {"term", ax::mojom::Role::kTerm}, + {"text", ax::mojom::Role::kStaticText}, + {"textbox", ax::mojom::Role::kTextField}, + {"timer", ax::mojom::Role::kTimer}, + {"toolbar", ax::mojom::Role::kToolbar}, + {"tooltip", ax::mojom::Role::kTooltip}, + {"tree", ax::mojom::Role::kTree}, + {"treegrid", ax::mojom::Role::kTreeGrid}, + {"treeitem", ax::mojom::Role::kTreeItem}}; struct InternalRoleEntry { - AccessibilityRole webcore_role; + ax::mojom::Role webcore_role; const char* internal_role_name; }; const InternalRoleEntry kInternalRoles[] = { - {kUnknownRole, "Unknown"}, - {kAbbrRole, "Abbr"}, - {kAlertDialogRole, "AlertDialog"}, - {kAlertRole, "Alert"}, - {kAnchorRole, "Anchor"}, - {kAnnotationRole, "Annotation"}, - {kApplicationRole, "Application"}, - {kArticleRole, "Article"}, - {kAudioRole, "Audio"}, - {kBannerRole, "Banner"}, - {kBlockquoteRole, "Blockquote"}, - {kButtonRole, "Button"}, - {kCanvasRole, "Canvas"}, - {kCaptionRole, "Caption"}, - {kCellRole, "Cell"}, - {kCheckBoxRole, "CheckBox"}, - {kColorWellRole, "ColorWell"}, - {kColumnHeaderRole, "ColumnHeader"}, - {kColumnRole, "Column"}, - {kComboBoxGroupingRole, "ComboBox"}, - {kComboBoxMenuButtonRole, "ComboBox"}, - {kComplementaryRole, "Complementary"}, - {kContentDeletionRole, "ContentDeletion"}, - {kContentInsertionRole, "ContentInsertion"}, - {kContentInfoRole, "ContentInfo"}, - {kDateRole, "Date"}, - {kDateTimeRole, "DateTime"}, - {kDefinitionRole, "Definition"}, - {kDescriptionListDetailRole, "DescriptionListDetail"}, - {kDescriptionListRole, "DescriptionList"}, - {kDescriptionListTermRole, "DescriptionListTerm"}, - {kDetailsRole, "Details"}, - {kDialogRole, "Dialog"}, - {kDirectoryRole, "Directory"}, - {kDisclosureTriangleRole, "DisclosureTriangle"}, + {ax::mojom::Role::kNone, "None"}, + {ax::mojom::Role::kAbbr, "Abbr"}, + {ax::mojom::Role::kAlertDialog, "AlertDialog"}, + {ax::mojom::Role::kAlert, "Alert"}, + {ax::mojom::Role::kAnchor, "Anchor"}, + {ax::mojom::Role::kAnnotation, "Annotation"}, + {ax::mojom::Role::kApplication, "Application"}, + {ax::mojom::Role::kArticle, "Article"}, + {ax::mojom::Role::kAudio, "Audio"}, + {ax::mojom::Role::kBanner, "Banner"}, + {ax::mojom::Role::kBlockquote, "Blockquote"}, + {ax::mojom::Role::kButton, "Button"}, + {ax::mojom::Role::kCanvas, "Canvas"}, + {ax::mojom::Role::kCaption, "Caption"}, + {ax::mojom::Role::kCaret, "Caret"}, + {ax::mojom::Role::kCell, "Cell"}, + {ax::mojom::Role::kCheckBox, "CheckBox"}, + {ax::mojom::Role::kClient, "Client"}, + {ax::mojom::Role::kColorWell, "ColorWell"}, + {ax::mojom::Role::kColumnHeader, "ColumnHeader"}, + {ax::mojom::Role::kColumn, "Column"}, + {ax::mojom::Role::kComboBoxGrouping, "ComboBox"}, + {ax::mojom::Role::kComboBoxMenuButton, "ComboBox"}, + {ax::mojom::Role::kComplementary, "Complementary"}, + {ax::mojom::Role::kContentDeletion, "ContentDeletion"}, + {ax::mojom::Role::kContentInsertion, "ContentInsertion"}, + {ax::mojom::Role::kContentInfo, "ContentInfo"}, + {ax::mojom::Role::kDate, "Date"}, + {ax::mojom::Role::kDateTime, "DateTime"}, + {ax::mojom::Role::kDefinition, "Definition"}, + {ax::mojom::Role::kDescriptionListDetail, "DescriptionListDetail"}, + {ax::mojom::Role::kDescriptionList, "DescriptionList"}, + {ax::mojom::Role::kDescriptionListTerm, "DescriptionListTerm"}, + {ax::mojom::Role::kDesktop, "Desktop"}, + {ax::mojom::Role::kDetails, "Details"}, + {ax::mojom::Role::kDialog, "Dialog"}, + {ax::mojom::Role::kDirectory, "Directory"}, + {ax::mojom::Role::kDisclosureTriangle, "DisclosureTriangle"}, // -------------------------------------------------------------- // DPub Roles: // https://www.w3.org/TR/dpub-aam-1.0/#mapping_role_table - {kDocAbstractRole, "DocAbstract"}, - {kDocAcknowledgmentsRole, "DocAcknowledgments"}, - {kDocAfterwordRole, "DocAfterword"}, - {kDocAppendixRole, "DocAppendix"}, - {kDocBackLinkRole, "DocBackLink"}, - {kDocBiblioEntryRole, "DocBiblioentry"}, - {kDocBibliographyRole, "DocBibliography"}, - {kDocBiblioRefRole, "DocBiblioref"}, - {kDocChapterRole, "DocChapter"}, - {kDocColophonRole, "DocColophon"}, - {kDocConclusionRole, "DocConclusion"}, - {kDocCoverRole, "DocCover"}, - {kDocCreditRole, "DocCredit"}, - {kDocCreditsRole, "DocCredits"}, - {kDocDedicationRole, "DocDedication"}, - {kDocEndnoteRole, "DocEndnote"}, - {kDocEndnotesRole, "DocEndnotes"}, - {kDocEpigraphRole, "DocEpigraph"}, - {kDocEpilogueRole, "DocEpilogue"}, - {kDocErrataRole, "DocErrata"}, - {kDocExampleRole, "DocExample"}, - {kDocFootnoteRole, "DocFootnote"}, - {kDocForewordRole, "DocForeword"}, - {kDocGlossaryRole, "DocGlossary"}, - {kDocGlossRefRole, "DocGlossref"}, - {kDocIndexRole, "DocIndex"}, - {kDocIntroductionRole, "DocIntroduction"}, - {kDocNoteRefRole, "DocNoteref"}, - {kDocNoticeRole, "DocNotice"}, - {kDocPageBreakRole, "DocPagebreak"}, - {kDocPageListRole, "DocPagelist"}, - {kDocPartRole, "DocPart"}, - {kDocPrefaceRole, "DocPreface"}, - {kDocPrologueRole, "DocPrologue"}, - {kDocPullquoteRole, "DocPullquote"}, - {kDocQnaRole, "DocQna"}, - {kDocSubtitleRole, "DocSubtitle"}, - {kDocTipRole, "DocTip"}, - {kDocTocRole, "DocToc"}, + {ax::mojom::Role::kDocAbstract, "DocAbstract"}, + {ax::mojom::Role::kDocAcknowledgments, "DocAcknowledgments"}, + {ax::mojom::Role::kDocAfterword, "DocAfterword"}, + {ax::mojom::Role::kDocAppendix, "DocAppendix"}, + {ax::mojom::Role::kDocBackLink, "DocBackLink"}, + {ax::mojom::Role::kDocBiblioEntry, "DocBiblioentry"}, + {ax::mojom::Role::kDocBibliography, "DocBibliography"}, + {ax::mojom::Role::kDocBiblioRef, "DocBiblioref"}, + {ax::mojom::Role::kDocChapter, "DocChapter"}, + {ax::mojom::Role::kDocColophon, "DocColophon"}, + {ax::mojom::Role::kDocConclusion, "DocConclusion"}, + {ax::mojom::Role::kDocCover, "DocCover"}, + {ax::mojom::Role::kDocCredit, "DocCredit"}, + {ax::mojom::Role::kDocCredits, "DocCredits"}, + {ax::mojom::Role::kDocDedication, "DocDedication"}, + {ax::mojom::Role::kDocEndnote, "DocEndnote"}, + {ax::mojom::Role::kDocEndnotes, "DocEndnotes"}, + {ax::mojom::Role::kDocEpigraph, "DocEpigraph"}, + {ax::mojom::Role::kDocEpilogue, "DocEpilogue"}, + {ax::mojom::Role::kDocErrata, "DocErrata"}, + {ax::mojom::Role::kDocExample, "DocExample"}, + {ax::mojom::Role::kDocFootnote, "DocFootnote"}, + {ax::mojom::Role::kDocForeword, "DocForeword"}, + {ax::mojom::Role::kDocGlossary, "DocGlossary"}, + {ax::mojom::Role::kDocGlossRef, "DocGlossref"}, + {ax::mojom::Role::kDocIndex, "DocIndex"}, + {ax::mojom::Role::kDocIntroduction, "DocIntroduction"}, + {ax::mojom::Role::kDocNoteRef, "DocNoteref"}, + {ax::mojom::Role::kDocNotice, "DocNotice"}, + {ax::mojom::Role::kDocPageBreak, "DocPagebreak"}, + {ax::mojom::Role::kDocPageList, "DocPagelist"}, + {ax::mojom::Role::kDocPart, "DocPart"}, + {ax::mojom::Role::kDocPreface, "DocPreface"}, + {ax::mojom::Role::kDocPrologue, "DocPrologue"}, + {ax::mojom::Role::kDocPullquote, "DocPullquote"}, + {ax::mojom::Role::kDocQna, "DocQna"}, + {ax::mojom::Role::kDocSubtitle, "DocSubtitle"}, + {ax::mojom::Role::kDocTip, "DocTip"}, + {ax::mojom::Role::kDocToc, "DocToc"}, // End DPub roles. // -------------------------------------------------------------- - {kDocumentRole, "Document"}, - {kEmbeddedObjectRole, "EmbeddedObject"}, - {kFeedRole, "feed"}, - {kFigcaptionRole, "Figcaption"}, - {kFigureRole, "Figure"}, - {kFooterRole, "Footer"}, - {kFormRole, "Form"}, - {kGenericContainerRole, "GenericContainer"}, + {ax::mojom::Role::kDocument, "Document"}, + {ax::mojom::Role::kEmbeddedObject, "EmbeddedObject"}, + {ax::mojom::Role::kFeed, "feed"}, + {ax::mojom::Role::kFigcaption, "Figcaption"}, + {ax::mojom::Role::kFigure, "Figure"}, + {ax::mojom::Role::kFooter, "Footer"}, + {ax::mojom::Role::kForm, "Form"}, + {ax::mojom::Role::kGenericContainer, "GenericContainer"}, // -------------------------------------------------------------- // ARIA Graphics module roles: // https://rawgit.com/w3c/graphics-aam/master/#mapping_role_table - {kGraphicsDocumentRole, "GraphicsDocument"}, - {kGraphicsObjectRole, "GraphicsObject"}, - {kGraphicsSymbolRole, "GraphicsSymbol"}, + {ax::mojom::Role::kGraphicsDocument, "GraphicsDocument"}, + {ax::mojom::Role::kGraphicsObject, "GraphicsObject"}, + {ax::mojom::Role::kGraphicsSymbol, "GraphicsSymbol"}, // End ARIA Graphics module roles. // -------------------------------------------------------------- - {kGridRole, "Grid"}, - {kGroupRole, "Group"}, - {kHeadingRole, "Heading"}, - {kIframePresentationalRole, "IframePresentational"}, - {kIframeRole, "Iframe"}, - {kIgnoredRole, "Ignored"}, - {kImageMapRole, "ImageMap"}, - {kImageRole, "Image"}, - {kInlineTextBoxRole, "InlineTextBox"}, - {kInputTimeRole, "InputTime"}, - {kLabelRole, "Label"}, - {kLayoutTableRole, "LayoutTable"}, - {kLayoutTableCellRole, "LayoutCellTable"}, - {kLayoutTableColumnRole, "LayoutColumnTable"}, - {kLayoutTableRowRole, "LayoutRowTable"}, - {kLegendRole, "Legend"}, - {kLinkRole, "Link"}, - {kLineBreakRole, "LineBreak"}, - {kListBoxOptionRole, "ListBoxOption"}, - {kListBoxRole, "ListBox"}, - {kListItemRole, "ListItem"}, - {kListMarkerRole, "ListMarker"}, - {kListRole, "List"}, - {kLogRole, "Log"}, - {kMainRole, "Main"}, - {kMarkRole, "Mark"}, - {kMarqueeRole, "Marquee"}, - {kMathRole, "Math"}, - {kMenuBarRole, "MenuBar"}, - {kMenuButtonRole, "MenuButton"}, - {kMenuItemRole, "MenuItem"}, - {kMenuItemCheckBoxRole, "MenuItemCheckBox"}, - {kMenuItemRadioRole, "MenuItemRadio"}, - {kMenuListOptionRole, "MenuListOption"}, - {kMenuListPopupRole, "MenuListPopup"}, - {kMenuRole, "Menu"}, - {kMeterRole, "Meter"}, - {kNavigationRole, "Navigation"}, - {kNoneRole, "None"}, - {kNoteRole, "Note"}, - {kParagraphRole, "Paragraph"}, - {kPopUpButtonRole, "PopUpButton"}, - {kPreRole, "Pre"}, - {kPresentationalRole, "Presentational"}, - {kProgressIndicatorRole, "ProgressIndicator"}, - {kRadioButtonRole, "RadioButton"}, - {kRadioGroupRole, "RadioGroup"}, - {kRegionRole, "Region"}, - {kRowHeaderRole, "RowHeader"}, - {kRowRole, "Row"}, - {kRubyRole, "Ruby"}, - {kSVGRootRole, "SVGRoot"}, - {kScrollBarRole, "ScrollBar"}, - {kSearchRole, "Search"}, - {kSearchBoxRole, "SearchBox"}, - {kSliderRole, "Slider"}, - {kSliderThumbRole, "SliderThumb"}, - {kSpinButtonRole, "SpinButton"}, - {kSplitterRole, "Splitter"}, - {kStaticTextRole, "StaticText"}, - {kStatusRole, "Status"}, - {kSwitchRole, "Switch"}, - {kTabListRole, "TabList"}, - {kTabPanelRole, "TabPanel"}, - {kTabRole, "Tab"}, - {kTableHeaderContainerRole, "TableHeaderContainer"}, - {kTableRole, "Table"}, - {kTermRole, "Term"}, - {kTextFieldRole, "TextField"}, - {kTextFieldWithComboBoxRole, "ComboBox"}, - {kTimeRole, "Time"}, - {kTimerRole, "Timer"}, - {kToggleButtonRole, "ToggleButton"}, - {kToolbarRole, "Toolbar"}, - {kTreeGridRole, "TreeGrid"}, - {kTreeItemRole, "TreeItem"}, - {kTreeRole, "Tree"}, - {kUserInterfaceTooltipRole, "UserInterfaceTooltip"}, - {kVideoRole, "Video"}, - {kWebAreaRole, "WebArea"}}; - -static_assert(arraysize(kInternalRoles) == kNumRoles, + {ax::mojom::Role::kGrid, "Grid"}, + {ax::mojom::Role::kGroup, "Group"}, + {ax::mojom::Role::kHeading, "Heading"}, + {ax::mojom::Role::kIframePresentational, "IframePresentational"}, + {ax::mojom::Role::kIframe, "Iframe"}, + {ax::mojom::Role::kIgnored, "Ignored"}, + {ax::mojom::Role::kImageMap, "ImageMap"}, + {ax::mojom::Role::kImage, "Image"}, + {ax::mojom::Role::kInlineTextBox, "InlineTextBox"}, + {ax::mojom::Role::kInputTime, "InputTime"}, + {ax::mojom::Role::kKeyboard, "Keyboard"}, + {ax::mojom::Role::kLabelText, "Label"}, + {ax::mojom::Role::kLayoutTable, "LayoutTable"}, + {ax::mojom::Role::kLayoutTableCell, "LayoutCellTable"}, + {ax::mojom::Role::kLayoutTableColumn, "LayoutColumnTable"}, + {ax::mojom::Role::kLayoutTableRow, "LayoutRowTable"}, + {ax::mojom::Role::kLegend, "Legend"}, + {ax::mojom::Role::kLink, "Link"}, + {ax::mojom::Role::kLineBreak, "LineBreak"}, + {ax::mojom::Role::kListBoxOption, "ListBoxOption"}, + {ax::mojom::Role::kListBox, "ListBox"}, + {ax::mojom::Role::kListItem, "ListItem"}, + {ax::mojom::Role::kListMarker, "ListMarker"}, + {ax::mojom::Role::kList, "List"}, + {ax::mojom::Role::kLog, "Log"}, + {ax::mojom::Role::kMain, "Main"}, + {ax::mojom::Role::kMark, "Mark"}, + {ax::mojom::Role::kMarquee, "Marquee"}, + {ax::mojom::Role::kMath, "Math"}, + {ax::mojom::Role::kMenuBar, "MenuBar"}, + {ax::mojom::Role::kMenuButton, "MenuButton"}, + {ax::mojom::Role::kMenuItem, "MenuItem"}, + {ax::mojom::Role::kMenuItemCheckBox, "MenuItemCheckBox"}, + {ax::mojom::Role::kMenuItemRadio, "MenuItemRadio"}, + {ax::mojom::Role::kMenuListOption, "MenuListOption"}, + {ax::mojom::Role::kMenuListPopup, "MenuListPopup"}, + {ax::mojom::Role::kMenu, "Menu"}, + {ax::mojom::Role::kMeter, "Meter"}, + {ax::mojom::Role::kNavigation, "Navigation"}, + {ax::mojom::Role::kNote, "Note"}, + {ax::mojom::Role::kPane, "Pane"}, + {ax::mojom::Role::kParagraph, "Paragraph"}, + {ax::mojom::Role::kPopUpButton, "PopUpButton"}, + {ax::mojom::Role::kPre, "Pre"}, + {ax::mojom::Role::kPresentational, "Presentational"}, + {ax::mojom::Role::kProgressIndicator, "ProgressIndicator"}, + {ax::mojom::Role::kRadioButton, "RadioButton"}, + {ax::mojom::Role::kRadioGroup, "RadioGroup"}, + {ax::mojom::Role::kRegion, "Region"}, + {ax::mojom::Role::kRootWebArea, "WebArea"}, + {ax::mojom::Role::kRowHeader, "RowHeader"}, + {ax::mojom::Role::kRow, "Row"}, + {ax::mojom::Role::kRuby, "Ruby"}, + {ax::mojom::Role::kSvgRoot, "SVGRoot"}, + {ax::mojom::Role::kScrollBar, "ScrollBar"}, + {ax::mojom::Role::kScrollView, "ScrollView"}, + {ax::mojom::Role::kSearch, "Search"}, + {ax::mojom::Role::kSearchBox, "SearchBox"}, + {ax::mojom::Role::kSlider, "Slider"}, + {ax::mojom::Role::kSliderThumb, "SliderThumb"}, + {ax::mojom::Role::kSpinButton, "SpinButton"}, + {ax::mojom::Role::kSplitter, "Splitter"}, + {ax::mojom::Role::kStaticText, "StaticText"}, + {ax::mojom::Role::kStatus, "Status"}, + {ax::mojom::Role::kSwitch, "Switch"}, + {ax::mojom::Role::kTabList, "TabList"}, + {ax::mojom::Role::kTabPanel, "TabPanel"}, + {ax::mojom::Role::kTab, "Tab"}, + {ax::mojom::Role::kTableHeaderContainer, "TableHeaderContainer"}, + {ax::mojom::Role::kTable, "Table"}, + {ax::mojom::Role::kTerm, "Term"}, + {ax::mojom::Role::kTextField, "TextField"}, + {ax::mojom::Role::kTextFieldWithComboBox, "ComboBox"}, + {ax::mojom::Role::kTime, "Time"}, + {ax::mojom::Role::kTimer, "Timer"}, + {ax::mojom::Role::kTitleBar, "TitleBar"}, + {ax::mojom::Role::kToggleButton, "ToggleButton"}, + {ax::mojom::Role::kToolbar, "Toolbar"}, + {ax::mojom::Role::kTreeGrid, "TreeGrid"}, + {ax::mojom::Role::kTreeItem, "TreeItem"}, + {ax::mojom::Role::kTree, "Tree"}, + {ax::mojom::Role::kTooltip, "UserInterfaceTooltip"}, + {ax::mojom::Role::kUnknown, "Unknown"}, + {ax::mojom::Role::kVideo, "Video"}, + {ax::mojom::Role::kWebArea, "WebArea"}, + {ax::mojom::Role::kWebView, "WebView"}, + {ax::mojom::Role::kWindow, "Window"}}; + +static_assert(base::size(kInternalRoles) == + static_cast<size_t>(ax::mojom::Role::kMaxValue) + 1, "Not all internal roles have an entry in internalRoles array"); // Roles which we need to map in the other direction -const RoleEntry kReverseRoles[] = {{"button", kToggleButtonRole}, - {"combobox", kPopUpButtonRole}, - {"contentinfo", kFooterRole}, - {"menuitem", kMenuButtonRole}, - {"menuitem", kMenuListOptionRole}, - {"progressbar", kMeterRole}, - {"textbox", kTextFieldRole}, - {"combobox", kComboBoxMenuButtonRole}, - {"combobox", kTextFieldWithComboBoxRole}}; +const RoleEntry kReverseRoles[] = { + {"button", ax::mojom::Role::kToggleButton}, + {"combobox", ax::mojom::Role::kPopUpButton}, + {"contentinfo", ax::mojom::Role::kFooter}, + {"menuitem", ax::mojom::Role::kMenuButton}, + {"menuitem", ax::mojom::Role::kMenuListOption}, + {"progressbar", ax::mojom::Role::kMeter}, + {"textbox", ax::mojom::Role::kTextField}, + {"combobox", ax::mojom::Role::kComboBoxMenuButton}, + {"combobox", ax::mojom::Role::kTextFieldWithComboBox}}; static ARIARoleMap* CreateARIARoleMap() { ARIARoleMap* role_map = new ARIARoleMap; - for (size_t i = 0; i < arraysize(kRoles); ++i) + for (size_t i = 0; i < base::size(kRoles); ++i) role_map->Set(String(kRoles[i].aria_role), kRoles[i].webcore_role); // Grids "ignore" their non-row children during computation of children. - role_map->Set(String("rowgroup"), kIgnoredRole); + role_map->Set(String("rowgroup"), ax::mojom::Role::kIgnored); return role_map; } static Vector<AtomicString>* CreateRoleNameVector() { - Vector<AtomicString>* role_name_vector = new Vector<AtomicString>(kNumRoles); - for (int i = 0; i < kNumRoles; i++) + Vector<AtomicString>* role_name_vector = + new Vector<AtomicString>(base::size(kInternalRoles)); + for (size_t i = 0; i < base::size(kInternalRoles); i++) (*role_name_vector)[i] = g_null_atom; - for (size_t i = 0; i < arraysize(kRoles); ++i) { - (*role_name_vector)[kRoles[i].webcore_role] = + for (size_t i = 0; i < base::size(kRoles); ++i) { + (*role_name_vector)[static_cast<size_t>(kRoles[i].webcore_role)] = AtomicString(kRoles[i].aria_role); } - for (size_t i = 0; i < arraysize(kReverseRoles); ++i) { - (*role_name_vector)[kReverseRoles[i].webcore_role] = + for (size_t i = 0; i < base::size(kReverseRoles); ++i) { + (*role_name_vector)[static_cast<size_t>(kReverseRoles[i].webcore_role)] = AtomicString(kReverseRoles[i].aria_role); } @@ -446,9 +458,10 @@ static Vector<AtomicString>* CreateRoleNameVector() { static Vector<AtomicString>* CreateInternalRoleNameVector() { Vector<AtomicString>* internal_role_name_vector = - new Vector<AtomicString>(kNumRoles); - for (size_t i = 0; i < arraysize(kInternalRoles); i++) { - (*internal_role_name_vector)[kInternalRoles[i].webcore_role] = + new Vector<AtomicString>(base::size(kInternalRoles)); + for (size_t i = 0; i < base::size(kInternalRoles); i++) { + (*internal_role_name_vector)[static_cast<size_t>( + kInternalRoles[i].webcore_role)] = AtomicString(kInternalRoles[i].internal_role_name); } @@ -466,8 +479,8 @@ unsigned AXObject::number_of_live_ax_objects_ = 0; AXObject::AXObject(AXObjectCacheImpl& ax_object_cache) : id_(0), have_children_(false), - role_(kUnknownRole), - aria_role_(kUnknownRole), + role_(ax::mojom::Role::kUnknown), + aria_role_(ax::mojom::Role::kUnknown), last_known_is_ignored_value_(kDefaultBehavior), explicit_container_id_(0), parent_(nullptr), @@ -656,30 +669,31 @@ void AXObject::GetSparseAXAttributes( } bool AXObject::IsARIATextControl() const { - return AriaRoleAttribute() == kTextFieldRole || - AriaRoleAttribute() == kSearchBoxRole || - AriaRoleAttribute() == kTextFieldWithComboBoxRole; + return AriaRoleAttribute() == ax::mojom::Role::kTextField || + AriaRoleAttribute() == ax::mojom::Role::kSearchBox || + AriaRoleAttribute() == ax::mojom::Role::kTextFieldWithComboBox; } bool AXObject::IsButton() const { - AccessibilityRole role = RoleValue(); + ax::mojom::Role role = RoleValue(); - return role == kButtonRole || role == kPopUpButtonRole || - role == kToggleButtonRole; + return role == ax::mojom::Role::kButton || + role == ax::mojom::Role::kPopUpButton || + role == ax::mojom::Role::kToggleButton; } bool AXObject::IsCheckable() const { switch (RoleValue()) { - case kCheckBoxRole: - case kMenuItemCheckBoxRole: - case kMenuItemRadioRole: - case kRadioButtonRole: - case kSwitchRole: - case kToggleButtonRole: + case ax::mojom::Role::kCheckBox: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kRadioButton: + case ax::mojom::Role::kSwitch: + case ax::mojom::Role::kToggleButton: return true; - case kTreeItemRole: - case kListBoxOptionRole: - case kMenuListOptionRole: + case ax::mojom::Role::kTreeItem: + case ax::mojom::Role::kListBoxOption: + case ax::mojom::Role::kMenuListOption: return AriaCheckedIsPresent(); default: return false; @@ -690,33 +704,34 @@ bool AXObject::IsCheckable() const { // Because an AXMenuListOption (<option>) can // have an ARIA role of menuitemcheckbox/menuitemradio // yet does not inherit from AXNodeObject -AccessibilityCheckedState AXObject::CheckedState() const { +ax::mojom::CheckedState AXObject::CheckedState() const { if (!IsCheckable()) - return kCheckedStateUndefined; + return ax::mojom::CheckedState::kNone; // Try ARIA checked/pressed state - const AccessibilityRole role = RoleValue(); - const auto prop = role == kToggleButtonRole ? AOMStringProperty::kPressed - : AOMStringProperty::kChecked; + const ax::mojom::Role role = RoleValue(); + const auto prop = role == ax::mojom::Role::kToggleButton + ? AOMStringProperty::kPressed + : AOMStringProperty::kChecked; const AtomicString& checked_attribute = GetAOMPropertyOrARIAAttribute(prop); if (checked_attribute) { if (EqualIgnoringASCIICase(checked_attribute, "mixed")) { // Only checkable role that doesn't support mixed is the switch. - if (role != kSwitchRole) - return kCheckedStateMixed; + if (role != ax::mojom::Role::kSwitch) + return ax::mojom::CheckedState::kMixed; } // Anything other than "false" should be treated as "true". return EqualIgnoringASCIICase(checked_attribute, "false") - ? kCheckedStateFalse - : kCheckedStateTrue; + ? ax::mojom::CheckedState::kFalse + : ax::mojom::CheckedState::kTrue; } // Native checked state - if (role != kToggleButtonRole) { + if (role != ax::mojom::Role::kToggleButton) { const Node* node = this->GetNode(); if (!node) - return kCheckedStateUndefined; + return ax::mojom::CheckedState::kNone; // Expose native checkbox mixed state as accessibility mixed state. However, // do not expose native radio mixed state as accessibility mixed state. @@ -724,15 +739,15 @@ AccessibilityCheckedState AXObject::CheckedState() const { // both checked and partially checked, but a native mixed native radio // button sinply means no radio buttons have been checked in the group yet. if (IsNativeCheckboxInMixedState(node)) - return kCheckedStateMixed; + return ax::mojom::CheckedState::kMixed; if (IsHTMLInputElement(*node) && ToHTMLInputElement(*node).ShouldAppearChecked()) { - return kCheckedStateTrue; + return ax::mojom::CheckedState::kTrue; } } - return kCheckedStateFalse; + return ax::mojom::CheckedState::kFalse; } bool AXObject::IsNativeCheckboxInMixedState(const Node* node) { @@ -748,34 +763,34 @@ bool AXObject::IsNativeCheckboxInMixedState(const Node* node) { bool AXObject::IsLandmarkRelated() const { switch (RoleValue()) { - case kApplicationRole: - case kArticleRole: - case kBannerRole: - case kComplementaryRole: - case kContentInfoRole: - case kDocAcknowledgmentsRole: - case kDocAfterwordRole: - case kDocAppendixRole: - case kDocBibliographyRole: - case kDocChapterRole: - case kDocConclusionRole: - case kDocCreditsRole: - case kDocEndnotesRole: - case kDocEpilogueRole: - case kDocErrataRole: - case kDocForewordRole: - case kDocGlossaryRole: - case kDocIntroductionRole: - case kDocPartRole: - case kDocPrefaceRole: - case kDocPrologueRole: - case kDocTocRole: - case kFooterRole: - case kFormRole: - case kMainRole: - case kNavigationRole: - case kRegionRole: - case kSearchRole: + case ax::mojom::Role::kApplication: + case ax::mojom::Role::kArticle: + case ax::mojom::Role::kBanner: + case ax::mojom::Role::kComplementary: + case ax::mojom::Role::kContentInfo: + case ax::mojom::Role::kDocAcknowledgments: + case ax::mojom::Role::kDocAfterword: + case ax::mojom::Role::kDocAppendix: + case ax::mojom::Role::kDocBibliography: + case ax::mojom::Role::kDocChapter: + case ax::mojom::Role::kDocConclusion: + case ax::mojom::Role::kDocCredits: + case ax::mojom::Role::kDocEndnotes: + case ax::mojom::Role::kDocEpilogue: + case ax::mojom::Role::kDocErrata: + case ax::mojom::Role::kDocForeword: + case ax::mojom::Role::kDocGlossary: + case ax::mojom::Role::kDocIntroduction: + case ax::mojom::Role::kDocPart: + case ax::mojom::Role::kDocPreface: + case ax::mojom::Role::kDocPrologue: + case ax::mojom::Role::kDocToc: + case ax::mojom::Role::kFooter: + case ax::mojom::Role::kForm: + case ax::mojom::Role::kMain: + case ax::mojom::Role::kNavigation: + case ax::mojom::Role::kRegion: + case ax::mojom::Role::kSearch: return true; default: return false; @@ -784,12 +799,12 @@ bool AXObject::IsLandmarkRelated() const { bool AXObject::IsMenuRelated() const { switch (RoleValue()) { - case kMenuRole: - case kMenuBarRole: - case kMenuButtonRole: - case kMenuItemRole: - case kMenuItemCheckBoxRole: - case kMenuItemRadioRole: + case ax::mojom::Role::kMenu: + case ax::mojom::Role::kMenuBar: + case ax::mojom::Role::kMenuButton: + case ax::mojom::Role::kMenuItem: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: return true; default: return false; @@ -805,11 +820,12 @@ bool AXObject::IsPasswordFieldAndShouldHideValue() const { } bool AXObject::IsTextObject() const { - // Objects with |kLineBreakRole| are HTML <br> elements and are not backed by - // DOM text nodes. We can't mark them as text objects for that reason. + // Objects with |ax::mojom::Role::kLineBreak| are HTML <br> elements and are + // not backed by DOM text nodes. We can't mark them as text objects for that + // reason. switch (RoleValue()) { - case kInlineTextBoxRole: - case kStaticTextRole: + case ax::mojom::Role::kInlineTextBox: + case ax::mojom::Role::kStaticText: return true; default: return false; @@ -820,21 +836,22 @@ bool AXObject::IsClickable() const { if (IsButton() || IsLink() || IsTextControl()) return true; - // TODO(dmazzoni): Ensure that kColorWellRole and kSpinButtonRole are - // correctly handled here via their constituent parts. + // TODO(dmazzoni): Ensure that ax::mojom::Role::kColorWell and + // ax::mojom::Role::kSpinButton are correctly handled here via their + // constituent parts. switch (RoleValue()) { - case kCheckBoxRole: - case kComboBoxMenuButtonRole: - case kDisclosureTriangleRole: - case kListBoxRole: - case kListBoxOptionRole: - case kMenuItemCheckBoxRole: - case kMenuItemRadioRole: - case kMenuItemRole: - case kMenuListOptionRole: - case kRadioButtonRole: - case kSwitchRole: - case kTabRole: + case ax::mojom::Role::kCheckBox: + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kDisclosureTriangle: + case ax::mojom::Role::kListBox: + case ax::mojom::Role::kListBoxOption: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kMenuItem: + case ax::mojom::Role::kMenuListOption: + case ax::mojom::Role::kRadioButton: + case ax::mojom::Role::kSwitch: + case ax::mojom::Role::kTab: return true; default: return false; @@ -1099,7 +1116,7 @@ bool AXObject::DispatchEventToAOMEventListeners(Event& event) { // Bubbling phase. event.SetEventPhase(Event::kBubblingPhase); - for (size_t i = 1; i < event_path.size(); i++) { + for (wtf_size_t i = 1; i < event_path.size(); i++) { event.SetCurrentTarget(event_path[i]); event_path[i]->FireEventListeners(event); if (event.PropagationStopped()) @@ -1133,10 +1150,10 @@ const AXObject* AXObject::DisabledAncestor() const { const AXObject* AXObject::DatetimeAncestor(int max_levels_to_check) const { switch (RoleValue()) { - case kDateTimeRole: - case kDateRole: - case kInputTimeRole: - case kTimeRole: + case ax::mojom::Role::kDateTime: + case ax::mojom::Role::kDate: + case ax::mojom::Role::kInputTime: + case ax::mojom::Role::kTime: return this; default: break; @@ -1185,17 +1202,17 @@ bool AXObject::CanReceiveAccessibilityFocus() const { bool AXObject::CanSetValueAttribute() const { switch (RoleValue()) { - case kColorWellRole: - case kDateRole: - case kDateTimeRole: - case kScrollBarRole: - case kSliderRole: - case kSpinButtonRole: - case kSplitterRole: - case kTextFieldRole: - case kTextFieldWithComboBoxRole: - case kTimeRole: - case kSearchBoxRole: + case ax::mojom::Role::kColorWell: + case ax::mojom::Role::kDate: + case ax::mojom::Role::kDateTime: + case ax::mojom::Role::kScrollBar: + case ax::mojom::Role::kSlider: + case ax::mojom::Role::kSpinButton: + case ax::mojom::Role::kSplitter: + case ax::mojom::Role::kTextField: + case ax::mojom::Role::kTextFieldWithComboBox: + case ax::mojom::Role::kTime: + case ax::mojom::Role::kSearchBox: return Restriction() == kNone; default: break; @@ -1213,7 +1230,7 @@ bool AXObject::CanSetFocusAttribute() const { // Children of elements with an aria-activedescendant attribute should be // focusable if they have a (non-presentational) ARIA role. - if (!IsPresentational() && AriaRoleAttribute() != kUnknownRole && + if (!IsPresentational() && AriaRoleAttribute() != ax::mojom::Role::kUnknown && CanBeActiveDescendant()) { return true; } @@ -1228,7 +1245,8 @@ bool AXObject::CanSetFocusAttribute() const { // don't help when the <option> is canvas fallback, and because // a common case for aria-owns from a textbox that points to a list // does not change the hierarchy (textboxes don't support children) - if (RoleValue() == kListBoxOptionRole || RoleValue() == kMenuListOptionRole) + if (RoleValue() == ax::mojom::Role::kListBoxOption || + RoleValue() == ax::mojom::Role::kMenuListOption) return true; return node->IsElementNode() && ToElement(node)->SupportsFocus(); @@ -1290,8 +1308,7 @@ bool AXObject::AncestorExposesActiveDescendant() const { if (!parent) return false; - if (parent->SupportsARIAActiveDescendant() && - parent->GetAOMPropertyOrARIAAttribute( + if (parent->GetAOMPropertyOrARIAAttribute( AOMRelationProperty::kActiveDescendant)) { return true; } @@ -1300,7 +1317,7 @@ bool AXObject::AncestorExposesActiveDescendant() const { } bool AXObject::HasIndirectChildren() const { - return IsTableCol() || RoleValue() == kTableHeaderContainerRole; + return IsTableCol() || RoleValue() == ax::mojom::Role::kTableHeaderContainer; } bool AXObject::CanSetSelectedAttribute() const { @@ -1310,11 +1327,11 @@ bool AXObject::CanSetSelectedAttribute() const { bool AXObject::IsSubWidget() const { switch (RoleValue()) { - case kCellRole: - case kColumnHeaderRole: - case kRowHeaderRole: - case kColumnRole: - case kRowRole: { + case ax::mojom::Role::kCell: + case ax::mojom::Role::kColumnHeader: + case ax::mojom::Role::kRowHeader: + case ax::mojom::Role::kColumn: + case ax::mojom::Role::kRow: { // If it has an explicit ARIA role, it's a subwidget. // // Reasoning: @@ -1328,7 +1345,7 @@ bool AXObject::IsSubWidget() const { // an ARIA 1.1 role of "table", should not be selectable. We may // need to create separate role enums for grid cells vs table cells // to implement this. - if (AriaRoleAttribute() != kUnknownRole) + if (AriaRoleAttribute() != ax::mojom::Role::kUnknown) return true; // Otherwise it's only a subwidget if it's in a grid or treegrid, @@ -1336,15 +1353,15 @@ bool AXObject::IsSubWidget() const { AXObject* parent = ParentObjectUnignored(); while (parent && !parent->IsTableLikeRole()) parent = parent->ParentObjectUnignored(); - if (parent && (parent->RoleValue() == kGridRole || - parent->RoleValue() == kTreeGridRole)) + if (parent && (parent->RoleValue() == ax::mojom::Role::kGrid || + parent->RoleValue() == ax::mojom::Role::kTreeGrid)) return true; return false; } - case kListBoxOptionRole: - case kMenuListOptionRole: - case kTabRole: - case kTreeItemRole: + case ax::mojom::Role::kListBoxOption: + case ax::mojom::Role::kMenuListOption: + case ax::mojom::Role::kTab: + case ax::mojom::Role::kTreeItem: return true; default: break; @@ -1354,17 +1371,17 @@ bool AXObject::IsSubWidget() const { bool AXObject::SupportsARIASetSizeAndPosInSet() const { switch (RoleValue()) { - case kArticleRole: - case kListBoxOptionRole: - case kListItemRole: - case kMenuItemRole: - case kMenuItemRadioRole: - case kMenuItemCheckBoxRole: - case kMenuListOptionRole: - case kRadioButtonRole: - case kRowRole: - case kTabRole: - case kTreeItemRole: + case ax::mojom::Role::kArticle: + case ax::mojom::Role::kListBoxOption: + case ax::mojom::Role::kListItem: + case ax::mojom::Role::kMenuItem: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuListOption: + case ax::mojom::Role::kRadioButton: + case ax::mojom::Role::kRow: + case ax::mojom::Role::kTab: + case ax::mojom::Role::kTreeItem: return true; default: break; @@ -1387,27 +1404,28 @@ String AXObject::CollapseWhitespace(const String& str) { } String AXObject::ComputedName() const { - AXNameFrom name_from; + ax::mojom::NameFrom name_from; AXObject::AXObjectVector name_objects; return GetName(name_from, &name_objects); } -String AXObject::GetName(AXNameFrom& name_from, +String AXObject::GetName(ax::mojom::NameFrom& name_from, AXObject::AXObjectVector* name_objects) const { HeapHashSet<Member<const AXObject>> visited; AXRelatedObjectVector related_objects; String text = TextAlternative(false, false, visited, name_from, &related_objects, nullptr); - AccessibilityRole role = RoleValue(); - if (!GetNode() || (!IsHTMLBRElement(GetNode()) && role != kStaticTextRole && - role != kInlineTextBoxRole)) + ax::mojom::Role role = RoleValue(); + if (!GetNode() || + (!IsHTMLBRElement(GetNode()) && role != ax::mojom::Role::kStaticText && + role != ax::mojom::Role::kInlineTextBox)) text = CollapseWhitespace(text); if (name_objects) { name_objects->clear(); - for (size_t i = 0; i < related_objects.size(); i++) - name_objects->push_back(related_objects[i]->object); + for (NameSourceRelatedObject* related_object : related_objects) + name_objects->push_back(related_object->object); } return text; @@ -1415,7 +1433,7 @@ String AXObject::GetName(AXNameFrom& name_from, String AXObject::GetName(NameSources* name_sources) const { AXObjectSet visited; - AXNameFrom tmp_name_from; + ax::mojom::NameFrom tmp_name_from; AXRelatedObjectVector tmp_related_objects; String text = TextAlternative(false, false, visited, tmp_name_from, &tmp_related_objects, name_sources); @@ -1426,12 +1444,20 @@ String AXObject::GetName(NameSources* name_sources) const { String AXObject::RecursiveTextAlternative(const AXObject& ax_obj, bool in_aria_labelled_by_traversal, AXObjectSet& visited) { + ax::mojom::NameFrom tmp_name_from; + return RecursiveTextAlternative(ax_obj, in_aria_labelled_by_traversal, + visited, tmp_name_from); +} + +String AXObject::RecursiveTextAlternative(const AXObject& ax_obj, + bool in_aria_labelled_by_traversal, + AXObjectSet& visited, + ax::mojom::NameFrom& name_from) { if (visited.Contains(&ax_obj) && !in_aria_labelled_by_traversal) return String(); - AXNameFrom tmp_name_from; return ax_obj.TextAlternative(true, in_aria_labelled_by_traversal, visited, - tmp_name_from, nullptr, nullptr); + name_from, nullptr, nullptr); } bool AXObject::IsHiddenForTextAlternativeCalculation() const { @@ -1464,7 +1490,7 @@ bool AXObject::IsHiddenForTextAlternativeCalculation() const { String AXObject::AriaTextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom& name_from, + ax::mojom::NameFrom& name_from, AXRelatedObjectVector* related_objects, NameSources* name_sources, bool* found_text_alternative) const { @@ -1483,7 +1509,7 @@ String AXObject::AriaTextAlternative(bool recursive, // Step 2B from: http://www.w3.org/TR/accname-aam-1.1 // If you change this logic, update AXNodeObject::nameFromLabelElement, too. if (!in_aria_labelled_by_traversal && !already_visited) { - name_from = kAXNameFromRelatedElement; + name_from = ax::mojom::NameFrom::kRelatedElement; // Check AOM property first. HeapVector<Member<Element>> elements; @@ -1560,7 +1586,7 @@ String AXObject::AriaTextAlternative(bool recursive, // Step 2C from: http://www.w3.org/TR/accname-aam-1.1 // If you change this logic, update AXNodeObject::nameFromLabelElement, too. - name_from = kAXNameFromAttribute; + name_from = ax::mojom::NameFrom::kAttribute; if (name_sources) { name_sources->push_back( NameSource(*found_text_alternative, aria_labelAttr)); @@ -1688,39 +1714,40 @@ void AXObject::TextCharacterOffsets(Vector<int>&) const {} void AXObject::GetWordBoundaries(Vector<AXRange>&) const {} -AXDefaultActionVerb AXObject::Action() const { +ax::mojom::DefaultActionVerb AXObject::Action() const { Element* action_element = ActionElement(); if (!action_element) - return AXDefaultActionVerb::kNone; + return ax::mojom::DefaultActionVerb::kNone; // TODO(dmazzoni): Ensure that combo box text field is handled here. if (IsTextControl()) - return AXDefaultActionVerb::kActivate; + return ax::mojom::DefaultActionVerb::kActivate; if (IsCheckable()) { - return CheckedState() != kCheckedStateTrue ? AXDefaultActionVerb::kCheck - : AXDefaultActionVerb::kUncheck; + return CheckedState() != ax::mojom::CheckedState::kTrue + ? ax::mojom::DefaultActionVerb::kCheck + : ax::mojom::DefaultActionVerb::kUncheck; } switch (RoleValue()) { - case kButtonRole: - case kDisclosureTriangleRole: - case kToggleButtonRole: - return AXDefaultActionVerb::kPress; - case kListBoxOptionRole: - case kMenuItemRadioRole: - case kMenuItemRole: - case kMenuListOptionRole: - return AXDefaultActionVerb::kSelect; - case kLinkRole: - return AXDefaultActionVerb::kJump; - case kComboBoxMenuButtonRole: - case kPopUpButtonRole: - return AXDefaultActionVerb::kOpen; + case ax::mojom::Role::kButton: + case ax::mojom::Role::kDisclosureTriangle: + case ax::mojom::Role::kToggleButton: + return ax::mojom::DefaultActionVerb::kPress; + case ax::mojom::Role::kListBoxOption: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kMenuItem: + case ax::mojom::Role::kMenuListOption: + return ax::mojom::DefaultActionVerb::kSelect; + case ax::mojom::Role::kLink: + return ax::mojom::DefaultActionVerb::kJump; + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kPopUpButton: + return ax::mojom::DefaultActionVerb::kOpen; default: if (action_element == GetNode()) - return AXDefaultActionVerb::kClick; - return AXDefaultActionVerb::kClickAncestor; + return ax::mojom::DefaultActionVerb::kClick; + return ax::mojom::DefaultActionVerb::kClickAncestor; } } @@ -1734,105 +1761,129 @@ bool AXObject::AriaCheckedIsPresent() const { return HasAOMPropertyOrARIAAttribute(AOMStringProperty::kChecked, result); } -bool AXObject::SupportsARIAActiveDescendant() const { - // According to the ARIA Spec, all ARIA composite widgets, ARIA text boxes, - // ARIA groups and ARIA application should be able to expose an active descendant. - // Implicitly, <input> and <textarea> elements should also have this ability. +bool AXObject::SupportsARIAExpanded() const { switch (RoleValue()) { - case kComboBoxGroupingRole: - case kComboBoxMenuButtonRole: - case kGridRole: - case kGroupRole: - case kListBoxRole: - case kMenuRole: - case kMenuBarRole: - case kRadioGroupRole: - case kRowRole: - case kSearchBoxRole: - case kTabListRole: - case kTextFieldRole: - case kTextFieldWithComboBoxRole: - case kToolbarRole: - case kTreeRole: - case kTreeGridRole: - case kApplicationRole: + case ax::mojom::Role::kAlertDialog: + case ax::mojom::Role::kAlert: + case ax::mojom::Role::kArticle: + case ax::mojom::Role::kBanner: + case ax::mojom::Role::kButton: + case ax::mojom::Role::kCell: + case ax::mojom::Role::kColumnHeader: + case ax::mojom::Role::kComboBoxGrouping: + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kComplementary: + case ax::mojom::Role::kContentInfo: + case ax::mojom::Role::kDefinition: + case ax::mojom::Role::kDialog: + case ax::mojom::Role::kDirectory: + case ax::mojom::Role::kDisclosureTriangle: + case ax::mojom::Role::kDocument: + case ax::mojom::Role::kFeed: + case ax::mojom::Role::kFigure: + case ax::mojom::Role::kForm: + case ax::mojom::Role::kGrid: + case ax::mojom::Role::kGroup: + case ax::mojom::Role::kHeading: + case ax::mojom::Role::kImage: + case ax::mojom::Role::kLayoutTable: + case ax::mojom::Role::kList: + case ax::mojom::Role::kListBox: + case ax::mojom::Role::kListBoxOption: + case ax::mojom::Role::kListItem: + case ax::mojom::Role::kLink: + case ax::mojom::Role::kLog: + case ax::mojom::Role::kMain: + case ax::mojom::Role::kMarquee: + case ax::mojom::Role::kMath: + case ax::mojom::Role::kMenu: + case ax::mojom::Role::kMenuBar: + case ax::mojom::Role::kMenuButton: + case ax::mojom::Role::kMenuItem: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kNavigation: + case ax::mojom::Role::kNote: + case ax::mojom::Role::kProgressIndicator: + case ax::mojom::Role::kRadioGroup: + case ax::mojom::Role::kRegion: + case ax::mojom::Role::kRow: + case ax::mojom::Role::kRowHeader: + case ax::mojom::Role::kSearch: + case ax::mojom::Role::kStatus: + case ax::mojom::Role::kTab: + case ax::mojom::Role::kTable: + case ax::mojom::Role::kTabPanel: + case ax::mojom::Role::kTerm: + case ax::mojom::Role::kTextFieldWithComboBox: + case ax::mojom::Role::kTimer: + case ax::mojom::Role::kToolbar: + case ax::mojom::Role::kTooltip: + case ax::mojom::Role::kTree: + case ax::mojom::Role::kTreeGrid: + case ax::mojom::Role::kTreeItem: return true; default: return false; } } -bool AXObject::SupportsARIAExpanded() const { - switch (RoleValue()) { - case kAlertDialogRole: - case kAlertRole: - case kArticleRole: - case kBannerRole: - case kButtonRole: - case kCellRole: - case kColumnHeaderRole: - case kComboBoxGroupingRole: - case kComboBoxMenuButtonRole: - case kComplementaryRole: - case kContentInfoRole: - case kDefinitionRole: - case kDialogRole: - case kDirectoryRole: - case kDisclosureTriangleRole: - case kDocumentRole: - case kFeedRole: - case kFigureRole: - case kFormRole: - case kGridRole: - case kGroupRole: - case kHeadingRole: - case kImageRole: - case kLayoutTableRole: - case kListRole: - case kListBoxRole: - case kListBoxOptionRole: - case kListItemRole: - case kLinkRole: - case kLogRole: - case kMainRole: - case kMarqueeRole: - case kMathRole: - case kMenuRole: - case kMenuBarRole: - case kMenuButtonRole: - case kMenuItemRole: - case kMenuItemCheckBoxRole: - case kMenuItemRadioRole: - case kNavigationRole: - case kNoteRole: - case kProgressIndicatorRole: - case kRadioGroupRole: - case kRegionRole: - case kRowRole: - case kRowHeaderRole: - case kSearchRole: - case kStatusRole: - case kTabRole: - case kTableRole: - case kTabPanelRole: - case kTermRole: - case kTextFieldWithComboBoxRole: - case kTimerRole: - case kToolbarRole: - case kUserInterfaceTooltipRole: - case kTreeRole: - case kTreeGridRole: - case kTreeItemRole: +bool AXObject::HasGlobalARIAAttribute() const { + if (!GetElement()) + return false; + + AttributeCollection attributes = GetElement()->AttributesWithoutUpdate(); + for (const Attribute& attr : attributes) { + // Attributes cache their uppercase names. + auto name = attr.GetName().LocalNameUpper(); + if (!name.StartsWith("ARIA")) + continue; + if (name.StartsWith("ARIA-ATOMIC")) + return true; + if (name.StartsWith("ARIA-BUSY")) + return true; + if (name.StartsWith("ARIA-CONTROLS")) + return true; + if (name.StartsWith("ARIA-CURRENT")) + return true; + if (name.StartsWith("ARIA-DESCRIBEDBY")) + return true; + if (name.StartsWith("ARIA-DETAILS")) + return true; + if (name.StartsWith("ARIA-DISABLED")) + return true; + if (name.StartsWith("ARIA-DROPEFFECT")) + return true; + if (name.StartsWith("ARIA-ERRORMESSAGE")) + return true; + if (name.StartsWith("ARIA-FLOWTO")) + return true; + if (name.StartsWith("ARIA-GRABBED")) + return true; + if (name.StartsWith("ARIA-HASPOPUP")) + return true; + if (name.StartsWith("ARIA-HIDDEN")) + return true; + if (name.StartsWith("ARIA-INVALID")) + return true; + if (name.StartsWith("ARIA-KEYSHORTCUTS")) + return true; + if (name.StartsWith("ARIA-LABEL")) + return true; + if (name.StartsWith("ARIA-LABELEDBY")) + return true; + if (name.StartsWith("ARIA-LABELLEDBY")) + return true; + if (name.StartsWith("ARIA-LIVE")) + return true; + if (name.StartsWith("ARIA-OWNS")) + return true; + if (name.StartsWith("ARIA-RELEVANT")) + return true; + if (name.StartsWith("ARIA-ROLEDESCRIPTION")) return true; - default: - return false; } -} - -bool AXObject::SupportsARIAAttributes() const { - return IsLiveRegion() || SupportsARIADragging() || SupportsARIADropping() || - SupportsARIAFlowTo() || SupportsARIAOwns() || - HasAttribute(aria_labelAttr) || HasAttribute(aria_currentAttr); + return false; } bool AXObject::SupportsRangeValue() const { @@ -1882,82 +1933,87 @@ AXRestriction AXObject::Restriction() const { return kNone; } -AccessibilityRole AXObject::DetermineAccessibilityRole() { +ax::mojom::Role AXObject::DetermineAccessibilityRole() { aria_role_ = DetermineAriaRoleAttribute(); return aria_role_; } -AccessibilityRole AXObject::AriaRoleAttribute() const { +ax::mojom::Role AXObject::AriaRoleAttribute() const { return aria_role_; } -AccessibilityRole AXObject::DetermineAriaRoleAttribute() const { +ax::mojom::Role AXObject::DetermineAriaRoleAttribute() const { const AtomicString& aria_role = GetAOMPropertyOrARIAAttribute(AOMStringProperty::kRole); if (aria_role.IsNull() || aria_role.IsEmpty()) - return kUnknownRole; + return ax::mojom::Role::kUnknown; - AccessibilityRole role = AriaRoleToWebCoreRole(aria_role); + ax::mojom::Role role = AriaRoleToWebCoreRole(aria_role); // ARIA states if an item can get focus, it should not be presentational. - if ((role == kNoneRole || role == kPresentationalRole) && - CanSetFocusAttribute()) - return kUnknownRole; - - if (role == kButtonRole) + // It also states user agents should ignore the presentational role if + // the element has global ARIA states and properties. + if ((role == ax::mojom::Role::kNone || + role == ax::mojom::Role::kPresentational) && + (CanSetFocusAttribute() || HasGlobalARIAAttribute())) + return ax::mojom::Role::kUnknown; + + if (role == ax::mojom::Role::kButton) role = ButtonRoleType(); role = RemapAriaRoleDueToParent(role); // Distinguish between different uses of the "combobox" role: // - // kComboBoxGroupingRole: + // ax::mojom::Role::kComboBoxGrouping: // <div role="combobox"><input></div> - // kTextFieldWithComboBoxRole: + // ax::mojom::Role::kTextFieldWithComboBox: // <input role="combobox"> - // kComboBoxMenuButtonRole: + // ax::mojom::Role::kComboBoxMenuButton: // <div tabindex=0 role="combobox">Select</div> - if (role == kComboBoxGroupingRole) { + if (role == ax::mojom::Role::kComboBoxGrouping) { if (IsNativeTextControl()) - role = kTextFieldWithComboBoxRole; + role = ax::mojom::Role::kTextFieldWithComboBox; else if (GetElement() && GetElement()->SupportsFocus()) - role = kComboBoxMenuButtonRole; + role = ax::mojom::Role::kComboBoxMenuButton; } - if (role) + if (role != ax::mojom::Role::kUnknown) return role; - return kUnknownRole; + return ax::mojom::Role::kUnknown; } -AccessibilityRole AXObject::RemapAriaRoleDueToParent( - AccessibilityRole role) const { +ax::mojom::Role AXObject::RemapAriaRoleDueToParent(ax::mojom::Role role) const { // Some objects change their role based on their parent. // However, asking for the unignoredParent calls accessibilityIsIgnored(), // which can trigger a loop. While inside the call stack of creating an // element, we need to avoid accessibilityIsIgnored(). // https://bugs.webkit.org/show_bug.cgi?id=65174 - if (role != kListBoxOptionRole && role != kMenuItemRole) + if (role != ax::mojom::Role::kListBoxOption && + role != ax::mojom::Role::kMenuItem) return role; for (AXObject* parent = ParentObject(); parent && !parent->AccessibilityIsIgnored(); parent = parent->ParentObject()) { - AccessibilityRole parent_aria_role = parent->AriaRoleAttribute(); + ax::mojom::Role parent_aria_role = parent->AriaRoleAttribute(); // Selects and listboxes both have options as child roles, but they map to // different roles within WebCore. - if (role == kListBoxOptionRole && parent_aria_role == kMenuRole) - return kMenuItemRole; + if (role == ax::mojom::Role::kListBoxOption && + parent_aria_role == ax::mojom::Role::kMenu) + return ax::mojom::Role::kMenuItem; // An aria "menuitem" may map to MenuButton or MenuItem depending on its // parent. - if (role == kMenuItemRole && parent_aria_role == kGroupRole) - return kMenuButtonRole; + if (role == ax::mojom::Role::kMenuItem && + parent_aria_role == ax::mojom::Role::kGroup) + return ax::mojom::Role::kMenuButton; // If the parent had a different role, then we don't need to continue // searching up the chain. - if (parent_aria_role) + if (parent_aria_role != ax::mojom::Role::kUnknown) break; } @@ -1981,7 +2037,8 @@ bool AXObject::LiveRegionAtomic() const { // ARIA roles "alert" and "status" should have an implicit aria-atomic value // of true. - return RoleValue() == kAlertRole || RoleValue() == kStatusRole; + return RoleValue() == ax::mojom::Role::kAlert || + RoleValue() == ax::mojom::Role::kStatus; } const AtomicString& AXObject::ContainerLiveRegionStatus() const { @@ -2195,18 +2252,18 @@ AXObject* AXObject::ParentObjectUnignored() const { // sub-widgets bool AXObject::IsContainerWidget() const { switch (RoleValue()) { - case kComboBoxGroupingRole: - case kComboBoxMenuButtonRole: - case kGridRole: - case kListBoxRole: - case kMenuBarRole: - case kMenuRole: - case kRadioGroupRole: - case kSpinButtonRole: - case kTabListRole: - case kToolbarRole: - case kTreeGridRole: - case kTreeRole: + case ax::mojom::Role::kComboBoxGrouping: + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kGrid: + case ax::mojom::Role::kListBox: + case ax::mojom::Role::kMenuBar: + case ax::mojom::Role::kMenu: + case ax::mojom::Role::kRadioGroup: + case ax::mojom::Role::kSpinButton: + case ax::mojom::Role::kTabList: + case ax::mojom::Role::kToolbar: + case ax::mojom::Role::kTreeGrid: + case ax::mojom::Role::kTree: return true; default: return false; @@ -2378,10 +2435,10 @@ void AXObject::SetScrollOffset(const IntPoint& offset) const { bool AXObject::IsTableLikeRole() const { switch (RoleValue()) { - case kLayoutTableRole: - case kTableRole: - case kGridRole: - case kTreeGridRole: + case ax::mojom::Role::kLayoutTable: + case ax::mojom::Role::kTable: + case ax::mojom::Role::kGrid: + case ax::mojom::Role::kTreeGrid: return true; default: return false; @@ -2389,15 +2446,16 @@ bool AXObject::IsTableLikeRole() const { } bool AXObject::IsTableRowLikeRole() const { - return RoleValue() == kRowRole || RoleValue() == kLayoutTableRowRole; + return RoleValue() == ax::mojom::Role::kRow || + RoleValue() == ax::mojom::Role::kLayoutTableRow; } bool AXObject::IsTableCellLikeRole() const { switch (RoleValue()) { - case kLayoutTableCellRole: - case kCellRole: - case kColumnHeaderRole: - case kRowHeaderRole: + case ax::mojom::Role::kLayoutTableCell: + case ax::mojom::Role::kCell: + case ax::mojom::Role::kColumnHeader: + case ax::mojom::Role::kRowHeader: return true; default: return false; @@ -2430,7 +2488,7 @@ void AXObject::ColumnHeaders(AXObjectVector& headers) const { for (const auto& row : TableRowChildren()) { for (const auto& cell : row->TableCellChildren()) { - if (cell->RoleValue() == kColumnHeaderRole) + if (cell->RoleValue() == ax::mojom::Role::kColumnHeader) headers.push_back(cell); } } @@ -2442,7 +2500,7 @@ void AXObject::RowHeaders(AXObjectVector& headers) const { for (const auto& row : TableRowChildren()) { for (const auto& cell : row->TableCellChildren()) { - if (cell->RoleValue() == kRowHeaderRole) + if (cell->RoleValue() == ax::mojom::Role::kRowHeader) headers.push_back(cell); } } @@ -2661,7 +2719,7 @@ AXObject::AXObjectVector AXObject::TableRowChildren() const { for (const auto& child : Children()) { if (child->IsTableRowLikeRole()) result.push_back(child); - else if (child->RoleValue() == kGenericContainerRole) + else if (child->RoleValue() == ax::mojom::Role::kGenericContainer) result.AppendVector(child->TableRowChildren()); } return result; @@ -2672,7 +2730,7 @@ AXObject::AXObjectVector AXObject::TableCellChildren() const { for (const auto& child : Children()) { if (child->IsTableCellLikeRole()) result.push_back(child); - else if (child->RoleValue() == kGenericContainerRole) + else if (child->RoleValue() == ax::mojom::Role::kGenericContainer) result.AppendVector(child->TableCellChildren()); } return result; @@ -2681,7 +2739,7 @@ AXObject::AXObjectVector AXObject::TableCellChildren() const { const AXObject* AXObject::TableRowParent() const { const AXObject* row = ParentObjectUnignored(); while (row && !row->IsTableRowLikeRole() && - row->RoleValue() == kGenericContainerRole) + row->RoleValue() == ax::mojom::Role::kGenericContainer) row = row->ParentObjectUnignored(); return row; } @@ -2689,7 +2747,7 @@ const AXObject* AXObject::TableRowParent() const { const AXObject* AXObject::TableParent() const { const AXObject* table = ParentObjectUnignored(); while (table && !table->IsTableLikeRole() && - table->RoleValue() == kGenericContainerRole) + table->RoleValue() == ax::mojom::Role::kGenericContainer) table = table->ParentObjectUnignored(); return table; } @@ -2856,8 +2914,8 @@ bool AXObject::OnNativeClickAction() { return false; std::unique_ptr<UserGestureIndicator> gesture_indicator = - Frame::NotifyUserActivation(document->GetFrame(), - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(document->GetFrame(), + UserGestureToken::kNewGesture); Element* element = GetElement(); if (!element && GetNode()) @@ -2933,12 +2991,10 @@ bool AXObject::RequestShowContextMenuAction() { } bool AXObject::InternalClearAccessibilityFocusAction() { - // TODO(mlamouri): implement return false; } bool AXObject::InternalSetAccessibilityFocusAction() { - // TODO(mlamouri): implement return false; } @@ -2955,7 +3011,7 @@ bool AXObject::OnNativeScrollToMakeVisibleAction() const { kProgrammaticScroll, false, kScrollBehaviorAuto)); AXObjectCache().PostNotification( AXObjectCache().GetOrCreate(GetDocument()->GetLayoutView()), - AXObjectCacheImpl::kAXLocationChanged); + ax::mojom::Event::kLocationChanged); return true; } @@ -2981,7 +3037,7 @@ bool AXObject::OnNativeScrollToMakeVisibleWithSubFocusAction( kProgrammaticScroll, false, kScrollBehaviorAuto)); AXObjectCache().PostNotification( AXObjectCache().GetOrCreate(GetDocument()->GetLayoutView()), - AXObjectCacheImpl::kAXLocationChanged); + ax::mojom::Event::kLocationChanged); return true; } @@ -3000,7 +3056,7 @@ bool AXObject::OnNativeScrollToGlobalPointAction( kProgrammaticScroll, false, kScrollBehaviorAuto)); AXObjectCache().PostNotification( AXObjectCache().GetOrCreate(GetDocument()->GetLayoutView()), - AXObjectCacheImpl::kAXLocationChanged); + ax::mojom::Event::kLocationChanged); return true; } @@ -3089,35 +3145,52 @@ int AXObject::LineForPosition(const VisiblePosition& position) const { } // static -bool AXObject::IsARIAControl(AccessibilityRole aria_role) { - return IsARIAInput(aria_role) || aria_role == kButtonRole || - aria_role == kComboBoxMenuButtonRole || aria_role == kSliderRole; +bool AXObject::IsARIAControl(ax::mojom::Role aria_role) { + return IsARIAInput(aria_role) || aria_role == ax::mojom::Role::kButton || + aria_role == ax::mojom::Role::kComboBoxMenuButton || + aria_role == ax::mojom::Role::kSlider; } // static -bool AXObject::IsARIAInput(AccessibilityRole aria_role) { - return aria_role == kRadioButtonRole || aria_role == kCheckBoxRole || - aria_role == kTextFieldRole || aria_role == kSwitchRole || - aria_role == kSearchBoxRole || aria_role == kTextFieldWithComboBoxRole; +bool AXObject::IsARIAInput(ax::mojom::Role aria_role) { + return aria_role == ax::mojom::Role::kRadioButton || + aria_role == ax::mojom::Role::kCheckBox || + aria_role == ax::mojom::Role::kTextField || + aria_role == ax::mojom::Role::kSwitch || + aria_role == ax::mojom::Role::kSearchBox || + aria_role == ax::mojom::Role::kTextFieldWithComboBox; } -AccessibilityRole AXObject::AriaRoleToWebCoreRole(const String& value) { +ax::mojom::Role AXObject::AriaRoleToWebCoreRole(const String& value) { DCHECK(!value.IsEmpty()); static const ARIARoleMap* role_map = CreateARIARoleMap(); Vector<String> role_vector; value.Split(' ', role_vector); - AccessibilityRole role = kUnknownRole; + ax::mojom::Role role = ax::mojom::Role::kUnknown; for (const auto& child : role_vector) { role = role_map->at(child); - if (role) + if (role != ax::mojom::Role::kUnknown) return role; } return role; } +bool AXObject::NameFromSelectedOption(bool recursive) const { + switch (RoleValue()) { + // Step 2E from: http://www.w3.org/TR/accname-aam-1.1 + case ax::mojom::Role::kComboBoxGrouping: + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kListBox: + case ax::mojom::Role::kPopUpButton: + return recursive; + default: + return false; + } +} + bool AXObject::NameFromContents(bool recursive) const { // ARIA 1.1, section 5.2.7.5. bool result = false; @@ -3125,191 +3198,200 @@ bool AXObject::NameFromContents(bool recursive) const { switch (RoleValue()) { // ----- NameFrom: contents ------------------------- // Get their own name from contents, or contribute to ancestors - case kAnchorRole: - case kButtonRole: - case kCellRole: - case kCheckBoxRole: - case kColumnHeaderRole: - case kComboBoxMenuButtonRole: - case kDocBackLinkRole: - case kDocBiblioRefRole: - case kDocNoteRefRole: - case kDocGlossRefRole: - case kDisclosureTriangleRole: - case kHeadingRole: - case kLayoutTableCellRole: - case kLineBreakRole: - case kLinkRole: - case kListBoxOptionRole: - case kMenuButtonRole: - case kMenuItemRole: - case kMenuItemCheckBoxRole: - case kMenuItemRadioRole: - case kMenuListOptionRole: - case kPopUpButtonRole: - case kRadioButtonRole: - case kRowHeaderRole: - case kStaticTextRole: - case kSwitchRole: - case kTabRole: - case kToggleButtonRole: - case kTreeItemRole: - case kUserInterfaceTooltipRole: + case ax::mojom::Role::kAnchor: + case ax::mojom::Role::kButton: + case ax::mojom::Role::kCell: + case ax::mojom::Role::kCheckBox: + case ax::mojom::Role::kColumnHeader: + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kDocBackLink: + case ax::mojom::Role::kDocBiblioRef: + case ax::mojom::Role::kDocNoteRef: + case ax::mojom::Role::kDocGlossRef: + case ax::mojom::Role::kDisclosureTriangle: + case ax::mojom::Role::kHeading: + case ax::mojom::Role::kLayoutTableCell: + case ax::mojom::Role::kLineBreak: + case ax::mojom::Role::kLink: + case ax::mojom::Role::kListBoxOption: + case ax::mojom::Role::kMenuButton: + case ax::mojom::Role::kMenuItem: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kMenuListOption: + case ax::mojom::Role::kPopUpButton: + case ax::mojom::Role::kRadioButton: + case ax::mojom::Role::kRowHeader: + case ax::mojom::Role::kStaticText: + case ax::mojom::Role::kSwitch: + case ax::mojom::Role::kTab: + case ax::mojom::Role::kToggleButton: + case ax::mojom::Role::kTreeItem: + case ax::mojom::Role::kTooltip: result = true; break; // ----- No name from contents ------------------------- // These never have or contribute a name from contents, as they are // containers for many subobjects. Superset of nameFrom:author ARIA roles. - case kAlertRole: - case kAlertDialogRole: - case kApplicationRole: - case kAudioRole: - case kArticleRole: - case kBannerRole: - case kBlockquoteRole: - case kColorWellRole: - case kColumnRole: - case kComboBoxGroupingRole: - case kComplementaryRole: - case kContentInfoRole: - case kDateRole: - case kDateTimeRole: - case kDefinitionRole: - case kDialogRole: - case kDirectoryRole: - case kDocCoverRole: - case kDocBiblioEntryRole: - case kDocEndnoteRole: - case kDocFootnoteRole: - case kDocPageBreakRole: - case kDocAbstractRole: - case kDocAcknowledgmentsRole: - case kDocAfterwordRole: - case kDocAppendixRole: - case kDocBibliographyRole: - case kDocChapterRole: - case kDocColophonRole: - case kDocConclusionRole: - case kDocCreditRole: - case kDocCreditsRole: - case kDocDedicationRole: - case kDocEndnotesRole: - case kDocEpigraphRole: - case kDocEpilogueRole: - case kDocErrataRole: - case kDocExampleRole: - case kDocForewordRole: - case kDocGlossaryRole: - case kDocIndexRole: - case kDocIntroductionRole: - case kDocNoticeRole: - case kDocPageListRole: - case kDocPartRole: - case kDocPrefaceRole: - case kDocPrologueRole: - case kDocPullquoteRole: - case kDocQnaRole: - case kDocSubtitleRole: - case kDocTipRole: - case kDocTocRole: - case kDocumentRole: - case kEmbeddedObjectRole: - case kFeedRole: - case kFigureRole: - case kFormRole: - case kGraphicsDocumentRole: - case kGraphicsObjectRole: - case kGraphicsSymbolRole: - case kGridRole: - case kGroupRole: - case kIframePresentationalRole: - case kIframeRole: - case kImageRole: - case kInputTimeRole: - case kListBoxRole: - case kLogRole: - case kMainRole: - case kMarqueeRole: - case kMathRole: - case kMenuListPopupRole: - case kMenuRole: - case kMenuBarRole: - case kMeterRole: - case kNavigationRole: - case kNoteRole: - case kProgressIndicatorRole: - case kRadioGroupRole: - case kScrollBarRole: - case kSearchRole: - case kSearchBoxRole: - case kSplitterRole: - case kSliderRole: - case kSpinButtonRole: - case kStatusRole: - case kSliderThumbRole: - case kSVGRootRole: - case kTableRole: - case kTableHeaderContainerRole: - case kTabListRole: - case kTabPanelRole: - case kTermRole: - case kTextFieldRole: - case kTextFieldWithComboBoxRole: - case kTimeRole: - case kTimerRole: - case kToolbarRole: - case kTreeRole: - case kTreeGridRole: - case kVideoRole: - case kWebAreaRole: + case ax::mojom::Role::kAlert: + case ax::mojom::Role::kAlertDialog: + case ax::mojom::Role::kApplication: + case ax::mojom::Role::kAudio: + case ax::mojom::Role::kArticle: + case ax::mojom::Role::kBanner: + case ax::mojom::Role::kBlockquote: + case ax::mojom::Role::kCaret: + case ax::mojom::Role::kClient: + case ax::mojom::Role::kColorWell: + case ax::mojom::Role::kColumn: + case ax::mojom::Role::kComboBoxGrouping: + case ax::mojom::Role::kComplementary: + case ax::mojom::Role::kContentInfo: + case ax::mojom::Role::kDate: + case ax::mojom::Role::kDateTime: + case ax::mojom::Role::kDefinition: + case ax::mojom::Role::kDesktop: + case ax::mojom::Role::kDialog: + case ax::mojom::Role::kDirectory: + case ax::mojom::Role::kDocCover: + case ax::mojom::Role::kDocBiblioEntry: + case ax::mojom::Role::kDocEndnote: + case ax::mojom::Role::kDocFootnote: + case ax::mojom::Role::kDocPageBreak: + case ax::mojom::Role::kDocAbstract: + case ax::mojom::Role::kDocAcknowledgments: + case ax::mojom::Role::kDocAfterword: + case ax::mojom::Role::kDocAppendix: + case ax::mojom::Role::kDocBibliography: + case ax::mojom::Role::kDocChapter: + case ax::mojom::Role::kDocColophon: + case ax::mojom::Role::kDocConclusion: + case ax::mojom::Role::kDocCredit: + case ax::mojom::Role::kDocCredits: + case ax::mojom::Role::kDocDedication: + case ax::mojom::Role::kDocEndnotes: + case ax::mojom::Role::kDocEpigraph: + case ax::mojom::Role::kDocEpilogue: + case ax::mojom::Role::kDocErrata: + case ax::mojom::Role::kDocExample: + case ax::mojom::Role::kDocForeword: + case ax::mojom::Role::kDocGlossary: + case ax::mojom::Role::kDocIndex: + case ax::mojom::Role::kDocIntroduction: + case ax::mojom::Role::kDocNotice: + case ax::mojom::Role::kDocPageList: + case ax::mojom::Role::kDocPart: + case ax::mojom::Role::kDocPreface: + case ax::mojom::Role::kDocPrologue: + case ax::mojom::Role::kDocPullquote: + case ax::mojom::Role::kDocQna: + case ax::mojom::Role::kDocSubtitle: + case ax::mojom::Role::kDocTip: + case ax::mojom::Role::kDocToc: + case ax::mojom::Role::kDocument: + case ax::mojom::Role::kEmbeddedObject: + case ax::mojom::Role::kFeed: + case ax::mojom::Role::kFigure: + case ax::mojom::Role::kForm: + case ax::mojom::Role::kGraphicsDocument: + case ax::mojom::Role::kGraphicsObject: + case ax::mojom::Role::kGraphicsSymbol: + case ax::mojom::Role::kGrid: + case ax::mojom::Role::kGroup: + case ax::mojom::Role::kIframePresentational: + case ax::mojom::Role::kIframe: + case ax::mojom::Role::kImage: + case ax::mojom::Role::kInputTime: + case ax::mojom::Role::kKeyboard: + case ax::mojom::Role::kListBox: + case ax::mojom::Role::kLog: + case ax::mojom::Role::kMain: + case ax::mojom::Role::kMarquee: + case ax::mojom::Role::kMath: + case ax::mojom::Role::kMenuListPopup: + case ax::mojom::Role::kMenu: + case ax::mojom::Role::kMenuBar: + case ax::mojom::Role::kMeter: + case ax::mojom::Role::kNavigation: + case ax::mojom::Role::kNote: + case ax::mojom::Role::kPane: + case ax::mojom::Role::kProgressIndicator: + case ax::mojom::Role::kRadioGroup: + case ax::mojom::Role::kRootWebArea: + case ax::mojom::Role::kScrollBar: + case ax::mojom::Role::kScrollView: + case ax::mojom::Role::kSearch: + case ax::mojom::Role::kSearchBox: + case ax::mojom::Role::kSplitter: + case ax::mojom::Role::kSlider: + case ax::mojom::Role::kSpinButton: + case ax::mojom::Role::kStatus: + case ax::mojom::Role::kSliderThumb: + case ax::mojom::Role::kSvgRoot: + case ax::mojom::Role::kTable: + case ax::mojom::Role::kTableHeaderContainer: + case ax::mojom::Role::kTabList: + case ax::mojom::Role::kTabPanel: + case ax::mojom::Role::kTerm: + case ax::mojom::Role::kTextField: + case ax::mojom::Role::kTextFieldWithComboBox: + case ax::mojom::Role::kTitleBar: + case ax::mojom::Role::kTime: + case ax::mojom::Role::kTimer: + case ax::mojom::Role::kToolbar: + case ax::mojom::Role::kTree: + case ax::mojom::Role::kTreeGrid: + case ax::mojom::Role::kVideo: + case ax::mojom::Role::kWebArea: + case ax::mojom::Role::kWebView: result = false; break; // ----- Conditional: contribute to ancestor only, unless focusable ------- // Some objects can contribute their contents to ancestor names, but // only have their own name if they are focusable - case kAbbrRole: - case kAnnotationRole: - case kCanvasRole: - case kCaptionRole: - case kContentDeletionRole: - case kContentInsertionRole: - case kDescriptionListDetailRole: - case kDescriptionListRole: - case kDescriptionListTermRole: - case kDetailsRole: - case kFigcaptionRole: - case kFooterRole: - case kGenericContainerRole: - case kIgnoredRole: - case kImageMapRole: - case kInlineTextBoxRole: - case kLabelRole: - case kLayoutTableRole: - case kLayoutTableColumnRole: - case kLayoutTableRowRole: - case kLegendRole: - case kListRole: - case kListItemRole: - case kListMarkerRole: - case kMarkRole: - case kNoneRole: - case kParagraphRole: - case kPreRole: - case kPresentationalRole: - case kRegionRole: + case ax::mojom::Role::kAbbr: + case ax::mojom::Role::kAnnotation: + case ax::mojom::Role::kCanvas: + case ax::mojom::Role::kCaption: + case ax::mojom::Role::kContentDeletion: + case ax::mojom::Role::kContentInsertion: + case ax::mojom::Role::kDescriptionListDetail: + case ax::mojom::Role::kDescriptionList: + case ax::mojom::Role::kDescriptionListTerm: + case ax::mojom::Role::kDetails: + case ax::mojom::Role::kFigcaption: + case ax::mojom::Role::kFooter: + case ax::mojom::Role::kGenericContainer: + case ax::mojom::Role::kIgnored: + case ax::mojom::Role::kImageMap: + case ax::mojom::Role::kInlineTextBox: + case ax::mojom::Role::kLabelText: + case ax::mojom::Role::kLayoutTable: + case ax::mojom::Role::kLayoutTableColumn: + case ax::mojom::Role::kLayoutTableRow: + case ax::mojom::Role::kLegend: + case ax::mojom::Role::kList: + case ax::mojom::Role::kListItem: + case ax::mojom::Role::kListMarker: + case ax::mojom::Role::kMark: + case ax::mojom::Role::kNone: + case ax::mojom::Role::kParagraph: + case ax::mojom::Role::kPre: + case ax::mojom::Role::kPresentational: + case ax::mojom::Role::kRegion: // Spec says we should always expose the name on rows, // but for performance reasons we only do it // if the row might receive focus - case kRowRole: - case kRubyRole: + case ax::mojom::Role::kRow: + case ax::mojom::Role::kRuby: result = recursive || (CanReceiveAccessibilityFocus() && !IsEditable()); break; - case kUnknownRole: - case kNumRoles: - LOG(ERROR) << "kUnknownRole for " << GetNode(); + case ax::mojom::Role::kUnknown: + case ax::mojom::Role::kMaxValue: + LOG(ERROR) << "ax::mojom::Role::kUnknown for " << GetNode(); NOTREACHED(); break; } @@ -3319,31 +3401,31 @@ bool AXObject::NameFromContents(bool recursive) const { bool AXObject::SupportsARIAReadOnly() const { switch (RoleValue()) { - case kCellRole: - case kCheckBoxRole: - case kColorWellRole: - case kColumnHeaderRole: - case kComboBoxGroupingRole: - case kComboBoxMenuButtonRole: - case kDateRole: - case kDateTimeRole: - case kGridRole: - case kInputTimeRole: - case kListBoxRole: - case kMenuButtonRole: - case kMenuItemCheckBoxRole: - case kMenuItemRadioRole: - case kPopUpButtonRole: - case kRadioGroupRole: - case kRowHeaderRole: - case kSearchBoxRole: - case kSliderRole: - case kSpinButtonRole: - case kSwitchRole: - case kTextFieldRole: - case kTextFieldWithComboBoxRole: - case kToggleButtonRole: - case kTreeGridRole: + case ax::mojom::Role::kCell: + case ax::mojom::Role::kCheckBox: + case ax::mojom::Role::kColorWell: + case ax::mojom::Role::kColumnHeader: + case ax::mojom::Role::kComboBoxGrouping: + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kDate: + case ax::mojom::Role::kDateTime: + case ax::mojom::Role::kGrid: + case ax::mojom::Role::kInputTime: + case ax::mojom::Role::kListBox: + case ax::mojom::Role::kMenuButton: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kPopUpButton: + case ax::mojom::Role::kRadioGroup: + case ax::mojom::Role::kRowHeader: + case ax::mojom::Role::kSearchBox: + case ax::mojom::Role::kSlider: + case ax::mojom::Role::kSpinButton: + case ax::mojom::Role::kSwitch: + case ax::mojom::Role::kTextField: + case ax::mojom::Role::kTextFieldWithComboBox: + case ax::mojom::Role::kToggleButton: + case ax::mojom::Role::kTreeGrid: return true; default: break; @@ -3351,32 +3433,32 @@ bool AXObject::SupportsARIAReadOnly() const { return false; } -AccessibilityRole AXObject::ButtonRoleType() const { +ax::mojom::Role AXObject::ButtonRoleType() const { // If aria-pressed is present, then it should be exposed as a toggle button. // http://www.w3.org/TR/wai-aria/states_and_properties#aria-pressed if (AriaPressedIsPresent()) - return kToggleButtonRole; - if (HasPopup()) - return kPopUpButtonRole; + return ax::mojom::Role::kToggleButton; + if (HasPopup() != ax::mojom::HasPopup::kFalse) + return ax::mojom::Role::kPopUpButton; // We don't contemplate RadioButtonRole, as it depends on the input // type. - return kButtonRole; + return ax::mojom::Role::kButton; } // static -const AtomicString& AXObject::RoleName(AccessibilityRole role) { +const AtomicString& AXObject::RoleName(ax::mojom::Role role) { static const Vector<AtomicString>* role_name_vector = CreateRoleNameVector(); - return role_name_vector->at(role); + return role_name_vector->at(static_cast<size_t>(role)); } // static -const AtomicString& AXObject::InternalRoleName(AccessibilityRole role) { +const AtomicString& AXObject::InternalRoleName(ax::mojom::Role role) { static const Vector<AtomicString>* internal_role_name_vector = CreateInternalRoleNameVector(); - return internal_role_name_vector->at(role); + return internal_role_name_vector->at(static_cast<size_t>(role)); } // static diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_object.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_object.h index 12df974b31e..34a1c79bd49 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object.h @@ -8,12 +8,14 @@ * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 2. + * Redistributiothird_party/blink/renderer/modules/exported/web_ax_object.ccns + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of Apple + * Computer, Inc. ("Apple") nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -45,8 +47,10 @@ #include "third_party/blink/renderer/platform/geometry/layout_rect.h" #include "third_party/blink/renderer/platform/graphics/color.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/vector.h" +#include "ui/accessibility/ax_enums.mojom-blink.h" class SkMatrix44; @@ -80,7 +84,7 @@ class AXSparseAttributeClient { }; class IgnoredReason { - DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + DISALLOW_NEW(); public: AXIgnoredReason reason; @@ -111,13 +115,13 @@ class NameSourceRelatedObject typedef HeapVector<Member<NameSourceRelatedObject>> AXRelatedObjectVector; class NameSource { - DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + DISALLOW_NEW(); public: String text; bool superseded = false; bool invalid = false; - AXNameFrom type = kAXNameFromUninitialized; + ax::mojom::NameFrom type = ax::mojom::NameFrom::kUninitialized; const QualifiedName& attribute; AtomicString attribute_value; AXTextFromNativeHTML native_source = kAXTextFromNativeHTMLUninitialized; @@ -133,13 +137,13 @@ class NameSource { }; class DescriptionSource { - DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + DISALLOW_NEW(); public: String text; bool superseded = false; bool invalid = false; - AXDescriptionFrom type = kAXDescriptionFromUninitialized; + ax::mojom::DescriptionFrom type = ax::mojom::DescriptionFrom::kUninitialized; const QualifiedName& attribute; AtomicString attribute_value; AXTextFromNativeHTML native_source = kAXTextFromNativeHTMLUninitialized; @@ -167,7 +171,7 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { typedef HeapVector<Member<AXObject>> AXObjectVector; struct AXSelection { - DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + DISALLOW_NEW(); // The deepest descendant in which the range starts. // (nullptr means the current object.) Persistent<AXObject> anchor_object; @@ -456,15 +460,17 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { virtual bool IsAXSVGRoot() const { return false; } // Check object role or purpose. - virtual AccessibilityRole RoleValue() const { return role_; } + virtual ax::mojom::Role RoleValue() const { return role_; } bool IsARIATextControl() const; virtual bool IsARIARow() const { return false; } virtual bool IsAnchor() const { return false; } bool IsButton() const; - bool IsCanvas() const { return RoleValue() == kCanvasRole; } - bool IsCheckbox() const { return RoleValue() == kCheckBoxRole; } + bool IsCanvas() const { return RoleValue() == ax::mojom::Role::kCanvas; } + bool IsCheckbox() const { return RoleValue() == ax::mojom::Role::kCheckBox; } bool IsCheckboxOrRadio() const { return IsCheckbox() || IsRadioButton(); } - bool IsColorWell() const { return RoleValue() == kColorWellRole; } + bool IsColorWell() const { + return RoleValue() == ax::mojom::Role::kColorWell; + } virtual bool IsControl() const { return false; } virtual bool IsEmbeddedObject() const { return false; } virtual bool IsFieldset() const { return false; } @@ -494,31 +500,40 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { virtual bool IsPasswordField() const { return false; } virtual bool IsPasswordFieldAndShouldHideValue() const; bool IsPresentational() const { - return RoleValue() == kNoneRole || RoleValue() == kPresentationalRole; + return RoleValue() == ax::mojom::Role::kNone || + RoleValue() == ax::mojom::Role::kPresentational; } virtual bool IsProgressIndicator() const { return false; } - bool IsRadioButton() const { return RoleValue() == kRadioButtonRole; } + bool IsRadioButton() const { + return RoleValue() == ax::mojom::Role::kRadioButton; + } bool IsRange() const { - return RoleValue() == kProgressIndicatorRole || - RoleValue() == kScrollBarRole || RoleValue() == kSliderRole || - RoleValue() == kSpinButtonRole || IsMoveableSplitter(); + return RoleValue() == ax::mojom::Role::kProgressIndicator || + RoleValue() == ax::mojom::Role::kScrollBar || + RoleValue() == ax::mojom::Role::kSlider || + RoleValue() == ax::mojom::Role::kSpinButton || IsMoveableSplitter(); + } + bool IsScrollbar() const { + return RoleValue() == ax::mojom::Role::kScrollBar; } - bool IsScrollbar() const { return RoleValue() == kScrollBarRole; } virtual bool IsSlider() const { return false; } virtual bool IsNativeSlider() const { return false; } virtual bool IsMoveableSplitter() const { return false; } - virtual bool IsSpinButton() const { return RoleValue() == kSpinButtonRole; } - bool IsTabItem() const { return RoleValue() == kTabRole; } + virtual bool IsSpinButton() const { + return RoleValue() == ax::mojom::Role::kSpinButton; + } + bool IsTabItem() const { return RoleValue() == ax::mojom::Role::kTab; } virtual bool IsTextControl() const { return false; } bool IsTextObject() const; - bool IsTree() const { return RoleValue() == kTreeRole; } + bool IsTree() const { return RoleValue() == ax::mojom::Role::kTree; } virtual bool IsVirtualObject() const { return false; } - bool IsWebArea() const { return RoleValue() == kWebAreaRole; } + bool IsWebArea() const { + return RoleValue() == ax::mojom::Role::kRootWebArea; + } // Check object state. virtual bool IsAutofillAvailable() { return false; } virtual bool IsClickable() const; - virtual bool IsCollapsed() const { return false; } virtual AccessibilityExpanded IsExpanded() const { return kExpandedUndefined; } @@ -577,7 +592,8 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { // Retrieves the accessible name of the object, an enum indicating where the // name was derived from, and a list of objects that were used to derive the // name, if any. - virtual String GetName(AXNameFrom&, AXObjectVector* name_objects) const; + virtual String GetName(ax::mojom::NameFrom&, + AXObjectVector* name_objects) const; typedef HeapVector<NameSource> NameSources; // Retrieves the accessible name of the object and a list of all potential @@ -589,16 +605,16 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { // accessible description of the object, which is secondary to |name|, an enum // indicating where the description was derived from, and a list of objects // that were used to derive the description, if any. - virtual String Description(AXNameFrom, - AXDescriptionFrom&, + virtual String Description(ax::mojom::NameFrom, + ax::mojom::DescriptionFrom&, AXObjectVector* description_objects) const { return String(); } // Same as above, but returns a list of all potential sources for the // description, indicating which were used. - virtual String Description(AXNameFrom, - AXDescriptionFrom&, + virtual String Description(ax::mojom::NameFrom, + ax::mojom::DescriptionFrom&, DescriptionSources*, AXRelatedObjectVector*) const { return String(); @@ -607,14 +623,14 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { // Takes the result of nameFrom and descriptionFrom from calling |name| and // |description|, above, and retrieves the placeholder of the object, if // present and if it wasn't already exposed by one of the two functions above. - virtual String Placeholder(AXNameFrom) const { return String(); } + virtual String Placeholder(ax::mojom::NameFrom) const { return String(); } // Internal functions used by name and description, above. typedef HeapHashSet<Member<const AXObject>> AXObjectSet; virtual String TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom& name_from, + ax::mojom::NameFrom& name_from, AXRelatedObjectVector* related_objects, NameSources* name_sources) const { return String(); @@ -662,10 +678,12 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { virtual AXObject* InPageLinkTarget() const { return nullptr; } virtual AccessibilityOrientation Orientation() const; virtual String GetText() const { return String(); } - virtual AccessibilityTextDirection GetTextDirection() const { - return kAccessibilityTextDirectionLTR; + virtual ax::mojom::TextDirection GetTextDirection() const { + return ax::mojom::TextDirection::kLtr; + } + virtual ax::mojom::TextPosition GetTextPosition() const { + return ax::mojom::TextPosition::kNone; } - virtual AXTextPosition GetTextPosition() const { return kAXTextPositionNone; } virtual int TextLength() const { return 0; } virtual TextStyle GetTextStyle() const { return kTextStyleNone; } virtual AXObjectVector RadioButtonsInGroup() const { @@ -694,13 +712,13 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { virtual void GetWordBoundaries(Vector<AXRange>&) const; // Properties of interactive elements. - AXDefaultActionVerb Action() const; - AccessibilityCheckedState CheckedState() const; - virtual AriaCurrentState GetAriaCurrentState() const { - return kAriaCurrentStateUndefined; + ax::mojom::DefaultActionVerb Action() const; + ax::mojom::CheckedState CheckedState() const; + virtual ax::mojom::AriaCurrentState GetAriaCurrentState() const { + return ax::mojom::AriaCurrentState::kNone; } - virtual InvalidState GetInvalidState() const { - return kInvalidStateUndefined; + virtual ax::mojom::InvalidState GetInvalidState() const { + return ax::mojom::InvalidState::kNone; } // Only used when invalidState() returns InvalidStateOther. virtual String AriaInvalidValue() const { return String(); } @@ -713,14 +731,16 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { virtual AXRestriction Restriction() const; // ARIA attributes. - virtual AccessibilityRole DetermineAccessibilityRole(); - AccessibilityRole DetermineAriaRoleAttribute() const; - virtual AccessibilityRole AriaRoleAttribute() const; + virtual ax::mojom::Role DetermineAccessibilityRole(); + ax::mojom::Role DetermineAriaRoleAttribute() const; + virtual ax::mojom::Role AriaRoleAttribute() const; virtual AXObject* ActiveDescendant() { return nullptr; } virtual String AriaAutoComplete() const { return String(); } virtual void AriaOwnsElements(AXObjectVector& owns) const {} virtual void AriaDescribedbyElements(AXObjectVector&) const {} - virtual AXHasPopup HasPopup() const { return kAXHasPopupFalse; } + virtual ax::mojom::HasPopup HasPopup() const { + return ax::mojom::HasPopup::kFalse; + } virtual bool IsEditable() const { return false; } bool IsEditableRoot() const; virtual bool ComputeIsEditableRoot() const { return false; } @@ -728,8 +748,7 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { virtual bool IsRichlyEditable() const { return false; } bool AriaCheckedIsPresent() const; bool AriaPressedIsPresent() const; - bool SupportsARIAActiveDescendant() const; - bool SupportsARIAAttributes() const; + bool HasGlobalARIAAttribute() const; bool SupportsARIAExpanded() const; virtual bool SupportsARIADragging() const { return false; } virtual bool SupportsARIADropping() const { return false; } @@ -836,6 +855,7 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { virtual void DetachFromParent() { parent_ = nullptr; } virtual AXObject* ScrollBar(AccessibilityOrientation) { return nullptr; } virtual void AddAccessibleNodeChildren(); + virtual void SelectedOptions(AXObjectVector&) const {} // Properties of the object's owning document or page. virtual double EstimatedLoadingProgress() const { return 0; } @@ -891,8 +911,8 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { virtual unsigned AriaRowIndex() const; virtual int AriaColumnCount() const; virtual int AriaRowCount() const; - virtual SortDirection GetSortDirection() const { - return kSortDirectionUndefined; + virtual ax::mojom::SortDirection GetSortDirection() const { + return ax::mojom::SortDirection::kNone; } // For a row or column. @@ -965,13 +985,13 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { virtual void LineBreaks(Vector<int>&) const {} // Static helper functions. - static bool IsARIAControl(AccessibilityRole); - static bool IsARIAInput(AccessibilityRole); + static bool IsARIAControl(ax::mojom::Role); + static bool IsARIAInput(ax::mojom::Role); // Is this a widget that requires container widget. bool IsSubWidget() const; - static AccessibilityRole AriaRoleToWebCoreRole(const String&); - static const AtomicString& RoleName(AccessibilityRole); - static const AtomicString& InternalRoleName(AccessibilityRole); + static ax::mojom::Role AriaRoleToWebCoreRole(const String&); + static const AtomicString& RoleName(ax::mojom::Role); + static const AtomicString& InternalRoleName(ax::mojom::Role); static void AccessibleNodeListToElementVector(const AccessibleNodeList&, HeapVector<Member<Element>>&); @@ -988,8 +1008,8 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { AXID id_; AXObjectVector children_; mutable bool have_children_; - AccessibilityRole role_; - AccessibilityRole aria_role_; + ax::mojom::Role role_; + ax::mojom::Role aria_role_; mutable AXObjectInclusion last_known_is_ignored_value_; LayoutRect explicit_element_rect_; AXID explicit_container_id_; @@ -999,11 +1019,15 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { static String RecursiveTextAlternative(const AXObject&, bool in_aria_labelled_by_traversal, AXObjectSet& visited); + static String RecursiveTextAlternative(const AXObject&, + bool in_aria_labelled_by_traversal, + AXObjectSet& visited, + ax::mojom::NameFrom& name_from); bool IsHiddenForTextAlternativeCalculation() const; String AriaTextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom&, + ax::mojom::NameFrom&, AXRelatedObjectVector*, NameSources*, bool* found_text_alternative) const; @@ -1027,8 +1051,9 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { bool CanReceiveAccessibilityFocus() const; bool NameFromContents(bool recursive) const; + bool NameFromSelectedOption(bool recursive) const; - AccessibilityRole ButtonRoleType() const; + ax::mojom::Role ButtonRoleType() const; virtual LayoutObject* LayoutObjectForRelativeBounds() const { return nullptr; @@ -1079,7 +1104,7 @@ class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> { static bool IsNativeCheckboxInMixedState(const Node*); static bool IncludesARIAWidgetRole(const String&); static bool HasInteractiveARIAAttribute(const Element&); - AccessibilityRole RemapAriaRoleDueToParent(AccessibilityRole) const; + ax::mojom::Role RemapAriaRoleDueToParent(ax::mojom::Role) const; unsigned ComputeAriaColumnIndex() const; unsigned ComputeAriaRowIndex() const; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc index 009e2d02edb..1f7c45f7ce8 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc @@ -456,14 +456,14 @@ AXObject* AXObjectCacheImpl::GetOrCreate( return new_obj; } -AXObject* AXObjectCacheImpl::GetOrCreate(AccessibilityRole role) { +AXObject* AXObjectCacheImpl::GetOrCreate(ax::mojom::Role role) { AXObject* obj = nullptr; switch (role) { - case kSliderThumbRole: + case ax::mojom::Role::kSliderThumb: obj = AXSliderThumb::Create(*this); break; - case kMenuListPopupRole: + case ax::mojom::Role::kMenuListPopup: obj = AXMenuListPopup::Create(*this); break; default: @@ -677,11 +677,11 @@ void AXObjectCacheImpl::TextChanged(AXObject* obj, if (node_for_relation_update) relation_cache_->UpdateRelatedTree(node_for_relation_update); - PostNotification(obj, AXObjectCacheImpl::kAXTextChanged); + PostNotification(obj, ax::mojom::Event::kTextChanged); } void AXObjectCacheImpl::DocumentTitleChanged() { - PostNotification(Root(), AXObjectCacheImpl::kAXDocumentTitleChanged); + PostNotification(Root(), ax::mojom::Event::kDocumentTitleChanged); } void AXObjectCacheImpl::UpdateCacheAfterNodeIsAttached(Node* node) { @@ -707,20 +707,49 @@ void AXObjectCacheImpl::DidInsertChildrenOfNode(Node* node) { } void AXObjectCacheImpl::ChildrenChanged(Node* node) { + if (!node) + return; + + if (node->GetDocument().NeedsLayoutTreeUpdateForNode(*node)) { + nodes_changed_during_layout_.push_back(node); + return; + } ChildrenChanged(Get(node), node); } void AXObjectCacheImpl::ChildrenChanged(LayoutObject* layout_object) { - if (layout_object) { - AXObject* object = Get(layout_object); - ChildrenChanged(object, layout_object->GetNode()); + if (!layout_object) + return; + Node* node = layout_object->GetNode(); + LayoutObject* parent = layout_object->Parent(); + while (!node && parent) { + node = layout_object->GetNode(); + parent = parent->Parent(); } + + if (!node) + return; + + if (node->GetDocument().NeedsLayoutTreeUpdateForNode(*node)) { + nodes_changed_during_layout_.push_back(node); + return; + } + + AXObject* object = Get(layout_object); + ChildrenChanged(object, layout_object->GetNode()); } void AXObjectCacheImpl::ChildrenChanged(AccessibleNode* accessible_node) { + if (!accessible_node) + return; + Element* element = accessible_node->element(); + if (element && + element->GetDocument().NeedsLayoutTreeUpdateForNode(*element)) { + nodes_changed_during_layout_.push_back(element); + return; + } AXObject* object = Get(accessible_node); - if (object) - ChildrenChanged(object, object->GetNode()); + ChildrenChanged(object, object ? object->GetNode() : nullptr); } void AXObjectCacheImpl::ChildrenChanged(AXObject* obj, Node* optional_node) { @@ -733,6 +762,21 @@ void AXObjectCacheImpl::ChildrenChanged(AXObject* obj, Node* optional_node) { } } +void AXObjectCacheImpl::ProcessUpdatesAfterLayout(Document& document) { + if (document.Lifecycle().GetState() < DocumentLifecycle::kLayoutClean) + return; + + HeapVector<Member<Node>> remaining_nodes; + for (auto node : nodes_changed_during_layout_) { + if (node->GetDocument() != document) { + remaining_nodes.push_back(node); + continue; + } + ChildrenChanged(Get(node), node); + } + nodes_changed_during_layout_.swap(remaining_nodes); +} + void AXObjectCacheImpl::NotificationPostTimerFired(TimerBase*) { notification_post_timer_.Stop(); @@ -757,10 +801,11 @@ void AXObjectCacheImpl::NotificationPostTimerFired(TimerBase*) { } #endif - AXNotification notification = notifications_to_post_[i].second; + ax::mojom::Event notification = notifications_to_post_[i].second; PostPlatformNotification(obj, notification); - if (notification == kAXChildrenChanged && obj->ParentObjectIfExists() && + if (notification == ax::mojom::Event::kChildrenChanged && + obj->ParentObjectIfExists() && obj->LastKnownIsIgnoredValue() != obj->AccessibilityIsIgnored()) ChildrenChanged(obj->ParentObject()); } @@ -769,21 +814,21 @@ void AXObjectCacheImpl::NotificationPostTimerFired(TimerBase*) { } void AXObjectCacheImpl::PostNotification(LayoutObject* layout_object, - AXNotification notification) { + ax::mojom::Event notification) { if (!layout_object) return; PostNotification(Get(layout_object), notification); } void AXObjectCacheImpl::PostNotification(Node* node, - AXNotification notification) { + ax::mojom::Event notification) { if (!node) return; PostNotification(Get(node), notification); } void AXObjectCacheImpl::PostNotification(AXObject* object, - AXNotification notification) { + ax::mojom::Event notification) { if (!object) return; @@ -809,16 +854,16 @@ void AXObjectCacheImpl::UpdateAriaOwns( } void AXObjectCacheImpl::CheckedStateChanged(Node* node) { - PostNotification(node, AXObjectCacheImpl::kAXCheckedStateChanged); + PostNotification(node, ax::mojom::Event::kCheckedStateChanged); } void AXObjectCacheImpl::ListboxOptionStateChanged(HTMLOptionElement* option) { - PostNotification(option, kAXCheckedStateChanged); + PostNotification(option, ax::mojom::Event::kCheckedStateChanged); } void AXObjectCacheImpl::ListboxSelectedChildrenChanged( HTMLSelectElement* select) { - PostNotification(select, kAXSelectedChildrenChanged); + PostNotification(select, ax::mojom::Event::kSelectedChildrenChanged); } void AXObjectCacheImpl::ListboxActiveIndexChanged(HTMLSelectElement* select) { @@ -830,7 +875,7 @@ void AXObjectCacheImpl::ListboxActiveIndexChanged(HTMLSelectElement* select) { } void AXObjectCacheImpl::LocationChanged(LayoutObject* layout_object) { - PostNotification(layout_object, kAXLocationChanged); + PostNotification(layout_object, ax::mojom::Event::kLocationChanged); } void AXObjectCacheImpl::RadiobuttonRemovedFromGroup( @@ -848,7 +893,7 @@ void AXObjectCacheImpl::RadiobuttonRemovedFromGroup( return; ToAXRadioInput(first_obj)->UpdatePosAndSetSize(1); - PostNotification(first_obj, kAXAriaAttributeChanged); + PostNotification(first_obj, ax::mojom::Event::kAriaAttributeChanged); ToAXRadioInput(first_obj)->RequestUpdateToNextNode(true); } @@ -862,12 +907,12 @@ void AXObjectCacheImpl::HandleLayoutComplete(LayoutObject* layout_object) { // end of a layout, and it allows an AX notification to be sent when a page // has its first layout, rather than when the document first loads. if (AXObject* obj = GetOrCreate(layout_object)) - PostNotification(obj, kAXLayoutComplete); + PostNotification(obj, ax::mojom::Event::kLayoutComplete); } void AXObjectCacheImpl::HandleClicked(Node* node) { if (AXObject* obj = GetOrCreate(node)) - PostNotification(obj, kAXClicked); + PostNotification(obj, ax::mojom::Event::kClicked); } void AXObjectCacheImpl::HandleAttributeChanged( @@ -875,7 +920,7 @@ void AXObjectCacheImpl::HandleAttributeChanged( AccessibleNode* accessible_node) { modification_count_++; if (AXObject* obj = Get(accessible_node)) - PostNotification(obj, kAXAriaAttributeChanged); + PostNotification(obj, ax::mojom::Event::kAriaAttributeChanged); } void AXObjectCacheImpl::HandleAriaExpandedChange(Node* node) { @@ -888,11 +933,11 @@ void AXObjectCacheImpl::HandleAriaSelectedChanged(Node* node) { if (!obj) return; - PostNotification(obj, kAXCheckedStateChanged); + PostNotification(obj, ax::mojom::Event::kCheckedStateChanged); AXObject* listbox = obj->ParentObjectUnignored(); - if (listbox && listbox->RoleValue() == kListBoxRole) - PostNotification(listbox, kAXSelectedChildrenChanged); + if (listbox && listbox->RoleValue() == ax::mojom::Role::kListBox) + PostNotification(listbox, ax::mojom::Event::kSelectedChildrenChanged); } // This might be the new target of a relation. Handle all possible cases. @@ -934,8 +979,12 @@ void AXObjectCacheImpl::HandlePossibleRoleChange(Node* node) { if (!node) return; // Virtual AOM node. + AXObject* obj = Get(node); + if (!obj && IsHTMLSelectElement(node)) + obj = GetOrCreate(node); + // Invalidate the current object and make the parent reconsider its children. - if (AXObject* obj = Get(node)) { + if (obj) { // Save parent for later use. AXObject* parent = obj->ParentObject(); @@ -978,7 +1027,7 @@ void AXObjectCacheImpl::HandleAttributeChanged(const QualifiedName& attr_name, if (attr_name == aria_activedescendantAttr) HandleActiveDescendantChanged(element); else if (attr_name == aria_valuenowAttr || attr_name == aria_valuetextAttr) - PostNotification(element, AXObjectCacheImpl::kAXValueChanged); + PostNotification(element, ax::mojom::Event::kValueChanged); else if (attr_name == aria_labelAttr || attr_name == aria_labeledbyAttr || attr_name == aria_labelledbyAttr) TextChanged(element); @@ -993,11 +1042,11 @@ void AXObjectCacheImpl::HandleAttributeChanged(const QualifiedName& attr_name, else if (attr_name == aria_hiddenAttr) ChildrenChanged(element->parentNode()); else if (attr_name == aria_invalidAttr) - PostNotification(element, AXObjectCacheImpl::kAXInvalidStatusChanged); + PostNotification(element, ax::mojom::Event::kInvalidStatusChanged); else if (attr_name == aria_ownsAttr) ChildrenChanged(element); else - PostNotification(element, AXObjectCacheImpl::kAXAriaAttributeChanged); + PostNotification(element, ax::mojom::Event::kAriaAttributeChanged); } void AXObjectCacheImpl::HandleAutofillStateChanged(Element* elem, @@ -1023,7 +1072,7 @@ void AXObjectCacheImpl::InlineTextBoxesUpdated( if (AXObject* obj = Get(layout_object)) { if (!obj->NeedsToUpdateChildren()) { obj->SetNeedsToUpdateChildren(); - PostNotification(layout_object, kAXChildrenChanged); + PostNotification(layout_object, ax::mojom::Event::kChildrenChanged); } } } @@ -1093,20 +1142,31 @@ bool IsNodeAriaVisible(Node* node) { return !is_null && !hidden; } -void AXObjectCacheImpl::PostPlatformNotification(AXObject* obj, - AXNotification notification) { - if (!obj || !obj->GetDocument() || !obj->DocumentFrameView() || - !obj->DocumentFrameView()->GetFrame().GetPage()) +void AXObjectCacheImpl::PostPlatformNotification( + AXObject* obj, + ax::mojom::Event notification) { + if (!document_ || !document_->View() || + !document_->View()->GetFrame().GetPage()) return; - // Send via WebLocalFrameClient - WebLocalFrameImpl* webframe = WebLocalFrameImpl::FromFrame( - obj->GetDocument()->AXObjectCacheOwner().GetFrame()); + + WebLocalFrameImpl* webframe = + WebLocalFrameImpl::FromFrame(document_->AXObjectCacheOwner().GetFrame()); if (webframe && webframe->Client()) { - webframe->Client()->PostAccessibilityEvent( - WebAXObject(obj), static_cast<WebAXEvent>(notification)); + webframe->Client()->PostAccessibilityEvent(WebAXObject(obj), notification); } } +void AXObjectCacheImpl::MarkAXObjectDirty(AXObject* obj, bool subtree) { + if (!document_ || !document_->View() || + !document_->View()->GetFrame().GetPage()) + return; + + WebLocalFrameImpl* webframe = + WebLocalFrameImpl::FromFrame(document_->AXObjectCacheOwner().GetFrame()); + if (webframe && webframe->Client()) + webframe->Client()->MarkWebAXObjectDirty(WebAXObject(obj), subtree); +} + void AXObjectCacheImpl::HandleFocusedUIElementChanged(Node* old_focused_node, Node* new_focused_node) { if (!new_focused_node) @@ -1122,12 +1182,12 @@ void AXObjectCacheImpl::HandleFocusedUIElementChanged(Node* old_focused_node, AXObject* old_focused_object = Get(old_focused_node); - PostPlatformNotification(old_focused_object, kAXBlur); - PostPlatformNotification(focused_object, kAXFocusedUIElementChanged); + PostPlatformNotification(old_focused_object, ax::mojom::Event::kBlur); + PostPlatformNotification(focused_object, ax::mojom::Event::kFocus); } void AXObjectCacheImpl::HandleInitialFocus() { - PostNotification(document_, kAXFocusedUIElementChanged); + PostNotification(document_, ax::mojom::Event::kFocus); } void AXObjectCacheImpl::HandleEditableTextContentChanged(Node* node) { @@ -1145,13 +1205,13 @@ void AXObjectCacheImpl::HandleEditableTextContentChanged(Node* node) { while (obj && !obj->IsNativeTextControl() && !obj->IsNonNativeTextControl()) obj = obj->ParentObject(); - PostNotification(obj, kAXValueChanged); + PostNotification(obj, ax::mojom::Event::kValueChanged); } void AXObjectCacheImpl::HandleScaleAndLocationChanged(Document* document) { if (!document) return; - PostNotification(document, kAXLocationChanged); + PostNotification(document, ax::mojom::Event::kLocationChanged); } void AXObjectCacheImpl::HandleTextFormControlChanged(Node* node) { @@ -1170,7 +1230,7 @@ void AXObjectCacheImpl::HandleTextMarkerDataAdded(Node* start, Node* end) { } void AXObjectCacheImpl::HandleValueChanged(Node* node) { - PostNotification(node, kAXValueChanged); + PostNotification(node, ax::mojom::Event::kValueChanged); } void AXObjectCacheImpl::HandleUpdateActiveMenuOption(LayoutMenuList* menu_list, @@ -1199,12 +1259,12 @@ void AXObjectCacheImpl::DidHideMenuListPopup(LayoutMenuList* menu_list) { } void AXObjectCacheImpl::HandleLoadComplete(Document* document) { - PostNotification(GetOrCreate(document), kAXLoadComplete); + PostNotification(GetOrCreate(document), ax::mojom::Event::kLoadComplete); AddPermissionStatusListener(); } void AXObjectCacheImpl::HandleLayoutComplete(Document* document) { - PostNotification(GetOrCreate(document), kAXLayoutComplete); + PostNotification(GetOrCreate(document), ax::mojom::Event::kLayoutComplete); } void AXObjectCacheImpl::HandleScrolledToAnchor(const Node* anchor_node) { @@ -1215,26 +1275,27 @@ void AXObjectCacheImpl::HandleScrolledToAnchor(const Node* anchor_node) { return; if (obj->AccessibilityIsIgnored()) obj = obj->ParentObjectUnignored(); - PostPlatformNotification(obj, kAXScrolledToAnchor); + PostPlatformNotification(obj, ax::mojom::Event::kScrolledToAnchor); } void AXObjectCacheImpl::HandleScrollPositionChanged( LocalFrameView* frame_view) { AXObject* target_ax_object = GetOrCreate(frame_view->GetFrame().GetDocument()); - PostPlatformNotification(target_ax_object, kAXScrollPositionChanged); + PostPlatformNotification(target_ax_object, + ax::mojom::Event::kScrollPositionChanged); } void AXObjectCacheImpl::HandleScrollPositionChanged( LayoutObject* layout_object) { PostPlatformNotification(GetOrCreate(layout_object), - kAXScrollPositionChanged); + ax::mojom::Event::kScrollPositionChanged); } const AtomicString& AXObjectCacheImpl::ComputedRoleForNode(Node* node) { AXObject* obj = GetOrCreate(node); if (!obj) - return AXObject::RoleName(kUnknownRole); + return AXObject::RoleName(ax::mojom::Role::kUnknown); return AXObject::RoleName(obj->RoleValue()); } @@ -1256,7 +1317,7 @@ void AXObjectCacheImpl::OnTouchAccessibilityHover(const IntPoint& location) { hit->GetLayoutObject()->IsLayoutEmbeddedContent()) return; - PostPlatformNotification(hit, kAXHover); + PostPlatformNotification(hit, ax::mojom::Event::kHover); } } @@ -1323,7 +1384,7 @@ void AXObjectCacheImpl::RequestAOMEventListenerPermission() { permission_service_->RequestPermission( CreatePermissionDescriptor( mojom::blink::PermissionName::ACCESSIBILITY_EVENTS), - Frame::HasTransientUserActivation(document_->GetFrame()), + LocalFrame::HasTransientUserActivation(document_->GetFrame()), WTF::Bind(&AXObjectCacheImpl::OnPermissionStatusChange, WrapPersistent(this))); } @@ -1340,61 +1401,9 @@ void AXObjectCacheImpl::Trace(blink::Visitor* visitor) { visitor->Trace(objects_); visitor->Trace(notifications_to_post_); + visitor->Trace(nodes_changed_during_layout_); AXObjectCache::Trace(visitor); } -STATIC_ASSERT_ENUM(kWebAXEventActiveDescendantChanged, - AXObjectCacheImpl::kAXActiveDescendantChanged); -STATIC_ASSERT_ENUM(kWebAXEventAriaAttributeChanged, - AXObjectCacheImpl::kAXAriaAttributeChanged); -STATIC_ASSERT_ENUM(kWebAXEventAutocorrectionOccured, - AXObjectCacheImpl::kAXAutocorrectionOccured); -STATIC_ASSERT_ENUM(kWebAXEventBlur, AXObjectCacheImpl::kAXBlur); -STATIC_ASSERT_ENUM(kWebAXEventCheckedStateChanged, - AXObjectCacheImpl::kAXCheckedStateChanged); -STATIC_ASSERT_ENUM(kWebAXEventChildrenChanged, - AXObjectCacheImpl::kAXChildrenChanged); -STATIC_ASSERT_ENUM(kWebAXEventClicked, AXObjectCacheImpl::kAXClicked); -STATIC_ASSERT_ENUM(kWebAXEventDocumentSelectionChanged, - AXObjectCacheImpl::kAXDocumentSelectionChanged); -STATIC_ASSERT_ENUM(kWebAXEventDocumentTitleChanged, - AXObjectCacheImpl::kAXDocumentTitleChanged); -STATIC_ASSERT_ENUM(kWebAXEventExpandedChanged, - AXObjectCacheImpl::kAXExpandedChanged); -STATIC_ASSERT_ENUM(kWebAXEventFocus, - AXObjectCacheImpl::kAXFocusedUIElementChanged); -STATIC_ASSERT_ENUM(kWebAXEventHide, AXObjectCacheImpl::kAXHide); -STATIC_ASSERT_ENUM(kWebAXEventHover, AXObjectCacheImpl::kAXHover); -STATIC_ASSERT_ENUM(kWebAXEventInvalidStatusChanged, - AXObjectCacheImpl::kAXInvalidStatusChanged); -STATIC_ASSERT_ENUM(kWebAXEventLayoutComplete, - AXObjectCacheImpl::kAXLayoutComplete); -STATIC_ASSERT_ENUM(kWebAXEventLiveRegionChanged, - AXObjectCacheImpl::kAXLiveRegionChanged); -STATIC_ASSERT_ENUM(kWebAXEventLoadComplete, AXObjectCacheImpl::kAXLoadComplete); -STATIC_ASSERT_ENUM(kWebAXEventLocationChanged, - AXObjectCacheImpl::kAXLocationChanged); -STATIC_ASSERT_ENUM(kWebAXEventMenuListItemSelected, - AXObjectCacheImpl::kAXMenuListItemSelected); -STATIC_ASSERT_ENUM(kWebAXEventMenuListItemUnselected, - AXObjectCacheImpl::kAXMenuListItemUnselected); -STATIC_ASSERT_ENUM(kWebAXEventMenuListValueChanged, - AXObjectCacheImpl::kAXMenuListValueChanged); -STATIC_ASSERT_ENUM(kWebAXEventRowCollapsed, AXObjectCacheImpl::kAXRowCollapsed); -STATIC_ASSERT_ENUM(kWebAXEventRowCountChanged, - AXObjectCacheImpl::kAXRowCountChanged); -STATIC_ASSERT_ENUM(kWebAXEventRowExpanded, AXObjectCacheImpl::kAXRowExpanded); -STATIC_ASSERT_ENUM(kWebAXEventScrollPositionChanged, - AXObjectCacheImpl::kAXScrollPositionChanged); -STATIC_ASSERT_ENUM(kWebAXEventScrolledToAnchor, - AXObjectCacheImpl::kAXScrolledToAnchor); -STATIC_ASSERT_ENUM(kWebAXEventSelectedChildrenChanged, - AXObjectCacheImpl::kAXSelectedChildrenChanged); -STATIC_ASSERT_ENUM(kWebAXEventSelectedTextChanged, - AXObjectCacheImpl::kAXSelectedTextChanged); -STATIC_ASSERT_ENUM(kWebAXEventShow, AXObjectCacheImpl::kAXShow); -STATIC_ASSERT_ENUM(kWebAXEventTextChanged, AXObjectCacheImpl::kAXTextChanged); -STATIC_ASSERT_ENUM(kWebAXEventValueChanged, AXObjectCacheImpl::kAXValueChanged); - } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h index 185c3fe3d47..cd015ac7347 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h @@ -41,6 +41,7 @@ #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" +#include "ui/accessibility/ax_enums.mojom-blink.h" namespace blink { @@ -56,40 +57,6 @@ class MODULES_EXPORT AXObjectCacheImpl public: static AXObjectCache* Create(Document&); - enum AXNotification { - kAXActiveDescendantChanged, - kAXAriaAttributeChanged, - kAXAutocorrectionOccured, - kAXBlur, - kAXCheckedStateChanged, - kAXChildrenChanged, - kAXClicked, - kAXDocumentSelectionChanged, - kAXDocumentTitleChanged, - kAXExpandedChanged, - kAXFocusedUIElementChanged, - kAXHide, - kAXHover, - kAXInvalidStatusChanged, - kAXLayoutComplete, - kAXLiveRegionChanged, - kAXLoadComplete, - kAXLocationChanged, - kAXMenuListItemSelected, - kAXMenuListItemUnselected, - kAXMenuListValueChanged, - kAXRowCollapsed, - kAXRowCountChanged, - kAXRowExpanded, - kAXScrollPositionChanged, - kAXScrolledToAnchor, - kAXSelectedChildrenChanged, - kAXSelectedTextChanged, - kAXShow, - kAXTextChanged, - kAXValueChanged - }; - explicit AXObjectCacheImpl(Document&); ~AXObjectCacheImpl() override; void Trace(blink::Visitor*) override; @@ -161,6 +128,7 @@ class MODULES_EXPORT AXObjectCacheImpl const LayoutRect&) override; void InlineTextBoxesUpdated(LineLayoutItem) override; + void ProcessUpdatesAfterLayout(Document&) override; // Called when the scroll offset changes. void HandleScrollPositionChanged(LocalFrameView*) override; @@ -179,7 +147,7 @@ class MODULES_EXPORT AXObjectCacheImpl AXObject* Root(); // used for objects without backing elements - AXObject* GetOrCreate(AccessibilityRole); + AXObject* GetOrCreate(ax::mojom::Role); AXObject* GetOrCreate(AccessibleNode*); AXObject* GetOrCreate(LayoutObject*) override; AXObject* GetOrCreate(const Node*); @@ -219,9 +187,10 @@ class MODULES_EXPORT AXObjectCacheImpl // values are cached as long as the modification count hasn't changed. int ModificationCount() const { return modification_count_; } - void PostNotification(LayoutObject*, AXNotification); - void PostNotification(Node*, AXNotification); - void PostNotification(AXObject*, AXNotification); + void PostNotification(LayoutObject*, ax::mojom::Event); + void PostNotification(Node*, ax::mojom::Event); + void PostNotification(AXObject*, ax::mojom::Event); + void MarkAXObjectDirty(AXObject*, bool subtree); // // Aria-owns support. @@ -258,7 +227,7 @@ class MODULES_EXPORT AXObjectCacheImpl void RequestAOMEventListenerPermission(); protected: - void PostPlatformNotification(AXObject*, AXNotification); + void PostPlatformNotification(AXObject*, ax::mojom::Event); void LabelChanged(Element*); AXObject* CreateFromRenderer(LayoutObject*); @@ -286,7 +255,7 @@ class MODULES_EXPORT AXObjectCacheImpl #endif TaskRunnerTimer<AXObjectCacheImpl> notification_post_timer_; - HeapVector<std::pair<Member<AXObject>, AXNotification>> + HeapVector<std::pair<Member<AXObject>, ax::mojom::Event>> notifications_to_post_; void NotificationPostTimerFired(TimerBase*); @@ -326,6 +295,8 @@ class MODULES_EXPORT AXObjectCacheImpl mojom::blink::PermissionServicePtr permission_service_; mojo::Binding<mojom::blink::PermissionObserver> permission_observer_binding_; + HeapVector<Member<Node>> nodes_changed_during_layout_; + DISALLOW_COPY_AND_ASSIGN(AXObjectCacheImpl); }; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_test.cc index 783667c202a..ed63425c53b 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_test.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_test.cc @@ -59,25 +59,22 @@ TEST_F(AccessibilityTest, SimpleTreeNavigation) { EXPECT_EQ(button, root->DeepestLastChild()); ASSERT_NE(nullptr, paragraph->FirstChild()); - EXPECT_EQ(AccessibilityRole::kStaticTextRole, - paragraph->FirstChild()->RoleValue()); + EXPECT_EQ(ax::mojom::Role::kStaticText, paragraph->FirstChild()->RoleValue()); ASSERT_NE(nullptr, paragraph->LastChild()); - EXPECT_EQ(AccessibilityRole::kStaticTextRole, - paragraph->LastChild()->RoleValue()); + EXPECT_EQ(ax::mojom::Role::kStaticText, paragraph->LastChild()->RoleValue()); ASSERT_NE(nullptr, paragraph->DeepestFirstChild()); - EXPECT_EQ(AccessibilityRole::kStaticTextRole, + EXPECT_EQ(ax::mojom::Role::kStaticText, paragraph->DeepestFirstChild()->RoleValue()); ASSERT_NE(nullptr, paragraph->DeepestLastChild()); - EXPECT_EQ(AccessibilityRole::kStaticTextRole, + EXPECT_EQ(ax::mojom::Role::kStaticText, paragraph->DeepestLastChild()->RoleValue()); EXPECT_EQ(paragraph->PreviousSibling(), input); EXPECT_EQ(paragraph, input->NextSibling()); ASSERT_NE(nullptr, br->NextSibling()); - EXPECT_EQ(AccessibilityRole::kStaticTextRole, br->NextSibling()->RoleValue()); + EXPECT_EQ(ax::mojom::Role::kStaticText, br->NextSibling()->RoleValue()); ASSERT_NE(nullptr, br->PreviousSibling()); - EXPECT_EQ(AccessibilityRole::kStaticTextRole, - br->PreviousSibling()->RoleValue()); + EXPECT_EQ(ax::mojom::Role::kStaticText, br->PreviousSibling()->RoleValue()); } TEST_F(AccessibilityTest, AXObjectComparisonOperators) { @@ -134,11 +131,11 @@ TEST_F(AccessibilityTest, AXObjectAncestorsIterator) { ASSERT_NE(nullptr, bold); AXObject* br = GetAXObjectByElementId("br"); ASSERT_NE(nullptr, br); - ASSERT_EQ(AccessibilityRole::kLineBreakRole, br->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kLineBreak, br->RoleValue()); AXObject::AncestorsIterator iter = br->AncestorsBegin(); EXPECT_EQ(*paragraph, *iter); - EXPECT_EQ(AccessibilityRole::kParagraphRole, iter->RoleValue()); + EXPECT_EQ(ax::mojom::Role::kParagraph, iter->RoleValue()); EXPECT_EQ(*root, *++iter); EXPECT_EQ(*root, *iter++); EXPECT_EQ(br->AncestorsEnd(), ++iter); @@ -157,13 +154,13 @@ TEST_F(AccessibilityTest, AXObjectInOrderTraversalIterator) { ++iter; // Skip the generic container which is an ignored object. EXPECT_NE(GetAXObjectCache().InOrderTraversalEnd(), iter); EXPECT_EQ(*button, *++iter); - EXPECT_EQ(AccessibilityRole::kButtonRole, iter->RoleValue()); + EXPECT_EQ(ax::mojom::Role::kButton, iter->RoleValue()); EXPECT_EQ(*button, *iter++); EXPECT_EQ(GetAXObjectCache().InOrderTraversalEnd(), iter); EXPECT_EQ(*button, *--iter); EXPECT_EQ(*button, *iter--); --iter; // Skip the generic container which is an ignored object. - EXPECT_EQ(AccessibilityRole::kWebAreaRole, iter->RoleValue()); + EXPECT_EQ(ax::mojom::Role::kRootWebArea, iter->RoleValue()); EXPECT_EQ(GetAXObjectCache().InOrderTraversalBegin(), iter); } diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_position.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_position.h index fe5b0e1b185..a2447816857 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_position.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_position.h @@ -39,7 +39,7 @@ enum class AXPositionAdjustmentBehavior { kMoveLeft, kMoveRight }; // between two characters. Another way of calling these types of positions is // object anchored and text anchored. class MODULES_EXPORT AXPosition final { - DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + DISALLOW_NEW(); public: // diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_position_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_position_test.cc index ce0fbac4342..90d30a05e25 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_position_test.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_position_test.cc @@ -90,7 +90,7 @@ TEST_F(AccessibilityTest, PositionInText) { const AXObject* ax_static_text = GetAXObjectByElementId("paragraph")->FirstChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreatePositionInTextObject(*ax_static_text, 3); @@ -113,7 +113,7 @@ TEST_F(AccessibilityTest, PositionBeforeText) { const AXObject* ax_static_text = GetAXObjectByElementId("paragraph")->FirstChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreatePositionBeforeObject(*ax_static_text); @@ -136,7 +136,7 @@ TEST_F(AccessibilityTest, PositionBeforeTextWithFirstLetterCSSRule) { const AXObject* ax_static_text = GetAXObjectByElementId("paragraph")->FirstChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreatePositionBeforeObject(*ax_static_text); @@ -160,7 +160,7 @@ TEST_F(AccessibilityTest, PositionAfterText) { const AXObject* ax_static_text = GetAXObjectByElementId("paragraph")->FirstChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreatePositionAfterObject(*ax_static_text); @@ -177,10 +177,10 @@ TEST_F(AccessibilityTest, PositionBeforeLineBreak) { SetBodyInnerHTML(R"HTML(Hello<br id="br">there)HTML"); const AXObject* ax_br = GetAXObjectByElementId("br"); ASSERT_NE(nullptr, ax_br); - ASSERT_EQ(AccessibilityRole::kLineBreakRole, ax_br->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kLineBreak, ax_br->RoleValue()); const AXObject* ax_div = ax_br->ParentObjectUnignored(); ASSERT_NE(nullptr, ax_div); - ASSERT_EQ(AccessibilityRole::kGenericContainerRole, ax_div->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_div->RoleValue()); const auto ax_position = AXPosition::CreatePositionBeforeObject(*ax_br); EXPECT_FALSE(ax_position.IsTextPosition()); @@ -200,13 +200,13 @@ TEST_F(AccessibilityTest, PositionAfterLineBreak) { SetBodyInnerHTML(R"HTML(Hello<br id="br">there)HTML"); const AXObject* ax_br = GetAXObjectByElementId("br"); ASSERT_NE(nullptr, ax_br); - ASSERT_EQ(AccessibilityRole::kLineBreakRole, ax_br->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kLineBreak, ax_br->RoleValue()); const AXObject* ax_div = ax_br->ParentObjectUnignored(); ASSERT_NE(nullptr, ax_div); - ASSERT_EQ(AccessibilityRole::kGenericContainerRole, ax_div->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_div->RoleValue()); const AXObject* ax_static_text = GetAXRootObject()->DeepestLastChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreatePositionAfterObject(*ax_br); EXPECT_FALSE(ax_position.IsTextPosition()); @@ -228,10 +228,10 @@ TEST_F(AccessibilityTest, FirstPositionInDivContainer) { ASSERT_NE(nullptr, div); const AXObject* ax_div = GetAXObjectByElementId("div"); ASSERT_NE(nullptr, ax_div); - ASSERT_EQ(AccessibilityRole::kGenericContainerRole, ax_div->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_div->RoleValue()); const AXObject* ax_static_text = GetAXRootObject()->DeepestFirstChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreateFirstPositionInObject(*ax_div); const auto position = ax_position.ToPositionWithAffinity(); @@ -250,7 +250,7 @@ TEST_F(AccessibilityTest, LastPositionInDivContainer) { ASSERT_NE(nullptr, div); const AXObject* ax_div = GetAXObjectByElementId("div"); ASSERT_NE(nullptr, ax_div); - ASSERT_EQ(AccessibilityRole::kGenericContainerRole, ax_div->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_div->RoleValue()); const auto ax_position = AXPosition::CreateLastPositionInObject(*ax_div); const auto position = ax_position.ToPositionWithAffinity(); @@ -269,7 +269,7 @@ TEST_F(AccessibilityTest, FirstPositionInTextContainer) { ASSERT_TRUE(text->IsTextNode()); const AXObject* ax_static_text = GetAXObjectByElementId("div")->FirstChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreateFirstPositionInObject(*ax_static_text); @@ -289,7 +289,7 @@ TEST_F(AccessibilityTest, LastPositionInTextContainer) { ASSERT_TRUE(text->IsTextNode()); const AXObject* ax_static_text = GetAXObjectByElementId("div")->LastChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreateLastPositionInObject(*ax_static_text); @@ -385,7 +385,7 @@ TEST_F(AccessibilityTest, PositionInTextWithWhiteSpace) { const AXObject* ax_static_text = GetAXObjectByElementId("paragraph")->FirstChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreatePositionInTextObject(*ax_static_text, 3); @@ -406,7 +406,7 @@ TEST_F(AccessibilityTest, PositionBeforeTextWithWhiteSpace) { const AXObject* ax_static_text = GetAXObjectByElementId("paragraph")->FirstChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreatePositionBeforeObject(*ax_static_text); @@ -427,7 +427,7 @@ TEST_F(AccessibilityTest, PositionAfterTextWithWhiteSpace) { const AXObject* ax_static_text = GetAXObjectByElementId("paragraph")->LastChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreatePositionAfterObject(*ax_static_text); @@ -444,10 +444,10 @@ TEST_F(AccessibilityTest, PositionBeforeLineBreakWithWhiteSpace) { SetBodyInnerHTML(R"HTML(Hello <br id="br"> there)HTML"); const AXObject* ax_br = GetAXObjectByElementId("br"); ASSERT_NE(nullptr, ax_br); - ASSERT_EQ(AccessibilityRole::kLineBreakRole, ax_br->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kLineBreak, ax_br->RoleValue()); const AXObject* ax_div = ax_br->ParentObjectUnignored(); ASSERT_NE(nullptr, ax_div); - ASSERT_EQ(AccessibilityRole::kGenericContainerRole, ax_div->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_div->RoleValue()); const auto ax_position = AXPosition::CreatePositionBeforeObject(*ax_br); EXPECT_FALSE(ax_position.IsTextPosition()); @@ -467,13 +467,13 @@ TEST_F(AccessibilityTest, PositionAfterLineBreakWithWhiteSpace) { SetBodyInnerHTML(R"HTML(Hello <br id="br"> there)HTML"); const AXObject* ax_br = GetAXObjectByElementId("br"); ASSERT_NE(nullptr, ax_br); - ASSERT_EQ(AccessibilityRole::kLineBreakRole, ax_br->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kLineBreak, ax_br->RoleValue()); const AXObject* ax_div = ax_br->ParentObjectUnignored(); ASSERT_NE(nullptr, ax_div); - ASSERT_EQ(AccessibilityRole::kGenericContainerRole, ax_div->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_div->RoleValue()); const AXObject* ax_static_text = GetAXRootObject()->DeepestLastChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreatePositionAfterObject(*ax_br); EXPECT_FALSE(ax_position.IsTextPosition()); @@ -495,10 +495,10 @@ TEST_F(AccessibilityTest, FirstPositionInDivContainerWithWhiteSpace) { ASSERT_NE(nullptr, div); const AXObject* ax_div = GetAXObjectByElementId("div"); ASSERT_NE(nullptr, ax_div); - ASSERT_EQ(AccessibilityRole::kGenericContainerRole, ax_div->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_div->RoleValue()); const AXObject* ax_static_text = GetAXRootObject()->DeepestFirstChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreateFirstPositionInObject(*ax_div); const auto position = ax_position.ToPositionWithAffinity(); @@ -517,7 +517,7 @@ TEST_F(AccessibilityTest, LastPositionInDivContainerWithWhiteSpace) { ASSERT_NE(nullptr, div); const AXObject* ax_div = GetAXObjectByElementId("div"); ASSERT_NE(nullptr, ax_div); - ASSERT_EQ(AccessibilityRole::kGenericContainerRole, ax_div->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_div->RoleValue()); const auto ax_position = AXPosition::CreateLastPositionInObject(*ax_div); const auto position = ax_position.ToPositionWithAffinity(); @@ -536,7 +536,7 @@ TEST_F(AccessibilityTest, FirstPositionInTextContainerWithWhiteSpace) { ASSERT_TRUE(text->IsTextNode()); const AXObject* ax_static_text = GetAXObjectByElementId("div")->FirstChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreateFirstPositionInObject(*ax_static_text); @@ -556,7 +556,7 @@ TEST_F(AccessibilityTest, LastPositionInTextContainerWithWhiteSpace) { ASSERT_TRUE(text->IsTextNode()); const AXObject* ax_static_text = GetAXObjectByElementId("div")->LastChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const auto ax_position = AXPosition::CreateLastPositionInObject(*ax_static_text); @@ -579,7 +579,7 @@ TEST_F(AccessibilityTest, AXPositionFromDOMPositionWithWhiteSpace) { ASSERT_EQ(15U, text->textContent().length()); const AXObject* ax_static_text = GetAXObjectByElementId("div")->FirstChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); const Position position_at_start(*text, 0); const auto ax_position_at_start = AXPosition::FromPosition(position_at_start); @@ -626,7 +626,7 @@ TEST_F(AccessibilityTest, PositionInTextWithAffinity) { const AXObject* ax_static_text = GetAXObjectByElementId("paragraph")->FirstChild(); ASSERT_NE(nullptr, ax_static_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_static_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_static_text->RoleValue()); // Converting from AX to DOM positions should maintain affinity. const auto ax_position = AXPosition::CreatePositionInTextObject( @@ -664,14 +664,14 @@ TEST_F(AccessibilityTest, PositionInHTMLLabel) { const AXObject* ax_root = GetAXRootObject(); ASSERT_NE(nullptr, ax_root); - ASSERT_EQ(AccessibilityRole::kWebAreaRole, ax_root->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kRootWebArea, ax_root->RoleValue()); // The HTML label element should be ignored. const AXObject* ax_label = GetAXObjectByElementId("label"); ASSERT_NE(nullptr, ax_label); ASSERT_TRUE(ax_label->AccessibilityIsIgnored()); const AXObject* ax_paragraph = GetAXObjectByElementId("paragraph"); ASSERT_NE(nullptr, ax_paragraph); - ASSERT_EQ(AccessibilityRole::kParagraphRole, ax_paragraph->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kParagraph, ax_paragraph->RoleValue()); // All of the following DOM positions should be ignored in the accessibility // tree. @@ -715,11 +715,11 @@ TEST_F(AccessibilityTest, PositionInIgnoredObject) { const AXObject* ax_root = GetAXRootObject(); ASSERT_NE(nullptr, ax_root); - ASSERT_EQ(AccessibilityRole::kWebAreaRole, ax_root->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kRootWebArea, ax_root->RoleValue()); ASSERT_EQ(1, ax_root->ChildCount()); const AXObject* ax_visible = ax_root->FirstChild(); ASSERT_NE(nullptr, ax_visible); - ASSERT_EQ(AccessibilityRole::kParagraphRole, ax_visible->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kParagraph, ax_visible->RoleValue()); // The fact that there is a hidden object before |visible| should not affect // setting a position before it. @@ -795,10 +795,10 @@ TEST_F(AccessibilityTest, BeforePositionInARIAHiddenShouldSkipARIAHidden) { const AXObject* ax_before = GetAXObjectByElementId("before"); ASSERT_NE(nullptr, ax_before); - ASSERT_EQ(AccessibilityRole::kParagraphRole, ax_before->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kParagraph, ax_before->RoleValue()); const AXObject* ax_after = GetAXObjectByElementId("after"); ASSERT_NE(nullptr, ax_after); - ASSERT_EQ(AccessibilityRole::kParagraphRole, ax_after->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kParagraph, ax_after->RoleValue()); ASSERT_NE(nullptr, GetAXObjectByElementId("ariaHidden")); ASSERT_TRUE(GetAXObjectByElementId("ariaHidden")->AccessibilityIsIgnored()); @@ -829,7 +829,7 @@ TEST_F(AccessibilityTest, PreviousPositionAfterARIAHiddenShouldSkipARIAHidden) { const AXObject* ax_after = GetAXObjectByElementId("after"); ASSERT_NE(nullptr, ax_after); - ASSERT_EQ(AccessibilityRole::kParagraphRole, ax_after->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kParagraph, ax_after->RoleValue()); ASSERT_NE(nullptr, GetAXObjectByElementId("ariaHidden")); ASSERT_TRUE(GetAXObjectByElementId("ariaHidden")->AccessibilityIsIgnored()); @@ -870,11 +870,11 @@ TEST_F(AccessibilityTest, FromPositionInARIAHidden) { const AXObject* ax_container = GetAXObjectByElementId("container"); ASSERT_NE(nullptr, ax_container); - ASSERT_EQ(AccessibilityRole::kMainRole, ax_container->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kMain, ax_container->RoleValue()); ASSERT_EQ(2, ax_container->ChildCount()); const AXObject* ax_after = GetAXObjectByElementId("after"); ASSERT_NE(nullptr, ax_after); - ASSERT_EQ(AccessibilityRole::kParagraphRole, ax_after->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kParagraph, ax_after->RoleValue()); ASSERT_NE(nullptr, GetAXObjectByElementId("ariaHidden")); ASSERT_TRUE(GetAXObjectByElementId("ariaHidden")->AccessibilityIsIgnored()); @@ -929,16 +929,16 @@ TEST_F(AccessibilityTest, PositionInCanvas) { const AXObject* ax_canvas_1 = GetAXObjectByElementId("canvas1"); ASSERT_NE(nullptr, ax_canvas_1); - ASSERT_EQ(AccessibilityRole::kCanvasRole, ax_canvas_1->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kCanvas, ax_canvas_1->RoleValue()); const AXObject* ax_text = ax_canvas_1->FirstChild(); ASSERT_NE(nullptr, ax_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_text->RoleValue()); const AXObject* ax_canvas_2 = GetAXObjectByElementId("canvas2"); ASSERT_NE(nullptr, ax_canvas_2); - ASSERT_EQ(AccessibilityRole::kCanvasRole, ax_canvas_2->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kCanvas, ax_canvas_2->RoleValue()); const AXObject* ax_button = GetAXObjectByElementId("button"); ASSERT_NE(nullptr, ax_button); - ASSERT_EQ(AccessibilityRole::kButtonRole, ax_button->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kButton, ax_button->RoleValue()); const auto ax_position_1 = AXPosition::CreateFirstPositionInObject(*ax_canvas_1); @@ -1020,11 +1020,11 @@ TEST_F(AccessibilityTest, PositionBeforeListMarker) { const AXObject* ax_item = GetAXObjectByElementId("listItem"); ASSERT_NE(nullptr, ax_item); - ASSERT_EQ(AccessibilityRole::kListItemRole, ax_item->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kListItem, ax_item->RoleValue()); ASSERT_EQ(2, ax_item->ChildCount()); const AXObject* ax_marker = ax_item->FirstChild(); ASSERT_NE(nullptr, ax_marker); - ASSERT_EQ(AccessibilityRole::kListMarkerRole, ax_marker->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kListMarker, ax_marker->RoleValue()); // // Test adjusting invalid DOM positions to the left. @@ -1100,14 +1100,14 @@ TEST_F(AccessibilityTest, PositionAfterListMarker) { const AXObject* ax_item = GetAXObjectByElementId("listItem"); ASSERT_NE(nullptr, ax_item); - ASSERT_EQ(AccessibilityRole::kListItemRole, ax_item->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kListItem, ax_item->RoleValue()); ASSERT_EQ(2, ax_item->ChildCount()); const AXObject* ax_marker = ax_item->FirstChild(); ASSERT_NE(nullptr, ax_marker); - ASSERT_EQ(AccessibilityRole::kListMarkerRole, ax_marker->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kListMarker, ax_marker->RoleValue()); const AXObject* ax_text = ax_item->LastChild(); ASSERT_NE(nullptr, ax_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_text->RoleValue()); const auto ax_position = AXPosition::CreatePositionAfterObject(*ax_marker); const auto position = ax_position.ToPositionWithAffinity(); @@ -1133,17 +1133,17 @@ TEST_F(AccessibilityTest, PositionInCSSContent) { const AXObject* ax_quote = GetAXObjectByElementId("quote"); ASSERT_NE(nullptr, ax_quote); - ASSERT_EQ(AccessibilityRole::kGenericContainerRole, ax_quote->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_quote->RoleValue()); ASSERT_EQ(3, ax_quote->ChildCount()); const AXObject* ax_css_before = ax_quote->FirstChild(); ASSERT_NE(nullptr, ax_css_before); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_css_before->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_css_before->RoleValue()); const AXObject* ax_text = *(ax_quote->Children().begin() + 1); ASSERT_NE(nullptr, ax_text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_text->RoleValue()); const AXObject* ax_css_after = ax_quote->LastChild(); ASSERT_NE(nullptr, ax_css_after); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, ax_css_after->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_css_after->RoleValue()); const auto ax_position_before = AXPosition::CreateFirstPositionInObject(*ax_css_before); @@ -1178,10 +1178,10 @@ TEST_F(AccessibilityTest, PositionBeforeAndAfterTable) { ASSERT_NE(nullptr, after); const AXObject* ax_table = GetAXObjectByElementId("table"); ASSERT_NE(nullptr, ax_table); - ASSERT_EQ(AccessibilityRole::kTableRole, ax_table->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kTable, ax_table->RoleValue()); const AXObject* ax_after = GetAXObjectByElementId("after"); ASSERT_NE(nullptr, ax_after); - ASSERT_EQ(AccessibilityRole::kParagraphRole, ax_after->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kParagraph, ax_after->RoleValue()); const auto ax_position_before = AXPosition::CreatePositionBeforeObject(*ax_table); @@ -1227,10 +1227,10 @@ TEST_F(AccessibilityTest, PositionAtStartAndEndOfTable) { const AXObject* ax_table = GetAXObjectByElementId("table"); ASSERT_NE(nullptr, ax_table); - ASSERT_EQ(AccessibilityRole::kTableRole, ax_table->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kTable, ax_table->RoleValue()); const AXObject* ax_header_row = GetAXObjectByElementId("headerRow"); ASSERT_NE(nullptr, ax_header_row); - ASSERT_EQ(AccessibilityRole::kRowRole, ax_header_row->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kRow, ax_header_row->RoleValue()); const auto ax_position_at_start = AXPosition::CreateFirstPositionInObject(*ax_table); @@ -1270,13 +1270,11 @@ TEST_F(AccessibilityTest, PositionInTableHeader) { const AXObject* ax_first_header_cell = GetAXObjectByElementId("firstHeaderCell"); ASSERT_NE(nullptr, ax_first_header_cell); - ASSERT_EQ(AccessibilityRole::kColumnHeaderRole, - ax_first_header_cell->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kColumnHeader, ax_first_header_cell->RoleValue()); const AXObject* ax_last_header_cell = GetAXObjectByElementId("lastHeaderCell"); ASSERT_NE(nullptr, ax_last_header_cell); - ASSERT_EQ(AccessibilityRole::kColumnHeaderRole, - ax_last_header_cell->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kColumnHeader, ax_last_header_cell->RoleValue()); const auto ax_position_before = AXPosition::CreatePositionBeforeObject(*ax_first_header_cell); @@ -1317,10 +1315,10 @@ TEST_F(AccessibilityTest, PositionInTableRow) { const AXObject* ax_first_cell = GetAXObjectByElementId("firstCell"); ASSERT_NE(nullptr, ax_first_cell); - ASSERT_EQ(AccessibilityRole::kRowHeaderRole, ax_first_cell->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kRowHeader, ax_first_cell->RoleValue()); const AXObject* ax_last_cell = GetAXObjectByElementId("lastCell"); ASSERT_NE(nullptr, ax_last_cell); - ASSERT_EQ(AccessibilityRole::kCellRole, ax_last_cell->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kCell, ax_last_cell->RoleValue()); const auto ax_position_before = AXPosition::CreatePositionBeforeObject(*ax_first_cell); @@ -1361,14 +1359,14 @@ TEST_F(AccessibilityTest, DISABLED_PositionInVirtualAOMNode) { const AXObject* ax_parent = GetAXObjectByElementId("aomParent"); ASSERT_NE(nullptr, ax_parent); - ASSERT_EQ(AccessibilityRole::kGenericContainerRole, ax_parent->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kGenericContainer, ax_parent->RoleValue()); ASSERT_EQ(1, ax_parent->ChildCount()); const AXObject* ax_button = ax_parent->FirstChild(); ASSERT_NE(nullptr, ax_button); - ASSERT_EQ(AccessibilityRole::kButtonRole, ax_button->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kButton, ax_button->RoleValue()); const AXObject* ax_after = GetAXObjectByElementId("after"); ASSERT_NE(nullptr, ax_after); - ASSERT_EQ(AccessibilityRole::kParagraphRole, ax_after->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kParagraph, ax_after->RoleValue()); const auto ax_position_before = AXPosition::CreatePositionBeforeObject(*ax_button); diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_progress_indicator.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_progress_indicator.cc index 00c46041ab5..3e8c77033fd 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_progress_indicator.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_progress_indicator.cc @@ -40,10 +40,10 @@ AXProgressIndicator* AXProgressIndicator::Create( return new AXProgressIndicator(layout_object, ax_object_cache); } -AccessibilityRole AXProgressIndicator::DetermineAccessibilityRole() { - if ((aria_role_ = DetermineAriaRoleAttribute()) != kUnknownRole) +ax::mojom::Role AXProgressIndicator::DetermineAccessibilityRole() { + if ((aria_role_ = DetermineAriaRoleAttribute()) != ax::mojom::Role::kUnknown) return aria_role_; - return kProgressIndicatorRole; + return ax::mojom::Role::kProgressIndicator; } bool AXProgressIndicator::ComputeAccessibilityIsIgnored( diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_progress_indicator.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_progress_indicator.h index 6296991b509..c4e2ab9aaa7 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_progress_indicator.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_progress_indicator.h @@ -35,7 +35,7 @@ class AXProgressIndicator final : public AXLayoutObject { static AXProgressIndicator* Create(LayoutProgress*, AXObjectCacheImpl&); private: - AccessibilityRole DetermineAccessibilityRole() final; + ax::mojom::Role DetermineAccessibilityRole() final; bool IsProgressIndicator() const override { return true; } diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_radio_input.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_radio_input.cc index 93a91192e75..dd1c41a885f 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_radio_input.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_radio_input.cc @@ -53,7 +53,7 @@ void AXRadioInput::RequestUpdateToNextNode(bool forward) { ToAXRadioInput(next_axobject)->UpdatePosAndSetSize(position); AXObjectCache().PostNotification(next_axobject, - AXObjectCacheImpl::kAXAriaAttributeChanged); + ax::mojom::Event::kAriaAttributeChanged); ToAXRadioInput(next_axobject)->RequestUpdateToNextNode(forward); } diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_range.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_range.h index b3b381c6202..a5cb18249e9 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_range.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_range.h @@ -18,7 +18,7 @@ namespace blink { class AXObject; class MODULES_EXPORT AXRange final { - DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + DISALLOW_NEW(); public: AXRange(const AXPosition& start, const AXPosition& end); diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_range_test.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_range_test.cc index 342bb0ba16f..25ade2647a9 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_range_test.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_range_test.cc @@ -24,12 +24,12 @@ TEST_F(AccessibilityTest, CommonAncestorContainerOfRange) { ASSERT_NE(nullptr, paragraph); const AXObject* text1 = paragraph->FirstChild(); ASSERT_NE(nullptr, text1); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, text1->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, text1->RoleValue()); const AXObject* br = GetAXObjectByElementId("br"); ASSERT_NE(nullptr, br); const AXObject* text2 = paragraph->LastChild(); ASSERT_NE(nullptr, text2); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, text2->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, text2->RoleValue()); const AXObject* button = GetAXObjectByElementId("button"); ASSERT_NE(nullptr, button); @@ -54,7 +54,7 @@ TEST_F(AccessibilityTest, IsCollapsedRange) { ASSERT_NE(nullptr, paragraph); const AXObject* text = paragraph->FirstChild(); ASSERT_NE(nullptr, text); - ASSERT_EQ(AccessibilityRole::kStaticTextRole, text->RoleValue()); + ASSERT_EQ(ax::mojom::Role::kStaticText, text->RoleValue()); const AXRange paragraph_range( AXPosition::CreateLastPositionInObject(*paragraph), diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc index 74902bd58c3..9a01cb2ba90 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc @@ -69,9 +69,8 @@ bool AXRelationCache::IsValidOwnsRelation(AXObject* owner, void AXRelationCache::UnmapOwnedChildren(const AXObject* owner, const Vector<AXID> child_ids) { - for (size_t i = 0; i < child_ids.size(); ++i) { + for (AXID removed_child_id : child_ids) { // Find the AXObject for the child that this owner no longer owns. - AXID removed_child_id = child_ids[i]; AXObject* removed_child = ObjectFromAXID(removed_child_id); // It's possible that this child has already been owned by some other @@ -102,10 +101,7 @@ void AXRelationCache::UnmapOwnedChildren(const AXObject* owner, void AXRelationCache::MapOwnedChildren(const AXObject* owner, const Vector<AXID> child_ids) { - for (size_t i = 0; i < child_ids.size(); ++i) { - // Find the AXObject for the child that will now be a child of this - // owner. - AXID added_child_id = child_ids[i]; + for (AXID added_child_id : child_ids) { AXObject* added_child = ObjectFromAXID(added_child_id); // Add this child to the mapping from child to owner. @@ -233,8 +229,8 @@ void AXRelationCache::UpdateRelatedText(Node* node) { void AXRelationCache::RemoveAXID(AXID obj_id) { if (aria_owner_to_children_mapping_.Contains(obj_id)) { Vector<AXID> child_axids = aria_owner_to_children_mapping_.at(obj_id); - for (size_t i = 0; i < child_axids.size(); ++i) - aria_owned_child_to_owner_mapping_.erase(child_axids[i]); + for (AXID child_axid : child_axids) + aria_owned_child_to_owner_mapping_.erase(child_axid); aria_owner_to_children_mapping_.erase(obj_id); } aria_owned_child_to_owner_mapping_.erase(obj_id); diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.h index 4571bc5b89b..fbcecc8843c 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_selection.h @@ -26,7 +26,7 @@ enum class AXSelectionBehavior { }; class MODULES_EXPORT AXSelection final { - DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + DISALLOW_NEW(); public: class Builder; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.cc index cb09e9c2029..aa00ce8b023 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.cc @@ -47,11 +47,11 @@ AXSlider* AXSlider::Create(LayoutObject* layout_object, return new AXSlider(layout_object, ax_object_cache); } -AccessibilityRole AXSlider::DetermineAccessibilityRole() { - if ((aria_role_ = DetermineAriaRoleAttribute()) != kUnknownRole) +ax::mojom::Role AXSlider::DetermineAccessibilityRole() { + if ((aria_role_ = DetermineAriaRoleAttribute()) != ax::mojom::Role::kUnknown) return aria_role_; - return kSliderRole; + return ax::mojom::Role::kSlider; } AccessibilityOrientation AXSlider::Orientation() const { @@ -88,8 +88,8 @@ void AXSlider::AddChildren() { AXObjectCacheImpl& cache = AXObjectCache(); - AXSliderThumb* thumb = - static_cast<AXSliderThumb*>(cache.GetOrCreate(kSliderThumbRole)); + AXSliderThumb* thumb = static_cast<AXSliderThumb*>( + cache.GetOrCreate(ax::mojom::Role::kSliderThumb)); thumb->SetParent(this); // Before actually adding the value indicator to the hierarchy, diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.h index eaf5c12c82e..ab68e7145a8 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_slider.h @@ -50,7 +50,7 @@ class AXSlider : public AXLayoutObject { HTMLInputElement* GetInputElement() const; AXObject* ElementAccessibilityHitTest(const IntPoint&) const final; - AccessibilityRole DetermineAccessibilityRole() final; + ax::mojom::Role DetermineAccessibilityRole() final; bool IsSlider() const final { return true; } bool IsControl() const final { return true; } @@ -67,7 +67,9 @@ class AXSliderThumb final : public AXMockObject { static AXSliderThumb* Create(AXObjectCacheImpl&); ~AXSliderThumb() override = default; - AccessibilityRole RoleValue() const override { return kSliderThumbRole; } + ax::mojom::Role RoleValue() const override { + return ax::mojom::Role::kSliderThumb; + } private: explicit AXSliderThumb(AXObjectCacheImpl&); diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc index a72f3e7e174..4f30248e597 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc @@ -2,8 +2,8 @@ // 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/accessibility/ax_object_cache_impl.h" #include "third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.h" +#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h" namespace blink { @@ -96,7 +96,11 @@ class ObjectVectorAttributeSetter : public AXSparseAttributeSetter { for (const auto& id : ids) { if (Element* id_element = scope.getElementById(AtomicString(id))) { AXObject* ax_id_element = obj.AXObjectCache().GetOrCreate(id_element); - if (ax_id_element && !ax_id_element->AccessibilityIsIgnored()) + if (!ax_id_element) + continue; + if (AXObject* parent = ax_id_element->ParentObject()) + parent->UpdateChildrenIfNecessary(); + if (!ax_id_element->AccessibilityIsIgnored()) objects.push_back(ax_id_element); } } @@ -222,7 +226,7 @@ void AXSparseAttributeAOMPropertyClient::AddRelationListProperty( } HeapVector<Member<AXObject>> objects; - for (size_t i = 0; i < relations.length(); ++i) { + for (unsigned i = 0; i < relations.length(); ++i) { AccessibleNode* accessible_node = relations.item(i); if (accessible_node) { Element* element = accessible_node->element(); diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.cc index 084a6f6d31d..db5d34482cb 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.cc @@ -63,10 +63,10 @@ AXObject* AXSVGRoot::ComputeParent() const { } // SVG AAM 1.0 S8.2: the default role for an SVG root is "group". -AccessibilityRole AXSVGRoot::DetermineAccessibilityRole() { - AccessibilityRole role = AXLayoutObject::DetermineAccessibilityRole(); - if (role == kUnknownRole) - role = kGroupRole; +ax::mojom::Role AXSVGRoot::DetermineAccessibilityRole() { + ax::mojom::Role role = AXLayoutObject::DetermineAccessibilityRole(); + if (role == ax::mojom::Role::kUnknown) + role = ax::mojom::Role::kGroup; return role; } diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.h index bd7b586189d..1427cb631f7 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_svg_root.h @@ -46,7 +46,7 @@ class AXSVGRoot final : public AXLayoutObject { void SetParent(AXObject*) override; - AccessibilityRole DetermineAccessibilityRole() override; + ax::mojom::Role DetermineAccessibilityRole() override; bool ComputeAccessibilityIsIgnored(IgnoredReasons*) const override; private: diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc index c4dfefe29d6..7719f9641e4 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc @@ -35,7 +35,7 @@ void AXVirtualObject::AddChildren() { void AXVirtualObject::ChildrenChanged() { ClearChildren(); - AXObjectCache().PostNotification(this, AXObjectCacheImpl::kAXChildrenChanged); + AXObjectCache().PostNotification(this, ax::mojom::Event::kChildrenChanged); } const AtomicString& AXVirtualObject::GetAOMPropertyOrARIAAttribute( @@ -63,7 +63,7 @@ AccessibleNode* AXVirtualObject::GetAccessibleNode() const { String AXVirtualObject::TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom& name_from, + ax::mojom::NameFrom& name_from, AXRelatedObjectVector* related_objects, NameSources* name_sources) const { if (!accessible_node_) diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h index 666f7dbfca0..c571d96f34b 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_virtual_object.h @@ -33,7 +33,7 @@ class MODULES_EXPORT AXVirtualObject : public AXObject { String TextAlternative(bool recursive, bool in_aria_labelled_by_traversal, AXObjectSet& visited, - AXNameFrom&, + ax::mojom::NameFrom&, AXRelatedObjectVector*, NameSources*) const override; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc b/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc index 33993771b77..55321ce8943 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc @@ -12,14 +12,16 @@ #include "third_party/blink/renderer/core/dom/flat_tree_traversal.h" #include "third_party/blink/renderer/core/dom/node.h" #include "third_party/blink/renderer/core/dom/node_list.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/html_names.h" #include "third_party/blink/renderer/core/inspector/identifiers_factory.h" +#include "third_party/blink/renderer/core/inspector/inspected_frames.h" #include "third_party/blink/renderer/core/inspector/inspector_dom_agent.h" #include "third_party/blink/renderer/core/inspector/inspector_style_sheet.h" -#include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/modules/accessibility/ax_object.h" #include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h" #include "third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.h" +#include "third_party/blink/renderer/platform/wtf/deque.h" namespace blink { @@ -40,37 +42,37 @@ namespace { static const AXID kIDForInspectedNodeWithNoAXNode = 0; -void AddHasPopupProperty(AXHasPopup has_popup, +void AddHasPopupProperty(ax::mojom::HasPopup has_popup, protocol::Array<AXProperty>& properties) { switch (has_popup) { - case kAXHasPopupFalse: + case ax::mojom::HasPopup::kFalse: break; - case kAXHasPopupTrue: + case ax::mojom::HasPopup::kTrue: properties.addItem( CreateProperty(AXPropertyNameEnum::HasPopup, CreateValue("true", AXValueTypeEnum::Token))); break; - case kAXHasPopupMenu: + case ax::mojom::HasPopup::kMenu: properties.addItem( CreateProperty(AXPropertyNameEnum::HasPopup, CreateValue("menu", AXValueTypeEnum::Token))); break; - case kAXHasPopupListbox: + case ax::mojom::HasPopup::kListbox: properties.addItem( CreateProperty(AXPropertyNameEnum::HasPopup, CreateValue("listbox", AXValueTypeEnum::Token))); break; - case kAXHasPopupTree: + case ax::mojom::HasPopup::kTree: properties.addItem( CreateProperty(AXPropertyNameEnum::HasPopup, CreateValue("tree", AXValueTypeEnum::Token))); break; - case kAXHasPopupGrid: + case ax::mojom::HasPopup::kGrid: properties.addItem( CreateProperty(AXPropertyNameEnum::HasPopup, CreateValue("grid", AXValueTypeEnum::Token))); break; - case kAXHasPopupDialog: + case ax::mojom::HasPopup::kDialog: properties.addItem( CreateProperty(AXPropertyNameEnum::HasPopup, CreateValue("dialog", AXValueTypeEnum::Token))); @@ -119,26 +121,26 @@ void FillGlobalStates(AXObject& ax_object, AddHasPopupProperty(ax_object.HasPopup(), properties); - InvalidState invalid_state = ax_object.GetInvalidState(); + ax::mojom::InvalidState invalid_state = ax_object.GetInvalidState(); switch (invalid_state) { - case kInvalidStateUndefined: + case ax::mojom::InvalidState::kNone: break; - case kInvalidStateFalse: + case ax::mojom::InvalidState::kFalse: properties.addItem( CreateProperty(AXPropertyNameEnum::Invalid, CreateValue("false", AXValueTypeEnum::Token))); break; - case kInvalidStateTrue: + case ax::mojom::InvalidState::kTrue: properties.addItem( CreateProperty(AXPropertyNameEnum::Invalid, CreateValue("true", AXValueTypeEnum::Token))); break; - case kInvalidStateSpelling: + case ax::mojom::InvalidState::kSpelling: properties.addItem( CreateProperty(AXPropertyNameEnum::Invalid, CreateValue("spelling", AXValueTypeEnum::Token))); break; - case kInvalidStateGrammar: + case ax::mojom::InvalidState::kGrammar: properties.addItem( CreateProperty(AXPropertyNameEnum::Invalid, CreateValue("grammar", AXValueTypeEnum::Token))); @@ -153,41 +155,52 @@ void FillGlobalStates(AXObject& ax_object, } } -bool RoleAllowsModal(AccessibilityRole role) { - return role == kDialogRole || role == kAlertDialogRole; +bool RoleAllowsModal(ax::mojom::Role role) { + return role == ax::mojom::Role::kDialog || + role == ax::mojom::Role::kAlertDialog; } -bool RoleAllowsMultiselectable(AccessibilityRole role) { - return role == kGridRole || role == kListBoxRole || role == kTabListRole || - role == kTreeGridRole || role == kTreeRole; +bool RoleAllowsMultiselectable(ax::mojom::Role role) { + return role == ax::mojom::Role::kGrid || role == ax::mojom::Role::kListBox || + role == ax::mojom::Role::kTabList || + role == ax::mojom::Role::kTreeGrid || role == ax::mojom::Role::kTree; } -bool RoleAllowsOrientation(AccessibilityRole role) { - return role == kScrollBarRole || role == kSplitterRole || role == kSliderRole; +bool RoleAllowsOrientation(ax::mojom::Role role) { + return role == ax::mojom::Role::kScrollBar || + role == ax::mojom::Role::kSplitter || role == ax::mojom::Role::kSlider; } -bool RoleAllowsReadonly(AccessibilityRole role) { - return role == kGridRole || role == kCellRole || role == kTextFieldRole || - role == kColumnHeaderRole || role == kRowHeaderRole || - role == kTreeGridRole; +bool RoleAllowsReadonly(ax::mojom::Role role) { + return role == ax::mojom::Role::kGrid || role == ax::mojom::Role::kCell || + role == ax::mojom::Role::kTextField || + role == ax::mojom::Role::kColumnHeader || + role == ax::mojom::Role::kRowHeader || + role == ax::mojom::Role::kTreeGrid; } -bool RoleAllowsRequired(AccessibilityRole role) { - return role == kComboBoxGroupingRole || role == kComboBoxMenuButtonRole || - role == kCellRole || role == kListBoxRole || role == kRadioGroupRole || - role == kSpinButtonRole || role == kTextFieldRole || - role == kTextFieldWithComboBoxRole || role == kTreeRole || - role == kColumnHeaderRole || role == kRowHeaderRole || - role == kTreeGridRole; +bool RoleAllowsRequired(ax::mojom::Role role) { + return role == ax::mojom::Role::kComboBoxGrouping || + role == ax::mojom::Role::kComboBoxMenuButton || + role == ax::mojom::Role::kCell || role == ax::mojom::Role::kListBox || + role == ax::mojom::Role::kRadioGroup || + role == ax::mojom::Role::kSpinButton || + role == ax::mojom::Role::kTextField || + role == ax::mojom::Role::kTextFieldWithComboBox || + role == ax::mojom::Role::kTree || + role == ax::mojom::Role::kColumnHeader || + role == ax::mojom::Role::kRowHeader || + role == ax::mojom::Role::kTreeGrid; } -bool RoleAllowsSort(AccessibilityRole role) { - return role == kColumnHeaderRole || role == kRowHeaderRole; +bool RoleAllowsSort(ax::mojom::Role role) { + return role == ax::mojom::Role::kColumnHeader || + role == ax::mojom::Role::kRowHeader; } void FillWidgetProperties(AXObject& ax_object, protocol::Array<AXProperty>& properties) { - AccessibilityRole role = ax_object.RoleValue(); + ax::mojom::Role role = ax_object.RoleValue(); String autocomplete = ax_object.AriaAutoComplete(); if (!autocomplete.IsEmpty()) properties.addItem( @@ -232,7 +245,7 @@ void FillWidgetProperties(AXObject& ax_object, } } - if (role == kTextFieldRole) { + if (role == ax::mojom::Role::kTextField) { properties.addItem( CreateProperty(AXPropertyNameEnum::Multiline, CreateBooleanValue(ax_object.IsMultiline()))); @@ -275,23 +288,23 @@ void FillWidgetProperties(AXObject& ax_object, void FillWidgetStates(AXObject& ax_object, protocol::Array<AXProperty>& properties) { - AccessibilityRole role = ax_object.RoleValue(); + ax::mojom::Role role = ax_object.RoleValue(); const char* checked_prop_val = nullptr; switch (ax_object.CheckedState()) { - case kCheckedStateTrue: + case ax::mojom::CheckedState::kTrue: checked_prop_val = "true"; break; - case kCheckedStateMixed: + case ax::mojom::CheckedState::kMixed: checked_prop_val = "mixed"; break; - case kCheckedStateFalse: + case ax::mojom::CheckedState::kFalse: checked_prop_val = "false"; break; - case kCheckedStateUndefined: + case ax::mojom::CheckedState::kNone: break; } if (checked_prop_val) { - auto* const checked_prop_name = role == kToggleButtonRole + auto* const checked_prop_name = role == ax::mojom::Role::kToggleButton ? AXPropertyNameEnum::Pressed : AXPropertyNameEnum::Checked; properties.addItem(CreateProperty( @@ -450,7 +463,7 @@ void FillRelationships(AXObject& ax_object, results.clear(); } -std::unique_ptr<AXValue> CreateRoleNameValue(AccessibilityRole role) { +std::unique_ptr<AXValue> CreateRoleNameValue(ax::mojom::Role role) { AtomicString role_name = AXObject::RoleName(role); std::unique_ptr<AXValue> role_name_value; if (!role_name.IsNull()) { @@ -465,9 +478,9 @@ std::unique_ptr<AXValue> CreateRoleNameValue(AccessibilityRole role) { } // namespace InspectorAccessibilityAgent::InspectorAccessibilityAgent( - Page* page, + InspectedFrames* inspected_frames, InspectorDOMAgent* dom_agent) - : page_(page), dom_agent_(dom_agent) {} + : inspected_frames_(inspected_frames), dom_agent_(dom_agent) {} Response InspectorAccessibilityAgent::getPartialAXTree( Maybe<int> dom_node_id, @@ -545,7 +558,7 @@ std::unique_ptr<AXNode> InspectorAccessibilityAgent::BuildObjectForIgnoredNode( .setNodeId(String::Number(ax_id)) .setIgnored(true) .build(); - AccessibilityRole role = AccessibilityRole::kIgnoredRole; + ax::mojom::Role role = ax::mojom::Role::kIgnored; ignored_node_object->setRole(CreateRoleNameValue(role)); if (ax_object && ax_object->IsAXLayoutObject()) { @@ -562,13 +575,15 @@ std::unique_ptr<AXNode> InspectorAccessibilityAgent::BuildObjectForIgnoredNode( ignored_reasons.push_back(IgnoredReason(kAXNotRendered)); } - if (dom_node) - ignored_node_object->setBackendDOMNodeId(DOMNodeIds::IdForNode(dom_node)); + if (dom_node) { + ignored_node_object->setBackendDOMNodeId( + IdentifiersFactory::IntIdForNode(dom_node)); + } std::unique_ptr<protocol::Array<AXProperty>> ignored_reason_properties = protocol::Array<AXProperty>::create(); - for (size_t i = 0; i < ignored_reasons.size(); i++) - ignored_reason_properties->addItem(CreateProperty(ignored_reasons[i])); + for (IgnoredReason& reason : ignored_reasons) + ignored_reason_properties->addItem(CreateProperty(reason)); ignored_node_object->setIgnoredReasons(std::move(ignored_reason_properties)); return ignored_node_object; @@ -619,7 +634,7 @@ std::unique_ptr<AXNode> InspectorAccessibilityAgent::BuildProtocolAXObject( bool fetch_relatives, std::unique_ptr<protocol::Array<AXNode>>& nodes, AXObjectCacheImpl& cache) const { - AccessibilityRole role = ax_object.RoleValue(); + ax::mojom::Role role = ax_object.RoleValue(); std::unique_ptr<AXNode> node_object = AXNode::create() .setNodeId(String::Number(ax_object.AXObjectID())) @@ -646,8 +661,7 @@ std::unique_ptr<AXNode> InspectorAccessibilityAgent::BuildProtocolAXObject( if (!name_sources.IsEmpty()) { std::unique_ptr<protocol::Array<AXValueSource>> name_source_properties = protocol::Array<AXValueSource>::create(); - for (size_t i = 0; i < name_sources.size(); ++i) { - NameSource& name_source = name_sources[i]; + for (NameSource& name_source : name_sources) { name_source_properties->addItem(CreateValueSource(name_source)); if (name_source.text.IsNull() || name_source.superseded) continue; @@ -669,6 +683,37 @@ std::unique_ptr<AXNode> InspectorAccessibilityAgent::BuildProtocolAXObject( return node_object; } +Response InspectorAccessibilityAgent::getFullAXTree( + std::unique_ptr<protocol::Array<AXNode>>* nodes) { + Document* document = inspected_frames_->Root()->GetDocument(); + if (!document) + return Response::Error("No document."); + *nodes = protocol::Array<protocol::Accessibility::AXNode>::create(); + AXContext ax_context(*document); + AXObjectCacheImpl& cache = ToAXObjectCacheImpl(ax_context.GetAXObjectCache()); + Deque<AXID> ids; + ids.push_back(cache.Root()->AXObjectID()); + while (!ids.empty()) { + AXID ax_id = ids.front(); + ids.pop_front(); + AXObject* ax_object = cache.ObjectFromAXID(ax_id); + std::unique_ptr<AXNode> node = + BuildProtocolAXObject(*ax_object, nullptr, false, *nodes, cache); + + std::unique_ptr<protocol::Array<AXNodeId>> child_ids = + protocol::Array<AXNodeId>::create(); + const AXObject::AXObjectVector& children = ax_object->Children(); + for (unsigned i = 0; i < children.size(); i++) { + AXObject& child_ax_object = *children[i].Get(); + child_ids->addItem(String::Number(child_ax_object.AXObjectID())); + ids.push_back(child_ax_object.AXObjectID()); + } + node->setChildIds(std::move(child_ids)); + (*nodes)->addItem(std::move(node)); + } + return Response::OK(); +} + void InspectorAccessibilityAgent::FillCoreProperties( AXObject& ax_object, AXObject* inspected_ax_object, @@ -676,11 +721,11 @@ void InspectorAccessibilityAgent::FillCoreProperties( AXNode& node_object, std::unique_ptr<protocol::Array<AXNode>>& nodes, AXObjectCacheImpl& cache) const { - AXNameFrom name_from; + ax::mojom::NameFrom name_from; AXObject::AXObjectVector name_objects; ax_object.GetName(name_from, &name_objects); - AXDescriptionFrom description_from; + ax::mojom::DescriptionFrom description_from; AXObject::AXObjectVector description_objects; String description = ax_object.Description(name_from, description_from, &description_objects); @@ -705,7 +750,7 @@ void InspectorAccessibilityAgent::FillCoreProperties( Node* node = ax_object.GetNode(); if (node) - node_object.setBackendDOMNodeId(DOMNodeIds::IdForNode(node)); + node_object.setBackendDOMNodeId(IdentifiersFactory::IntIdForNode(node)); } void InspectorAccessibilityAgent::PopulateRelatives( @@ -764,7 +809,7 @@ void InspectorAccessibilityAgent::AddChildren( } void InspectorAccessibilityAgent::Trace(blink::Visitor* visitor) { - visitor->Trace(page_); + visitor->Trace(inspected_frames_); visitor->Trace(dom_agent_); InspectorBaseAgent::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.h b/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.h index 497df05f9b8..c28a394523d 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.h @@ -15,7 +15,7 @@ namespace blink { class AXObject; class AXObjectCacheImpl; class InspectorDOMAgent; -class Page; +class InspectedFrames; using protocol::Accessibility::AXNode; using protocol::Accessibility::AXNodeId; @@ -23,7 +23,7 @@ using protocol::Accessibility::AXNodeId; class MODULES_EXPORT InspectorAccessibilityAgent : public InspectorBaseAgent<protocol::Accessibility::Metainfo> { public: - InspectorAccessibilityAgent(Page*, InspectorDOMAgent*); + InspectorAccessibilityAgent(InspectedFrames*, InspectorDOMAgent*); // Base agent methods. void Trace(blink::Visitor*) override; @@ -36,6 +36,9 @@ class MODULES_EXPORT InspectorAccessibilityAgent protocol::Maybe<bool> fetch_relatives, std::unique_ptr<protocol::Array<protocol::Accessibility::AXNode>>*) override; + protocol::Response getFullAXTree( + std::unique_ptr<protocol::Array<protocol::Accessibility::AXNode>>*) + override; private: std::unique_ptr<AXNode> BuildObjectForIgnoredNode( @@ -86,7 +89,7 @@ class MODULES_EXPORT InspectorAccessibilityAgent std::unique_ptr<protocol::Array<AXNode>>& nodes, AXObjectCacheImpl&) const; - Member<Page> page_; + Member<InspectedFrames> inspected_frames_; Member<InspectorDOMAgent> dom_agent_; DISALLOW_COPY_AND_ASSIGN(InspectorAccessibilityAgent); diff --git a/chromium/third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.cc b/chromium/third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.cc index fe1fc402dff..91169601a87 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.cc @@ -5,6 +5,7 @@ #include "third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.h" #include "third_party/blink/renderer/core/dom/dom_node_ids.h" +#include "third_party/blink/renderer/core/inspector/identifiers_factory.h" #include "third_party/blink/renderer/modules/accessibility/ax_object.h" #include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h" @@ -46,7 +47,7 @@ String IgnoredReasonName(AXIgnoredReason reason) { return "notRendered"; case kAXNotVisible: return "notVisible"; - case kAXPresentationalRole: + case kAXPresentational: return "presentationalRole"; case kAXProbablyPresentational: return "probablyPresentational"; @@ -102,7 +103,7 @@ std::unique_ptr<AXRelatedNode> RelatedNodeForAXObject(const AXObject& ax_object, Node* node = ax_object.GetNode(); if (!node) return nullptr; - int backend_node_id = DOMNodeIds::IdForNode(node); + int backend_node_id = IdentifiersFactory::IntIdForNode(node); if (!backend_node_id) return nullptr; std::unique_ptr<AXRelatedNode> related_node = @@ -167,19 +168,19 @@ std::unique_ptr<AXValue> CreateRelatedNodeListValue( .build(); } -String ValueSourceType(AXNameFrom name_from) { +String ValueSourceType(ax::mojom::NameFrom name_from) { switch (name_from) { - case kAXNameFromAttribute: - case kAXNameFromAttributeExplicitlyEmpty: - case kAXNameFromTitle: - case kAXNameFromValue: + case ax::mojom::NameFrom::kAttribute: + case ax::mojom::NameFrom::kAttributeExplicitlyEmpty: + case ax::mojom::NameFrom::kTitle: + case ax::mojom::NameFrom::kValue: return AXValueSourceTypeEnum::Attribute; - case kAXNameFromContents: + case ax::mojom::NameFrom::kContents: return AXValueSourceTypeEnum::Contents; - case kAXNameFromPlaceholder: + case ax::mojom::NameFrom::kPlaceholder: return AXValueSourceTypeEnum::Placeholder; - case kAXNameFromCaption: - case kAXNameFromRelatedElement: + case ax::mojom::NameFrom::kCaption: + case ax::mojom::NameFrom::kRelatedElement: return AXValueSourceTypeEnum::RelatedElement; default: return AXValueSourceTypeEnum::Implicit; // TODO(aboxhall): what to do diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/BUILD.gn b/chromium/third_party/blink/renderer/modules/animationworklet/BUILD.gn index 54193864a31..ddde73a9135 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/animationworklet/BUILD.gn @@ -12,8 +12,8 @@ blink_modules_sources("animationworklet") { "animation_worklet_global_scope.h", "animation_worklet_messaging_proxy.cc", "animation_worklet_messaging_proxy.h", - "animation_worklet_proxy_client_impl.cc", - "animation_worklet_proxy_client_impl.h", + "animation_worklet_proxy_client.cc", + "animation_worklet_proxy_client.h", "animation_worklet_thread.cc", "animation_worklet_thread.h", "animator.cc", diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc index cea538e58ea..2722b7d0e25 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc +++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc @@ -6,12 +6,11 @@ #include "base/atomic_sequence_num.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" -#include "third_party/blink/renderer/core/dom/animation_worklet_proxy_client.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/page/chrome_client.h" #include "third_party/blink/renderer/core/workers/worker_clients.h" #include "third_party/blink/renderer/modules/animationworklet/animation_worklet_messaging_proxy.h" -#include "third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.h" +#include "third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h" #include "third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.h" base::AtomicSequenceNumber g_next_worklet_id; @@ -39,9 +38,9 @@ WorkletGlobalScopeProxy* AnimationWorklet::CreateGlobalScope() { DCHECK(NeedsToCreateGlobalScope()); AnimationWorkletThread::EnsureSharedBackingThread(); - Document* document = ToDocument(GetExecutionContext()); + Document* document = To<Document>(GetExecutionContext()); AnimationWorkletProxyClient* proxy_client = - AnimationWorkletProxyClientImpl::FromDocument(document, scope_id_); + AnimationWorkletProxyClient::FromDocument(document, scope_id_); WorkerClients* worker_clients = WorkerClients::Create(); ProvideAnimationWorkletProxyClientTo(worker_clients, proxy_client); diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.h b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.h index fa07268915d..5cd1e179f90 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.h +++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet.h @@ -7,7 +7,7 @@ #include "third_party/blink/renderer/core/workers/worklet.h" #include "third_party/blink/renderer/modules/modules_export.h" -#include "third_party/blink/renderer/platform/graphics/compositor_animators_state.h" +#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutators_state.h" #include "third_party/blink/renderer/platform/heap/handle.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc index e559ac300fa..c7912c97333 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc +++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc @@ -7,8 +7,9 @@ #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h" #include "third_party/blink/renderer/bindings/core/v8/v8_object_parser.h" #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h" -#include "third_party/blink/renderer/core/dom/animation_worklet_proxy_client.h" #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" +#include "third_party/blink/renderer/core/workers/worker_thread.h" +#include "third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h" #include "third_party/blink/renderer/modules/animationworklet/worklet_animation_options.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h" @@ -23,9 +24,9 @@ void UpdateAnimation(Animator* animator, ScriptState* script_state, WorkletAnimationId id, double current_time, - CompositorMutatorOutputState* result) { - CompositorMutatorOutputState::AnimationState animation_output(id, - base::nullopt); + AnimationWorkletDispatcherOutput* result) { + AnimationWorkletDispatcherOutput::AnimationState animation_output( + id, base::nullopt); if (animator->Animate(script_state, current_time, &animation_output)) { result->animations.push_back(std::move(animation_output)); } @@ -35,25 +36,23 @@ void UpdateAnimation(Animator* animator, AnimationWorkletGlobalScope* AnimationWorkletGlobalScope::Create( std::unique_ptr<GlobalScopeCreationParams> creation_params, - v8::Isolate* isolate, WorkerThread* thread) { - return new AnimationWorkletGlobalScope(std::move(creation_params), isolate, - thread); + return new AnimationWorkletGlobalScope(std::move(creation_params), thread); } AnimationWorkletGlobalScope::AnimationWorkletGlobalScope( std::unique_ptr<GlobalScopeCreationParams> creation_params, - v8::Isolate* isolate, WorkerThread* thread) - : ThreadedWorkletGlobalScope(std::move(creation_params), isolate, thread) { -} + : WorkletGlobalScope(std::move(creation_params), + thread->GetWorkerReportingProxy(), + thread) {} AnimationWorkletGlobalScope::~AnimationWorkletGlobalScope() = default; void AnimationWorkletGlobalScope::Trace(blink::Visitor* visitor) { visitor->Trace(animator_definitions_); visitor->Trace(animators_); - ThreadedWorkletGlobalScope::Trace(visitor); + WorkletGlobalScope::Trace(visitor); } void AnimationWorkletGlobalScope::Dispose() { @@ -61,7 +60,7 @@ void AnimationWorkletGlobalScope::Dispose() { if (AnimationWorkletProxyClient* proxy_client = AnimationWorkletProxyClient::From(Clients())) proxy_client->Dispose(); - ThreadedWorkletGlobalScope::Dispose(); + WorkletGlobalScope::Dispose(); } Animator* AnimationWorkletGlobalScope::CreateAnimatorFor( @@ -119,6 +118,15 @@ std::unique_ptr<AnimationWorkletOutput> AnimationWorkletGlobalScope::Mutate( animation.current_time, result.get()); } + for (const auto& worklet_animation_id : mutator_input.peeked_animations) { + int id = worklet_animation_id.animation_id; + Animator* animator = animators_.at(id); + + result->animations.emplace_back( + worklet_animation_id, + animator ? animator->GetLastLocalTime() : base::nullopt); + } + return result; } @@ -190,9 +198,11 @@ Animator* AnimationWorkletGlobalScope::CreateInstance( if (options && options->GetData()) value = options->GetData()->Deserialize(isolate); - v8::Local<v8::Object> instance; - if (!V8ObjectConstructor::NewInstance(isolate, constructor, - !value.IsEmpty() ? 1 : 0, &value) + v8::Local<v8::Value> instance; + if (!V8ScriptRunner::CallAsConstructor( + isolate, constructor, + ExecutionContext::From(ScriptController()->GetScriptState()), + !value.IsEmpty() ? 1 : 0, &value) .ToLocal(&instance)) return nullptr; diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h index cfcb8da7720..c0ee79bc731 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h +++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h @@ -6,12 +6,12 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_ANIMATION_WORKLET_GLOBAL_SCOPE_H_ #include "third_party/blink/renderer/bindings/core/v8/script_value.h" -#include "third_party/blink/renderer/core/workers/threaded_worklet_global_scope.h" +#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" #include "third_party/blink/renderer/modules/animationworklet/animator.h" #include "third_party/blink/renderer/modules/animationworklet/animator_definition.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" -#include "third_party/blink/renderer/platform/graphics/compositor_animators_state.h" +#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutators_state.h" namespace blink { @@ -27,14 +27,12 @@ class WorkletAnimationOptions; // The scope keeps a map of these animator definitions and can look them up // based on their name. The scope also owns a list of active animators that it // animates. -class MODULES_EXPORT AnimationWorkletGlobalScope - : public ThreadedWorkletGlobalScope { +class MODULES_EXPORT AnimationWorkletGlobalScope : public WorkletGlobalScope { DEFINE_WRAPPERTYPEINFO(); public: static AnimationWorkletGlobalScope* Create( std::unique_ptr<GlobalScopeCreationParams>, - v8::Isolate*, WorkerThread*); ~AnimationWorkletGlobalScope() override; void Trace(blink::Visitor*) override; @@ -54,7 +52,6 @@ class MODULES_EXPORT AnimationWorkletGlobalScope private: AnimationWorkletGlobalScope(std::unique_ptr<GlobalScopeCreationParams>, - v8::Isolate*, WorkerThread*); void RegisterWithProxyClientIfNeeded(); diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc index 04887c17559..1b5aea328ee 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc +++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc @@ -12,7 +12,6 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/v8_cache_options.h" #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h" -#include "third_party/blink/renderer/core/dom/animation_worklet_proxy_client.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h" #include "third_party/blink/renderer/core/script/script.h" @@ -21,6 +20,7 @@ #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h" #include "third_party/blink/renderer/core/workers/worklet_module_responses_map.h" #include "third_party/blink/renderer/modules/animationworklet/animation_worklet.h" +#include "third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h" #include "third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.h" #include "third_party/blink/renderer/modules/animationworklet/animator.h" #include "third_party/blink/renderer/modules/animationworklet/animator_definition.h" @@ -36,17 +36,14 @@ namespace blink { namespace { -class MockAnimationWorkletProxyClient - : public GarbageCollected<MockAnimationWorkletProxyClient>, - public AnimationWorkletProxyClient { - USING_GARBAGE_COLLECTED_MIXIN(MockAnimationWorkletProxyClient); - +class MockAnimationWorkletProxyClient : public AnimationWorkletProxyClient { public: - MockAnimationWorkletProxyClient() : did_set_global_scope_(false) {} + MockAnimationWorkletProxyClient() + : AnimationWorkletProxyClient(0, nullptr, nullptr, nullptr, nullptr), + did_set_global_scope_(false) {} void SetGlobalScope(WorkletGlobalScope*) override { did_set_global_scope_ = true; } - void Dispose() override {} bool did_set_global_scope() { return did_set_global_scope_; } private: @@ -60,7 +57,7 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase { AnimationWorkletGlobalScopeTest() = default; void SetUp() override { - AnimationWorkletThread::CreateSharedBackingThreadForTest(); + AnimationWorkletThread::EnsureSharedBackingThread(); PageTestBase::SetUp(IntSize()); Document* document = &GetDocument(); document->SetURL(KURL("https://example.com/")); @@ -262,13 +259,14 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase { ScriptState::Scope scope(script_state); global_scope->ScriptController()->Evaluate(ScriptSourceCode( - R"JS( + R"JS( registerAnimator('test', class { animate (currentTime, effect) { effect.localTime = 123; } }); - )JS")); + )JS"), + kSharableCrossOrigin); // Passing a new input state with a new animation id should cause the // worklet to create and animate an animator. @@ -307,13 +305,14 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase { ScriptState::Scope scope(script_state); global_scope->ScriptController()->Evaluate(ScriptSourceCode( - R"JS( + R"JS( registerAnimator('test', class { animate (currentTime, effect) { effect.localTime = 123; } }); - )JS")); + )JS"), + kSharableCrossOrigin); cc::WorkletAnimationId animation_id = {1, 1}; AnimationWorkletInput state; @@ -355,13 +354,14 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase { ScriptState::Scope scope(script_state); global_scope->ScriptController()->Evaluate(ScriptSourceCode( - R"JS( + R"JS( registerAnimator('test', class { animate (currentTime, effect) { effect.localTime = 123; } }); - )JS")); + )JS"), + kSharableCrossOrigin); cc::WorkletAnimationId animation_id = {1, 1}; AnimationWorkletInput state; diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_messaging_proxy.h b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_messaging_proxy.h index a58f2c46ce0..a13f3627e5b 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_messaging_proxy.h +++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_messaging_proxy.h @@ -6,8 +6,8 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_ANIMATION_WORKLET_MESSAGING_PROXY_H_ #include <memory> -#include "third_party/blink/renderer/core/dom/animation_worklet_proxy_client.h" #include "third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.h" +#include "third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.cc new file mode 100644 index 00000000000..2c9082e2901 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.cc @@ -0,0 +1,149 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h" + +#include "third_party/blink/renderer/core/animation/worklet_animation_controller.h" +#include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h" +#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" +#include "third_party/blink/renderer/core/workers/worker_thread.h" +#include "third_party/blink/renderer/platform/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h" + +namespace blink { + +const char AnimationWorkletProxyClient::kSupplementName[] = + "AnimationWorkletProxyClient"; + +AnimationWorkletProxyClient::AnimationWorkletProxyClient( + int scope_id, + base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> + compositor_mutator_dispatcher, + scoped_refptr<base::SingleThreadTaskRunner> compositor_mutator_runner, + base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> + main_thread_mutator_dispatcher, + scoped_refptr<base::SingleThreadTaskRunner> main_thread_mutator_runner) + : scope_id_(scope_id), state_(RunState::kUninitialized) { + DCHECK(IsMainThread()); + mutator_items_.emplace_back(std::move(compositor_mutator_dispatcher), + std::move(compositor_mutator_runner)); + mutator_items_.emplace_back(std::move(main_thread_mutator_dispatcher), + std::move(main_thread_mutator_runner)); +} + +void AnimationWorkletProxyClient::Trace(blink::Visitor* visitor) { + Supplement<WorkerClients>::Trace(visitor); + AnimationWorkletMutator::Trace(visitor); +} + +void AnimationWorkletProxyClient::SetGlobalScope( + WorkletGlobalScope* global_scope) { + DCHECK(global_scope); + DCHECK(global_scope->IsContextThread()); + if (state_ == RunState::kDisposed) + return; + DCHECK(state_ == RunState::kUninitialized); + + global_scope_ = static_cast<AnimationWorkletGlobalScope*>(global_scope); + // TODO(majidvp): Add an AnimationWorklet task type when the spec is final. + scoped_refptr<base::SingleThreadTaskRunner> global_scope_runner = + global_scope_->GetThread()->GetTaskRunner(TaskType::kMiscPlatformAPI); + state_ = RunState::kWorking; + + for (auto& mutator_item : mutator_items_) { + DCHECK(mutator_item.mutator_runner); + PostCrossThreadTask( + *mutator_item.mutator_runner, FROM_HERE, + CrossThreadBind(&AnimationWorkletMutatorDispatcherImpl:: + RegisterAnimationWorkletMutator, + mutator_item.mutator_dispatcher, + WrapCrossThreadPersistent(this), global_scope_runner)); + } +} + +void AnimationWorkletProxyClient::Dispose() { + if (state_ == RunState::kWorking) { + // At worklet scope termination break the reference to the clients if it is + // still alive. + for (auto& mutator_item : mutator_items_) { + DCHECK(mutator_item.mutator_runner); + PostCrossThreadTask( + *mutator_item.mutator_runner, FROM_HERE, + CrossThreadBind(&AnimationWorkletMutatorDispatcherImpl:: + UnregisterAnimationWorkletMutator, + mutator_item.mutator_dispatcher, + WrapCrossThreadPersistent(this))); + } + + DCHECK(global_scope_); + DCHECK(global_scope_->IsContextThread()); + + // At worklet scope termination break the reference cycle between + // AnimationWorkletGlobalScope and AnimationWorkletProxyClient. + global_scope_ = nullptr; + } + + mutator_items_.clear(); + + DCHECK(state_ != RunState::kDisposed); + state_ = RunState::kDisposed; +} + +std::unique_ptr<AnimationWorkletOutput> AnimationWorkletProxyClient::Mutate( + std::unique_ptr<AnimationWorkletInput> input) { + DCHECK(input); +#if DCHECK_IS_ON() + DCHECK(input->ValidateScope(scope_id_)) + << "Input has state that does not belong to this global scope: " + << scope_id_; +#endif + + if (!global_scope_) + return nullptr; + + auto output = global_scope_->Mutate(*input); + + // TODO(petermayo): https://crbug.com/791280 PostCrossThreadTask to supply + // this rather than return it. + return output; +} + +// static +AnimationWorkletProxyClient* AnimationWorkletProxyClient::FromDocument( + Document* document, + int scope_id) { + WebLocalFrameImpl* local_frame = + WebLocalFrameImpl::FromFrame(document->GetFrame()); + + scoped_refptr<base::SingleThreadTaskRunner> compositor_host_queue; + base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> + compositor_mutator_dispatcher = + local_frame->LocalRootFrameWidget() + ->EnsureCompositorMutatorDispatcher(&compositor_host_queue); + + scoped_refptr<base::SingleThreadTaskRunner> main_thread_host_queue; + base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> + main_thread_mutator_dispatcher = + document->GetWorkletAnimationController() + .EnsureMainThreadMutatorDispatcher(&main_thread_host_queue); + + return new AnimationWorkletProxyClient( + scope_id, std::move(compositor_mutator_dispatcher), + std::move(compositor_host_queue), + std::move(main_thread_mutator_dispatcher), + std::move(main_thread_host_queue)); +} + +AnimationWorkletProxyClient* AnimationWorkletProxyClient::From( + WorkerClients* clients) { + return Supplement<WorkerClients>::From<AnimationWorkletProxyClient>(clients); +} + +void ProvideAnimationWorkletProxyClientTo(WorkerClients* clients, + AnimationWorkletProxyClient* client) { + clients->ProvideSupplement(client); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h new file mode 100644 index 00000000000..6de77a34940 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h @@ -0,0 +1,85 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_ANIMATION_WORKLET_PROXY_CLIENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_ANIMATION_WORKLET_PROXY_CLIENT_H_ + +#include "base/macros.h" +#include "base/single_thread_task_runner.h" +#include "third_party/blink/renderer/core/workers/worker_clients.h" +#include "third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h" +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator.h" + +namespace blink { + +class AnimationWorkletMutatorDispatcherImpl; +class Document; +class WorkletGlobalScope; + +// Mediates between animation worklet global scope and its associated +// dispatchers. An AnimationWorkletProxyClient is associated with a single +// global scope and up to two dispatchers representing main and compositor +// threads. +// +// This is constructed on the main thread but it is used in the worklet backing +// thread. +class MODULES_EXPORT AnimationWorkletProxyClient + : public GarbageCollectedFinalized<AnimationWorkletProxyClient>, + public Supplement<WorkerClients>, + public AnimationWorkletMutator { + USING_GARBAGE_COLLECTED_MIXIN(AnimationWorkletProxyClient); + DISALLOW_COPY_AND_ASSIGN(AnimationWorkletProxyClient); + + public: + static const char kSupplementName[]; + + // This client is hooked to the given |mutatee|, on the given + // |mutatee_runner|. + explicit AnimationWorkletProxyClient( + int scope_id, + base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> compositor_mutatee, + scoped_refptr<base::SingleThreadTaskRunner> compositor_mutatee_runner, + base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> main_thread_mutatee, + scoped_refptr<base::SingleThreadTaskRunner> main_thread_mutatee_runner); + void Trace(blink::Visitor*) override; + + virtual void SetGlobalScope(WorkletGlobalScope*); + void Dispose(); + + // AnimationWorkletMutator: + // These methods are invoked on the animation worklet thread. + int GetScopeId() const override { return scope_id_; } + std::unique_ptr<AnimationWorkletOutput> Mutate( + std::unique_ptr<AnimationWorkletInput> input) override; + + static AnimationWorkletProxyClient* FromDocument(Document*, int scope_id); + static AnimationWorkletProxyClient* From(WorkerClients*); + + private: + const int scope_id_; + + struct MutatorItem { + base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> mutator_dispatcher; + scoped_refptr<base::SingleThreadTaskRunner> mutator_runner; + MutatorItem( + base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> mutator_dispatcher, + scoped_refptr<base::SingleThreadTaskRunner> mutator_runner) + : mutator_dispatcher(std::move(mutator_dispatcher)), + mutator_runner(std::move(mutator_runner)) {} + }; + WTF::Vector<MutatorItem> mutator_items_; + + CrossThreadPersistent<AnimationWorkletGlobalScope> global_scope_; + + enum RunState { kUninitialized, kWorking, kDisposed } state_; +}; + +void MODULES_EXPORT +ProvideAnimationWorkletProxyClientTo(WorkerClients*, + AnimationWorkletProxyClient*); + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_ANIMATION_WORKLET_PROXY_CLIENT_H_ diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.cc deleted file mode 100644 index 61db57bb25d..00000000000 --- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.cc +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.h" - -#include "third_party/blink/renderer/core/dom/document.h" -#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h" -#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" -#include "third_party/blink/renderer/core/workers/worker_thread.h" -#include "third_party/blink/renderer/platform/cross_thread_functional.h" -#include "third_party/blink/renderer/platform/graphics/compositor_mutator_impl.h" - -namespace blink { - -AnimationWorkletProxyClientImpl::AnimationWorkletProxyClientImpl( - int scope_id, - base::WeakPtr<CompositorMutatorImpl> mutator, - scoped_refptr<base::SingleThreadTaskRunner> mutator_runner) - : scope_id_(scope_id), - mutator_(std::move(mutator)), - mutator_runner_(std::move(mutator_runner)), - state_(RunState::kUninitialized) { - DCHECK(IsMainThread()); -} - -void AnimationWorkletProxyClientImpl::Trace(blink::Visitor* visitor) { - AnimationWorkletProxyClient::Trace(visitor); - CompositorAnimator::Trace(visitor); -} - -void AnimationWorkletProxyClientImpl::SetGlobalScope( - WorkletGlobalScope* global_scope) { - DCHECK(global_scope); - DCHECK(global_scope->IsContextThread()); - if (state_ == RunState::kDisposed) - return; - DCHECK(state_ == RunState::kUninitialized); - - global_scope_ = static_cast<AnimationWorkletGlobalScope*>(global_scope); - // TODO(majidvp): Add an AnimationWorklet task type when the spec is final. - scoped_refptr<base::SingleThreadTaskRunner> global_scope_runner = - global_scope_->GetThread()->GetTaskRunner(TaskType::kMiscPlatformAPI); - state_ = RunState::kWorking; - DCHECK(mutator_runner_); - PostCrossThreadTask( - *mutator_runner_, FROM_HERE, - CrossThreadBind(&CompositorMutatorImpl::RegisterCompositorAnimator, - mutator_, WrapCrossThreadPersistent(this), - global_scope_runner)); -} - -void AnimationWorkletProxyClientImpl::Dispose() { - if (state_ == RunState::kWorking) { - // At worklet scope termination break the reference to the Client from - // the compositor if it is still alive. - DCHECK(mutator_runner_); - PostCrossThreadTask( - *mutator_runner_, FROM_HERE, - CrossThreadBind(&CompositorMutatorImpl::UnregisterCompositorAnimator, - mutator_, WrapCrossThreadPersistent(this))); - - DCHECK(global_scope_); - DCHECK(global_scope_->IsContextThread()); - - // At worklet scope termination break the reference cycle between - // AnimationWorkletGlobalScope and AnimationWorkletProxyClientImpl. - global_scope_ = nullptr; - } - - mutator_runner_ = nullptr; - DCHECK(state_ != RunState::kDisposed); - state_ = RunState::kDisposed; -} - -std::unique_ptr<AnimationWorkletOutput> AnimationWorkletProxyClientImpl::Mutate( - std::unique_ptr<AnimationWorkletInput> input) { - DCHECK(input); -#if DCHECK_IS_ON() - DCHECK(input->ValidateScope(scope_id_)) - << "Input has state that does not belong to this global scope: " - << scope_id_; -#endif - - if (!global_scope_) - return nullptr; - - auto output = global_scope_->Mutate(*input); - - // TODO(petermayo): https://crbug.com/791280 PostCrossThreadTask to supply - // this rather than return it. - return output; -} - -// static -AnimationWorkletProxyClientImpl* AnimationWorkletProxyClientImpl::FromDocument( - Document* document, - int scope_id) { - WebLocalFrameImpl* local_frame = - WebLocalFrameImpl::FromFrame(document->GetFrame()); - scoped_refptr<base::SingleThreadTaskRunner> mutator_queue; - base::WeakPtr<CompositorMutatorImpl> mutator = - local_frame->LocalRootFrameWidget()->EnsureCompositorMutator( - &mutator_queue); - return new AnimationWorkletProxyClientImpl(scope_id, std::move(mutator), - std::move(mutator_queue)); -} - -} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.h b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.h deleted file mode 100644 index a63b30eb3ed..00000000000 --- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_ANIMATION_WORKLET_PROXY_CLIENT_IMPL_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_ANIMATION_WORKLET_PROXY_CLIENT_IMPL_H_ - -#include "base/single_thread_task_runner.h" -#include "third_party/blink/renderer/core/dom/animation_worklet_proxy_client.h" -#include "third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h" -#include "third_party/blink/renderer/modules/modules_export.h" -#include "third_party/blink/renderer/platform/graphics/compositor_animator.h" -#include "third_party/blink/renderer/platform/wtf/noncopyable.h" - -namespace blink { - -class CompositorMutatorImpl; -class Document; -class WorkletGlobalScope; - -// Mediates between one Animator and the associated CompositorMutatorImpl. There -// is one AnimationWorkletProxyClientImpl per Animator but there may be multiple -// for a given mutator and animatorWorklet. -// -// This is constructed on the main thread but it is used in the worklet backing -// thread. -class MODULES_EXPORT AnimationWorkletProxyClientImpl final - : public GarbageCollectedFinalized<AnimationWorkletProxyClientImpl>, - public AnimationWorkletProxyClient, - public CompositorAnimator { - WTF_MAKE_NONCOPYABLE(AnimationWorkletProxyClientImpl); - USING_GARBAGE_COLLECTED_MIXIN(AnimationWorkletProxyClientImpl); - - public: - // This client is hooked to the given |mutatee|, on the given - // |mutatee_runner|. - explicit AnimationWorkletProxyClientImpl( - int scope_id, - base::WeakPtr<CompositorMutatorImpl> mutatee, - scoped_refptr<base::SingleThreadTaskRunner> mutatee_runner); - void Trace(blink::Visitor*) override; - - // AnimationWorkletProxyClient: - void SetGlobalScope(WorkletGlobalScope*) override; - void Dispose() override; - - // CompositorAnimator: - // These methods are invoked on the animation worklet thread. - int GetScopeId() const override { return scope_id_; } - std::unique_ptr<AnimationWorkletOutput> Mutate( - std::unique_ptr<AnimationWorkletInput> input) override; - - static AnimationWorkletProxyClientImpl* FromDocument(Document*, int scope_id); - - private: - const int scope_id_; - base::WeakPtr<CompositorMutatorImpl> mutator_; - scoped_refptr<base::SingleThreadTaskRunner> mutator_runner_; - - CrossThreadPersistent<AnimationWorkletGlobalScope> global_scope_; - - enum RunState { kUninitialized, kWorking, kDisposed } state_; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_ANIMATION_WORKLET_PROXY_CLIENT_IMPL_H_ diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.cc index cd9d5f2ce83..6f0476646ec 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.cc +++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.cc @@ -31,12 +31,6 @@ AnimationWorkletThread::AnimationWorkletThread( AnimationWorkletThread::~AnimationWorkletThread() = default; -WebThread* AnimationWorkletThread::GetSharedBackingThread() { - auto* instance = WorkletThreadHolder<AnimationWorkletThread>::GetInstance(); - DCHECK(instance); - return &(instance->GetThread()->BackingThread().PlatformThread()); -} - WorkerBackingThread& AnimationWorkletThread::GetWorkerBackingThread() { return *WorkletThreadHolder<AnimationWorkletThread>::GetInstance() ->GetThread(); @@ -61,24 +55,18 @@ void AnimationWorkletThread::CollectAllGarbage() { void AnimationWorkletThread::EnsureSharedBackingThread() { WorkletThreadHolder<AnimationWorkletThread>::EnsureInstance( - WebThreadCreationParams(WebThreadType::kAnimationWorkletThread)); + ThreadCreationParams(WebThreadType::kAnimationWorkletThread)); } void AnimationWorkletThread::ClearSharedBackingThread() { WorkletThreadHolder<AnimationWorkletThread>::ClearInstance(); } -void AnimationWorkletThread::CreateSharedBackingThreadForTest() { - WorkletThreadHolder<AnimationWorkletThread>::CreateForTest( - WebThreadCreationParams(WebThreadType::kAnimationWorkletThread)); -} - WorkerOrWorkletGlobalScope* AnimationWorkletThread::CreateWorkerGlobalScope( std::unique_ptr<GlobalScopeCreationParams> creation_params) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("animation-worklet"), "AnimationWorkletThread::CreateWorkerGlobalScope"); - return AnimationWorkletGlobalScope::Create(std::move(creation_params), - GetIsolate(), this); + return AnimationWorkletGlobalScope::Create(std::move(creation_params), this); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.h b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.h index 78fe953d9de..622a77127cf 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.h +++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.h @@ -32,13 +32,6 @@ class MODULES_EXPORT AnimationWorkletThread final : public WorkerThread { static void EnsureSharedBackingThread(); static void ClearSharedBackingThread(); - static void CreateSharedBackingThreadForTest(); - - // This only can be called after EnsureSharedBackingThread() is performed. - // Currently AnimationWorkletThread owns only one thread and it is shared - // by all the customers. - static WebThread* GetSharedBackingThread(); - private: explicit AnimationWorkletThread(WorkerReportingProxy&); diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread_test.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread_test.cc index c1b6d4aa1ec..e7462ff02ac 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread_test.cc +++ b/chromium/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread_test.cc @@ -13,7 +13,6 @@ #include "third_party/blink/renderer/bindings/core/v8/source_location.h" #include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h" #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h" -#include "third_party/blink/renderer/core/dom/animation_worklet_proxy_client.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h" #include "third_party/blink/renderer/core/script/script.h" @@ -25,10 +24,10 @@ #include "third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h" #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h" #include "third_party/blink/renderer/core/workers/worklet_module_responses_map.h" +#include "third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h" #include "third_party/blink/renderer/platform/cross_thread_functional.h" #include "third_party/blink/renderer/platform/loader/fetch/access_control_status.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h" -#include "third_party/blink/renderer/platform/testing/testing_platform_support.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" #include "third_party/blink/renderer/platform/waitable_event.h" #include "third_party/blink/renderer/platform/web_thread_supporting_gc.h" @@ -37,26 +36,11 @@ namespace blink { namespace { -class AnimationWorkletTestPlatform : public TestingPlatformSupport { +class TestAnimationWorkletProxyClient : public AnimationWorkletProxyClient { public: - // Need to override the thread creating support so we can actually run - // Animation Worklet code that would go on a backing thread in non-test - // code. i.e. most tests remove the extra threads, but we need this one. - std::unique_ptr<WebThread> CreateThread( - const blink::WebThreadCreationParams& params) override { - return old_platform_->CreateThread(params); - } -}; - -class TestAnimationWorkletProxyClient - : public GarbageCollected<TestAnimationWorkletProxyClient>, - public AnimationWorkletProxyClient { - USING_GARBAGE_COLLECTED_MIXIN(TestAnimationWorkletProxyClient); - - public: - TestAnimationWorkletProxyClient() = default; + TestAnimationWorkletProxyClient() + : AnimationWorkletProxyClient(0, nullptr, nullptr, nullptr, nullptr){}; void SetGlobalScope(WorkletGlobalScope*) override {} - void Dispose() override {} }; } // namespace @@ -64,7 +48,7 @@ class TestAnimationWorkletProxyClient class AnimationWorkletThreadTest : public PageTestBase { public: void SetUp() override { - AnimationWorkletThread::CreateSharedBackingThreadForTest(); + AnimationWorkletThread::EnsureSharedBackingThread(); PageTestBase::SetUp(IntSize()); Document* document = &GetDocument(); document->SetURL(KURL("https://example.com/")); @@ -131,7 +115,6 @@ class AnimationWorkletThreadTest : public PageTestBase { } std::unique_ptr<WorkerReportingProxy> reporting_proxy_; - ScopedTestingPlatformSupport<AnimationWorkletTestPlatform> platform_; }; TEST_F(AnimationWorkletThreadTest, Basic) { diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animator.cc b/chromium/third_party/blink/renderer/modules/animationworklet/animator.cc index 01716224d8d..5faecda350b 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/animator.cc +++ b/chromium/third_party/blink/renderer/modules/animationworklet/animator.cc @@ -15,7 +15,7 @@ namespace blink { Animator::Animator(v8::Isolate* isolate, AnimatorDefinition* definition, - v8::Local<v8::Object> instance) + v8::Local<v8::Value> instance) : definition_(definition), instance_(isolate, instance), effect_(new EffectProxy()) {} @@ -25,15 +25,16 @@ Animator::~Animator() = default; void Animator::Trace(blink::Visitor* visitor) { visitor->Trace(definition_); visitor->Trace(effect_); - visitor->Trace(instance_.Cast<v8::Value>()); + visitor->Trace(instance_); } -bool Animator::Animate(ScriptState* script_state, - double current_time, - CompositorMutatorOutputState::AnimationState* output) { +bool Animator::Animate( + ScriptState* script_state, + double current_time, + AnimationWorkletDispatcherOutput::AnimationState* output) { v8::Isolate* isolate = script_state->GetIsolate(); - v8::Local<v8::Object> instance = instance_.NewLocal(isolate); + v8::Local<v8::Value> instance = instance_.NewLocal(isolate); v8::Local<v8::Function> animate = definition_->AnimateLocal(isolate); if (IsUndefinedOrNull(instance) || IsUndefinedOrNull(animate)) diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/animator.h b/chromium/third_party/blink/renderer/modules/animationworklet/animator.h index d4b302429e5..c37bf14d182 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/animator.h +++ b/chromium/third_party/blink/renderer/modules/animationworklet/animator.h @@ -9,7 +9,7 @@ #include "third_party/blink/renderer/platform/bindings/name_client.h" #include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h" #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h" -#include "third_party/blink/renderer/platform/graphics/compositor_animators_state.h" +#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutators_state.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/wtf/time.h" #include "v8/include/v8.h" @@ -25,7 +25,7 @@ class ScriptState; class Animator final : public GarbageCollectedFinalized<Animator>, public NameClient { public: - Animator(v8::Isolate*, AnimatorDefinition*, v8::Local<v8::Object> instance); + Animator(v8::Isolate*, AnimatorDefinition*, v8::Local<v8::Value> instance); ~Animator(); void Trace(blink::Visitor*); const char* NameInHeapSnapshot() const override { return "Animator"; } @@ -35,13 +35,16 @@ class Animator final : public GarbageCollectedFinalized<Animator>, // the output state with new updates. bool Animate(ScriptState*, double current_time, - CompositorMutatorOutputState::AnimationState*); + AnimationWorkletDispatcherOutput::AnimationState*); + base::Optional<TimeDelta> GetLastLocalTime() const { + return effect_->local_time(); + } private: // This object keeps the definition object, and animator instance alive. // It participates in wrapper tracing as it holds onto V8 wrappers. TraceWrapperMember<AnimatorDefinition> definition_; - TraceWrapperV8Reference<v8::Object> instance_; + TraceWrapperV8Reference<v8::Value> instance_; Member<EffectProxy> effect_; }; diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc index c9789998870..0ce6e7feb26 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc +++ b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc @@ -57,13 +57,6 @@ bool ConvertAnimationEffects( return false; } - if (keyframe_effects.size() > 1) { - // TODO(yigu): We should allow group effects eventually by spec. See - // crbug.com/767043. - error_string = "Multiple effects are not currently supported"; - return false; - } - // TODO(crbug.com/781816): Allow using effects with no target. for (const auto& effect : keyframe_effects) { if (!effect->target()) { @@ -82,6 +75,21 @@ bool ConvertAnimationEffects( return true; } +bool IsActive(const Animation::AnimationPlayState& state) { + switch (state) { + case Animation::kIdle: + case Animation::kPending: + return false; + case Animation::kRunning: + case Animation::kPaused: + return true; + default: + // kUnset and kFinished are not used in WorkletAnimation. + NOTREACHED(); + return false; + } +} + bool ValidateTimeline(const DocumentTimelineOrScrollTimeline& timeline, String& error_string) { if (timeline.IsScrollTimeline()) { @@ -140,6 +148,10 @@ CompositorScrollTimeline::ScrollDirection ConvertOrientation( case ScrollTimeline::Inline: return is_horizontal_writing_mode ? CompositorScrollTimeline::Horizontal : CompositorScrollTimeline::Vertical; + case ScrollTimeline::Horizontal: + return CompositorScrollTimeline::Horizontal; + case ScrollTimeline::Vertical: + return CompositorScrollTimeline::Vertical; default: NOTREACHED(); return CompositorScrollTimeline::Vertical; @@ -227,13 +239,6 @@ WorkletAnimation* WorkletAnimation::Create( ExceptionState& exception_state) { DCHECK(IsMainThread()); - if (!Platform::Current()->IsThreadedAnimationEnabled()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kInvalidStateError, - "AnimationWorklet requires threaded animations to be enabled"); - return nullptr; - } - HeapVector<Member<KeyframeEffect>> keyframe_effects; String error_string; if (!ConvertAnimationEffects(effects, keyframe_effects, error_string)) { @@ -275,16 +280,18 @@ WorkletAnimation::WorkletAnimation( id_(id), animator_name_(animator_name), play_state_(Animation::kIdle), + last_play_state_(play_state_), document_(document), effects_(effects), timeline_(timeline), options_(std::make_unique<WorkletAnimationOptions>(options)), effect_needs_restart_(false) { DCHECK(IsMainThread()); - DCHECK(Platform::Current()->IsThreadedAnimationEnabled()); - AnimationEffect* target_effect = effects_.at(0); - target_effect->Attach(this); + for (auto& effect : effects_) { + AnimationEffect* target_effect = effect; + target_effect->Attach(this); + } if (timeline_->IsScrollTimeline()) ToScrollTimeline(timeline_)->AttachAnimation(); @@ -295,20 +302,29 @@ String WorkletAnimation::playState() { return Animation::PlayStateString(play_state_); } -void WorkletAnimation::play() { +void WorkletAnimation::play(ExceptionState& exception_state) { DCHECK(IsMainThread()); if (play_state_ == Animation::kPending) return; - document_->GetWorkletAnimationController().AttachAnimation(*this); - play_state_ = Animation::kPending; - Element* target = GetEffect()->target(); - if (!target) + String failure_message; + if (!CheckCanStart(&failure_message)) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + failure_message); return; - target->EnsureElementAnimations().GetWorkletAnimations().insert(this); - // TODO(majidvp): This should be removed once worklet animation correctly - // updates its effect timing. https://crbug.com/814851. - target->SetNeedsAnimationStyleRecalc(); + } + + document_->GetWorkletAnimationController().AttachAnimation(*this); + SetPlayState(Animation::kPending); + + for (auto& effect : effects_) { + Element* target = effect->target(); + DCHECK(target); + target->EnsureElementAnimations().GetWorkletAnimations().insert(this); + // TODO(majidvp): This should be removed once worklet animation correctly + // updates its effect timing. https://crbug.com/814851. + target->SetNeedsAnimationStyleRecalc(); + } } void WorkletAnimation::cancel() { @@ -322,15 +338,27 @@ void WorkletAnimation::cancel() { DestroyCompositorAnimation(); } - play_state_ = Animation::kIdle; - - Element* target = GetEffect()->target(); - if (!target) - return; - target->EnsureElementAnimations().GetWorkletAnimations().erase(this); - // TODO(majidvp): This should be removed once worklet animation correctly - // updates its effect timing. https://crbug.com/814851. - target->SetNeedsAnimationStyleRecalc(); + local_time_ = base::nullopt; + start_time_ = base::nullopt; + running_on_main_thread_ = false; + // TODO(yigu): Because this animation has been detached and will not receive + // updates anymore, we have to update its value upon cancel. Similar to + // regular animations, we should not detach them immediately and update the + // value in the next frame. See https://crbug.com/883312. + if (IsActive(play_state_)) { + for (auto& effect : effects_) + effect->UpdateInheritedTime(NullValue(), kTimingUpdateOnDemand); + } + SetPlayState(Animation::kIdle); + + for (auto& effect : effects_) { + Element* target = effect->target(); + DCHECK(target); + target->EnsureElementAnimations().GetWorkletAnimations().erase(this); + // TODO(majidvp): This should be removed once worklet animation correctly + // updates its effect timing. https://crbug.com/814851. + target->SetNeedsAnimationStyleRecalc(); + } } bool WorkletAnimation::Playing() const { @@ -344,8 +372,7 @@ void WorkletAnimation::UpdateIfNecessary() { } void WorkletAnimation::EffectInvalidated() { - effect_needs_restart_ = true; - document_->GetWorkletAnimationController().InvalidateAnimation(*this); + InvalidateCompositingState(); } void WorkletAnimation::Update(TimingUpdateReason reason) { @@ -355,40 +382,92 @@ void WorkletAnimation::Update(TimingUpdateReason reason) { if (!start_time_) return; - // TODO(crbug.com/756359): For now we use 0 as inherited time in but we will - // need to get the inherited time from worklet context. + // TODO(crbug.com/756539): For now we use 0 as inherited time for compositor + // worklet animations. Will need to get the inherited time from worklet + // context. double inherited_time_seconds = 0; - GetEffect()->UpdateInheritedTime(inherited_time_seconds, reason); + + if (local_time_) + inherited_time_seconds = local_time_->InSecondsF(); + + for (auto& effect : effects_) + effect->UpdateInheritedTime(inherited_time_seconds, reason); } -bool WorkletAnimation::UpdateCompositingState() { - switch (play_state_) { - case Animation::kPending: { - String failure_message; - if (StartOnCompositor(&failure_message)) - return true; - document_->AddConsoleMessage(ConsoleMessage::Create( - kOtherMessageSource, kWarningMessageLevel, failure_message)); - return false; +bool WorkletAnimation::CheckCanStart(String* failure_message) { + DCHECK(IsMainThread()); + + for (auto& effect : effects_) { + if (effect->Model()->HasFrames()) + continue; + *failure_message = "Animation effect has no keyframes"; + return false; + } + + return true; +} + +void WorkletAnimation::SetStartTimeToNow() { + DCHECK(!start_time_); + bool is_null; + double time = timeline_->currentTime(is_null); + if (!is_null) + start_time_ = base::TimeDelta::FromSecondsD(time); +} + +void WorkletAnimation::UpdateCompositingState() { + DCHECK(play_state_ != Animation::kIdle && play_state_ != Animation::kUnset); + + if (play_state_ == Animation::kPending) { + String warning_message; + DCHECK(CheckCanStart(&warning_message)); + DCHECK(warning_message.IsEmpty()); + if (StartOnCompositor(&warning_message)) { + return; } - case Animation::kRunning: { + String message = "The animation cannot be accelerated. Reason: "; + message = message + warning_message; + document_->AddConsoleMessage(ConsoleMessage::Create( + kOtherMessageSource, kWarningMessageLevel, message)); + StartOnMain(); + } else if (play_state_ == Animation::kRunning) { + // TODO(majidvp): If keyframes have changed then it may be possible to now + // run the animation on compositor. The current logic does not allow this + // switch from main to compositor to happen. + if (!running_on_main_thread_) UpdateOnCompositor(); - return false; - } - default: - return false; } + DCHECK(running_on_main_thread_ != !!compositor_animation_) + << "Active worklet animation should either run on main or compositor"; +} + +void WorkletAnimation::InvalidateCompositingState() { + effect_needs_restart_ = true; + document_->GetWorkletAnimationController().InvalidateAnimation(*this); +} + +void WorkletAnimation::StartOnMain() { + running_on_main_thread_ = true; + SetStartTimeToNow(); + SetPlayState(Animation::kRunning); } bool WorkletAnimation::StartOnCompositor(String* failure_message) { DCHECK(IsMainThread()); + if (effects_.size() > 1) { + // Compositor doesn't support multiple effects but they can be run via main. + *failure_message = + "Multiple effects with composited properties are not currently " + "supported on compositor"; + return false; + } + Element& target = *GetEffect()->target(); // TODO(crbug.com/836393): This should not be possible but it is currently // happening and needs to be investigated/fixed. if (!target.GetComputedStyle()) { - if (failure_message) - *failure_message = "The target element does not have style."; + *failure_message = "The target element does not have style"; return false; } // CheckCanStartAnimationOnCompositor requires that the property-specific @@ -398,21 +477,19 @@ bool WorkletAnimation::StartOnCompositor(String* failure_message) { GetEffect()->Model()->SnapshotAllCompositorKeyframesIfNecessary( target, target.ComputedStyleRef(), target.ParentComputedStyle()); - if (!CheckElementComposited(target)) { - if (failure_message) - *failure_message = "The target element is not composited."; - return false; - } - double playback_rate = 1; CompositorAnimations::FailureCode failure_code = GetEffect()->CheckCanStartAnimationOnCompositor( base::Optional<CompositorElementIdSet>(), playback_rate); if (!failure_code.Ok()) { - play_state_ = Animation::kIdle; - if (failure_message) - *failure_message = failure_code.reason; + SetPlayState(Animation::kIdle); + *failure_message = failure_code.reason; + return false; + } + + if (!CheckElementComposited(target)) { + *failure_message = "The target element is not composited"; return false; } @@ -434,12 +511,12 @@ bool WorkletAnimation::StartOnCompositor(String* failure_message) { // TODO(smcgruer): We need to start all of the effects, not just the first. StartEffectOnCompositor(compositor_animation_.get(), GetEffect()); - play_state_ = Animation::kRunning; + SetPlayState(Animation::kRunning); bool is_null; double time = timeline_->currentTime(is_null); if (!is_null) - start_time_ = time; + start_time_ = base::TimeDelta::FromSecondsD(time); return true; } @@ -480,6 +557,50 @@ KeyframeEffect* WorkletAnimation::GetEffect() const { return effects_.at(0); } +bool WorkletAnimation::IsActiveAnimation() const { + return IsActive(play_state_); +} + +void WorkletAnimation::UpdateInputState( + AnimationWorkletDispatcherInput* input_state) { + if (!running_on_main_thread_) { + input_state->Peek(id_); + return; + } + + bool was_active = IsActive(last_play_state_); + bool is_active = IsActive(play_state_); + + DCHECK(start_time_); + DCHECK(last_current_time_ || !was_active); + bool is_null; + double current_time = timeline_->currentTime(is_null); + + bool did_time_change = + !last_current_time_ || current_time != last_current_time_->InSecondsF(); + last_current_time_ = base::TimeDelta::FromSecondsD(current_time); + + if (!was_active && is_active) { + input_state->Add( + {id_, + std::string(animator_name_.Ascii().data(), animator_name_.length()), + current_time, CloneOptions()}); + } else if (was_active && is_active) { + // Skip if the input time is not changed. + if (did_time_change) + input_state->Update({id_, current_time}); + } else if (was_active && !is_active) { + input_state->Remove(id_); + } + last_play_state_ = play_state_; +} + +void WorkletAnimation::SetOutputState( + const AnimationWorkletOutput::AnimationState& state) { + DCHECK(state.worklet_animation_id == id_); + local_time_ = state.local_time; +} + void WorkletAnimation::Dispose() { DCHECK(IsMainThread()); if (timeline_->IsScrollTimeline()) diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h index c9977fd5a38..c8c6d5a22da 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h +++ b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.h @@ -16,7 +16,7 @@ #include "third_party/blink/renderer/platform/animation/compositor_animation.h" #include "third_party/blink/renderer/platform/animation/compositor_animation_client.h" #include "third_party/blink/renderer/platform/animation/compositor_animation_delegate.h" -#include "third_party/blink/renderer/platform/graphics/compositor_animators_state.h" +#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutators_state.h" namespace blink { @@ -66,7 +66,7 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase, AnimationTimeline* timeline() { return timeline_; } String playState(); - void play(); + void play(ExceptionState& exception_state); void cancel(); // AnimationEffectOwner implementation: @@ -87,7 +87,8 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase, // WorkletAnimationBase implementation. void Update(TimingUpdateReason) override; - bool UpdateCompositingState() override; + void UpdateCompositingState() override; + void InvalidateCompositingState() override; // CompositorAnimationClient implementation. CompositorAnimation* GetCompositorAnimation() const override { @@ -106,6 +107,14 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase, const String& Name() { return animator_name_; } KeyframeEffect* GetEffect() const override; + const WorkletAnimationId& GetWorkletAnimationId() const override { + return id_; + } + bool IsActiveAnimation() const override; + + void UpdateInputState(AnimationWorkletDispatcherInput* input_state) override; + void SetOutputState( + const AnimationWorkletOutput::AnimationState& state) override; void Trace(blink::Visitor*) override; @@ -119,21 +128,38 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase, void DestroyCompositorAnimation(); // Attempts to start the animation on the compositor side, returning true if - // it succeeds or false otherwise. If false is returned and failure_message - // was non-null, failure_message may be filled with an error description. + // it succeeds or false otherwise. If false is returned and the animation + // cannot be started on main and failure_message was non-null, failure_message + // may be filled with an error description. bool StartOnCompositor(String* failure_message); + void StartOnMain(); + bool CheckCanStart(String* failure_message); + void SetStartTimeToNow(); // Updates a running animation on the compositor side. void UpdateOnCompositor(); + std::unique_ptr<cc::AnimationOptions> CloneOptions() const { + return options_ ? options_->Clone() : nullptr; + } + + void SetPlayState(const Animation::AnimationPlayState& state) { + play_state_ = state; + } + unsigned sequence_number_; WorkletAnimationId id_; const String animator_name_; Animation::AnimationPlayState play_state_; + Animation::AnimationPlayState last_play_state_; // Start time in ms. - base::Optional<double> start_time_; + base::Optional<base::TimeDelta> start_time_; + base::Optional<base::TimeDelta> local_time_; + // We use this to skip updating if current time has not changed since last + // update. + base::Optional<base::TimeDelta> last_current_time_; Member<Document> document_; @@ -142,6 +168,7 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase, std::unique_ptr<WorkletAnimationOptions> options_; std::unique_ptr<CompositorAnimation> compositor_animation_; + bool running_on_main_thread_; // Tracks whether any KeyframeEffect associated with this WorkletAnimation has // been invalidated and needs to be restarted. Used to avoid unnecessarily diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.idl b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.idl index 675fec20c1f..0f7a4feb633 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.idl +++ b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation.idl @@ -18,6 +18,6 @@ ] interface WorkletAnimation { readonly attribute AnimationTimeline? timeline; readonly attribute AnimationPlayState playState; - void play(); + [RaisesException] void play(); void cancel(); }; diff --git a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc index ca3880c3278..225c0807761 100644 --- a/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc +++ b/chromium/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc @@ -35,7 +35,7 @@ KeyframeEffectModelBase* CreateEffectModel() { KeyframeEffect* CreateKeyframeEffect(Element* element) { Timing timing; - timing.iteration_duration = 30; + timing.iteration_duration = AnimationTimeDelta::FromSecondsD(30); return KeyframeEffect::Create(element, CreateEffectModel(), timing); } @@ -76,7 +76,8 @@ class WorkletAnimationTest : public RenderingTest { }; TEST_F(WorkletAnimationTest, WorkletAnimationInElementAnimations) { - worklet_animation_->play(); + DummyExceptionStateForTesting exception_state; + worklet_animation_->play(exception_state); EXPECT_EQ(1u, element_->EnsureElementAnimations().GetWorkletAnimations().size()); worklet_animation_->cancel(); @@ -88,7 +89,8 @@ TEST_F(WorkletAnimationTest, StyleHasCurrentAnimation) { scoped_refptr<ComputedStyle> style = GetDocument().EnsureStyleResolver().StyleForElement(element_).get(); EXPECT_EQ(false, style->HasCurrentOpacityAnimation()); - worklet_animation_->play(); + DummyExceptionStateForTesting exception_state; + worklet_animation_->play(exception_state); element_->EnsureElementAnimations().UpdateAnimationFlags(*style); EXPECT_EQ(true, style->HasCurrentOpacityAnimation()); } diff --git a/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.cc b/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.cc index 333d7bc3947..bd1c1a095ed 100644 --- a/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.cc +++ b/chromium/third_party/blink/renderer/modules/app_banner/before_install_prompt_event.cc @@ -80,10 +80,10 @@ ScriptPromise BeforeInstallPromptEvent::prompt(ScriptState* script_state) { } ExecutionContext* context = ExecutionContext::From(script_state); - Document* doc = ToDocumentOrNull(context); + Document* doc = To<Document>(context); - if (require_gesture_ && - !Frame::ConsumeTransientUserActivation(doc ? doc->GetFrame() : nullptr)) { + if (require_gesture_ && !LocalFrame::ConsumeTransientUserActivation( + doc ? doc->GetFrame() : nullptr)) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create( diff --git a/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client.cc b/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client.cc index fa18d821a0f..fde89244bde 100644 --- a/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client.cc +++ b/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client.cc @@ -16,17 +16,12 @@ AudioOutputDeviceClient::AudioOutputDeviceClient(LocalFrame& frame) const char AudioOutputDeviceClient::kSupplementName[] = "AudioOutputDeviceClient"; -AudioOutputDeviceClient* AudioOutputDeviceClient::From( - ExecutionContext* context) { - if (!context || !context->IsDocument()) - return nullptr; - - const Document* document = ToDocument(context); - if (!document->GetFrame()) +AudioOutputDeviceClient* AudioOutputDeviceClient::From(Document& document) { + if (!document.GetFrame()) return nullptr; return Supplement<LocalFrame>::From<AudioOutputDeviceClient>( - document->GetFrame()); + document.GetFrame()); } void ProvideAudioOutputDeviceClientTo(LocalFrame& frame, diff --git a/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client.h b/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client.h index 3ed14c55ee8..ac712d54519 100644 --- a/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client.h +++ b/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client.h @@ -13,7 +13,7 @@ namespace blink { -class ExecutionContext; +class Document; class WebString; class MODULES_EXPORT AudioOutputDeviceClient : public Supplement<LocalFrame> { @@ -26,14 +26,14 @@ class MODULES_EXPORT AudioOutputDeviceClient : public Supplement<LocalFrame> { // Checks that a given sink exists and has permissions to be used from the // origin of the current frame. virtual void CheckIfAudioSinkExistsAndIsAuthorized( - ExecutionContext*, + Document&, const WebString& sink_id, std::unique_ptr<WebSetSinkIdCallbacks>) = 0; void Trace(blink::Visitor*) override; // Supplement requirements. - static AudioOutputDeviceClient* From(ExecutionContext*); + static AudioOutputDeviceClient* From(Document&); }; MODULES_EXPORT void ProvideAudioOutputDeviceClientTo(LocalFrame&, diff --git a/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client_impl.cc b/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client_impl.cc index 7eb90d424ed..26012a3ae68 100644 --- a/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client_impl.cc +++ b/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client_impl.cc @@ -18,14 +18,11 @@ AudioOutputDeviceClientImpl::AudioOutputDeviceClientImpl(LocalFrame& frame) AudioOutputDeviceClientImpl::~AudioOutputDeviceClientImpl() = default; void AudioOutputDeviceClientImpl::CheckIfAudioSinkExistsAndIsAuthorized( - ExecutionContext* context, + Document& document, const WebString& sink_id, std::unique_ptr<WebSetSinkIdCallbacks> callbacks) { - DCHECK(context); - DCHECK(context->IsDocument()); - Document* document = ToDocument(context); WebLocalFrameImpl* web_frame = - WebLocalFrameImpl::FromFrame(document->GetFrame()); + WebLocalFrameImpl::FromFrame(document.GetFrame()); web_frame->Client()->CheckIfAudioSinkExistsAndIsAuthorized( sink_id, callbacks.release()); } diff --git a/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client_impl.h b/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client_impl.h index a99b5f60738..6d42f29402d 100644 --- a/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client_impl.h +++ b/chromium/third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client_impl.h @@ -25,7 +25,7 @@ class MODULES_EXPORT AudioOutputDeviceClientImpl // AudioOutputDeviceClient implementation. void CheckIfAudioSinkExistsAndIsAuthorized( - ExecutionContext*, + Document&, const WebString& sink_id, std::unique_ptr<WebSetSinkIdCallbacks>) override; diff --git a/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc b/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc index d14d53257ee..76e72a8ea2c 100644 --- a/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc +++ b/chromium/third_party/blink/renderer/modules/audio_output_devices/html_media_element_audio_output_device.cc @@ -9,6 +9,7 @@ #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" +#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/modules/audio_output_devices/audio_output_device_client.h" @@ -67,8 +68,6 @@ void SetSinkIdResolver::StartAsync() { void SetSinkIdResolver::TimerFired(TimerBase* timer) { ExecutionContext* context = GetExecutionContext(); - DCHECK(context); - DCHECK(context->IsDocument()); std::unique_ptr<SetSinkIdCallbacks> callbacks = std::make_unique<SetSinkIdCallbacks>(this, *element_, sink_id_); WebMediaPlayer* web_media_player = element_->GetWebMediaPlayer(); @@ -78,9 +77,10 @@ void SetSinkIdResolver::TimerFired(TimerBase* timer) { web_media_player->SetSinkId(sink_id_, callbacks.release()); } else { + auto& document = *To<Document>(context); if (AudioOutputDeviceClient* client = - AudioOutputDeviceClient::From(context)) { - client->CheckIfAudioSinkExistsAndIsAuthorized(context, sink_id_, + AudioOutputDeviceClient::From(document)) { + client->CheckIfAudioSinkExistsAndIsAuthorized(document, sink_id_, std::move(callbacks)); } else { // The context has been detached. Impossible to get a security origin to diff --git a/chromium/third_party/blink/renderer/modules/audio_output_devices/set_sink_id_callbacks.h b/chromium/third_party/blink/renderer/modules/audio_output_devices/set_sink_id_callbacks.h index 3bf22ca4c8e..acb45844512 100644 --- a/chromium/third_party/blink/renderer/modules/audio_output_devices/set_sink_id_callbacks.h +++ b/chromium/third_party/blink/renderer/modules/audio_output_devices/set_sink_id_callbacks.h @@ -7,7 +7,7 @@ #include "base/memory/scoped_refptr.h" #include "third_party/blink/public/platform/web_set_sink_id_callbacks.h" -#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/timer.h" #include "third_party/blink/renderer/platform/wtf/noncopyable.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc index e5bc03686bc..022104ceead 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc @@ -64,10 +64,11 @@ void BackgroundFetchBridge::Fetch( Vector<WebServiceWorkerRequest> requests, mojom::blink::BackgroundFetchOptionsPtr options, const SkBitmap& icon, + mojom::blink::BackgroundFetchUkmDataPtr ukm_data, RegistrationCallback callback) { GetService()->Fetch( GetSupplementable()->WebRegistration()->RegistrationId(), developer_id, - std::move(requests), std::move(options), icon, + std::move(requests), std::move(options), icon, std::move(ukm_data), WTF::Bind(&BackgroundFetchBridge::DidGetRegistration, WrapPersistent(this), WTF::Passed(std::move(callback)))); } @@ -112,7 +113,7 @@ void BackgroundFetchBridge::DidGetRegistration( if (registration) { DCHECK_EQ(error, mojom::blink::BackgroundFetchError::NONE); - DCHECK_EQ(registration->state(), "pending"); + DCHECK_EQ(registration->result(), ""); registration->Initialize(GetSupplementable()); } diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h index b6dba87ebab..f295ce6d1c7 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h @@ -54,6 +54,7 @@ class BackgroundFetchBridge final Vector<WebServiceWorkerRequest> requests, mojom::blink::BackgroundFetchOptionsPtr options, const SkBitmap& icon, + mojom::blink::BackgroundFetchUkmDataPtr ukm_data, RegistrationCallback callback); // Gets the size of the icon to be displayed in Background Fetch UI. @@ -62,7 +63,7 @@ class BackgroundFetchBridge final // Matches completed requests for the fetch associated with the |developer_id| // and |unique_id| and returns the {request, response} pairs based on the rest // of the arguments. If |filter_by_request| is true, only response(s) for - // |request_to_match| are returned. |cache_query_params| are options for the + // |request_to_match| are returned. |cache_query_params|s are options for the // query to the cache storage. |match_all|, when true, returns all responses // from the result set, and when false, returns only the first one. void MatchRequests( diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_event.idl b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_event.idl index e4c633e4e3c..65c470ad54e 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_event.idl +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_event.idl @@ -7,7 +7,7 @@ [ Constructor(DOMString type, BackgroundFetchEventInit init), Exposed=ServiceWorker, - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchEvent : ExtendableEvent { readonly attribute BackgroundFetchRegistration registration; }; diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.idl b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.idl index c87e1568886..df03e494252 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.idl +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.idl @@ -6,7 +6,7 @@ [ Exposed=(Window,Worker), - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchFetch { readonly attribute Request request; }; diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.cc index 419441d0ecb..813131fc695 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.cc +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.cc @@ -71,14 +71,16 @@ void BackgroundFetchIconLoader::DidGetIconDisplaySizeIfSoLoadIcon( // If |icon_display_size_pixels_| is empty then no image will be displayed by // the UI powering Background Fetch. Bail out immediately. if (icon_display_size_pixels_.IsEmpty()) { - std::move(icon_callback).Run(SkBitmap()); + std::move(icon_callback) + .Run(SkBitmap(), -1 /* ideal_to_chosen_icon_size_times_hundred */); return; } KURL best_icon_url = PickBestIconForDisplay(execution_context); if (best_icon_url.IsEmpty()) { // None of the icons provided was suitable. - std::move(icon_callback).Run(SkBitmap()); + std::move(icon_callback) + .Run(SkBitmap(), -1 /* ideal_to_chosen_icon_size_times_hundred */); return; } @@ -89,9 +91,14 @@ void BackgroundFetchIconLoader::DidGetIconDisplaySizeIfSoLoadIcon( resource_loader_options.request_initiator_context = kWorkerContext; ResourceRequest resource_request(best_icon_url); - resource_request.SetRequestContext(WebURLRequest::kRequestContextImage); + resource_request.SetRequestContext(mojom::RequestContextType::IMAGE); resource_request.SetPriority(ResourceLoadPriority::kMedium); - resource_request.SetRequestorOrigin(execution_context->GetSecurityOrigin()); + resource_request.SetKeepalive(true); + resource_request.SetFetchRequestMode( + network::mojom::FetchRequestMode::kNoCORS); + resource_request.SetFetchCredentialsMode( + network::mojom::FetchCredentialsMode::kInclude); + resource_request.SetSkipServiceWorker(true); threadable_loader_ = new ThreadableLoader(*execution_context, this, resource_loader_options); @@ -107,10 +114,18 @@ KURL BackgroundFetchIconLoader::PickBestIconForDisplay( // Update the src of |icon| to include the base URL in case relative paths // were used. icon.setSrc(execution_context->CompleteURL(icon.src())); - icons.emplace_back(blink::ConvertManifestImageResource(icon)); + Manifest::ImageResource candidate_icon = + blink::ConvertManifestImageResource(icon); + // Provide default values for 'purpose' and 'sizes' if they are missing. + if (candidate_icon.sizes.empty()) + candidate_icon.sizes.emplace_back(gfx::Size(0, 0)); + if (candidate_icon.purpose.empty()) { + candidate_icon.purpose.emplace_back( + Manifest::ImageResource::Purpose::ANY); + } + icons.emplace_back(candidate_icon); } - // TODO(crbug.com/868875): Handle cases where `sizes` or `purpose` is empty. return KURL(ManifestIconSelector::FindBestMatchingIcon( std::move(icons), icon_display_size_pixels_.height, kMinimumIconSizeInPx, Manifest::ImageResource::Purpose::ANY)); @@ -161,14 +176,12 @@ void BackgroundFetchIconLoader::DecodeAndResizeImageOnBackgroundThread( DCHECK(task_runner); DCHECK(data); - // Explicitly pass in the |icon_display_size_pixels_| to benefit from decoders - // that have optimizations for partial decoding. std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create( std::move(data), /* data_complete= */ true, ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth, - ColorBehavior::TransformToSRGB(), - {icon_display_size_pixels_.width, icon_display_size_pixels_.height}); + ColorBehavior::TransformToSRGB()); + int64_t ideal_to_chosen_icon_size_times_hundred = -1; if (decoder) { ImageFrame* image_frame = decoder->DecodeFrameBufferAtIndex(0); if (image_frame) { @@ -184,6 +197,8 @@ void BackgroundFetchIconLoader::DecodeAndResizeImageOnBackgroundThread( static_cast<double>(icon_display_size_pixels_.width) / width, static_cast<double>(icon_display_size_pixels_.height) / height); + ideal_to_chosen_icon_size_times_hundred = std::round(scale * 100.0); + if (scale < 1) { width = ClampToRange(scale * width, 1, icon_display_size_pixels_.width); height = @@ -200,7 +215,8 @@ void BackgroundFetchIconLoader::DecodeAndResizeImageOnBackgroundThread( PostCrossThreadTask(*task_runner, FROM_HERE, CrossThreadBind(&BackgroundFetchIconLoader::RunCallback, - WrapCrossThreadPersistent(this))); + WrapCrossThreadPersistent(this), + ideal_to_chosen_icon_size_times_hundred)); } void BackgroundFetchIconLoader::DidFail(const ResourceError& error) { @@ -211,18 +227,20 @@ void BackgroundFetchIconLoader::DidFailRedirectCheck() { RunCallbackWithEmptyBitmap(); } -void BackgroundFetchIconLoader::RunCallback() { +void BackgroundFetchIconLoader::RunCallback( + int64_t ideal_to_chosen_icon_size_times_hundred) { // If this has been stopped it is not desirable to trigger further work, // there is a shutdown of some sort in progress. if (stopped_) return; - std::move(icon_callback_).Run(decoded_icon_); + std::move(icon_callback_) + .Run(decoded_icon_, ideal_to_chosen_icon_size_times_hundred); } void BackgroundFetchIconLoader::RunCallbackWithEmptyBitmap() { DCHECK(decoded_icon_.isNull()); - RunCallback(); + RunCallback(-1 /* ideal_to_chosen_icon_size_times_hundred */); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.h b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.h index 2e7a2c83d66..180699c417d 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.h +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.h @@ -24,9 +24,11 @@ class MODULES_EXPORT BackgroundFetchIconLoader final : public GarbageCollectedFinalized<BackgroundFetchIconLoader>, public ThreadableLoaderClient { public: - // The bitmap may be empty if the request failed or the image data - // could not be decoded. - using IconCallback = base::OnceCallback<void(const SkBitmap&)>; + // The bitmap may be empty if the request failed or the image data could not + // be decoded. The int64_t returned is the scale of the ideal to chosen icon, + // before resizing. This is -1 if the ideal icon size is empty, or if no icon + // provided was suitable. + using IconCallback = base::OnceCallback<void(const SkBitmap&, int64_t)>; BackgroundFetchIconLoader(); ~BackgroundFetchIconLoader() override; @@ -56,7 +58,7 @@ class MODULES_EXPORT BackgroundFetchIconLoader final private: friend class BackgroundFetchIconLoaderTest; - void RunCallback(); + void RunCallback(int64_t ideal_to_chosen_icon_size_times_hundred); void RunCallbackWithEmptyBitmap(); // Callback for BackgroundFetchBridge::GetIconDisplaySize() diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc index f0b678602c2..76709846e49 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc @@ -64,7 +64,9 @@ class BackgroundFetchIconLoaderTest : public PageTestBase { // Callback for BackgroundFetchIconLoader. This will set up the state of the // load as either success or failed based on whether the bitmap is empty. - void IconLoaded(base::OnceClosure quit_closure, const SkBitmap& bitmap) { + void IconLoaded(base::OnceClosure quit_closure, + const SkBitmap& bitmap, + int64_t ideal_to_chosen_icon_size) { bitmap_ = bitmap; if (!bitmap_.isNull()) @@ -95,12 +97,14 @@ class BackgroundFetchIconLoaderTest : public PageTestBase { void LoadIcon(const KURL& url, const WebSize& maximum_size, - base::OnceClosure quit_closure) { + base::OnceClosure quit_closure, + const String& sizes = "500x500", + const String& purpose = "ANY") { ManifestImageResource icon; icon.setSrc(url.GetString()); icon.setType("image/png"); - icon.setSizes("500x500"); - icon.setPurpose("ANY"); + icon.setSizes(sizes); + icon.setPurpose(purpose); HeapVector<ManifestImageResource> icons(1, icon); loader_->icons_ = std::move(icons); loader_->DidGetIconDisplaySizeIfSoLoadIcon( @@ -181,4 +185,34 @@ TEST_F(BackgroundFetchIconLoaderTest, PickRightIcon) { kBackgroundFetchImageLoaderIcon48x48)); } +TEST_F(BackgroundFetchIconLoaderTest, EmptySizes) { + base::RunLoop run_loop; + + WebSize maximum_size{192, 168}; + LoadIcon(KURL(kBackgroundFetchImageLoaderIcon500x500FullPath), maximum_size, + run_loop.QuitClosure(), "", "ANY"); + + platform_->GetURLLoaderMockFactory()->ServeAsynchronousRequests(); + + run_loop.Run(); + + ASSERT_EQ(BackgroundFetchLoadState::kLoadSuccessful, loaded_); + ASSERT_FALSE(bitmap_.drawsNothing()); +} + +TEST_F(BackgroundFetchIconLoaderTest, EmptyPurpose) { + base::RunLoop run_loop; + + WebSize maximum_size{192, 168}; + LoadIcon(KURL(kBackgroundFetchImageLoaderIcon500x500FullPath), maximum_size, + run_loop.QuitClosure(), "500X500", ""); + + platform_->GetURLLoaderMockFactory()->ServeAsynchronousRequests(); + + run_loop.Run(); + + ASSERT_EQ(BackgroundFetchLoadState::kLoadSuccessful, loaded_); + ASSERT_FALSE(bitmap_.drawsNothing()); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc index dbe549d7100..58d84e020b7 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc @@ -4,20 +4,16 @@ #include "third_party/blink/renderer/modules/background_fetch/background_fetch_manager.h" -#include "base/memory/scoped_refptr.h" #include "base/metrics/histogram_macros.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h" #include "third_party/blink/renderer/bindings/core/v8/request_or_usv_string.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/bindings/modules/v8/request_or_usv_string_or_request_or_usv_string_sequence.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" -#include "third_party/blink/renderer/core/fetch/body.h" -#include "third_party/blink/renderer/core/fetch/body_stream_buffer.h" #include "third_party/blink/renderer/core/fetch/request.h" #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h" #include "third_party/blink/renderer/core/frame/deprecation.h" #include "third_party/blink/renderer/core/frame/use_counter.h" -#include "third_party/blink/renderer/core/loader/mixed_content_checker.h" #include "third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h" #include "third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.h" #include "third_party/blink/renderer/modules/background_fetch/background_fetch_options.h" @@ -27,13 +23,14 @@ #include "third_party/blink/renderer/platform/bindings/exception_code.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h" -#include "third_party/blink/renderer/platform/blob/blob_data.h" #include "third_party/blink/renderer/platform/loader/cors/cors.h" #include "third_party/blink/renderer/platform/loader/fetch/fetch_utils.h" #include "third_party/blink/renderer/platform/network/network_utils.h" #include "third_party/blink/renderer/platform/weborigin/known_ports.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" +#include "third_party/blink/renderer/platform/weborigin/kurl_hash.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" +#include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/skia/include/core/SkBitmap.h" namespace blink { @@ -86,14 +83,6 @@ bool ShouldBlockScheme(const KURL& request_url) { !request_url.ProtocolIs(WTF::g_https_atom); } -bool ShouldBlockMixedContent(ExecutionContext* execution_context, - const KURL& request_url) { - // TODO(crbug.com/757441): Using MixedContentChecker::ShouldBlockFetch would - // log better metrics. - return MixedContentChecker::IsMixedContent( - execution_context->GetSecurityOrigin(), request_url); -} - bool ShouldBlockDanglingMarkup(const KURL& request_url) { // "If request's url's potentially-dangling-markup flag is set, and request's // url's scheme is an HTTP(S) scheme, then set response to a network error." @@ -103,29 +92,9 @@ bool ShouldBlockDanglingMarkup(const KURL& request_url) { request_url.ProtocolIsInHTTPFamily(); } -bool ShouldBlockCORSPreflight(ExecutionContext* execution_context, - const WebServiceWorkerRequest& web_request, - const KURL& request_url) { - // Requests that require CORS preflights are temporarily blocked, because the - // browser side of Background Fetch doesn't yet support performing CORS - // checks. TODO(crbug.com/711354): Remove this temporary block. - - // Same origin requests don't require a CORS preflight. - // https://fetch.spec.whatwg.org/#main-fetch - // TODO(crbug.com/711354): Make sure that cross-origin redirects are disabled. - bool same_origin = - execution_context->GetSecurityOrigin()->CanRequest(request_url); - if (same_origin) - return false; - - // Requests that are more involved than what is possible with HTML's form - // element require a CORS-preflight request. - // https://fetch.spec.whatwg.org/#main-fetch - if (!CORS::IsCORSSafelistedMethod(web_request.Method()) || - !CORS::ContainsOnlyCORSSafelistedHeaders(web_request.Headers())) { - return true; - } - +bool ShouldBlockGateWayAttacks(ExecutionContext* execution_context, + const WebServiceWorkerRequest& web_request, + const KURL& request_url) { if (RuntimeEnabledFeatures::CorsRFC1918Enabled()) { mojom::IPAddressSpace requestor_space = execution_context->GetSecurityContext().AddressSpace(); @@ -147,38 +116,12 @@ bool ShouldBlockCORSPreflight(ExecutionContext* execution_context, return false; } -scoped_refptr<BlobDataHandle> ExtractBlobHandle( - Request* request, - ExceptionState& exception_state) { - DCHECK(request); - - if (request->IsBodyLocked(exception_state) == Body::BodyLocked::kLocked || - request->IsBodyUsed(exception_state) == Body::BodyUsed::kUsed) { - DCHECK(!exception_state.HadException()); - exception_state.ThrowTypeError("Request body is already used"); - return nullptr; - } - - BodyStreamBuffer* buffer = request->BodyBuffer(); - if (!buffer) - return nullptr; - - auto blob_handle = buffer->DrainAsBlobDataHandle( - BytesConsumer::BlobSizePolicy::kDisallowBlobWithInvalidSize, - exception_state); - if (exception_state.HadException()) - return nullptr; - - return blob_handle; -} - } // namespace BackgroundFetchManager::BackgroundFetchManager( ServiceWorkerRegistration* registration) : ContextLifecycleObserver(registration->GetExecutionContext()), - registration_(registration), - loader_(new BackgroundFetchIconLoader()) { + registration_(registration) { DCHECK(registration); bridge_ = BackgroundFetchBridge::From(registration_); } @@ -197,27 +140,37 @@ ScriptPromise BackgroundFetchManager::fetch( "the ServiceWorkerRegistration.")); } - Vector<WebServiceWorkerRequest> web_requests = - CreateWebRequestVector(script_state, requests, exception_state); + bool has_requests_with_body; + Vector<WebServiceWorkerRequest> web_requests = CreateWebRequestVector( + script_state, requests, exception_state, &has_requests_with_body); if (exception_state.HadException()) return ScriptPromise(); + // Record whether any requests had a body. If there were, reject the promise. + UMA_HISTOGRAM_BOOLEAN("BackgroundFetch.HasRequestsWithBody", + has_requests_with_body); + + // TODO(crbug.com/789854): Stop bailing here once we support uploads. + if (has_requests_with_body) { + return ScriptPromise::Reject( + script_state, V8ThrowException::CreateTypeError( + script_state->GetIsolate(), + "Requests with a body are not yet supported. " + "For updates check http://crbug.com/774054")); + } + ExecutionContext* execution_context = ExecutionContext::From(script_state); + // A HashSet to find whether there are any duplicate requests within the + // fetch. https://bugs.chromium.org/p/chromium/issues/detail?id=871174. + HashSet<KURL> kurls; + // Based on security steps from https://fetch.spec.whatwg.org/#main-fetch // TODO(crbug.com/757441): Remove all this duplicative code once Fetch (and // all its security checks) are implemented in the Network Service, such that // the Download Service in the browser process can use it without having to // spin up a renderer process. for (const WebServiceWorkerRequest& web_request : web_requests) { - // TODO(crbug.com/757441): Decide whether to support upgrading requests to - // potentially secure URLs (https://w3c.github.io/webappsec-upgrade- - // insecure-requests/) and/or HSTS rewriting. Since this is a new API only - // exposed on Secure Contexts, and the Mixed Content check below will block - // any requests to insecure contexts, it'd be cleanest not to support it. - // Depends how closely compatible with Fetch we want to be. If support is - // added, make sure to report CSP violations before upgrading the URL. - KURL request_url(web_request.Url()); if (!request_url.IsValid()) { @@ -234,7 +187,7 @@ ScriptPromise BackgroundFetchManager::fetch( } // Check this before mixed content, so that if mixed content is blocked by - // CSP they get a CSP warning rather than a mixed content warning. + // CSP they get a CSP warning rather than a mixed content failure. if (ShouldBlockDueToCSP(execution_context, request_url)) { return RejectWithTypeError(script_state, request_url, "it violates the Content Security Policy"); @@ -256,43 +209,61 @@ ScriptPromise BackgroundFetchManager::fetch( "for loopback IPs"); } - // Blocking fetches due to mixed content is done after Content Security - // Policy to prioritize warnings caused by the latter. - if (ShouldBlockMixedContent(execution_context, request_url)) { - return RejectWithTypeError(script_state, request_url, - "it is insecure; use https instead"); - } - if (ShouldBlockDanglingMarkup(request_url)) { return RejectWithTypeError(script_state, request_url, "it contains dangling markup"); } - if (ShouldBlockCORSPreflight(execution_context, web_request, request_url)) { + if (ShouldBlockGateWayAttacks(execution_context, web_request, + request_url)) { return RejectWithTypeError(script_state, request_url, - "CORS preflights are not yet supported " - "by this browser"); + "Requestor IP address space doesn't match the " + "target address space."); } + + kurls.insert(request_url); + } + + const bool has_duplicate_requests = kurls.size() != web_requests.size(); + + UMA_HISTOGRAM_BOOLEAN("BackgroundFetch.HasDuplicateRequests", + has_duplicate_requests); + + // Note: This is a proprietary check, due to the way Chrome currently handles + // storing background fetch records. Entries are keyed by the URL, so if two + // requests have the same URL, and different responses, the first response + // will be lost when the second request/response pair is stored. + if (has_duplicate_requests) { + return ScriptPromise::Reject( + script_state, + V8ThrowException::CreateTypeError( + script_state->GetIsolate(), + "Fetches with duplicate requests are not yet supported. " + "Consider adding query params to make the requests unique. " + "For updates check http://crbug.com/871174")); } ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); - // Load Icons. Right now, we just load the first icon. Lack of icons or - // inability to load them should not be fatal to the fetch. + // Pick the best icon, and load it. + // Inability to load them should not be fatal to the fetch. mojom::blink::BackgroundFetchOptionsPtr options_ptr = mojom::blink::BackgroundFetchOptions::From(options); if (options.icons().size()) { - loader_->Start( + BackgroundFetchIconLoader* loader = new BackgroundFetchIconLoader(); + loaders_.push_back(loader); + loader->Start( bridge_.Get(), execution_context, options.icons(), WTF::Bind(&BackgroundFetchManager::DidLoadIcons, WrapPersistent(this), id, WTF::Passed(std::move(web_requests)), - std::move(options_ptr), WrapPersistent(resolver))); + std::move(options_ptr), WrapPersistent(resolver), + WrapWeakPersistent(loader))); return promise; } DidLoadIcons(id, std::move(web_requests), std::move(options_ptr), resolver, - SkBitmap()); + nullptr, SkBitmap(), -1 /* ideal_to_chosen_icon_size */); return promise; } @@ -301,9 +272,17 @@ void BackgroundFetchManager::DidLoadIcons( Vector<WebServiceWorkerRequest> web_requests, mojom::blink::BackgroundFetchOptionsPtr options, ScriptPromiseResolver* resolver, - const SkBitmap& icon) { + BackgroundFetchIconLoader* loader, + const SkBitmap& icon, + int64_t ideal_to_chosen_icon_size) { + if (loader) + loaders_.erase(std::find(loaders_.begin(), loaders_.end(), loader)); + + auto ukm_data = mojom::blink::BackgroundFetchUkmData::New(); + ukm_data->ideal_to_chosen_icon_size = ideal_to_chosen_icon_size; bridge_->Fetch( id, std::move(web_requests), std::move(options), icon, + std::move(ukm_data), WTF::Bind(&BackgroundFetchManager::DidFetch, WrapPersistent(this), WrapPersistent(resolver), base::Time::Now())); } @@ -350,6 +329,11 @@ void BackgroundFetchManager::DidFetch( resolver->Reject(DOMException::Create( DOMExceptionCode::kQuotaExceededError, "Quota exceeded.")); return; + case mojom::blink::BackgroundFetchError::REGISTRATION_LIMIT_EXCEEDED: + resolver->Reject(V8ThrowException::CreateTypeError( + script_state->GetIsolate(), + "There are too many active fetches for this origin.")); + return; case mojom::blink::BackgroundFetchError::INVALID_ARGUMENT: case mojom::blink::BackgroundFetchError::INVALID_ID: // Not applicable for this callback. @@ -366,6 +350,15 @@ ScriptPromise BackgroundFetchManager::get(ScriptState* script_state, if (!registration_->active()) return ScriptPromise::CastUndefined(script_state); + ScriptState::Scope scope(script_state); + + if (id.IsEmpty()) { + return ScriptPromise::Reject( + script_state, + V8ThrowException::CreateTypeError(script_state->GetIsolate(), + "The provided id is invalid.")); + } + ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); @@ -381,8 +374,12 @@ ScriptPromise BackgroundFetchManager::get(ScriptState* script_state, Vector<WebServiceWorkerRequest> BackgroundFetchManager::CreateWebRequestVector( ScriptState* script_state, const RequestOrUSVStringOrRequestOrUSVStringSequence& requests, - ExceptionState& exception_state) { + ExceptionState& exception_state, + bool* has_requests_with_body) { + DCHECK(has_requests_with_body); + Vector<WebServiceWorkerRequest> web_requests; + *has_requests_with_body = false; if (requests.IsRequestOrUSVStringSequence()) { HeapVector<RequestOrUSVString> request_vector = @@ -396,7 +393,7 @@ Vector<WebServiceWorkerRequest> BackgroundFetchManager::CreateWebRequestVector( web_requests.resize(request_vector.size()); - for (size_t i = 0; i < request_vector.size(); ++i) { + for (wtf_size_t i = 0; i < request_vector.size(); ++i) { const RequestOrUSVString& request_or_url = request_vector[i]; Request* request = nullptr; @@ -413,16 +410,21 @@ Vector<WebServiceWorkerRequest> BackgroundFetchManager::CreateWebRequestVector( } DCHECK(request); + *has_requests_with_body |= request->HasBody(); + // TODO(crbug.com/774054): Set blob data handle when adding support for + // requests with body. request->PopulateWebServiceWorkerRequest(web_requests[i]); - web_requests[i].SetBlobDataHandle( - ExtractBlobHandle(request, exception_state)); } } else if (requests.IsRequest()) { - DCHECK(requests.GetAsRequest()); + auto* request = requests.GetAsRequest(); + DCHECK(request); + + // TODO(crbug.com/774054): Set blob data handle when adding support for + // requests with body. + + *has_requests_with_body = request->HasBody(); web_requests.resize(1); - requests.GetAsRequest()->PopulateWebServiceWorkerRequest(web_requests[0]); - web_requests[0].SetBlobDataHandle( - ExtractBlobHandle(requests.GetAsRequest(), exception_state)); + request->PopulateWebServiceWorkerRequest(web_requests[0]); } else if (requests.IsUSVString()) { Request* request = Request::Create(script_state, requests.GetAsUSVString(), exception_state); @@ -430,6 +432,7 @@ Vector<WebServiceWorkerRequest> BackgroundFetchManager::CreateWebRequestVector( return Vector<WebServiceWorkerRequest>(); DCHECK(request); + *has_requests_with_body = request->HasBody(); web_requests.resize(1); request->PopulateWebServiceWorkerRequest(web_requests[0]); } else { @@ -475,6 +478,7 @@ void BackgroundFetchManager::DidGetRegistration( case mojom::blink::BackgroundFetchError::INVALID_ARGUMENT: case mojom::blink::BackgroundFetchError::PERMISSION_DENIED: case mojom::blink::BackgroundFetchError::QUOTA_EXCEEDED: + case mojom::blink::BackgroundFetchError::REGISTRATION_LIMIT_EXCEEDED: // Not applicable for this callback. break; } @@ -526,6 +530,7 @@ void BackgroundFetchManager::DidGetDeveloperIds( case mojom::blink::BackgroundFetchError::PERMISSION_DENIED: case mojom::blink::BackgroundFetchError::SERVICE_WORKER_UNAVAILABLE: case mojom::blink::BackgroundFetchError::QUOTA_EXCEEDED: + case mojom::blink::BackgroundFetchError::REGISTRATION_LIMIT_EXCEEDED: // Not applicable for this callback. break; } @@ -536,15 +541,17 @@ void BackgroundFetchManager::DidGetDeveloperIds( void BackgroundFetchManager::Trace(blink::Visitor* visitor) { visitor->Trace(registration_); visitor->Trace(bridge_); - visitor->Trace(loader_); + visitor->Trace(loaders_); ContextLifecycleObserver::Trace(visitor); ScriptWrappable::Trace(visitor); } void BackgroundFetchManager::ContextDestroyed(ExecutionContext* context) { - if (loader_) { - loader_->Stop(); + for (const auto& loader : loaders_) { + if (loader) + loader->Stop(); } + loaders_.clear(); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.h b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.h index ac445e7d1d0..c850731ac69 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.h +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.h @@ -67,16 +67,20 @@ class MODULES_EXPORT BackgroundFetchManager final // Creates a vector of WebServiceWorkerRequest objects for the given set of // |requests|, which can be either Request objects or URL strings. + // |has_requests_with_body| will be set if any of the |requests| has a body. static Vector<WebServiceWorkerRequest> CreateWebRequestVector( ScriptState* script_state, const RequestOrUSVStringOrRequestOrUSVStringSequence& requests, - ExceptionState& exception_state); + ExceptionState& exception_state, + bool* has_requests_with_body); void DidLoadIcons(const String& id, Vector<WebServiceWorkerRequest> web_requests, mojom::blink::BackgroundFetchOptionsPtr options, ScriptPromiseResolver* resolver, - const SkBitmap& icon); + BackgroundFetchIconLoader* loader, + const SkBitmap& icon, + int64_t ideal_to_chosen_icon_size); void DidFetch(ScriptPromiseResolver* resolver, base::Time time_started, mojom::blink::BackgroundFetchError error, @@ -92,7 +96,7 @@ class MODULES_EXPORT BackgroundFetchManager final Member<ServiceWorkerRegistration> registration_; Member<BackgroundFetchBridge> bridge_; - Member<BackgroundFetchIconLoader> loader_; + HeapVector<Member<BackgroundFetchIconLoader>> loaders_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl index 12e59cc0473..cd401cc4bd4 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl @@ -6,9 +6,9 @@ [ Exposed=(Window,Worker), - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchManager { - [CallWith=ScriptState, RaisesException] Promise<BackgroundFetchRegistration> fetch(DOMString id, (RequestInfo or sequence<RequestInfo>) requests, optional BackgroundFetchOptions options); - [CallWith=ScriptState] Promise<BackgroundFetchRegistration?> get(DOMString id); - [CallWith=ScriptState] Promise<FrozenArray<DOMString>> getIds(); + [CallWith=ScriptState, RaisesException, MeasureAs=BackgroundFetchManagerFetch] Promise<BackgroundFetchRegistration> fetch(DOMString id, (RequestInfo or sequence<RequestInfo>) requests, optional BackgroundFetchOptions options); + [CallWith=ScriptState, MeasureAs=BackgroundFetchManagerGet] Promise<BackgroundFetchRegistration?> get(DOMString id); + [CallWith=ScriptState, MeasureAs=BackgroundFetchManagerGetIds] Promise<FrozenArray<DOMString>> getIds(); }; diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager_test.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager_test.cc index 063d42f25d4..688658b3fa0 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager_test.cc +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_manager_test.cc @@ -14,7 +14,6 @@ #include "third_party/blink/renderer/core/fetch/request_init.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" -#include "third_party/blink/renderer/platform/blob/blob_data.h" namespace blink { @@ -26,8 +25,10 @@ class BackgroundFetchManagerTest : public testing::Test { Vector<WebServiceWorkerRequest> CreateWebRequestVector( V8TestingScope& scope, const RequestOrUSVStringOrRequestOrUSVStringSequence& requests) { + bool has_requests_with_body; return BackgroundFetchManager::CreateWebRequestVector( - scope.GetScriptState(), requests, scope.GetExceptionState()); + scope.GetScriptState(), requests, scope.GetExceptionState(), + &has_requests_with_body); } }; @@ -176,48 +177,4 @@ TEST_F(BackgroundFetchManagerTest, SequenceWithNullValue) { ESErrorType::kTypeError); } -TEST_F(BackgroundFetchManagerTest, BlobsExtracted) { - V8TestingScope scope; - - KURL image_url("https://www.example.com/my_image.png"); - KURL icon_url("https://www.example.com/my_icon.jpg"); - - // Create first request with a body. - String body_text = "cat_pic"; - RequestInit request_init; - request_init.setMethod("POST"); - request_init.setBody(blink::ScriptValue( - scope.GetScriptState(), ToV8(body_text, scope.GetScriptState()))); - Request* image_request = - Request::Create(scope.GetScriptState(), image_url.GetString(), - request_init, scope.GetExceptionState()); - ASSERT_FALSE(scope.GetExceptionState().HadException()); - ASSERT_TRUE(image_request); - ASSERT_TRUE(image_request->HasBody()); - - // Create second request without a body. - RequestOrUSVString icon_request = - RequestOrUSVString::FromUSVString(icon_url.GetString()); - - // Create a request sequence with both requests. - HeapVector<RequestOrUSVString> request_sequence; - request_sequence.push_back(RequestOrUSVString::FromRequest(image_request)); - request_sequence.push_back(icon_request); - - RequestOrUSVStringOrRequestOrUSVStringSequence requests = - RequestOrUSVStringOrRequestOrUSVStringSequence:: - FromRequestOrUSVStringSequence(request_sequence); - - // Extract the blobs. - auto web_requests = CreateWebRequestVector(scope, requests); - ASSERT_FALSE(scope.GetExceptionState().HadException()); - - ASSERT_EQ(web_requests.size(), 2u); - - ASSERT_TRUE(web_requests[0].GetBlobDataHandle()); - EXPECT_EQ(web_requests[0].GetBlobDataHandle()->size(), body_text.length()); - - EXPECT_FALSE(web_requests[1].GetBlobDataHandle()); -} - } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl index a3e4080f498..bf812380814 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl @@ -6,7 +6,7 @@ [ Exposed=(ServiceWorker), - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchRecord { readonly attribute Request request; [CallWith=ScriptState] readonly attribute Promise<Response> responseReady; diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc index bf5b6d9e84c..e425272b6d7 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc @@ -30,7 +30,7 @@ BackgroundFetchRegistration::BackgroundFetchRegistration( unsigned long long uploaded, unsigned long long download_total, unsigned long long downloaded, - mojom::BackgroundFetchState state, + mojom::BackgroundFetchResult result, mojom::BackgroundFetchFailureReason failure_reason) : developer_id_(developer_id), unique_id_(unique_id), @@ -38,7 +38,7 @@ BackgroundFetchRegistration::BackgroundFetchRegistration( uploaded_(uploaded), download_total_(download_total), downloaded_(downloaded), - state_(state), + result_(result), failure_reason_(failure_reason), observer_binding_(this) {} @@ -51,7 +51,7 @@ BackgroundFetchRegistration::BackgroundFetchRegistration( uploaded_(web_registration.uploaded), download_total_(web_registration.download_total), downloaded_(web_registration.downloaded), - state_(web_registration.state), + result_(web_registration.result), failure_reason_(web_registration.failure_reason), observer_binding_(this) { DCHECK(registration); @@ -74,14 +74,19 @@ void BackgroundFetchRegistration::Initialize( ->AddRegistrationObserver(unique_id_, std::move(observer)); } -void BackgroundFetchRegistration::OnProgress(uint64_t upload_total, - uint64_t uploaded, - uint64_t download_total, - uint64_t downloaded) { +void BackgroundFetchRegistration::OnProgress( + uint64_t upload_total, + uint64_t uploaded, + uint64_t download_total, + uint64_t downloaded, + mojom::BackgroundFetchResult result, + mojom::BackgroundFetchFailureReason failure_reason) { upload_total_ = upload_total; uploaded_ = uploaded; download_total_ = download_total; downloaded_ = downloaded; + result_ = result; + failure_reason_ = failure_reason; ExecutionContext* context = GetExecutionContext(); if (!context || context->IsContextDestroyed()) @@ -91,6 +96,10 @@ void BackgroundFetchRegistration::OnProgress(uint64_t upload_total, DispatchEvent(*Event::Create(EventTypeNames::progress)); } +void BackgroundFetchRegistration::OnRecordsUnavailable() { + records_available_ = false; +} + String BackgroundFetchRegistration::id() const { return developer_id_; } @@ -111,6 +120,10 @@ unsigned long long BackgroundFetchRegistration::downloaded() const { return downloaded_; } +bool BackgroundFetchRegistration::recordsAvailable() const { + return records_available_; +} + const AtomicString& BackgroundFetchRegistration::InterfaceName() const { return EventTargetNames::BackgroundFetchRegistration; } @@ -167,29 +180,51 @@ ScriptPromise BackgroundFetchRegistration::MatchImpl( mojom::blink::QueryParamsPtr cache_query_params, ExceptionState& exception_state, bool match_all) { + // TODO(crbug.com/875201): Update this check once we support access to active + // fetches. + if (result_ == mojom::BackgroundFetchResult::UNSET) { + return ScriptPromise::RejectWithDOMException( + script_state, + DOMException::Create( + DOMExceptionCode::kInvalidStateError, + "Access to records for in-progress background fetches is not yet " + "implemented. Please see crbug.com/875201 for more details.")); + } + + if (!records_available_) { + return ScriptPromise::RejectWithDOMException( + script_state, + DOMException::Create( + DOMExceptionCode::kInvalidStateError, + "The records associated with this background fetch are no longer " + "available.")); + } + ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); // Convert |request| to WebServiceWorkerRequest. - base::Optional<WebServiceWorkerRequest> request_to_match; + base::Optional<WebServiceWorkerRequest> optional_request; if (request.has_value()) { + WebServiceWorkerRequest request_to_match; if (request->IsRequest()) { request->GetAsRequest()->PopulateWebServiceWorkerRequest( - request_to_match.value()); + request_to_match); } else { Request* new_request = Request::Create( script_state, request->GetAsUSVString(), exception_state); if (exception_state.HadException()) return ScriptPromise(); - new_request->PopulateWebServiceWorkerRequest(request_to_match.value()); + new_request->PopulateWebServiceWorkerRequest(request_to_match); } + optional_request = request_to_match; } DCHECK(registration_); BackgroundFetchBridge::From(registration_) ->MatchRequests( - developer_id_, unique_id_, request_to_match, + developer_id_, unique_id_, optional_request, std::move(cache_query_params), match_all, WTF::Bind(&BackgroundFetchRegistration::DidGetMatchingRequests, WrapPersistent(this), WrapPersistent(resolver), match_all)); @@ -219,6 +254,11 @@ void BackgroundFetchRegistration::DidGetMatchingRequests( } if (!return_all) { + if (settled_fetches.IsEmpty()) { + // Nothing was matched. Resolve with `undefined`. + resolver->Resolve(); + return; + } DCHECK_EQ(settled_fetches.size(), 1u); DCHECK_EQ(to_return.size(), 1u); resolver->Resolve(to_return[0]); @@ -247,6 +287,7 @@ void BackgroundFetchRegistration::DidAbort( case mojom::blink::BackgroundFetchError::INVALID_ARGUMENT: case mojom::blink::BackgroundFetchError::PERMISSION_DENIED: case mojom::blink::BackgroundFetchError::QUOTA_EXCEEDED: + case mojom::blink::BackgroundFetchError::REGISTRATION_LIMIT_EXCEEDED: // Not applicable for this callback. break; } @@ -254,14 +295,14 @@ void BackgroundFetchRegistration::DidAbort( NOTREACHED(); } -const String BackgroundFetchRegistration::state() const { - switch (state_) { - case mojom::BackgroundFetchState::SUCCESS: +const String BackgroundFetchRegistration::result() const { + switch (result_) { + case mojom::BackgroundFetchResult::SUCCESS: return "success"; - case mojom::BackgroundFetchState::FAILURE: + case mojom::BackgroundFetchResult::FAILURE: return "failure"; - case mojom::BackgroundFetchState::PENDING: - return "pending"; + case mojom::BackgroundFetchResult::UNSET: + return ""; } NOTREACHED(); } diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h index 4d94efee4b5..bb2adb7c16e 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h @@ -39,7 +39,7 @@ class BackgroundFetchRegistration final unsigned long long uploaded, unsigned long long download_total, unsigned long long downloaded, - mojom::BackgroundFetchState state, + mojom::BackgroundFetchResult result, mojom::BackgroundFetchFailureReason failure_reason); BackgroundFetchRegistration( @@ -57,7 +57,10 @@ class BackgroundFetchRegistration final void OnProgress(uint64_t upload_total, uint64_t uploaded, uint64_t download_total, - uint64_t downloaded) override; + uint64_t downloaded, + mojom::BackgroundFetchResult result, + mojom::BackgroundFetchFailureReason failure_reason) override; + void OnRecordsUnavailable() override; // Web Exposed attribute defined in the IDL file. Corresponds to the // |developer_id| used elsewhere in the codebase. @@ -77,7 +80,8 @@ class BackgroundFetchRegistration final unsigned long long uploaded() const; unsigned long long downloadTotal() const; unsigned long long downloaded() const; - const String state() const; + bool recordsAvailable() const; + const String result() const; const String failureReason() const; const String& unique_id() const { return unique_id_; } @@ -122,7 +126,8 @@ class BackgroundFetchRegistration final unsigned long long uploaded_; unsigned long long download_total_; unsigned long long downloaded_; - mojom::BackgroundFetchState state_; + bool records_available_ = true; + mojom::BackgroundFetchResult result_; mojom::BackgroundFetchFailureReason failure_reason_; mojo::Binding<blink::mojom::blink::BackgroundFetchRegistrationObserver> diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl index bb5a4c5bbd6..5760956f4d0 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl @@ -3,8 +3,6 @@ // found in the LICENSE file. // https://wicg.github.io/background-fetch/#background-fetch-registration -enum BackgroundFetchState { "pending", "success", "failure" }; - enum BackgroundFetchFailureReason { "", // The operation was aborted by the user, or abort() was called. @@ -20,24 +18,27 @@ enum BackgroundFetchFailureReason { "total-download-exceeded" }; +enum BackgroundFetchResult { "", "success", "failure" }; + [ Exposed=(Window,Worker), - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchRegistration : EventTarget { readonly attribute DOMString id; readonly attribute unsigned long long uploadTotal; readonly attribute unsigned long long uploaded; readonly attribute unsigned long long downloadTotal; readonly attribute unsigned long long downloaded; - readonly attribute BackgroundFetchState state; + readonly attribute BackgroundFetchResult result; readonly attribute BackgroundFetchFailureReason failureReason; + readonly attribute boolean recordsAvailable; attribute EventHandler onprogress; - [CallWith=ScriptState] Promise<boolean> abort(); + [CallWith=ScriptState, MeasureAs=BackgroundFetchRegistrationAbort] Promise<boolean> abort(); // TODO(crbug.com/875201): Change to (Window,Worker) once we support // match() and matchAll() for active fetches. - [CallWith=ScriptState, Exposed=ServiceWorker, RaisesException] Promise<BackgroundFetchRecord> match(RequestInfo request, optional CacheQueryOptions options); - [CallWith=ScriptState, Exposed=ServiceWorker, RaisesException] Promise<sequence<BackgroundFetchRecord>> matchAll(optional RequestInfo request, optional CacheQueryOptions options); + [CallWith=ScriptState, Exposed=ServiceWorker, RaisesException, MeasureAs=BackgroundFetchRegistrationMatch] Promise<BackgroundFetchRecord> match(RequestInfo request, optional CacheQueryOptions options); + [CallWith=ScriptState, Exposed=ServiceWorker, RaisesException, MeasureAs=BackgroundFetchRegistrationMatchAll] Promise<sequence<BackgroundFetchRecord>> matchAll(optional RequestInfo request, optional CacheQueryOptions options); }; diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_settled_fetch.idl b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_settled_fetch.idl index 74090be5ba1..8bee778bbfe 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_settled_fetch.idl +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_settled_fetch.idl @@ -7,7 +7,7 @@ [ Constructor(Request request, Response response), Exposed=ServiceWorker, - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchSettledFetch : BackgroundFetchFetch { readonly attribute Response? response; }; diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc index 92b011daf5e..385b64a2999 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.cc @@ -23,7 +23,7 @@ TypeConverter<blink::BackgroundFetchRegistration*, mojo_registration->developer_id, mojo_registration->unique_id, mojo_registration->upload_total, mojo_registration->uploaded, mojo_registration->download_total, mojo_registration->downloaded, - mojo_registration->state, mojo_registration->failure_reason); + mojo_registration->result, mojo_registration->failure_reason); } blink::mojom::blink::BackgroundFetchOptionsPtr TypeConverter< diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc index 20080f5a5c6..824f86a52dd 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc @@ -72,7 +72,8 @@ ScriptPromise BackgroundFetchUpdateUIEvent::updateUI( ScriptPromise promise = resolver->Promise(); if (ui_options.icons().IsEmpty()) { - DidGetIcon(resolver, ui_options.title(), SkBitmap()); + DidGetIcon(resolver, ui_options.title(), SkBitmap(), + -1 /* ideal_to_chosen_icon_size */); } else { DCHECK(!loader_); loader_ = new BackgroundFetchIconLoader(); @@ -87,9 +88,11 @@ ScriptPromise BackgroundFetchUpdateUIEvent::updateUI( return promise; } -void BackgroundFetchUpdateUIEvent::DidGetIcon(ScriptPromiseResolver* resolver, - const String& title, - const SkBitmap& icon) { +void BackgroundFetchUpdateUIEvent::DidGetIcon( + ScriptPromiseResolver* resolver, + const String& title, + const SkBitmap& icon, + int64_t ideal_to_chosen_icon_size) { BackgroundFetchBridge::From(service_worker_registration_) ->UpdateUI(registration_->id(), registration_->unique_id(), title, icon, WTF::Bind(&BackgroundFetchUpdateUIEvent::DidUpdateUI, @@ -114,6 +117,7 @@ void BackgroundFetchUpdateUIEvent::DidUpdateUI( case mojom::blink::BackgroundFetchError::SERVICE_WORKER_UNAVAILABLE: case mojom::blink::BackgroundFetchError::PERMISSION_DENIED: case mojom::blink::BackgroundFetchError::QUOTA_EXCEEDED: + case mojom::blink::BackgroundFetchError::REGISTRATION_LIMIT_EXCEEDED: // Not applicable for this callback. break; } diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.h b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.h index 81d9e85d77c..e6090c44a29 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.h +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.h @@ -61,7 +61,8 @@ class MODULES_EXPORT BackgroundFetchUpdateUIEvent final void DidGetIcon(ScriptPromiseResolver* resolver, const String& title, - const SkBitmap& icon); + const SkBitmap& icon, + int64_t ideal_to_chosen_icon_size); void DidUpdateUI(ScriptPromiseResolver* resolver, mojom::blink::BackgroundFetchError error); diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.idl b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.idl index b494c006376..20a3655e666 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.idl +++ b/chromium/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.idl @@ -7,7 +7,7 @@ [ Constructor(DOMString type, BackgroundFetchEventInit init), Exposed=ServiceWorker, - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchUpdateUIEvent : BackgroundFetchEvent { [CallWith=ScriptState] Promise<void> updateUI(BackgroundFetchUIOptions options); };
\ No newline at end of file diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/service_worker_global_scope_background_fetch.idl b/chromium/third_party/blink/renderer/modules/background_fetch/service_worker_global_scope_background_fetch.idl index 2f9f6c023e5..7dc81fe2fdb 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/service_worker_global_scope_background_fetch.idl +++ b/chromium/third_party/blink/renderer/modules/background_fetch/service_worker_global_scope_background_fetch.idl @@ -6,7 +6,7 @@ [ ImplementedAs=ServiceWorkerGlobalScopeBackgroundFetch, - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] partial interface ServiceWorkerGlobalScope { attribute EventHandler onbackgroundfetchsuccess; attribute EventHandler onbackgroundfetchfail; diff --git a/chromium/third_party/blink/renderer/modules/background_fetch/service_worker_registration_background_fetch.idl b/chromium/third_party/blink/renderer/modules/background_fetch/service_worker_registration_background_fetch.idl index a1d9dee789e..529646b9909 100644 --- a/chromium/third_party/blink/renderer/modules/background_fetch/service_worker_registration_background_fetch.idl +++ b/chromium/third_party/blink/renderer/modules/background_fetch/service_worker_registration_background_fetch.idl @@ -7,7 +7,7 @@ [ Exposed=(Window,Worker), ImplementedAs=ServiceWorkerRegistrationBackgroundFetch, - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] partial interface ServiceWorkerRegistration { readonly attribute BackgroundFetchManager backgroundFetch; }; diff --git a/chromium/third_party/blink/renderer/modules/badging/BUILD.gn b/chromium/third_party/blink/renderer/modules/badging/BUILD.gn new file mode 100644 index 00000000000..8af60813b49 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/badging/BUILD.gn @@ -0,0 +1,12 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/blink/renderer/modules/modules.gni") + +blink_modules_sources("badging") { + sources = [ + "badge.cc", + "badge.h", + ] +} diff --git a/chromium/third_party/blink/renderer/modules/badging/OWNERS b/chromium/third_party/blink/renderer/modules/badging/OWNERS new file mode 100644 index 00000000000..c8216ae7d7f --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/badging/OWNERS @@ -0,0 +1,5 @@ +estevenson@chromium.org +mgiuca@chromium.org + +# TEAM: apps-dev@chromium.org +# COMPONENT: Platform>Apps diff --git a/chromium/third_party/blink/renderer/modules/badging/README.md b/chromium/third_party/blink/renderer/modules/badging/README.md new file mode 100644 index 00000000000..ad293263220 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/badging/README.md @@ -0,0 +1,24 @@ +# Badging + +This module contains the implementation of the [Badging API]. The implementation +is under [active development]. + +[Badging API]: https://github.com/WICG/badging +[active development]: https://crbug.com/719176 + +### API + +See the [explainer] for details. The Badge interface is a member on Window +and exposes two static methods: + +[explainer]: https://github.com/WICG/badging/blob/master/explainer.md + +* `set(contents)`: Sets the associated app's badge as a "flag" (the argument + is ignored). +* `clear()`: Sets the associated app's badge to nothing. + +### Testing + +`LayoutTests/badging/*.html` tests that the API accepts/rejects the appropriate +inputs (with a mock Mojo service). Testing at other layers will be added +during implementation. diff --git a/chromium/third_party/blink/renderer/modules/badging/badge.cc b/chromium/third_party/blink/renderer/modules/badging/badge.cc new file mode 100644 index 00000000000..e751f41bb75 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/badging/badge.cc @@ -0,0 +1,84 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file + +#include "third_party/blink/renderer/modules/badging/badge.h" + +#include "services/service_manager/public/cpp/interface_provider.h" +#include "third_party/blink/renderer/bindings/modules/v8/usv_string_or_long.h" +#include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/bindings/script_state.h" + +namespace blink { + +const char Badge::kSupplementName[] = "Badge"; + +Badge::~Badge() = default; + +// static +Badge* Badge::From(ExecutionContext* context) { + Badge* supplement = Supplement<ExecutionContext>::From<Badge>(context); + if (!supplement) { + supplement = new Badge(context); + ProvideTo(*context, supplement); + } + return supplement; +} + +// static +void Badge::set(ScriptState* script_state, ExceptionState& exception_state) { + BadgeFromState(script_state)->Set(nullptr, exception_state); +} + +// static +void Badge::set(ScriptState* script_state, + USVStringOrLong& contents, + ExceptionState& exception_state) { + BadgeFromState(script_state)->Set(&contents, exception_state); +} + +// static +void Badge::clear(ScriptState* script_state) { + BadgeFromState(script_state)->Clear(); +} + +void Badge::Set(USVStringOrLong* contents, ExceptionState& exception_state) { + if (contents) { + if (contents->IsLong() && contents->GetAsLong() <= 0) { + exception_state.ThrowTypeError("Badge contents should be > 0"); + return; + } + if (contents->IsUSVString() && contents->GetAsUSVString() == "") { + exception_state.ThrowTypeError( + "Badge contents cannot be the empty string"); + return; + } + } + // TODO(estevenson): Add support for sending badge contents to the browser. + // TODO(estevenson): Verify that contents is a single grapheme cluster. + badge_service_->SetBadge(); +} + +void Badge::Clear() { + badge_service_->ClearBadge(); +} + +void Badge::Trace(blink::Visitor* visitor) { + Supplement<ExecutionContext>::Trace(visitor); + ScriptWrappable::Trace(visitor); +} + +Badge::Badge(ExecutionContext* context) { + context->GetInterfaceProvider()->GetInterface( + mojo::MakeRequest(&badge_service_)); + DCHECK(badge_service_); +} + +// static +Badge* Badge::BadgeFromState(ScriptState* script_state) { + return Badge::From(ExecutionContext::From(script_state)); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/badging/badge.h b/chromium/third_party/blink/renderer/modules/badging/badge.h new file mode 100644 index 00000000000..c6a742a659e --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/badging/badge.h @@ -0,0 +1,51 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_BADGING_BADGE_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_BADGING_BADGE_H_ + +#include "third_party/blink/public/platform/modules/badging/badging.mojom-blink.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/supplementable.h" + +namespace blink { + +class ExceptionState; +class ExecutionContext; +class ScriptState; +class USVStringOrLong; + +class Badge final : public ScriptWrappable, + public Supplement<ExecutionContext> { + DEFINE_WRAPPERTYPEINFO(); + USING_GARBAGE_COLLECTED_MIXIN(Badge); + + public: + static const char kSupplementName[]; + + static Badge* From(ExecutionContext*); + + ~Badge() override; + + // Badge IDL interface. + static void set(ScriptState*, ExceptionState&); + static void set(ScriptState*, USVStringOrLong&, ExceptionState&); + static void clear(ScriptState*); + + void Set(USVStringOrLong*, ExceptionState&); + void Clear(); + + void Trace(blink::Visitor*) override; + + private: + explicit Badge(ExecutionContext*); + + static Badge* BadgeFromState(ScriptState* script_state); + + blink::mojom::blink::BadgeServicePtr badge_service_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_BADGING_BADGE_H_ diff --git a/chromium/third_party/blink/renderer/modules/badging/badge.idl b/chromium/third_party/blink/renderer/modules/badging/badge.idl new file mode 100644 index 00000000000..3c5ec519b2d --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/badging/badge.idl @@ -0,0 +1,16 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// TODO(estevenson): Add link to spec once complete. +// https://github.com/WICG/badging/blob/master/explainer.md + +[ + RuntimeEnabled=Badging, + // TODO(estevenson): Expose the Badge interface to Worker. + Exposed=Window +] interface Badge { + [CallWith=ScriptState, RaisesException] + static void set(optional (USVString or long) contents); + [CallWith=ScriptState] static void clear(); +}; diff --git a/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc b/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc index 7dc24a05041..a5948bf7b64 100644 --- a/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc +++ b/chromium/third_party/blink/renderer/modules/battery/battery_dispatcher.cc @@ -13,9 +13,9 @@ namespace blink { BatteryDispatcher& BatteryDispatcher::Instance() { - DEFINE_STATIC_LOCAL(BatteryDispatcher, battery_dispatcher, + DEFINE_STATIC_LOCAL(Persistent<BatteryDispatcher>, battery_dispatcher, (new BatteryDispatcher)); - return battery_dispatcher; + return *battery_dispatcher; } BatteryDispatcher::BatteryDispatcher() : has_latest_data_(false) {} diff --git a/chromium/third_party/blink/renderer/modules/battery/battery_manager.cc b/chromium/third_party/blink/renderer/modules/battery/battery_manager.cc index 81f73d98547..7f4e94f96ce 100644 --- a/chromium/third_party/blink/renderer/modules/battery/battery_manager.cc +++ b/chromium/third_party/blink/renderer/modules/battery/battery_manager.cc @@ -22,7 +22,7 @@ BatteryManager* BatteryManager::Create(ExecutionContext* context) { BatteryManager::~BatteryManager() = default; BatteryManager::BatteryManager(ExecutionContext* context) - : PausableObject(context), PlatformEventController(ToDocument(context)) {} + : PausableObject(context), PlatformEventController(To<Document>(context)) {} ScriptPromise BatteryManager::StartRequest(ScriptState* script_state) { if (!battery_property_) { @@ -68,7 +68,7 @@ void BatteryManager::DidUpdateData() { return; } - Document* document = ToDocument(GetExecutionContext()); + Document* document = To<Document>(GetExecutionContext()); DCHECK(document); if (document->IsContextPaused() || document->IsContextDestroyed()) return; diff --git a/chromium/third_party/blink/renderer/modules/battery/navigator_battery.cc b/chromium/third_party/blink/renderer/modules/battery/navigator_battery.cc index dca9a1b1b13..3a80ad95c17 100644 --- a/chromium/third_party/blink/renderer/modules/battery/navigator_battery.cc +++ b/chromium/third_party/blink/renderer/modules/battery/navigator_battery.cc @@ -24,8 +24,8 @@ ScriptPromise NavigatorBattery::getBattery(ScriptState* script_state) { // Check to see if this request would be blocked according to the Battery // Status API specification. - if (context->IsDocument()) { - LocalFrame* frame = ToDocument(context)->GetFrame(); + if (auto* document = To<Document>(context)) { + LocalFrame* frame = document->GetFrame(); if (frame) { if (!context->IsSecureContext()) UseCounter::Count(frame, WebFeature::kBatteryStatusInsecureOrigin); diff --git a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc index 5e56ac7ac2f..a875e13ae06 100644 --- a/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc +++ b/chromium/third_party/blink/renderer/modules/bluetooth/bluetooth.cc @@ -167,8 +167,8 @@ ScriptPromise Bluetooth::requestDevice(ScriptState* script_state, // If the algorithm is not allowed to show a popup, reject promise with a // SecurityError and abort these steps. - Document* doc = ToDocumentOrNull(context); - if (!Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr)) { + auto& doc = *To<Document>(context); + if (!LocalFrame::HasTransientUserActivation(doc.GetFrame())) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create( @@ -176,8 +176,8 @@ ScriptPromise Bluetooth::requestDevice(ScriptState* script_state, "Must be handling a user gesture to show a permission request.")); } - if (!service_ && doc) { - LocalFrame* frame = doc->GetFrame(); + if (!service_) { + LocalFrame* frame = doc.GetFrame(); if (frame) { frame->GetInterfaceProvider().GetInterface(mojo::MakeRequest(&service_)); } @@ -198,9 +198,7 @@ ScriptPromise Bluetooth::requestDevice(ScriptState* script_state, return ScriptPromise(); // Record the eTLD+1 of the frame using the API. - Document* document = ToDocument(context); - Platform::Current()->RecordRapporURL("Bluetooth.APIUsage.Origin", - document->Url()); + Platform::Current()->RecordRapporURL("Bluetooth.APIUsage.Origin", doc.Url()); // Subsequent steps are handled in the browser process. ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc b/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc index 6808dec50a9..c5758cd913d 100644 --- a/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc +++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache.cc @@ -26,7 +26,7 @@ #include "third_party/blink/renderer/core/fetch/request.h" #include "third_party/blink/renderer/core/fetch/request_init.h" #include "third_party/blink/renderer/core/fetch/response.h" -#include "third_party/blink/renderer/core/frame/use_counter.h" +#include "third_party/blink/renderer/core/frame/deprecation.h" #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/modules/cache_storage/cache_storage_error.h" @@ -169,7 +169,7 @@ class Cache::FetchResolvedForAdd final : public ScriptFunction { class Cache::BarrierCallbackForPut final : public GarbageCollectedFinalized<BarrierCallbackForPut> { public: - BarrierCallbackForPut(int number_of_operations, + BarrierCallbackForPut(wtf_size_t number_of_operations, Cache* cache, const String& method_name, ScriptPromiseResolver* resolver) @@ -181,7 +181,7 @@ class Cache::BarrierCallbackForPut final batch_operations_.resize(number_of_operations); } - void OnSuccess(size_t index, + void OnSuccess(wtf_size_t index, mojom::blink::BatchOperationPtr batch_operation) { DCHECK_LT(index, batch_operations_.size()); if (!StillActive()) @@ -224,7 +224,7 @@ class Cache::BarrierCallbackForPut final if (error->message.Contains( blink::cache_storage:: kDuplicateOperationBaseMessage)) { - UseCounter::Count( + Deprecation::CountDeprecation( context, WebFeature::kCacheStorageAddAllSuccessWithDuplicate); } @@ -314,7 +314,7 @@ class Cache::BlobHandleCallbackForPut final USING_GARBAGE_COLLECTED_MIXIN(BlobHandleCallbackForPut); public: - BlobHandleCallbackForPut(size_t index, + BlobHandleCallbackForPut(wtf_size_t index, BarrierCallbackForPut* barrier_callback, Request* request, Response* response) @@ -347,7 +347,7 @@ class Cache::BlobHandleCallbackForPut final } private: - const size_t index_; + const wtf_size_t index_; Member<BarrierCallbackForPut> barrier_callback_; WebServiceWorkerRequest web_request_; @@ -361,7 +361,7 @@ class Cache::CodeCacheHandleCallbackForPut final public: CodeCacheHandleCallbackForPut(ScriptState* script_state, - size_t index, + wtf_size_t index, BarrierCallbackForPut* barrier_callback, Request* request, Response* response) @@ -432,7 +432,7 @@ class Cache::CodeCacheHandleCallbackForPut final private: const Member<ScriptState> script_state_; - const size_t index_; + const wtf_size_t index_; Member<BarrierCallbackForPut> barrier_callback_; const String mime_type_; @@ -708,7 +708,7 @@ ScriptPromise Cache::AddAllImpl(ScriptState* script_state, request_infos.resize(requests.size()); Vector<ScriptPromise> promises; promises.resize(requests.size()); - for (size_t i = 0; i < requests.size(); ++i) { + for (wtf_size_t i = 0; i < requests.size(); ++i) { if (!requests[i]->url().ProtocolIsInHTTPFamily()) { return ScriptPromise::Reject(script_state, V8ThrowException::CreateTypeError( @@ -813,7 +813,7 @@ ScriptPromise Cache::PutImpl(ScriptState* script_state, BarrierCallbackForPut* barrier_callback = new BarrierCallbackForPut(requests.size(), this, method_name, resolver); - for (size_t i = 0; i < requests.size(); ++i) { + for (wtf_size_t i = 0; i < requests.size(); ++i) { KURL url(NullURL(), requests[i]->url()); if (!url.ProtocolIsInHTTPFamily()) { barrier_callback->OnError("Request scheme '" + url.Protocol() + diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/cache_test.cc b/chromium/third_party/blink/renderer/modules/cache_storage/cache_test.cc index 77710ea24af..e3fe6e8fc93 100644 --- a/chromium/third_party/blink/renderer/modules/cache_storage/cache_test.cc +++ b/chromium/third_party/blink/renderer/modules/cache_storage/cache_test.cc @@ -14,7 +14,6 @@ #include "services/network/public/mojom/fetch_api.mojom-blink.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h" -#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h" #include "third_party/blink/public/platform/web_url_response.h" #include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" @@ -214,7 +213,7 @@ class ErrorCacheForTests : public mojom::blink::CacheStorageCache { if (expected_batch_operations[i]->response) { ASSERT_EQ(expected_batch_operations[i]->response->url_list.size(), batch_operations[i]->response->url_list.size()); - for (size_t j = 0; + for (wtf_size_t j = 0; j < expected_batch_operations[i]->response->url_list.size(); ++j) { EXPECT_EQ(expected_batch_operations[i]->response->url_list[j], batch_operations[i]->response->url_list[j]); @@ -516,12 +515,11 @@ TEST_F(CacheStorageTest, BatchOperationArguments) { Request* request = NewRequestFromUrl(url); DCHECK(request); - WebServiceWorkerResponse web_response; - std::vector<KURL> url_list; - url_list.push_back(KURL(url)); - web_response.SetURLList(url_list); - web_response.SetStatusText("OK"); - Response* response = Response::Create(GetScriptState(), web_response); + auto fetch_response = mojom::blink::FetchAPIResponse::New(); + fetch_response->url_list.push_back(KURL(url)); + fetch_response->response_type = network::mojom::FetchResponseType::kDefault; + fetch_response->status_text = String("OK"); + Response* response = Response::Create(GetScriptState(), *fetch_response); Vector<mojom::blink::BatchOperationPtr> expected_delete_operations; { diff --git a/chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc b/chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc index fac5814cd84..dec003076ee 100644 --- a/chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc +++ b/chromium/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc @@ -33,6 +33,7 @@ #include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/ref_counted.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/blink/renderer/platform/wtf/text/base64.h" #include "third_party/blink/renderer/platform/wtf/time.h" #include "third_party/blink/renderer/platform/wtf/vector.h" @@ -72,7 +73,7 @@ String BuildCacheId(const String& security_origin, const String& cache_name) { ProtocolResponse ParseCacheId(const String& id, String* security_origin, String* cache_name) { - size_t pipe = id.find('|'); + wtf_size_t pipe = id.find('|'); if (pipe == WTF::kNotFound) return ProtocolResponse::Error("Invalid cache id."); *security_origin = id.Substring(0, pipe); @@ -189,13 +190,13 @@ struct RequestResponse { class ResponsesAccumulator : public RefCounted<ResponsesAccumulator> { public: - ResponsesAccumulator(int num_responses, + ResponsesAccumulator(wtf_size_t num_responses, const DataRequestParams& params, mojom::blink::CacheStorageCacheAssociatedPtr cache_ptr, std::unique_ptr<RequestEntriesCallback> callback) : params_(params), num_responses_left_(num_responses), - responses_(static_cast<size_t>(num_responses)), + responses_(num_responses), cache_ptr_(std::move(cache_ptr)), callback_(std::move(callback)) {} @@ -364,7 +365,8 @@ class CachedResponseFileReaderLoaderClient final void DidFinishLoading() override { std::unique_ptr<CachedResponse> response = CachedResponse::create() - .setBody(Base64Encode(data_->Data(), data_->size())) + .setBody( + Base64Encode(data_->Data(), SafeCast<unsigned>(data_->size()))) .build(); callback_->sendSuccess(std::move(response)); dispose(); diff --git a/chromium/third_party/blink/renderer/modules/canvas/OWNERS b/chromium/third_party/blink/renderer/modules/canvas/OWNERS index 99c09426e40..0a9e139f0c3 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/OWNERS +++ b/chromium/third_party/blink/renderer/modules/canvas/OWNERS @@ -2,8 +2,8 @@ fserb@chromium.org junov@chromium.org # canvas, imagebitmap senorblanco@chromium.org -# OffscreenCanvas -xlai@chromium.org +# lowLatency +mcasas@chromium.org # TEAM: paint-dev@chromium.org # COMPONENT: Blink>Canvas diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc index 783f5c3e3dd..5bd0cdfee88 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc @@ -360,11 +360,8 @@ const Vector<double>& BaseRenderingContext2D::getLineDash() const { } static bool LineDashSequenceIsValid(const Vector<double>& dash) { - for (size_t i = 0; i < dash.size(); i++) { - if (!std::isfinite(dash[i]) || dash[i] < 0) - return false; - } - return true; + return std::all_of(dash.begin(), dash.end(), + [](double d) { return std::isfinite(d) && d >= 0; }); } void BaseRenderingContext2D::setLineDash(const Vector<double>& dash) { @@ -1794,7 +1791,7 @@ void BaseRenderingContext2D::putImageData(ImageData* data, // Color / format convert ImageData to context 2D settings if needed. Color / // format conversion is not needed only if context 2D and ImageData are both - // in sRGB color space and use 8-8-8-8 pixel storage format. We use RGBA pixel + // in sRGB color space and use uint8 pixel storage format. We use RGBA pixel // order for both ImageData and CanvasResourceProvider, therefore no // additional swizzling is needed. CanvasColorParams data_color_params = data->GetCanvasColorParams(); @@ -1802,7 +1799,7 @@ void BaseRenderingContext2D::putImageData(ImageData* data, CanvasColorParams(ColorParams().ColorSpace(), PixelFormat(), kNonOpaque); if (data_color_params.NeedsColorConversion(context_color_params) || PixelFormat() == kF16CanvasPixelFormat) { - unsigned data_length = + size_t data_length = data->Size().Area() * context_color_params.BytesPerPixel(); std::unique_ptr<uint8_t[]> converted_pixels(new uint8_t[data_length]); if (data->ImageDataInCanvasColorSettings( @@ -1975,9 +1972,8 @@ void BaseRenderingContext2D::CheckOverdraw( } float BaseRenderingContext2D::GetFontBaseline( - const FontMetrics& font_metrics) const { - return TextMetrics::GetFontBaseline(GetState().GetTextBaseline(), - font_metrics); + const SimpleFontData& font_data) const { + return TextMetrics::GetFontBaseline(GetState().GetTextBaseline(), font_data); } String BaseRenderingContext2D::textAlign() const { diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h index a5ba638548a..695f9bc16ad 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h @@ -372,7 +372,7 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin, virtual void NeedsFinalizeFrame(){}; - float GetFontBaseline(const FontMetrics&) const; + float GetFontBaseline(const SimpleFontData&) const; static const char kDefaultFont[]; static const char kInheritDirectionString[]; diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc index 8c7e75769ee..3674c02711f 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc @@ -356,7 +356,8 @@ void CanvasRenderingContext2D::ScrollPathIntoViewInternal(const Path& path) { // We first map canvas coordinates to layout coordinates. LayoutRect path_rect(bounding_rect); - IntRect canvas_rect = layout_box->AbsoluteContentBox(); + LayoutRect canvas_rect = layout_box->PhysicalContentBoxRect(); + canvas_rect.MoveBy(LayoutPoint(layout_box->LocalToAbsolute())); path_rect.SetX( (canvas_rect.X() + path_rect.X() * canvas_rect.Width() / Width())); path_rect.SetY( @@ -365,7 +366,7 @@ void CanvasRenderingContext2D::ScrollPathIntoViewInternal(const Path& path) { path_rect.SetHeight((path_rect.Height() * canvas_rect.Height() / Height())); // Then we clip the bounding box to the canvas visible range. - path_rect.Intersect(LayoutRect(canvas_rect)); + path_rect.Intersect(canvas_rect); bool is_horizontal_writing_mode = canvas()->EnsureComputedStyle()->IsHorizontalWritingMode(); @@ -841,7 +842,7 @@ void CanvasRenderingContext2D::DrawTextInternal( text_run.SetNormalizeSpace(true); // Draw the item text at the correct point. FloatPoint location(clampTo<float>(x), - clampTo<float>(y + GetFontBaseline(font_metrics))); + clampTo<float>(y + GetFontBaseline(*font_data))); double font_width = font.Width(text_run); bool use_max_width = (max_width && *max_width < font_width); diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h index ca5ab3b5dda..5a34779343e 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h @@ -27,7 +27,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_RENDERING_CONTEXT_2D_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_RENDERING_CONTEXT_2D_H_ -#include "third_party/blink/public/platform/web_thread.h" #include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h" #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h" #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context_factory.h" @@ -40,6 +39,7 @@ #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/graphics/graphics_types.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace cc { @@ -195,6 +195,8 @@ class MODULES_EXPORT CanvasRenderingContext2D final void Trace(blink::Visitor*) override; + CanvasColorParams ColorParamsForTest() const { return ColorParams(); }; + protected: void NeedsFinalizeFrame() override { CanvasRenderingContext::NeedsFinalizeFrame(); diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl index 6e0b7cec601..fee85211f2b 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl @@ -23,7 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#canvasrenderingcontext2d +// https://html.spec.whatwg.org/multipage/canvas.html#canvasrenderingcontext2d // The spec specifies: // typedef (HTMLImageElement or @@ -77,7 +77,7 @@ interface CanvasRenderingContext2D { attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (default black) CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1); [RaisesException] CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1); - [CallWith=ScriptState, RaisesException] CanvasPattern? createPattern(CanvasImageSource image, [TreatNullAs=NullString] DOMString repetitionType); + [CallWith=ScriptState, RaisesException] CanvasPattern? createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetitionType); // shadows attribute unrestricted double shadowOffsetX; diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_settings.idl b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_settings.idl index 268f1b3060c..93c38d72a27 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_settings.idl +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_settings.idl @@ -8,6 +8,6 @@ dictionary CanvasRenderingContext2DSettings { boolean alpha = true; [RuntimeEnabled=CanvasColorManagement] CanvasColorSpace colorSpace = "srgb"; - [RuntimeEnabled=CanvasColorManagement] CanvasPixelFormat pixelFormat = "8-8-8-8"; + [RuntimeEnabled=CanvasColorManagement] CanvasPixelFormat pixelFormat = "uint8"; }; diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc index ff04d8d5ec3..c71b69a3b18 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc @@ -155,8 +155,8 @@ void CanvasRenderingContext2DState::SetLineDash(const Vector<double>& dash) { } static bool HasANonZeroElement(const Vector<double>& line_dash) { - for (size_t i = 0; i < line_dash.size(); i++) { - if (line_dash[i] != 0.0) + for (double dash : line_dash) { + if (dash != 0.0) return true; } return false; diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc index 896ba70a40e..a1cb3e79b7c 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc @@ -16,9 +16,11 @@ #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" #include "third_party/blink/renderer/core/html/canvas/image_data.h" +#include "third_party/blink/renderer/core/html/html_image_element.h" #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h" #include "third_party/blink/renderer/core/imagebitmap/image_bitmap_options.h" #include "third_party/blink/renderer/core/layout/layout_box_model_object.h" +#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" #include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.h" @@ -34,11 +36,12 @@ #include "third_party/blink/renderer/platform/graphics/test/fake_gles2_interface.h" #include "third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h" #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h" +#include "third_party/blink/renderer/platform/shared_buffer.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" -#include "third_party/skia/include/core/SkColorSpaceXform.h" +#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkSurface.h" -#include "third_party/skia/include/core/SkSwizzle.h" +#include "third_party/skia/third_party/skcms/skcms.h" using testing::_; using testing::InSequence; @@ -233,7 +236,8 @@ void CanvasRenderingContext2DTest::SetUp() { StringOrCanvasGradientOrCanvasPattern wrapped_alpha_gradient; this->AlphaGradient().SetCanvasGradient(alpha_gradient); - global_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create()); + global_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create( + blink::scheduler::GetSingleThreadTaskRunnerForTesting())); } void CanvasRenderingContext2DTest::TearDown() { @@ -278,6 +282,30 @@ class FakeCanvas2DLayerBridge : public Canvas2DLayerBridge { //============================================================================ +class FakeCanvasResourceProvider : public CanvasResourceProvider { + public: + FakeCanvasResourceProvider(const IntSize& size, + CanvasColorParams color_params, + AccelerationHint hint) + : CanvasResourceProvider(size, color_params, nullptr, nullptr), + is_accelerated_(hint != kPreferNoAcceleration) {} + ~FakeCanvasResourceProvider() override = default; + bool IsAccelerated() const override { return is_accelerated_; } + scoped_refptr<CanvasResource> ProduceFrame() override { + return scoped_refptr<CanvasResource>(); + } + bool SupportsDirectCompositing() const override { return false; } + bool IsValid() const override { return false; } + sk_sp<SkSurface> CreateSkSurface() const override { + return sk_sp<SkSurface>(); + } + + private: + bool is_accelerated_; +}; + +//============================================================================ + class MockImageBufferSurfaceForOverwriteTesting : public Canvas2DLayerBridge { public: MockImageBufferSurfaceForOverwriteTesting(const IntSize& size, @@ -297,8 +325,8 @@ class MockImageBufferSurfaceForOverwriteTesting : public Canvas2DLayerBridge { std::make_unique<MockImageBufferSurfaceForOverwriteTesting>( \ size, CanvasColorParams()); \ MockImageBufferSurfaceForOverwriteTesting* surface_ptr = mock_surface.get(); \ - CanvasElement().SetCanvas2DLayerBridgeForTesting(std::move(mock_surface), \ - size); \ + CanvasElement().SetResourceProviderForTesting( \ + nullptr, std::move(mock_surface), size); \ EXPECT_CALL(*surface_ptr, WillOverwriteCanvas()).Times(EXPECTED_OVERDRAWS); \ Context2d()->save(); @@ -546,13 +574,17 @@ TEST_F(CanvasRenderingContext2DTest, GPUMemoryUpdateForAcceleratedCanvas) { CreateContext(kNonOpaque); IntSize size(10, 10); - std::unique_ptr<FakeCanvas2DLayerBridge> fake_accelerate_surface = + std::unique_ptr<FakeCanvasResourceProvider> fake_resource_provider = + std::make_unique<FakeCanvasResourceProvider>(size, CanvasColorParams(), + kPreferAcceleration); + std::unique_ptr<FakeCanvas2DLayerBridge> fake_2d_layer_bridge = std::make_unique<FakeCanvas2DLayerBridge>(size, CanvasColorParams(), kPreferAcceleration); - FakeCanvas2DLayerBridge* fake_accelerate_surface_ptr = - fake_accelerate_surface.get(); - CanvasElement().SetCanvas2DLayerBridgeForTesting( - std::move(fake_accelerate_surface), size); + FakeCanvas2DLayerBridge* fake_2d_layer_bridge_ptr = + fake_2d_layer_bridge.get(); + CanvasElement().SetResourceProviderForTesting( + std::move(fake_resource_provider), std::move(fake_2d_layer_bridge), size); + // 800 = 10 * 10 * 4 * 2 where 10*10 is canvas size, 4 is num of bytes per // pixel per buffer, and 2 is an estimate of num of gpu buffers required EXPECT_EQ(800, GetCurrentGPUMemoryUsage()); @@ -560,14 +592,14 @@ TEST_F(CanvasRenderingContext2DTest, GPUMemoryUpdateForAcceleratedCanvas) { EXPECT_EQ(1u, GetGlobalAcceleratedContextCount()); // Switching accelerated mode to non-accelerated mode - fake_accelerate_surface_ptr->SetIsAccelerated(false); + fake_2d_layer_bridge_ptr->SetIsAccelerated(false); CanvasElement().UpdateMemoryUsage(); EXPECT_EQ(0, GetCurrentGPUMemoryUsage()); EXPECT_EQ(0, GetGlobalGPUMemoryUsage()); EXPECT_EQ(0u, GetGlobalAcceleratedContextCount()); // Switching non-accelerated mode to accelerated mode - fake_accelerate_surface_ptr->SetIsAccelerated(true); + fake_2d_layer_bridge_ptr->SetIsAccelerated(true); CanvasElement().UpdateMemoryUsage(); EXPECT_EQ(800, GetCurrentGPUMemoryUsage()); EXPECT_EQ(800, GetGlobalGPUMemoryUsage()); @@ -579,17 +611,22 @@ TEST_F(CanvasRenderingContext2DTest, GPUMemoryUpdateForAcceleratedCanvas) { CanvasContextCreationAttributesCore attributes; anotherCanvas->GetCanvasRenderingContext("2d", attributes); IntSize size2(10, 5); - auto fake_accelerate_surface2 = std::make_unique<FakeCanvas2DLayerBridge>( - size2, CanvasColorParams(), kPreferAcceleration); - anotherCanvas->SetCanvas2DLayerBridgeForTesting( - std::move(fake_accelerate_surface2), size2); + std::unique_ptr<FakeCanvas2DLayerBridge> fake_2d_layer_bridge2 = + std::make_unique<FakeCanvas2DLayerBridge>(size2, CanvasColorParams(), + kPreferAcceleration); + std::unique_ptr<FakeCanvasResourceProvider> fake_resource_provider2 = + std::make_unique<FakeCanvasResourceProvider>(size2, CanvasColorParams(), + kPreferAcceleration); + anotherCanvas->SetResourceProviderForTesting( + std::move(fake_resource_provider2), std::move(fake_2d_layer_bridge2), + size2); EXPECT_EQ(800, GetCurrentGPUMemoryUsage()); EXPECT_EQ(1200, GetGlobalGPUMemoryUsage()); EXPECT_EQ(2u, GetGlobalAcceleratedContextCount()); // Tear down the first image buffer that resides in current canvas element CanvasElement().SetSize(IntSize(20, 20)); - Mock::VerifyAndClearExpectations(fake_accelerate_surface_ptr); + Mock::VerifyAndClearExpectations(fake_2d_layer_bridge_ptr); EXPECT_EQ(400, GetGlobalGPUMemoryUsage()); EXPECT_EQ(1u, GetGlobalAcceleratedContextCount()); @@ -634,7 +671,8 @@ TEST_F(CanvasRenderingContext2DTest, MAYBE_GetImageDataDisablesAcceleration) { IntSize size(300, 300); std::unique_ptr<Canvas2DLayerBridge> bridge = MakeBridge(size, Canvas2DLayerBridge::kForceAccelerationForTesting); - CanvasElement().SetCanvas2DLayerBridgeForTesting(std::move(bridge), size); + CanvasElement().SetResourceProviderForTesting(nullptr, std::move(bridge), + size); DrawSomething(); // Lock-in gpu acceleration EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated()); EXPECT_EQ(1u, GetGlobalAcceleratedContextCount()); @@ -668,63 +706,6 @@ TEST_F(CanvasRenderingContext2DTest, MAYBE_GetImageDataDisablesAcceleration) { } } -TEST_F(CanvasRenderingContext2DTest, TextureUploadHeuristics) { - ScopedCanvas2dFixedRenderingModeForTest canvas_2d_fixed_rendering_mode(false); - - enum TestVariants { - kLargeTextureDisablesAcceleration = 0, - kSmallTextureDoesNotDisableAcceleration = 1, - - kTestVariantCount = 2, - }; - - for (int test_variant = 0; test_variant < kTestVariantCount; test_variant++) { - int delta = test_variant == kLargeTextureDisablesAcceleration ? 1 : -1; - int src_size = - std::sqrt(static_cast<float>( - CanvasHeuristicParameters::kDrawImageTextureUploadSoftSizeLimit)) + - delta; - int dst_size = - src_size / - std::sqrt(static_cast<float>( - CanvasHeuristicParameters:: - kDrawImageTextureUploadSoftSizeLimitScaleThreshold)) - - delta; - - CreateContext(kNonOpaque); - IntSize size(dst_size, dst_size); - std::unique_ptr<Canvas2DLayerBridge> bridge = - MakeBridge(size, Canvas2DLayerBridge::kEnableAcceleration); - CanvasElement().SetCanvas2DLayerBridgeForTesting(std::move(bridge), size); - - EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated()); - EXPECT_EQ(1u, GetGlobalAcceleratedContextCount()); - // 4 bytes per pixel * 2 buffers = 8 - EXPECT_EQ(8 * dst_size * dst_size, GetGlobalGPUMemoryUsage()); - sk_sp<SkSurface> sk_surface = - SkSurface::MakeRasterN32Premul(src_size, src_size); - scoped_refptr<StaticBitmapImage> big_bitmap = - StaticBitmapImage::Create(sk_surface->makeImageSnapshot()); - ASSERT_TRUE(big_bitmap); - ImageBitmap* big_image = ImageBitmap::Create(std::move(big_bitmap)); - NonThrowableExceptionState exception_state; - V8TestingScope scope; - Context2d()->drawImage(scope.GetScriptState(), big_image, 0, 0, src_size, - src_size, 0, 0, dst_size, dst_size, exception_state); - EXPECT_FALSE(exception_state.HadException()); - - if (test_variant == kLargeTextureDisablesAcceleration) { - EXPECT_FALSE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated()); - EXPECT_EQ(0u, GetGlobalAcceleratedContextCount()); - EXPECT_EQ(0, GetGlobalGPUMemoryUsage()); - } else { - EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated()); - EXPECT_EQ(1u, GetGlobalAcceleratedContextCount()); - EXPECT_EQ(8 * dst_size * dst_size, GetGlobalGPUMemoryUsage()); - } - } -} - TEST_F(CanvasRenderingContext2DTest, NoResourceProviderInCanvas2DBufferInitialization) { // This test enforces that there is no eager creation of @@ -737,21 +718,22 @@ TEST_F(CanvasRenderingContext2DTest, IntSize size(10, 10); auto fake_accelerate_surface = std::make_unique<FakeCanvas2DLayerBridge>( size, CanvasColorParams(), kPreferAcceleration); - CanvasElement().SetCanvas2DLayerBridgeForTesting( - std::move(fake_accelerate_surface), size); + CanvasElement().SetResourceProviderForTesting( + nullptr, std::move(fake_accelerate_surface), size); EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()); EXPECT_FALSE(CanvasElement().ResourceProvider()); } -TEST_F(CanvasRenderingContext2DTest, DisableAcceleration_UpdateGPUMemoryUsage) { +TEST_F(CanvasRenderingContext2DTest, + DISABLED_DisableAcceleration_UpdateGPUMemoryUsage) { CreateContext(kNonOpaque); IntSize size(10, 10); auto fake_accelerate_surface = std::make_unique<FakeCanvas2DLayerBridge>( size, CanvasColorParams(), kPreferAcceleration); - CanvasElement().SetCanvas2DLayerBridgeForTesting( - std::move(fake_accelerate_surface), size); + CanvasElement().SetResourceProviderForTesting( + nullptr, std::move(fake_accelerate_surface), size); CanvasRenderingContext2D* context = Context2d(); // 800 = 10 * 10 * 4 * 2 where 10*10 is canvas size, 4 is num of bytes per @@ -783,8 +765,8 @@ TEST_F(CanvasRenderingContext2DTest, IntSize size(10, 10); auto fake_accelerate_surface = std::make_unique<FakeCanvas2DLayerBridge>( size, CanvasColorParams(), kPreferAcceleration); - CanvasElement().SetCanvas2DLayerBridgeForTesting( - std::move(fake_accelerate_surface), size); + CanvasElement().SetResourceProviderForTesting( + nullptr, std::move(fake_accelerate_surface), size); FakeCanvasResourceHost host(size); auto fake_deaccelerate_surface = std::make_unique<FakeCanvas2DLayerBridge>( @@ -811,27 +793,111 @@ TEST_F(CanvasRenderingContext2DTest, Mock::VerifyAndClearExpectations(surface_ptr); } -enum class ColorSpaceConversion : uint8_t { - NONE = 0, - DEFAULT_COLOR_CORRECTED = 1, - SRGB = 2, - LINEAR_RGB = 3, - P3 = 4, - REC2020 = 5, +static void TestDrawSingleHighBitDepthPNGOnCanvas( + String filepath, + CanvasRenderingContext2D* context, + Document& document, + ScriptState* script_state) { + scoped_refptr<SharedBuffer> pixel_buffer = test::ReadFromFile(filepath); + ASSERT_EQ(false, pixel_buffer->IsEmpty()); + + ImageResourceContent* resource_content = + ImageResourceContent::CreateNotStarted(); + const bool all_data_received = true; + const bool is_multipart = false; + ImageResourceContent::UpdateImageResult update_result = + resource_content->UpdateImage( + pixel_buffer, ResourceStatus::kPending, + ImageResourceContent::UpdateImageOption::kUpdateImage, + all_data_received, is_multipart); + ASSERT_EQ(ImageResourceContent::UpdateImageResult::kNoDecodeError, + update_result); + + HTMLImageElement* image_element = HTMLImageElement::Create(document); + image_element->SetImageForTest(resource_content); + + context->clearRect(0, 0, 2, 2); + NonThrowableExceptionState exception_state; + CanvasImageSourceUnion image_union; + image_union.SetHTMLImageElement(image_element); + context->drawImage(script_state, image_union, 0, 0, exception_state); + + ImageData* image_data = context->getImageData(0, 0, 2, 2, exception_state); + ImageDataArray data_array = image_data->dataUnion(); + ASSERT_TRUE(data_array.IsFloat32Array()); + DOMArrayBufferView* buffer_view = data_array.GetAsFloat32Array().View(); + ASSERT_EQ(16u, buffer_view->byteLength() / buffer_view->TypeSize()); + float* actual_pixels = static_cast<float*>(buffer_view->BaseAddress()); + + sk_sp<SkImage> decoded_image = + resource_content->GetImage()->PaintImageForCurrentFrame().GetSkImage(); + ASSERT_EQ(kRGBA_F16_SkColorType, decoded_image->colorType()); + sk_sp<SkImage> color_converted_image = decoded_image->makeColorSpace( + context->ColorParamsForTest().GetSkColorSpaceForSkSurfaces()); + float expected_pixels[16]; + SkImageInfo expected_info_no_color_space = SkImageInfo::Make( + 2, 2, kRGBA_F32_SkColorType, kUnpremul_SkAlphaType, nullptr); + color_converted_image->readPixels( + expected_info_no_color_space, expected_pixels, + expected_info_no_color_space.minRowBytes(), 0, 0); + ColorCorrectionTestUtils::CompareColorCorrectedPixels( + actual_pixels, expected_pixels, 4, kPixelFormat_ffff); +} + +static void TestDrawHighBitDepthPNGsOnWideGamutCanvas( + String canvas_color_space, + Document& document, + Persistent<HTMLCanvasElement> canvas, + ScriptState* script_state) { + // Prepare the wide gamut context with the given color space. + CanvasContextCreationAttributesCore attributes; + attributes.alpha = true; + attributes.color_space = canvas_color_space; + attributes.pixel_format = "float16"; + CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>( + canvas->GetCanvasRenderingContext("2d", attributes)); - LAST = REC2020 -}; + // Prepare the png file path and call the test routine + std::vector<String> interlace_status = {"", "_interlaced"}; + std::vector<String> color_profiles = {"_sRGB", "_e-sRGB", "_AdobeRGB", + "_DisplayP3", "_ProPhoto", "_Rec2020"}; + std::vector<String> alpha_status = {"_opaque", "_transparent"}; + + String path = test::CoreTestDataPath(); + path.append("/png-16bit/"); + for (auto interlace : interlace_status) { + for (auto color_profile : color_profiles) { + for (auto alpha : alpha_status) { + String filename = "2x2_16bit"; + filename.append(interlace); + filename.append(color_profile); + filename.append(alpha); + filename.append(".png"); + String full_path = path; + full_path.append(filename); + TestDrawSingleHighBitDepthPNGOnCanvas(full_path, context, document, + script_state); + } + } + } +} + +TEST_F(CanvasRenderingContext2DTest, DrawHighBitDepthPngOnLinearRGBCanvas) { + TestDrawHighBitDepthPNGsOnWideGamutCanvas( + "linear-rgb", GetDocument(), + Persistent<HTMLCanvasElement>(CanvasElement()), GetScriptState()); +} -static ImageBitmapOptions PrepareBitmapOptionsAndSetRuntimeFlags( - const ColorSpaceConversion& color_space_conversion) { - // Set the color space conversion in ImageBitmapOptions - ImageBitmapOptions options; - static const Vector<String> kConversions = { - "none", "default", "srgb", "linear-rgb", "p3", "rec2020"}; - options.setColorSpaceConversion( - kConversions[static_cast<uint8_t>(color_space_conversion)]); +TEST_F(CanvasRenderingContext2DTest, DrawHighBitDepthPngOnP3Canvas) { + TestDrawHighBitDepthPNGsOnWideGamutCanvas( + "p3", GetDocument(), Persistent<HTMLCanvasElement>(CanvasElement()), + GetScriptState()); +} - return options; +TEST_F(CanvasRenderingContext2DTest, DrawHighBitDepthPngOnRec2020Canvas) { + TestDrawHighBitDepthPNGsOnWideGamutCanvas( + "rec2020", GetDocument(), Persistent<HTMLCanvasElement>(CanvasElement()), + GetScriptState()); } TEST_F(CanvasRenderingContext2DTest, ImageBitmapColorSpaceConversion) { @@ -845,89 +911,62 @@ TEST_F(CanvasRenderingContext2DTest, ImageBitmapColorSpaceConversion) { StringOrCanvasGradientOrCanvasPattern fill_style; fill_style.SetString("#FFC08040"); // 255,192,128,64 context->setFillStyle(fill_style); - context->fillRect(0, 0, 4, 4); - NonThrowableExceptionState exception_state; - uint8_t* src_pixel = - context->getImageData(2, 2, 1, 1, exception_state)->data()->Data(); + context->fillRect(0, 0, 1, 1); + scoped_refptr<StaticBitmapImage> snapshot = + canvas->Snapshot(kFrontBuffer, kPreferNoAcceleration); + ASSERT_TRUE(snapshot); + sk_sp<SkImage> source_image = + snapshot->PaintImageForCurrentFrame().GetSkImage(); + SkPixmap source_pixmap; + source_image->peekPixels(&source_pixmap); // Create and test the ImageBitmap objects. - base::Optional<IntRect> crop_rect = IntRect(0, 0, 4, 4); - sk_sp<SkColorSpace> color_space = nullptr; - SkColorType color_type = SkColorType::kRGBA_8888_SkColorType; - SkColorSpaceXform::ColorFormat color_format32 = - SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat; - SkColorSpaceXform::ColorFormat color_format = color_format32; - sk_sp<SkColorSpace> src_rgb_color_space = SkColorSpace::MakeSRGB(); - - for (uint8_t i = - static_cast<uint8_t>(ColorSpaceConversion::DEFAULT_COLOR_CORRECTED); - i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) { - ColorSpaceConversion color_space_conversion = - static_cast<ColorSpaceConversion>(i); - - switch (color_space_conversion) { - case ColorSpaceConversion::NONE: - NOTREACHED(); - break; - case ColorSpaceConversion::DEFAULT_COLOR_CORRECTED: - case ColorSpaceConversion::SRGB: - color_space = SkColorSpace::MakeSRGB(); - color_format = color_format32; - break; - case ColorSpaceConversion::LINEAR_RGB: - color_space = SkColorSpace::MakeSRGBLinear(); - color_type = SkColorType::kRGBA_F16_SkColorType; - color_format = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat; - break; - case ColorSpaceConversion::P3: - color_space = - SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, - SkColorSpace::kDCIP3_D65_Gamut); - color_type = SkColorType::kRGBA_F16_SkColorType; - color_format = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat; - break; - case ColorSpaceConversion::REC2020: - color_space = - SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, - SkColorSpace::kRec2020_Gamut); - color_type = SkColorType::kRGBA_F16_SkColorType; - color_format = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat; - break; - default: - NOTREACHED(); - } - + base::Optional<IntRect> crop_rect = IntRect(0, 0, 1, 1); + for (int conversion_iterator = kColorSpaceConversion_Default; + conversion_iterator <= kColorSpaceConversion_Last; + conversion_iterator++) { // Color convert using ImageBitmap - ImageBitmapOptions options = - PrepareBitmapOptionsAndSetRuntimeFlags(color_space_conversion); + ImageBitmapOptions options; + options.setColorSpaceConversion( + ColorCorrectionTestUtils::ColorSpaceConversionToString( + static_cast<ColorSpaceConversion>(conversion_iterator))); ImageBitmap* image_bitmap = ImageBitmap::Create(canvas, crop_rect, options); ASSERT_TRUE(image_bitmap); sk_sp<SkImage> converted_image = image_bitmap->BitmapImage()->PaintImageForCurrentFrame().GetSkImage(); ASSERT_TRUE(converted_image); - SkImageInfo image_info = - SkImageInfo::Make(1, 1, color_type, SkAlphaType::kUnpremul_SkAlphaType, - converted_image->refColorSpace()); - std::unique_ptr<uint8_t[]> converted_pixel( - new uint8_t[image_info.bytesPerPixel()]()); - EXPECT_TRUE(converted_image->readPixels(image_info, converted_pixel.get(), - image_info.minRowBytes(), 2, 2)); - - // Transform the source pixel and check if the image bitmap color conversion - // is done correctly. - std::unique_ptr<SkColorSpaceXform> color_space_xform = - SkColorSpaceXform::New(src_rgb_color_space.get(), color_space.get()); - std::unique_ptr<uint8_t[]> transformed_pixel( - new uint8_t[image_info.bytesPerPixel()]()); - EXPECT_TRUE(color_space_xform->apply(color_format, transformed_pixel.get(), - color_format32, src_pixel, 1, - SkAlphaType::kUnpremul_SkAlphaType)); + SkPixmap converted_pixmap; + converted_image->peekPixels(&converted_pixmap); + + // Manual color convert for testing + sk_sp<SkColorSpace> color_space = + ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace( + static_cast<ColorSpaceConversion>(conversion_iterator)); + if (conversion_iterator == kColorSpaceConversion_Preserve) + color_space = SkColorSpace::MakeSRGB(); + + // TODO: crbug.com/768855: Remove if statement when CanvasResourceProvider + // does not use SkColorSpaceXformCanvas (which rips off sRGB from + // ImageBitmap). + if (!color_space->isSRGB()) { + EXPECT_TRUE(SkColorSpace::Equals(color_space.get(), + converted_image->colorSpace())); + } + + SkColorType color_type = SkColorType::kN32_SkColorType; + if (color_space && color_space->gammaIsLinear()) + color_type = kRGBA_F16_SkColorType; + SkImageInfo image_info = SkImageInfo::Make( + 1, 1, color_type, SkAlphaType::kPremul_SkAlphaType, color_space); + SkBitmap manual_converted_bitmap; + EXPECT_TRUE(manual_converted_bitmap.tryAllocPixels(image_info)); + source_pixmap.readPixels(manual_converted_bitmap.pixmap(), 0, 0); ColorCorrectionTestUtils::CompareColorCorrectedPixels( - converted_pixel.get(), transformed_pixel.get(), 1, - (color_type == kRGBA_8888_SkColorType) ? kUint8ClampedArrayStorageFormat - : kUint16ArrayStorageFormat, - kAlphaUnmultiplied, kUnpremulRoundTripTolerance); + converted_pixmap.addr(), manual_converted_bitmap.pixmap().addr(), 1, + (color_type == kN32_SkColorType) ? kPixelFormat_8888 + : kPixelFormat_hhhh, + kAlphaMultiplied, kNoUnpremulRoundTripTolerance); } } @@ -1050,8 +1089,7 @@ void TestPutImageDataOnCanvasWithColorSpaceSettings( data_array->BaseAddress(), data_length, image_data_color_spaces[i], image_data_storage_formats[j], canvas_color_spaces[k], canvas_pixel_formats[k], - pixels_converted_manually, - SkColorSpaceXform::ColorFormat::kRGBA_F32_ColorFormat)); + pixels_converted_manually, kPixelFormat_ffff)); // Create a canvas and call putImageData and getImageData to make sure // the conversion is done correctly. @@ -1073,8 +1111,8 @@ void TestPutImageDataOnCanvasWithColorSpaceSettings( pixels_from_get_image_data, pixels_converted_manually.get(), num_pixels, (canvas_pixel_formats[k] == kRGBA8CanvasPixelFormat) - ? kUint8ClampedArrayStorageFormat - : kFloat32ArrayStorageFormat, + ? kPixelFormat_8888 + : kPixelFormat_ffff, kAlphaUnmultiplied, kUnpremulRoundTripTolerance); } } @@ -1132,7 +1170,8 @@ TEST_F(CanvasRenderingContext2DTestWithTestingPlatform, MakeBridge(size, Canvas2DLayerBridge::kEnableAcceleration); // Force hibernatation to occur in an immediate task. bridge->DontUseIdleSchedulingForTesting(); - CanvasElement().SetCanvas2DLayerBridgeForTesting(std::move(bridge), size); + CanvasElement().SetResourceProviderForTesting(nullptr, std::move(bridge), + size); EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated()); // Take a snapshot to trigger lazy resource provider creation @@ -1174,7 +1213,8 @@ TEST_F(CanvasRenderingContext2DTestWithTestingPlatform, MakeBridge(size, Canvas2DLayerBridge::kEnableAcceleration); // Force hibernatation to occur in an immediate task. bridge->DontUseIdleSchedulingForTesting(); - CanvasElement().SetCanvas2DLayerBridgeForTesting(std::move(bridge), size); + CanvasElement().SetResourceProviderForTesting(nullptr, std::move(bridge), + size); EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated()); diff --git a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_module.idl b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_module.idl index 7b655dd12a7..98875e974f5 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_module.idl +++ b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_module.idl @@ -22,7 +22,7 @@ // N.B.: Web IDL doesn't support multiple inheritance of dictionaries. enum CanvasPixelFormat { - "8-8-8-8", // default + "uint8", // default "10-10-10-2", "12-12-12-12", "float16", @@ -39,7 +39,7 @@ dictionary CanvasContextCreationAttributesModule { // Canvas 2D attributes boolean alpha = true; // Also used for WebGL. [RuntimeEnabled=CanvasColorManagement] CanvasColorSpace colorSpace = "srgb"; - [RuntimeEnabled=CanvasColorManagement] CanvasPixelFormat pixelFormat = "8-8-8-8"; + [RuntimeEnabled=CanvasColorManagement] CanvasPixelFormat pixelFormat = "uint8"; // WebGL attributes boolean depth = true; diff --git a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc index dfa1d902e3e..cded2b9122e 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc @@ -18,7 +18,7 @@ void HTMLCanvasElementModule::getContext( const CanvasContextCreationAttributesModule& attributes, ExceptionState& exception_state, RenderingContext& result) { - if (canvas.SurfaceLayerBridge()) { + if (canvas.SurfaceLayerBridge() && !canvas.LowLatencyEnabled()) { // The existence of canvas surfaceLayerBridge indicates that // HTMLCanvasElement.transferControlToOffscreen() has been called. exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, @@ -30,9 +30,8 @@ void HTMLCanvasElementModule::getContext( CanvasRenderingContext* context = canvas.GetCanvasRenderingContext( type, ToCanvasContextCreationAttributes(attributes)); - if (context) { + if (context) context->SetCanvasGetContextResult(result); - } } OffscreenCanvas* HTMLCanvasElementModule::transferControlToOffscreen( diff --git a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc index 87c5826c214..121b82b5c80 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc @@ -5,17 +5,46 @@ #include "third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.h" #include <memory> + +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/platform/modules/frame_sinks/embedded_frame_sink.mojom-blink.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/dom_node_ids.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" +#include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h" +#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h" #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" #include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" +#include "third_party/blink/renderer/platform/graphics/test/mock_compositor_frame_sink.h" +#include "third_party/blink/renderer/platform/graphics/test/mock_embedded_frame_sink_provider.h" + +using ::testing::_; +using ::testing::Values; namespace blink { -class HTMLCanvasElementModuleTest : public PageTestBase { +namespace { + +// This class allows for overriding GenerateFrameSinkId() so that the +// HTMLCanvasElement's SurfaceLayerBridge will get a syntactically correct +// FrameSinkId. +class TestingPlatformSupportWithGenerateFrameSinkId + : public TestingPlatformSupport { + public: + viz::FrameSinkId GenerateFrameSinkId() override { + // Doesn't matter what we return as long as is not zero. + constexpr uint32_t kClientId = 2; + constexpr uint32_t kSinkId = 1; + return viz::FrameSinkId(kClientId, kSinkId); + } +}; + +} // unnamed namespace + +class HTMLCanvasElementModuleTest : public PageTestBase, + public ::testing::WithParamInterface<bool> { protected: void SetUp() override { PageTestBase::SetUp(); @@ -23,28 +52,83 @@ class HTMLCanvasElementModuleTest : public PageTestBase { canvas_element_ = ToHTMLCanvasElement(GetElementById("c")); } - HTMLCanvasElement& CanvasElement() const { return *canvas_element_; } - OffscreenCanvas* TransferControlToOffscreen(ExceptionState&); + HTMLCanvasElement& canvas_element() const { return *canvas_element_; } + OffscreenCanvas* TransferControlToOffscreen(ExceptionState& exception_state) { + return HTMLCanvasElementModule::TransferControlToOffscreenInternal( + canvas_element(), exception_state); + } - private: Persistent<HTMLCanvasElement> canvas_element_; + Persistent<CanvasRenderingContext> context_; }; -OffscreenCanvas* HTMLCanvasElementModuleTest::TransferControlToOffscreen( - ExceptionState& exception_state) { - // This unit test only tests if the Canvas Id is associated correctly, so we - // exclude the part that creates surface layer bridge because a mojo message - // pipe cannot be tested using webkit unit tests. - return HTMLCanvasElementModule::TransferControlToOffscreenInternal( - CanvasElement(), exception_state); -} - +// Tests if the Canvas Id is associated correctly. TEST_F(HTMLCanvasElementModuleTest, TransferControlToOffscreen) { NonThrowableExceptionState exception_state; - OffscreenCanvas* offscreen_canvas = + const OffscreenCanvas* offscreen_canvas = TransferControlToOffscreen(exception_state); - DOMNodeId canvas_id = offscreen_canvas->PlaceholderCanvasId(); - EXPECT_EQ(canvas_id, DOMNodeIds::IdForNode(&(CanvasElement()))); + const DOMNodeId canvas_id = offscreen_canvas->PlaceholderCanvasId(); + EXPECT_EQ(canvas_id, DOMNodeIds::IdForNode(&(canvas_element()))); +} + +// Verifies that a lowLatency canvas has the appropriate opacity/blending +// information sent to the CompositorFrameSink. +TEST_P(HTMLCanvasElementModuleTest, LowLatencyCanvasCompositorFrameOpacity) { + ScopedTestingPlatformSupport<TestingPlatformSupportWithGenerateFrameSinkId> + platform; + + // To intercept SubmitCompositorFrame/SubmitCompositorFrameSync messages sent + // by a canvas's CanvasResourceDispatcher, we have to override the Mojo + // EmbeddedFrameSinkProvider interface impl and its CompositorFrameSinkClient. + MockEmbeddedFrameSinkProvider mock_embedded_frame_sink_provider; + mojo::Binding<mojom::blink::EmbeddedFrameSinkProvider> + embedded_frame_sink_provider_binding(&mock_embedded_frame_sink_provider); + auto override = + mock_embedded_frame_sink_provider.CreateScopedOverrideMojoInterface( + &embedded_frame_sink_provider_binding); + + const bool context_alpha = GetParam(); + CanvasContextCreationAttributesCore attrs; + attrs.alpha = context_alpha; + attrs.low_latency = true; + // |context_| creation triggers a SurfaceLayerBridge creation which connects + // to a MockEmbeddedFrameSinkProvider to create a new CompositorFrameSink, + // that will receive a SetNeedsBeginFrame() upon construction. + mock_embedded_frame_sink_provider + .set_num_expected_set_needs_begin_frame_on_sink_construction(1); + EXPECT_CALL(mock_embedded_frame_sink_provider, CreateCompositorFrameSink_(_)); + context_ = canvas_element().GetCanvasRenderingContext(String("2d"), attrs); + EXPECT_EQ(context_->CreationAttributes().alpha, attrs.alpha); + EXPECT_TRUE(context_->CreationAttributes().low_latency); + EXPECT_TRUE(canvas_element().LowLatencyEnabled()); + EXPECT_TRUE(canvas_element().SurfaceLayerBridge()); + platform->RunUntilIdle(); + + // This call simulates having drawn something before FinalizeFrame(). + canvas_element().DidDraw(); + + ::testing::InSequence s; + EXPECT_CALL(mock_embedded_frame_sink_provider.mock_compositor_frame_sink(), + DidAllocateSharedBitmap(_, _)); + EXPECT_CALL(mock_embedded_frame_sink_provider.mock_compositor_frame_sink(), + SubmitCompositorFrame_(_)) + .WillOnce(::testing::WithArg<0>( + ::testing::Invoke([context_alpha](const viz::CompositorFrame* frame) { + ASSERT_EQ(frame->render_pass_list.size(), 1u); + + const auto& quad_list = frame->render_pass_list[0]->quad_list; + ASSERT_EQ(quad_list.size(), 1u); + EXPECT_EQ(quad_list.front()->needs_blending, context_alpha); + + const auto& shared_quad_state_list = + frame->render_pass_list[0]->shared_quad_state_list; + ASSERT_EQ(shared_quad_state_list.size(), 1u); + EXPECT_NE(shared_quad_state_list.front()->are_contents_opaque, + context_alpha); + }))); + canvas_element().FinalizeFrame(); + platform->RunUntilIdle(); } +INSTANTIATE_TEST_CASE_P(, HTMLCanvasElementModuleTest, Values(true, false)); } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc index d1e3db9986c..061ca895e20 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc @@ -2,6 +2,8 @@ // 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/core/offscreencanvas/offscreen_canvas.h" + #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h" @@ -9,43 +11,50 @@ #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" -#include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" #include "third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.h" #include "third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h" #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h" #include "third_party/blink/renderer/platform/graphics/test/fake_gles2_interface.h" #include "third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h" +#include "third_party/blink/renderer/platform/graphics/test/mock_compositor_frame_sink.h" +#include "third_party/blink/renderer/platform/graphics/test/mock_embedded_frame_sink_provider.h" #include "third_party/blink/renderer/platform/testing/testing_platform_support.h" -using testing::Mock; +using ::testing::_; +using ::testing::Combine; +using ::testing::ValuesIn; namespace blink { -class OffscreenCanvasTest : public PageTestBase { +namespace { +constexpr uint32_t kClientId = 2; +constexpr uint32_t kSinkId = 1; + +struct TestParams { + bool alpha; + bool low_latency; +}; +} // unnamed namespace + +class OffscreenCanvasTest : public PageTestBase, + public ::testing::WithParamInterface<TestParams> { protected: OffscreenCanvasTest(); void SetUp() override; void TearDown() override; - HTMLCanvasElement& CanvasElement() const { return *canvas_element_; } - OffscreenCanvas& OSCanvas() const { return *offscreen_canvas_; } + OffscreenCanvas& offscreen_canvas() const { return *offscreen_canvas_; } CanvasResourceDispatcher* Dispatcher() const { return offscreen_canvas_->GetOrCreateResourceDispatcher(); } - OffscreenCanvasRenderingContext2D& Context() const { return *context_; } ScriptState* GetScriptState() const { return ToScriptStateForMainWorld(GetDocument().GetFrame()); } - ScopedTestingPlatformSupport<TestingPlatformSupport>& platform() { - return platform_; - } private: - Persistent<HTMLCanvasElement> canvas_element_; Persistent<OffscreenCanvas> offscreen_canvas_; Persistent<OffscreenCanvasRenderingContext2D> context_; - ScopedTestingPlatformSupport<TestingPlatformSupport> platform_; FakeGLES2Interface gl_; }; @@ -62,11 +71,20 @@ void OffscreenCanvasTest::SetUp() { WTF::BindRepeating(factory, WTF::Unretained(&gl_))); PageTestBase::SetUp(); SetHtmlInnerHTML("<body><canvas id='c'></canvas></body>"); - canvas_element_ = ToHTMLCanvasElement(GetElementById("c")); + HTMLCanvasElement* canvas_element = ToHTMLCanvasElement(GetElementById("c")); + DummyExceptionStateForTesting exception_state; offscreen_canvas_ = HTMLCanvasElementModule::transferControlToOffscreen( - *canvas_element_, exception_state); + *canvas_element, exception_state); + // |offscreen_canvas_| should inherit the FrameSinkId from |canvas_element|s + // SurfaceLayerBridge, but in tests this id is zero; fill it up by hand. + offscreen_canvas_->SetFrameSinkId(kClientId, kSinkId); + CanvasContextCreationAttributesCore attrs; + if (testing::UnitTest::GetInstance()->current_test_info()->value_param()) { + attrs.alpha = GetParam().alpha; + attrs.low_latency = GetParam().low_latency; + } context_ = static_cast<OffscreenCanvasRenderingContext2D*>( offscreen_canvas_->GetCanvasRenderingContext(&GetDocument(), String("2d"), attrs)); @@ -81,4 +99,84 @@ TEST_F(OffscreenCanvasTest, AnimationNotInitiallySuspended) { EXPECT_FALSE(Dispatcher()->IsAnimationSuspended()); } +// Verifies that an offscreen_canvas()s PushFrame()/Commit() has the appropriate +// opacity/blending information sent to the CompositorFrameSink. +TEST_P(OffscreenCanvasTest, CompositorFrameOpacity) { + ScopedTestingPlatformSupport<TestingPlatformSupport> platform; + ScriptState::Scope scope(GetScriptState()); + ::testing::InSequence s; + + // To intercept SubmitCompositorFrame/SubmitCompositorFrameSync messages sent + // by OffscreenCanvas's CanvasResourceDispatcher, we have to override the Mojo + // EmbeddedFrameSinkProvider interface impl and its CompositorFrameSinkClient. + MockEmbeddedFrameSinkProvider mock_embedded_frame_sink_provider; + mojo::Binding<mojom::blink::EmbeddedFrameSinkProvider> + embedded_frame_sink_provider_binding(&mock_embedded_frame_sink_provider); + auto override = + mock_embedded_frame_sink_provider.CreateScopedOverrideMojoInterface( + &embedded_frame_sink_provider_binding); + + // Call here DidDraw() to simulate having drawn something before PushFrame()/ + // Commit(); DidDraw() will in turn cause a CanvasResourceDispatcher to be + // created and a CreateCompositorFrameSink() to be issued; this sink will get + // a SetNeedsBeginFrame() message sent upon construction. + mock_embedded_frame_sink_provider + .set_num_expected_set_needs_begin_frame_on_sink_construction(1); + EXPECT_CALL(mock_embedded_frame_sink_provider, + CreateCompositorFrameSink_(viz::FrameSinkId(kClientId, kSinkId))); + offscreen_canvas().DidDraw(); + platform->RunUntilIdle(); + + const bool context_alpha = GetParam().alpha; + + const auto canvas_resource = CanvasResourceSharedBitmap::Create( + offscreen_canvas().Size(), CanvasColorParams(), nullptr /* provider */, + kLow_SkFilterQuality); + EXPECT_TRUE(!!canvas_resource); + + EXPECT_CALL(mock_embedded_frame_sink_provider.mock_compositor_frame_sink(), + SubmitCompositorFrame_(_)) + .WillOnce(::testing::WithArg<0>( + ::testing::Invoke([context_alpha](const viz::CompositorFrame* frame) { + ASSERT_EQ(frame->render_pass_list.size(), 1u); + + const auto& quad_list = frame->render_pass_list[0]->quad_list; + ASSERT_EQ(quad_list.size(), 1u); + EXPECT_EQ(quad_list.front()->needs_blending, context_alpha); + + const auto& shared_quad_state_list = + frame->render_pass_list[0]->shared_quad_state_list; + ASSERT_EQ(shared_quad_state_list.size(), 1u); + EXPECT_NE(shared_quad_state_list.front()->are_contents_opaque, + context_alpha); + }))); + offscreen_canvas().PushFrame(canvas_resource, SkIRect::MakeWH(10, 10)); + platform->RunUntilIdle(); + + EXPECT_CALL(mock_embedded_frame_sink_provider.mock_compositor_frame_sink(), + SubmitCompositorFrameSync_(_)) + .WillOnce(::testing::WithArg<0>( + ::testing::Invoke([context_alpha](const viz::CompositorFrame* frame) { + ASSERT_EQ(frame->render_pass_list.size(), 1u); + + const auto& quad_list = frame->render_pass_list[0]->quad_list; + ASSERT_EQ(quad_list.size(), 1u); + EXPECT_EQ(quad_list.front()->needs_blending, context_alpha); + + const auto& shared_quad_state_list = + frame->render_pass_list[0]->shared_quad_state_list; + ASSERT_EQ(shared_quad_state_list.size(), 1u); + EXPECT_NE(shared_quad_state_list.front()->are_contents_opaque, + context_alpha); + }))); + offscreen_canvas().Commit(canvas_resource, SkIRect::MakeWH(10, 10)); + platform->RunUntilIdle(); +} + +const TestParams kTestCases[] = {{false /* alpha */, false /* low_latency */}, + {false, true}, + {true, false}, + {true, true}}; + +INSTANTIATE_TEST_CASE_P(, OffscreenCanvasTest, ValuesIn(kTestCases)); } // namespace blink 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 291c37fc2e1..37e47045d2b 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 @@ -33,8 +33,8 @@ OffscreenCanvasRenderingContext2D::OffscreenCanvasRenderingContext2D( const CanvasContextCreationAttributesCore& attrs) : CanvasRenderingContext(canvas, attrs) { ExecutionContext* execution_context = canvas->GetTopExecutionContext(); - if (execution_context->IsDocument()) { - Settings* settings = ToDocument(execution_context)->GetSettings(); + if (auto* document = DynamicTo<Document>(execution_context)) { + Settings* settings = document->GetSettings(); if (settings->GetDisableReadingFromCanvas()) canvas->SetDisableReadingFromCanvasTrue(); return; @@ -418,7 +418,7 @@ void OffscreenCanvasRenderingContext2D::DrawTextInternal( false); text_run.SetNormalizeSpace(true); // Draw the item text at the correct point. - FloatPoint location(x, y + GetFontBaseline(font_metrics)); + FloatPoint location(x, y + GetFontBaseline(*font_data)); double font_width = font.Width(text_run); bool use_max_width = (max_width && *max_width < font_width); diff --git a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl index aed21d6d0f6..b9a3f6e7f1b 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl +++ b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl @@ -39,7 +39,7 @@ attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (default black) CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1); [RaisesException] CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1); - [CallWith=ScriptState, RaisesException] CanvasPattern? createPattern(CanvasImageSource image, [TreatNullAs=NullString] DOMString repetitionType); + [CallWith=ScriptState, RaisesException] CanvasPattern? createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetitionType); // shadows attribute unrestricted double shadowOffsetX; diff --git a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc index d681b440b04..27c7198ff1f 100644 --- a/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc +++ b/chromium/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc @@ -95,8 +95,7 @@ PermissionService* ClipboardPromise::GetPermissionService() { } bool ClipboardPromise::IsFocusedDocument(ExecutionContext* context) { - DCHECK(context->IsDocument()); - Document* doc = ToDocumentOrNull(context); + Document* doc = To<Document>(context); return doc && doc->hasFocus(); } @@ -182,8 +181,8 @@ void ClipboardPromise::HandleReadTextWithPermission(PermissionStatus status) { // TODO(garykac): This currently only handles plain text. void ClipboardPromise::HandleWrite(DataTransfer* data) { // Scan DataTransfer and extract data types that we support. - size_t num_items = data->items()->length(); - for (unsigned long i = 0; i < num_items; i++) { + uint32_t num_items = data->items()->length(); + for (uint32_t i = 0; i < num_items; i++) { DataTransferItem* item = data->items()->item(i); DataObjectItem* objectItem = item->GetDataObjectItem(); if (objectItem->Kind() == DataObjectItem::kStringKind && diff --git a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.cc b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.cc index 9dc633c5e85..d3a45bab3ea 100644 --- a/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.cc +++ b/chromium/third_party/blink/renderer/modules/cookie_store/cookie_store.cc @@ -195,10 +195,8 @@ void ToCookieChangeSubscription( const KURL& DefaultCookieURL(ExecutionContext* execution_context) { DCHECK(execution_context); - if (execution_context->IsDocument()) { - Document* document = ToDocument(execution_context); + if (auto* document = DynamicTo<Document>(execution_context)) return document->CookieURL(); - } DCHECK(execution_context->IsServiceWorkerGlobalScope()); ServiceWorkerGlobalScope* scope = @@ -209,10 +207,8 @@ const KURL& DefaultCookieURL(ExecutionContext* execution_context) { KURL DefaultSiteForCookies(ExecutionContext* execution_context) { DCHECK(execution_context); - if (execution_context->IsDocument()) { - Document* document = ToDocument(execution_context); + if (auto* document = DynamicTo<Document>(execution_context)) return document->SiteForCookies(); - } DCHECK(execution_context->IsServiceWorkerGlobalScope()); ServiceWorkerGlobalScope* scope = diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.cc index 39b513ca069..e7b9e67b932 100644 --- a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.cc +++ b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.cc @@ -4,23 +4,37 @@ #include "third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.h" +#include "third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h" + namespace blink { AuthenticatorAttestationResponse* AuthenticatorAttestationResponse::Create( DOMArrayBuffer* client_data_json, - DOMArrayBuffer* attestation_object) { - return new AuthenticatorAttestationResponse(client_data_json, - attestation_object); + DOMArrayBuffer* attestation_object, + Vector<mojom::AuthenticatorTransport> transports) { + return new AuthenticatorAttestationResponse( + client_data_json, attestation_object, std::move(transports)); } AuthenticatorAttestationResponse::AuthenticatorAttestationResponse( DOMArrayBuffer* client_data_json, - DOMArrayBuffer* attestation_object) + DOMArrayBuffer* attestation_object, + Vector<mojom::AuthenticatorTransport> transports) : AuthenticatorResponse(client_data_json), - attestation_object_(attestation_object) {} + attestation_object_(attestation_object), + transports_(std::move(transports)) {} AuthenticatorAttestationResponse::~AuthenticatorAttestationResponse() = default; +Vector<String> AuthenticatorAttestationResponse::getTransports() const { + Vector<String> ret; + for (auto transport : transports_) { + ret.emplace_back(mojo::ConvertTo<String>(transport)); + } + std::sort(ret.begin(), ret.end(), WTF::CodePointCompareLessThan); + return ret; +} + void AuthenticatorAttestationResponse::Trace(blink::Visitor* visitor) { visitor->Trace(attestation_object_); AuthenticatorResponse::Trace(visitor); diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.h b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.h index 5ca9d3f2741..c0ffb0cb22d 100644 --- a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.h +++ b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.h @@ -5,10 +5,13 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CREDENTIALMANAGER_AUTHENTICATOR_ATTESTATION_RESPONSE_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_CREDENTIALMANAGER_AUTHENTICATOR_ATTESTATION_RESPONSE_H_ +#include "third_party/blink/public/platform/modules/webauthn/authenticator.mojom-blink.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" #include "third_party/blink/renderer/modules/credentialmanager/authenticator_response.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { @@ -19,7 +22,8 @@ class MODULES_EXPORT AuthenticatorAttestationResponse final public: static AuthenticatorAttestationResponse* Create( DOMArrayBuffer* client_data_json, - DOMArrayBuffer* attestation_object); + DOMArrayBuffer* attestation_object, + Vector<mojom::AuthenticatorTransport> transports); ~AuthenticatorAttestationResponse() override; @@ -27,13 +31,18 @@ class MODULES_EXPORT AuthenticatorAttestationResponse final return attestation_object_.Get(); } + Vector<String> getTransports() const; + void Trace(blink::Visitor*) override; private: - explicit AuthenticatorAttestationResponse(DOMArrayBuffer* client_data_json, - DOMArrayBuffer* attestation_object); + AuthenticatorAttestationResponse( + DOMArrayBuffer* client_data_json, + DOMArrayBuffer* attestation_object, + Vector<mojom::AuthenticatorTransport> transports); const Member<DOMArrayBuffer> attestation_object_; + const Vector<mojom::AuthenticatorTransport> transports_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.idl b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.idl index 4205aeddb31..980b705aaca 100644 --- a/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.idl +++ b/chromium/third_party/blink/renderer/modules/credentialmanager/authenticator_attestation_response.idl @@ -10,4 +10,5 @@ Exposed=Window ] interface AuthenticatorAttestationResponse : AuthenticatorResponse { [SameObject] readonly attribute ArrayBuffer attestationObject; + [RuntimeEnabled=WebAuthGetTransports] sequence<AuthenticatorTransport> getTransports(); }; diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.cc index 9d34774512e..aa6950e46b3 100644 --- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.cc +++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.cc @@ -12,8 +12,8 @@ namespace blink { -CredentialManagerProxy::CredentialManagerProxy(Document* document) { - LocalFrame* frame = document->GetFrame(); +CredentialManagerProxy::CredentialManagerProxy(Document& document) { + LocalFrame* frame = document.GetFrame(); DCHECK(frame); frame->GetInterfaceProvider().GetInterface(&credential_manager_); frame->GetInterfaceProvider().GetInterface( @@ -23,13 +23,12 @@ CredentialManagerProxy::CredentialManagerProxy(Document* document) { CredentialManagerProxy::~CredentialManagerProxy() {} // static -CredentialManagerProxy* CredentialManagerProxy::From(Document* document) { - DCHECK(document); +CredentialManagerProxy* CredentialManagerProxy::From(Document& document) { auto* supplement = Supplement<Document>::From<CredentialManagerProxy>(document); if (!supplement) { supplement = new CredentialManagerProxy(document); - ProvideTo(*document, supplement); + ProvideTo(document, supplement); } return supplement; } @@ -38,7 +37,7 @@ CredentialManagerProxy* CredentialManagerProxy::From(Document* document) { CredentialManagerProxy* CredentialManagerProxy::From( ScriptState* script_state) { DCHECK(script_state->ContextIsValid()); - return From(ToDocumentOrNull(ExecutionContext::From(script_state))); + return From(To<Document>(*ExecutionContext::From(script_state))); } // static diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h index 5d9c7b68b00..ff96bb62a3d 100644 --- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h +++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h @@ -35,7 +35,7 @@ class MODULES_EXPORT CredentialManagerProxy public: static const char kSupplementName[]; - explicit CredentialManagerProxy(Document*); + explicit CredentialManagerProxy(Document&); virtual ~CredentialManagerProxy(); mojom::blink::CredentialManager* CredentialManager() { @@ -51,7 +51,7 @@ class MODULES_EXPORT CredentialManagerProxy // Both flavors must be called only with arguments representing a valid // context corresponding to an attached Document. static CredentialManagerProxy* From(ScriptState*); - static CredentialManagerProxy* From(Document*); + static CredentialManagerProxy* From(Document&); private: mojom::blink::AuthenticatorPtr authenticator_; diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc index 54615eef0ef..2f3eb1f6f5a 100644 --- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc +++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc @@ -130,6 +130,9 @@ TypeConverter<CredentialManagerError, AuthenticatorStatus>::Convert( return CredentialManagerError::NOT_IMPLEMENTED; case blink::mojom::blink::AuthenticatorStatus::NOT_FOCUSED: return CredentialManagerError::NOT_FOCUSED; + case blink::mojom::blink::AuthenticatorStatus:: + RESIDENT_CREDENTIALS_UNSUPPORTED: + return CredentialManagerError::RESIDENT_CREDENTIALS_UNSUPPORTED; case blink::mojom::blink::AuthenticatorStatus::ALGORITHM_UNSUPPORTED: return CredentialManagerError::ANDROID_ALGORITHM_UNSUPPORTED; case blink::mojom::blink::AuthenticatorStatus::EMPTY_ALLOW_CREDENTIALS: @@ -211,6 +214,23 @@ AuthenticatorTransport TypeConverter<AuthenticatorTransport, String>::Convert( } // static +String TypeConverter<String, AuthenticatorTransport>::Convert( + const AuthenticatorTransport& transport) { + if (transport == AuthenticatorTransport::USB) + return "usb"; + if (transport == AuthenticatorTransport::NFC) + return "nfc"; + if (transport == AuthenticatorTransport::BLE) + return "ble"; + if (transport == AuthenticatorTransport::CABLE) + return "cable"; + if (transport == AuthenticatorTransport::INTERNAL) + return "internal"; + NOTREACHED(); + return "usb"; +} + +// static UserVerificationRequirement TypeConverter<UserVerificationRequirement, String>::Convert( const String& requirement) { diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h index 987e102a7ad..7da3e65c514 100644 --- a/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h +++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h @@ -66,6 +66,11 @@ struct TypeConverter<blink::mojom::blink::AuthenticatorTransport, String> { }; template <> +struct TypeConverter<String, blink::mojom::blink::AuthenticatorTransport> { + static String Convert(const blink::mojom::blink::AuthenticatorTransport&); +}; + +template <> struct TypeConverter<blink::mojom::blink::UserVerificationRequirement, String> { static blink::mojom::blink::UserVerificationRequirement Convert( const String&); diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc index 863f1fd71b0..4daa0598c63 100644 --- a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc +++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc @@ -241,6 +241,11 @@ DOMException* CredentialManagerErrorToDOMException( return DOMException::Create(DOMExceptionCode::kNotAllowedError, "The operation is not allowed at this time " "because the page does not have focus."); + case CredentialManagerError::RESIDENT_CREDENTIALS_UNSUPPORTED: + return DOMException::Create(DOMExceptionCode::kNotSupportedError, + "Resident credentials or empty " + "'allowCredentials' lists are not supported " + "at this time."); case CredentialManagerError::ANDROID_ALGORITHM_UNSUPPORTED: return DOMException::Create(DOMExceptionCode::kNotSupportedError, "None of the algorithms specified in " @@ -335,8 +340,8 @@ void OnMakePublicKeyCredentialComplete( DOMArrayBuffer* attestation_buffer = VectorToDOMArrayBuffer(std::move(credential->attestation_object)); AuthenticatorAttestationResponse* authenticator_response = - AuthenticatorAttestationResponse::Create(client_data_buffer, - attestation_buffer); + AuthenticatorAttestationResponse::Create( + client_data_buffer, attestation_buffer, credential->transports); resolver->Resolve(PublicKeyCredential::Create(credential->info->id, raw_id, authenticator_response, {} /* extensions_outputs */)); diff --git a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc index 2e8d07119b7..2f86f686c2f 100644 --- a/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc +++ b/chromium/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc @@ -148,7 +148,7 @@ TEST(CredentialsContainerTest, MockCredentialManager mock_credential_manager; CredentialManagerTestingContext context(&mock_credential_manager); - auto* proxy = CredentialManagerProxy::From(context.GetDocument()); + auto* proxy = CredentialManagerProxy::From(*context.GetDocument()); auto promise = CredentialsContainer::Create()->get( context.GetScriptState(), CredentialRequestOptions()); mock_credential_manager.WaitForCallToGet(); diff --git a/chromium/third_party/blink/renderer/modules/crypto/crypto_key.cc b/chromium/third_party/blink/renderer/modules/crypto/crypto_key.cc index 6a37e560b13..8d2319a5a68 100644 --- a/chromium/third_party/blink/renderer/modules/crypto/crypto_key.cc +++ b/chromium/third_party/blink/renderer/modules/crypto/crypto_key.cc @@ -38,6 +38,7 @@ #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/to_v8.h" #include "third_party/blink/renderer/platform/crypto_result.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" namespace blink { @@ -122,7 +123,8 @@ class DictionaryBuilder : public WebCryptoKeyAlgorithmDictionary { void SetUint8Array(const char* property_name, const WebVector<unsigned char>& vector) override { builder_.Add(property_name, - DOMUint8Array::Create(vector.Data(), vector.size())); + DOMUint8Array::Create(vector.Data(), + SafeCast<wtf_size_t>(vector.size()))); } private: @@ -227,7 +229,7 @@ bool CryptoKey::ParseUsageMask(const Vector<String>& usages, WebCryptoKeyUsageMask& mask, CryptoResult* result) { mask = 0; - for (size_t i = 0; i < usages.size(); ++i) { + for (wtf_size_t i = 0; i < usages.size(); ++i) { WebCryptoKeyUsageMask usage = KeyUsageStringToMask(usages[i]); if (!usage) { result->CompleteWithError(kWebCryptoErrorTypeType, diff --git a/chromium/third_party/blink/renderer/modules/crypto/normalize_algorithm.cc b/chromium/third_party/blink/renderer/modules/crypto/normalize_algorithm.cc index 013cfada404..ab0355a47e7 100644 --- a/chromium/third_party/blink/renderer/modules/crypto/normalize_algorithm.cc +++ b/chromium/third_party/blink/renderer/modules/crypto/normalize_algorithm.cc @@ -228,17 +228,18 @@ class ErrorContext { return String(); StringBuilder result; - const char* separator = ": "; + constexpr const char* separator = ": "; - size_t length = (messages_.size() - 1) * strlen(separator); - for (size_t i = 0; i < messages_.size(); ++i) + wtf_size_t length = (messages_.size() - 1) * strlen(separator); + for (wtf_size_t i = 0; i < messages_.size(); ++i) length += strlen(messages_[i]); result.ReserveCapacity(length); - for (size_t i = 0; i < messages_.size(); ++i) { + for (wtf_size_t i = 0; i < messages_.size(); ++i) { if (i) result.Append(separator, strlen(separator)); - result.Append(messages_[i], strlen(messages_[i])); + result.Append(messages_[i], + static_cast<wtf_size_t>(strlen(messages_[i]))); } return result.ToString(); diff --git a/chromium/third_party/blink/renderer/modules/csspaint/css_paint_definition.cc b/chromium/third_party/blink/renderer/modules/csspaint/css_paint_definition.cc index 4ab1a291ccd..ffd88e09052 100644 --- a/chromium/third_party/blink/renderer/modules/csspaint/css_paint_definition.cc +++ b/chromium/third_party/blink/renderer/modules/csspaint/css_paint_definition.cc @@ -80,7 +80,7 @@ scoped_refptr<Image> CSSPaintDefinition::Paint( MaybeCreatePaintInstance(); v8::Isolate* isolate = script_state_->GetIsolate(); - v8::Local<v8::Object> instance = instance_.NewLocal(isolate); + v8::Local<v8::Value> instance = instance_.NewLocal(isolate); // We may have failed to create an instance class, in which case produce an // invalid image. @@ -144,11 +144,11 @@ void CSSPaintDefinition::MaybeCreatePaintInstance() { v8::Local<v8::Function> constructor = constructor_.NewLocal(isolate); DCHECK(!IsUndefinedOrNull(constructor)); - v8::Local<v8::Object> paint_instance; - if (V8ObjectConstructor::NewInstance(isolate, constructor) - .ToLocal(&paint_instance)) { + v8::Local<v8::Value> paint_instance; + if (V8ScriptRunner::CallAsConstructor( + isolate, constructor, ExecutionContext::From(script_state_), 0, {}) + .ToLocal(&paint_instance)) instance_.Set(isolate, paint_instance); - } did_call_constructor_ = true; } @@ -156,7 +156,7 @@ void CSSPaintDefinition::MaybeCreatePaintInstance() { void CSSPaintDefinition::Trace(Visitor* visitor) { visitor->Trace(constructor_.Cast<v8::Value>()); visitor->Trace(paint_.Cast<v8::Value>()); - visitor->Trace(instance_.Cast<v8::Value>()); + visitor->Trace(instance_); visitor->Trace(script_state_); } diff --git a/chromium/third_party/blink/renderer/modules/csspaint/css_paint_definition.h b/chromium/third_party/blink/renderer/modules/csspaint/css_paint_definition.h index dede4c7bf87..4622a7b84a1 100644 --- a/chromium/third_party/blink/renderer/modules/csspaint/css_paint_definition.h +++ b/chromium/third_party/blink/renderer/modules/csspaint/css_paint_definition.h @@ -97,7 +97,7 @@ class MODULES_EXPORT CSSPaintDefinition final TraceWrapperV8Reference<v8::Function> paint_; // At the moment there is only ever one instance of a paint class per type. - TraceWrapperV8Reference<v8::Object> instance_; + TraceWrapperV8Reference<v8::Value> instance_; bool did_call_constructor_; diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl b/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl index 7d69e7685fb..e7f43a5a2d2 100644 --- a/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl +++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl @@ -36,7 +36,7 @@ attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (default black) CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1); [RaisesException] CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1); - [CallWith=ScriptState, RaisesException] CanvasPattern? createPattern(CanvasImageSource image, [TreatNullAs=NullString] DOMString repetitionType); + [CallWith=ScriptState, RaisesException] CanvasPattern? createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetitionType); // shadows attribute unrestricted double shadowOffsetX; diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc index 0095e149001..b668a6f2623 100644 --- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc +++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet.cc @@ -124,7 +124,7 @@ bool PaintWorklet::NeedsToCreateGlobalScope() { WorkletGlobalScopeProxy* PaintWorklet::CreateGlobalScope() { DCHECK(NeedsToCreateGlobalScope()); return new PaintWorkletGlobalScopeProxy( - ToDocument(GetExecutionContext())->GetFrame(), ModuleResponsesMap(), + To<Document>(GetExecutionContext())->GetFrame(), ModuleResponsesMap(), pending_generator_registry_, GetNumberOfGlobalScopes() + 1); } diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc index 69116afaa98..7e2bbcf3193 100644 --- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc +++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc @@ -111,9 +111,7 @@ PaintWorkletGlobalScope::PaintWorkletGlobalScope( std::unique_ptr<GlobalScopeCreationParams> creation_params, WorkerReportingProxy& reporting_proxy, PaintWorkletPendingGeneratorRegistry* pending_generator_registry) - : MainThreadWorkletGlobalScope(frame, - std::move(creation_params), - reporting_proxy), + : WorkletGlobalScope(std::move(creation_params), reporting_proxy, frame), pending_generator_registry_(pending_generator_registry) {} PaintWorkletGlobalScope::~PaintWorkletGlobalScope() = default; @@ -121,9 +119,8 @@ PaintWorkletGlobalScope::~PaintWorkletGlobalScope() = default; void PaintWorkletGlobalScope::Dispose() { MainThreadDebugger::Instance()->ContextWillBeDestroyed( ScriptController()->GetScriptState()); - pending_generator_registry_ = nullptr; - MainThreadWorkletGlobalScope::Dispose(); + WorkletGlobalScope::Dispose(); } void PaintWorkletGlobalScope::registerPaint( @@ -230,7 +227,7 @@ double PaintWorkletGlobalScope::devicePixelRatio() const { void PaintWorkletGlobalScope::Trace(blink::Visitor* visitor) { visitor->Trace(paint_definitions_); visitor->Trace(pending_generator_registry_); - MainThreadWorkletGlobalScope::Trace(visitor); + WorkletGlobalScope::Trace(visitor); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.h b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.h index 1817e5dfc8b..6bd200d8dde 100644 --- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.h +++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.h @@ -7,7 +7,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" -#include "third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.h" +#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" #include "third_party/blink/renderer/modules/csspaint/paint_worklet_pending_generator_registry.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" @@ -18,8 +18,7 @@ class CSSPaintDefinition; class ExceptionState; class WorkerReportingProxy; -class MODULES_EXPORT PaintWorkletGlobalScope final - : public MainThreadWorkletGlobalScope { +class MODULES_EXPORT PaintWorkletGlobalScope final : public WorkletGlobalScope { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(PaintWorkletGlobalScope); diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc index c3da5aac23f..d4c9ec466ab 100644 --- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc +++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.cc @@ -73,7 +73,7 @@ void PaintWorkletGlobalScopeProxy::WorkletObjectDestroyed() { void PaintWorkletGlobalScopeProxy::TerminateWorkletGlobalScope() { DCHECK(IsMainThread()); - global_scope_->Terminate(); + global_scope_->Dispose(); // Nullify these fields to cut a potential reference cycle. global_scope_ = nullptr; reporting_proxy_.reset(); diff --git a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_test.cc b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_test.cc index a9f8c45c0bc..a58249d1bd6 100644 --- a/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_test.cc +++ b/chromium/third_party/blink/renderer/modules/csspaint/paint_worklet_test.cc @@ -106,7 +106,8 @@ class PaintWorkletTest : public PageTestBase { TEST_F(PaintWorkletTest, GarbageCollectionOfCSSPaintDefinition) { PaintWorkletGlobalScope* global_scope = GetProxy()->global_scope(); global_scope->ScriptController()->Evaluate( - ScriptSourceCode("registerPaint('foo', class { paint() { } });")); + ScriptSourceCode("registerPaint('foo', class { paint() { } });"), + kSharableCrossOrigin); CSSPaintDefinition* definition = global_scope->FindDefinition("foo"); DCHECK(definition); @@ -147,7 +148,8 @@ TEST_F(PaintWorkletTest, GarbageCollectionOfCSSPaintDefinition) { TEST_F(PaintWorkletTest, PaintWithNullPaintArguments) { PaintWorkletGlobalScope* global_scope = GetProxy()->global_scope(); global_scope->ScriptController()->Evaluate( - ScriptSourceCode("registerPaint('foo', class { paint() { } });")); + ScriptSourceCode("registerPaint('foo', class { paint() { } });"), + kSharableCrossOrigin); CSSPaintDefinition* definition = global_scope->FindDefinition("foo"); ASSERT_TRUE(definition); @@ -168,7 +170,8 @@ TEST_F(PaintWorkletTest, PaintWithNullPaintArguments) { TEST_F(PaintWorkletTest, SinglyRegisteredDocumentDefinitionNotUsed) { PaintWorkletGlobalScope* global_scope = GetProxy()->global_scope(); global_scope->ScriptController()->Evaluate( - ScriptSourceCode("registerPaint('foo', class { paint() { } });")); + ScriptSourceCode("registerPaint('foo', class { paint() { } });"), + kSharableCrossOrigin); CSSPaintImageGeneratorImpl* generator = static_cast<CSSPaintImageGeneratorImpl*>( diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_controller.cc b/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_controller.cc index 01c1ade0c72..4e4431be7aa 100644 --- a/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_controller.cc +++ b/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_controller.cc @@ -92,12 +92,12 @@ void DeviceMotionController::RegisterWithDispatcher() { frame->GetTaskRunner(TaskType::kSensor); motion_event_pump_ = new DeviceMotionEventPump(task_runner); } - motion_event_pump_->AddController(this); + motion_event_pump_->SetController(this); } void DeviceMotionController::UnregisterWithDispatcher() { if (motion_event_pump_) - motion_event_pump_->RemoveController(this); + motion_event_pump_->RemoveController(); } Event* DeviceMotionController::LastEvent() const { diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump.cc b/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump.cc index 0ef859cca95..47deaede78a 100644 --- a/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump.cc +++ b/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump.cc @@ -4,9 +4,12 @@ #include <cmath> +#include "base/auto_reset.h" #include "services/device/public/mojom/sensor.mojom-blink.h" #include "services/service_manager/public/cpp/interface_provider.h" +#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/core/frame/platform_event_controller.h" #include "third_party/blink/renderer/modules/device_orientation/device_motion_data.h" #include "third_party/blink/renderer/modules/device_orientation/device_motion_event_pump.h" #include "ui/gfx/geometry/angle_conversions.h" @@ -33,13 +36,28 @@ DeviceMotionEventPump::~DeviceMotionEventPump() { StopIfObserving(); } +void DeviceMotionEventPump::SetController(PlatformEventController* controller) { + DCHECK(controller); + DCHECK(!controller_); + + controller_ = controller; + StartListening(controller_->GetDocument() + ? controller_->GetDocument()->GetFrame() + : nullptr); +} + +void DeviceMotionEventPump::RemoveController() { + controller_ = nullptr; + StopListening(); +} + DeviceMotionData* DeviceMotionEventPump::LatestDeviceMotionData() { return data_.Get(); } void DeviceMotionEventPump::Trace(blink::Visitor* visitor) { visitor->Trace(data_); - PlatformEventDispatcher::Trace(visitor); + visitor->Trace(controller_); } void DeviceMotionEventPump::StartListening(LocalFrame* frame) { @@ -81,13 +99,18 @@ void DeviceMotionEventPump::SendStopMessage() { gyroscope_.Stop(); } +void DeviceMotionEventPump::NotifyController() { + DCHECK(controller_); + controller_->DidUpdateData(); +} + void DeviceMotionEventPump::FireEvent(TimerBase*) { DeviceMotionData* data = GetDataFromSharedMemory(); // data is null if not all sensors are active if (data) { data_ = data; - NotifyControllers(); + NotifyController(); } } diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump.h b/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump.h index 751d5660bc3..b9f30170d1e 100644 --- a/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump.h +++ b/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump.h @@ -6,7 +6,6 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_DEVICE_ORIENTATION_DEVICE_MOTION_EVENT_PUMP_H_ #include "base/macros.h" -#include "third_party/blink/renderer/core/frame/platform_event_dispatcher.h" #include "third_party/blink/renderer/modules/device_orientation/device_sensor_event_pump.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/heap/handle.h" @@ -14,21 +13,22 @@ namespace blink { class DeviceMotionData; +class PlatformEventController; class MODULES_EXPORT DeviceMotionEventPump : public GarbageCollectedFinalized<DeviceMotionEventPump>, - public DeviceSensorEventPump, - public PlatformEventDispatcher { - USING_GARBAGE_COLLECTED_MIXIN(DeviceMotionEventPump); - + public DeviceSensorEventPump { public: explicit DeviceMotionEventPump(scoped_refptr<base::SingleThreadTaskRunner>); ~DeviceMotionEventPump() override; + void SetController(PlatformEventController*); + void RemoveController(); + // Note that the returned object is owned by this class. DeviceMotionData* LatestDeviceMotionData(); - void Trace(blink::Visitor*) override; + void Trace(blink::Visitor*); // DeviceSensorEventPump: void SendStartMessage(LocalFrame* frame) override; @@ -45,9 +45,9 @@ class MODULES_EXPORT DeviceMotionEventPump private: friend class DeviceMotionEventPumpTest; - // Inherited from PlatformEventDispatcher. - void StartListening(LocalFrame*) override; - void StopListening() override; + void StartListening(LocalFrame*); + void StopListening(); + void NotifyController(); // DeviceSensorEventPump: bool SensorsReadyOrErrored() const override; @@ -55,6 +55,7 @@ class MODULES_EXPORT DeviceMotionEventPump DeviceMotionData* GetDataFromSharedMemory(); Member<DeviceMotionData> data_; + WeakMember<PlatformEventController> controller_; DISALLOW_COPY_AND_ASSIGN(DeviceMotionEventPump); }; diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump_unittest.cc b/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump_unittest.cc index a9d5238ec33..3001690cdc5 100644 --- a/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump_unittest.cc +++ b/chromium/third_party/blink/renderer/modules/device_orientation/device_motion_event_pump_unittest.cc @@ -46,13 +46,11 @@ class MockDeviceMotionController final int number_of_events() const { return number_of_events_; } - void RegisterWithDispatcher() override { motion_pump_->AddController(this); } + void RegisterWithDispatcher() override { motion_pump_->SetController(this); } bool HasLastData() override { return motion_pump_->LatestDeviceMotionData(); } - void UnregisterWithDispatcher() override { - motion_pump_->RemoveController(this); - } + void UnregisterWithDispatcher() override { motion_pump_->RemoveController(); } const DeviceMotionData* data() { return motion_pump_->LatestDeviceMotionData(); diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_controller.cc b/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_controller.cc index 6df6db6ba2e..8e132701f9a 100644 --- a/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_controller.cc +++ b/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_controller.cc @@ -4,6 +4,7 @@ #include "third_party/blink/renderer/modules/device_orientation/device_orientation_controller.h" +#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/deprecation.h" @@ -15,7 +16,6 @@ #include "third_party/blink/renderer/modules/device_orientation/device_orientation_event.h" #include "third_party/blink/renderer/modules/device_orientation/device_orientation_event_pump.h" #include "third_party/blink/renderer/modules/event_modules.h" -#include "third_party/blink/renderer/platform/feature_policy/feature_policy.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_event_pump.cc b/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_event_pump.cc index 362f5c3f7d1..145c861b579 100644 --- a/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_event_pump.cc +++ b/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_event_pump.cc @@ -9,6 +9,7 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/modules/device_orientation/device_orientation_data.h" #include "third_party/blink/renderer/modules/device_orientation/device_orientation_event_pump.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" namespace { diff --git a/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_inspector_agent.cc b/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_inspector_agent.cc index 5e777aab9b4..217e50af7f3 100644 --- a/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_inspector_agent.cc +++ b/chromium/third_party/blink/renderer/modules/device_orientation/device_orientation_inspector_agent.cc @@ -20,7 +20,8 @@ DeviceOrientationInspectorAgent::~DeviceOrientationInspectorAgent() = default; DeviceOrientationInspectorAgent::DeviceOrientationInspectorAgent( InspectedFrames* inspected_frames) : inspected_frames_(inspected_frames), - sensor_agent_(new SensorInspectorAgent(inspected_frames->Root())), + sensor_agent_( + new SensorInspectorAgent(inspected_frames->Root()->GetDocument())), enabled_(&agent_state_, /*default_value=*/false), alpha_(&agent_state_, /*default_value=*/0.0), beta_(&agent_state_, /*default_value=*/0.0), @@ -79,6 +80,7 @@ void DeviceOrientationInspectorAgent::DidCommitLoadForLocalFrame( if (frame == inspected_frames_->Root()) { // New document in main frame - apply override there. // No need to cleanup previous one, as it's already gone. + sensor_agent_->DidCommitLoadForLocalFrame(frame); Restore(); } } diff --git a/chromium/third_party/blink/renderer/modules/document_metadata/copyless_paste_extractor.cc b/chromium/third_party/blink/renderer/modules/document_metadata/copyless_paste_extractor.cc index 2f8f53f7a33..0c91daa2cbb 100644 --- a/chromium/third_party/blink/renderer/modules/document_metadata/copyless_paste_extractor.cc +++ b/chromium/third_party/blink/renderer/modules/document_metadata/copyless_paste_extractor.cc @@ -47,9 +47,9 @@ constexpr int kMaxDepth = 4; // App Indexing supports strings up to length 20k. constexpr int kMaxStringLength = 200; // Enforced by App Indexing, so stop processing early if possible. -constexpr size_t kMaxNumFields = 20; +constexpr wtf_size_t kMaxNumFields = 20; // Enforced by App Indexing, so stop processing early if possible. -constexpr size_t kMaxRepeatedSize = 100; +constexpr wtf_size_t kMaxRepeatedSize = 100; constexpr char kJSONLDKeyType[] = "@type"; constexpr char kJSONLDKeyGraph[] = "@graph"; @@ -101,7 +101,7 @@ bool parseRepeatedValue(const JSONArray& arr, default: break; } - for (size_t j = 0; j < std::min(arr.size(), kMaxRepeatedSize); ++j) { + for (wtf_size_t j = 0; j < std::min(arr.size(), kMaxRepeatedSize); ++j) { const JSONValue* innerVal = arr.at(j); if (innerVal->GetType() != type) { // App Indexing doesn't support mixed types. If there are mixed @@ -157,7 +157,7 @@ void extractEntity(const JSONObject& val, Entity& entity, int recursionLevel) { type = "Thing"; } entity.type = type; - for (size_t i = 0; i < std::min(val.size(), kMaxNumFields); ++i) { + for (wtf_size_t i = 0; i < std::min(val.size(), kMaxNumFields); ++i) { PropertyPtr property = Property::New(); const JSONObject::Entry& entry = val.at(i); property->name = entry.first; diff --git a/chromium/third_party/blink/renderer/modules/encoding/BUILD.gn b/chromium/third_party/blink/renderer/modules/encoding/BUILD.gn index 62605ab9359..c89c50ed8be 100644 --- a/chromium/third_party/blink/renderer/modules/encoding/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/encoding/BUILD.gn @@ -10,7 +10,11 @@ blink_modules_sources("encoding") { "encoding.h", "text_decoder.cc", "text_decoder.h", + "text_decoder_stream.cc", + "text_decoder_stream.h", "text_encoder.cc", "text_encoder.h", + "text_encoder_stream.cc", + "text_encoder_stream.h", ] } diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.cc b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.cc new file mode 100644 index 00000000000..2c0fe8dcd47 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.cc @@ -0,0 +1,202 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/encoding/text_decoder_stream.h" + +#include <memory> +#include <utility> + +#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" +#include "third_party/blink/renderer/core/streams/retain_wrapper_during_construction.h" +#include "third_party/blink/renderer/core/streams/transform_stream_default_controller.h" +#include "third_party/blink/renderer/core/streams/transform_stream_transformer.h" +#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" +#include "third_party/blink/renderer/modules/encoding/encoding.h" +#include "third_party/blink/renderer/modules/encoding/text_decoder_options.h" +#include "third_party/blink/renderer/platform/bindings/exception_messages.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/bindings/to_v8.h" +#include "third_party/blink/renderer/platform/wtf/string_extras.h" +#include "third_party/blink/renderer/platform/wtf/text/text_codec.h" +#include "third_party/blink/renderer/platform/wtf/text/text_encoding.h" +#include "third_party/blink/renderer/platform/wtf/text/text_encoding_registry.h" + +namespace blink { + +class TextDecoderStream::Transformer final : public TransformStreamTransformer { + public: + explicit Transformer(ScriptState* script_state, + WTF::TextEncoding encoding, + bool fatal, + bool ignore_bom) + : decoder_(NewTextCodec(encoding)), + script_state_(script_state), + fatal_(fatal), + ignore_bom_(ignore_bom), + encoding_has_bom_removal_(EncodingHasBomRemoval(encoding)) {} + + // Implements the type conversion part of the "decode and enqueue a chunk" + // algorithm. + void Transform(v8::Local<v8::Value> chunk, + TransformStreamDefaultController* controller, + ExceptionState& exception_state) override { + ArrayBufferOrArrayBufferView bufferSource; + V8ArrayBufferOrArrayBufferView::ToImpl( + script_state_->GetIsolate(), chunk, bufferSource, + UnionTypeConversionMode::kNotNullable, exception_state); + if (exception_state.HadException()) + return; + + // This implements the "get a copy of the bytes held by the buffer source" + // algorithm (https://heycam.github.io/webidl/#dfn-get-buffer-source-copy). + if (bufferSource.IsArrayBufferView()) { + const auto* view = bufferSource.GetAsArrayBufferView().View(); + // If IsDetachedBuffer(O), then throw a TypeError. + if (view->buffer()->IsNeutered()) { + exception_state.ThrowTypeError( + ExceptionMessages::FailedToConvertJSValue("BufferSource")); + return; + } + const char* start = static_cast<const char*>(view->BaseAddress()); + size_t length = view->byteLength(); + DecodeAndEnqueue(start, length, WTF::FlushBehavior::kDoNotFlush, + controller, exception_state); + return; + } + DCHECK(bufferSource.IsArrayBuffer()); + const auto* array_buffer = bufferSource.GetAsArrayBuffer(); + // If IsDetachedBuffer(O), then throw a TypeError. + if (array_buffer->IsNeutered()) { + exception_state.ThrowTypeError( + ExceptionMessages::FailedToConvertJSValue("BufferSource")); + return; + } + const char* start = static_cast<const char*>(array_buffer->Data()); + size_t length = array_buffer->ByteLength(); + DecodeAndEnqueue(start, length, WTF::FlushBehavior::kDoNotFlush, controller, + exception_state); + } + + // Implements the "encode and flush" algorithm. + void Flush(TransformStreamDefaultController* controller, + ExceptionState& exception_state) override { + DecodeAndEnqueue(nullptr, 0u, WTF::FlushBehavior::kDataEOF, controller, + exception_state); + } + + void Trace(Visitor* visitor) override { + visitor->Trace(script_state_); + TransformStreamTransformer::Trace(visitor); + } + + private: + // Implements the second part of "decode and enqueue a chunk" as well as the + // "flush and enqueue" algorithm. + void DecodeAndEnqueue(const char* start, + size_t length, + WTF::FlushBehavior flush, + TransformStreamDefaultController* controller, + ExceptionState& exception_state) { + const UChar kBOM = 0xFEFF; + + bool saw_error = false; + String outputChunk = + decoder_->Decode(start, length, flush, fatal_, saw_error); + + if (fatal_ && saw_error) { + exception_state.ThrowTypeError("The encoded data was not valid."); + return; + } + + if (outputChunk.IsEmpty()) + return; + + if (!ignore_bom_ && !bom_seen_) { + bom_seen_ = true; + if (encoding_has_bom_removal_ && outputChunk[0] == kBOM) { + outputChunk.Remove(0); + if (outputChunk.IsEmpty()) + return; + } + } + + controller->Enqueue(ToV8(outputChunk, script_state_), exception_state); + } + + static bool EncodingHasBomRemoval(const WTF::TextEncoding& encoding) { + String name(encoding.GetName()); + return name == "UTF-8" || name == "UTF-16LE" || name == "UTF-16BE"; + } + + std::unique_ptr<WTF::TextCodec> decoder_; + // There is no danger of ScriptState leaking across worlds because a + // TextDecoderStream can only be accessed from the world that created it. + Member<ScriptState> script_state_; + const bool fatal_; + const bool ignore_bom_; + const bool encoding_has_bom_removal_; + bool bom_seen_; + + DISALLOW_COPY_AND_ASSIGN(Transformer); +}; + +TextDecoderStream* TextDecoderStream::Create(ScriptState* script_state, + const String& label, + const TextDecoderOptions& options, + ExceptionState& exception_state) { + WTF::TextEncoding encoding( + label.StripWhiteSpace(&Encoding::IsASCIIWhiteSpace)); + // The replacement encoding is not valid, but the Encoding API also + // rejects aliases of the replacement encoding. + if (!encoding.IsValid() || + strcasecmp(encoding.GetName(), "replacement") == 0) { + exception_state.ThrowRangeError("The encoding label provided ('" + label + + "') is invalid."); + return nullptr; + } + + return new TextDecoderStream(script_state, encoding, options, + exception_state); +} + +TextDecoderStream::~TextDecoderStream() = default; + +String TextDecoderStream::encoding() const { + return String(encoding_.GetName()).LowerASCII(); +} + +ScriptValue TextDecoderStream::readable(ScriptState* script_state, + ExceptionState& exception_state) const { + return transform_->Readable(script_state, exception_state); +} + +ScriptValue TextDecoderStream::writable(ScriptState* script_state, + ExceptionState& exception_state) const { + return transform_->Writable(script_state, exception_state); +} + +void TextDecoderStream::Trace(Visitor* visitor) { + visitor->Trace(transform_); + ScriptWrappable::Trace(visitor); +} + +TextDecoderStream::TextDecoderStream(ScriptState* script_state, + const WTF::TextEncoding& encoding, + const TextDecoderOptions& options, + ExceptionState& exception_state) + : transform_(new TransformStream()), + encoding_(encoding), + fatal_(options.fatal()), + ignore_bom_(options.ignoreBOM()) { + if (!RetainWrapperDuringConstruction(this, script_state)) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "Cannot queue task to retain wrapper"); + return; + } + transform_->Init(new Transformer(script_state, encoding, fatal_, ignore_bom_), + script_state, exception_state); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.h b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.h new file mode 100644 index 00000000000..5bf4d10fd40 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.h @@ -0,0 +1,64 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ENCODING_TEXT_DECODER_STREAM_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_ENCODING_TEXT_DECODER_STREAM_H_ + +#include "third_party/blink/renderer/bindings/core/v8/script_value.h" +#include "third_party/blink/renderer/core/streams/transform_stream.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h" +#include "third_party/blink/renderer/platform/wtf/text/text_encoding.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace blink { + +class ExceptionState; +class ScriptState; +class TextDecoderOptions; +class Visitor; + +// Implements the TextDecoderStream interface as specified at +// https://encoding.spec.whatwg.org/#interface-textdecoderstream. +// Converts a stream of binary data in the form of BufferSource chunks to a +// stream of text data in the form of string chunks. After construction +// functionality is delegated to the owner TransformStream. +class TextDecoderStream final : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + static TextDecoderStream* Create(ScriptState*, + const String& label, + const TextDecoderOptions&, + ExceptionState&); + ~TextDecoderStream() override; + + // From text_decoder_stream.idl + String encoding() const; + bool fatal() const { return fatal_; } + bool ignoreBOM() const { return ignore_bom_; } + ScriptValue readable(ScriptState*, ExceptionState&) const; + ScriptValue writable(ScriptState*, ExceptionState&) const; + + void Trace(Visitor* visitor) override; + + private: + class Transformer; + + TextDecoderStream(ScriptState*, + const WTF::TextEncoding&, + const TextDecoderOptions&, + ExceptionState&); + + const TraceWrapperMember<TransformStream> transform_; + const WTF::TextEncoding encoding_; + const bool fatal_; + const bool ignore_bom_; + + DISALLOW_COPY_AND_ASSIGN(TextDecoderStream); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ENCODING_TEXT_DECODER_STREAM_H_ diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.idl b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.idl new file mode 100644 index 00000000000..cf5600ceb1e --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/encoding/text_decoder_stream.idl @@ -0,0 +1,19 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://encoding.spec.whatwg.org/#interface-textdecoderstream +[ + Exposed=(Window,Worker), + Constructor(optional DOMString label = "utf-8", optional TextDecoderOptions options), + ConstructorCallWith=ScriptState, + RaisesException=Constructor, + MeasureAs=TextDecoderStreamConstructor, + RuntimeEnabled=EncodingStreams +] interface TextDecoderStream { + readonly attribute DOMString encoding; + readonly attribute boolean fatal; + readonly attribute boolean ignoreBOM; + [CallWith=ScriptState, RaisesException] readonly attribute any readable; + [CallWith=ScriptState, RaisesException] readonly attribute any writable; +}; diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_encoder.cc b/chromium/third_party/blink/renderer/modules/encoding/text_encoder.cc index 81726d58ca0..3f9161f58db 100644 --- a/chromium/third_party/blink/renderer/modules/encoding/text_encoder.cc +++ b/chromium/third_party/blink/renderer/modules/encoding/text_encoder.cc @@ -67,10 +67,10 @@ NotShared<DOMUint8Array> TextEncoder::encode(const String& input) { // are present in the input. if (input.Is8Bit()) { result = codec_->Encode(input.Characters8(), input.length(), - WTF::kEntitiesForUnencodables); + WTF::kNoUnencodables); } else { result = codec_->Encode(input.Characters16(), input.length(), - WTF::kEntitiesForUnencodables); + WTF::kNoUnencodables); } const char* buffer = result.data(); diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.cc b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.cc new file mode 100644 index 00000000000..1c5aa8fa6e4 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.cc @@ -0,0 +1,200 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/encoding/text_encoder_stream.h" + +#include <stdint.h> +#include <string.h> + +#include <memory> +#include <utility> + +#include "base/optional.h" +#include "base/stl_util.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_string_resource.h" +#include "third_party/blink/renderer/core/streams/retain_wrapper_during_construction.h" +#include "third_party/blink/renderer/core/streams/transform_stream_default_controller.h" +#include "third_party/blink/renderer/core/streams/transform_stream_transformer.h" +#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/bindings/script_state.h" +#include "third_party/blink/renderer/platform/bindings/to_v8.h" +#include "third_party/blink/renderer/platform/wtf/text/cstring.h" +#include "third_party/blink/renderer/platform/wtf/text/text_codec.h" +#include "third_party/blink/renderer/platform/wtf/text/text_encoding.h" +#include "third_party/blink/renderer/platform/wtf/text/text_encoding_registry.h" +#include "v8/include/v8.h" + +namespace blink { + +class TextEncoderStream::Transformer final : public TransformStreamTransformer { + public: + explicit Transformer(ScriptState* script_state) + : encoder_(NewTextCodec(WTF::TextEncoding("utf-8"))), + script_state_(script_state) {} + + // Implements the "encode and enqueue a chunk" algorithm. For efficiency, only + // the characters at the end of chunks are special-cased. + void Transform(v8::Local<v8::Value> chunk, + TransformStreamDefaultController* controller, + ExceptionState& exception_state) override { + // Let |input| be the result of converting |chunk| to a DOMString. If this + // throws an exception, then return a promise rejected with that exception. + V8StringResource<> input_resource = chunk; + if (!input_resource.Prepare(script_state_->GetIsolate(), exception_state)) + return; + const String input = input_resource; + if (input.IsEmpty()) + return; + + const base::Optional<UChar> high_surrogate = pending_high_surrogate_; + pending_high_surrogate_ = base::nullopt; + CString prefix; + CString result; + if (input.Is8Bit()) { + if (high_surrogate.has_value()) { + // An 8-bit code unit can never be part of an astral character, so no + // check is needed. + prefix = ReplacementCharacterInUtf8(); + } + result = encoder_->Encode(input.Characters8(), input.length(), + WTF::kNoUnencodables); + } else { + bool have_output = + Encode16BitString(input, high_surrogate, &prefix, &result); + if (!have_output) + return; + } + + DOMUint8Array* array = + CreateDOMUint8ArrayFromTwoCStringsConcatenated(prefix, result); + controller->Enqueue(ToV8(array, script_state_), exception_state); + } + + // Implements the "encode and flush" algorithm. + void Flush(TransformStreamDefaultController* controller, + ExceptionState& exception_state) override { + if (!pending_high_surrogate_.has_value()) + return; + + const CString replacement_character = ReplacementCharacterInUtf8(); + const uint8_t* u8buffer = + reinterpret_cast<const uint8_t*>(replacement_character.data()); + controller->Enqueue( + ToV8(DOMUint8Array::Create(u8buffer, replacement_character.length()), + script_state_), + exception_state); + } + + void Trace(Visitor* visitor) override { + visitor->Trace(script_state_); + TransformStreamTransformer::Trace(visitor); + } + + private: + static CString ReplacementCharacterInUtf8() { + constexpr char kRawBytes[] = {0xEF, 0xBF, 0xBD}; + return CString(kRawBytes, sizeof(kRawBytes)); + } + + static DOMUint8Array* CreateDOMUint8ArrayFromTwoCStringsConcatenated( + const CString& string1, + const CString& string2) { + const size_t length1 = string1.length(); + const size_t length2 = string2.length(); + DOMUint8Array* const array = DOMUint8Array::Create(length1 + length2); + if (length1 > 0) + memcpy(array->Data(), string1.data(), length1); + if (length2 > 0) + memcpy(array->Data() + length1, string2.data(), length2); + return array; + } + + // Returns true if either |*prefix| or |*result| have been set to a non-empty + // value. + bool Encode16BitString(const String& input, + base::Optional<UChar> high_surrogate, + CString* prefix, + CString* result) { + const UChar* begin = input.Characters16(); + const UChar* end = input.Characters16() + input.length(); + DCHECK_GT(end, begin); + if (high_surrogate.has_value()) { + if (*begin >= 0xDC00 && *begin <= 0xDFFF) { + const UChar astral_character[2] = {high_surrogate.value(), *begin}; + // Third argument is ignored, as above. + *prefix = + encoder_->Encode(astral_character, base::size(astral_character), + WTF::kNoUnencodables); + ++begin; + if (begin == end) + return true; + } else { + *prefix = ReplacementCharacterInUtf8(); + } + } + + const UChar final_token = *(end - 1); + if (final_token >= 0xD800 && final_token <= 0xDBFF) { + pending_high_surrogate_ = final_token; + --end; + if (begin == end) + return prefix->length() != 0; + } + + // Third argument is ignored, as above. + *result = + encoder_->Encode(begin, end - begin, WTF::kEntitiesForUnencodables); + DCHECK_NE(result->length(), 0u); + return true; + } + + std::unique_ptr<WTF::TextCodec> encoder_; + // There is no danger of ScriptState leaking across worlds because a + // TextEncoderStream can only be accessed from the world that created it. + Member<ScriptState> script_state_; + base::Optional<UChar> pending_high_surrogate_; + + DISALLOW_COPY_AND_ASSIGN(Transformer); +}; + +TextEncoderStream* TextEncoderStream::Create(ScriptState* script_state, + ExceptionState& exception_state) { + return new TextEncoderStream(script_state, exception_state); +} + +TextEncoderStream::~TextEncoderStream() = default; + +String TextEncoderStream::encoding() const { + return "utf-8"; +} + +ScriptValue TextEncoderStream::readable(ScriptState* script_state, + ExceptionState& exception_state) const { + return transform_->Readable(script_state, exception_state); +} + +ScriptValue TextEncoderStream::writable(ScriptState* script_state, + ExceptionState& exception_state) const { + return transform_->Writable(script_state, exception_state); +} + +void TextEncoderStream::Trace(Visitor* visitor) { + visitor->Trace(transform_); + ScriptWrappable::Trace(visitor); +} + +TextEncoderStream::TextEncoderStream(ScriptState* script_state, + ExceptionState& exception_state) + : transform_(new TransformStream()) { + if (!RetainWrapperDuringConstruction(this, script_state)) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "Cannot queue task to retain wrapper"); + return; + } + transform_->Init(new Transformer(script_state), script_state, + exception_state); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.h b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.h new file mode 100644 index 00000000000..2aa28ddc7a4 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.h @@ -0,0 +1,51 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ENCODING_TEXT_ENCODER_STREAM_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_ENCODING_TEXT_ENCODER_STREAM_H_ + +#include "third_party/blink/renderer/bindings/core/v8/script_value.h" +#include "third_party/blink/renderer/core/streams/transform_stream.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace blink { + +class ExceptionState; +class ScriptState; +class Visitor; + +// Implements the TextDecoderStream interface as specified at +// https://encoding.spec.whatwg.org/#interface-textencoderstream. +// Converts a stream of text data in the form of string chunks to a stream of +// binary data in the form of UInt8Array chunks. After construction +// functionality is delegated to the owned TransformStream. +class TextEncoderStream final : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + static TextEncoderStream* Create(ScriptState*, ExceptionState&); + ~TextEncoderStream() override; + + // From text_encoder_stream.idl + String encoding() const; + ScriptValue readable(ScriptState*, ExceptionState&) const; + ScriptValue writable(ScriptState*, ExceptionState&) const; + + void Trace(Visitor* visitor) override; + + private: + class Transformer; + + TextEncoderStream(ScriptState*, ExceptionState&); + + const TraceWrapperMember<TransformStream> transform_; + + DISALLOW_COPY_AND_ASSIGN(TextEncoderStream); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ENCODING_TEXT_ENCODER_STREAM_H_ diff --git a/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.idl b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.idl new file mode 100644 index 00000000000..98ee518e622 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/encoding/text_encoder_stream.idl @@ -0,0 +1,17 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://encoding.spec.whatwg.org/#interface-textencoderstream +[ + Exposed=(Window,Worker), + Constructor(), + ConstructorCallWith=ScriptState, + RaisesException=Constructor, + MeasureAs=TextEncoderStreamConstructor, + RuntimeEnabled=EncodingStreams +] interface TextEncoderStream { + readonly attribute DOMString encoding; + [CallWith=ScriptState, RaisesException] readonly attribute any readable; + [CallWith=ScriptState, RaisesException] readonly attribute any writable; +}; diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys_controller.cc b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys_controller.cc index ef27221f757..959fa7196eb 100644 --- a/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys_controller.cc +++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/media_keys_controller.cc @@ -18,7 +18,7 @@ MediaKeysController::MediaKeysController() = default; WebEncryptedMediaClient* MediaKeysController::EncryptedMediaClient( ExecutionContext* context) { - Document* document = ToDocument(context); + Document* document = To<Document>(context); WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(document->GetFrame()); return web_frame->Client()->EncryptedMediaClient(); diff --git a/chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc b/chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc index 9a0acee798e..9f9702555d5 100644 --- a/chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc +++ b/chromium/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc @@ -19,6 +19,7 @@ #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/frame/deprecation.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/modules/encryptedmedia/encrypted_media_utils.h" #include "third_party/blink/renderer/modules/encryptedmedia/media_key_session.h" @@ -299,11 +300,10 @@ ScriptPromise NavigatorRequestMediaKeySystemAccess::requestMediaKeySystemAccess( DVLOG(3) << __func__; ExecutionContext* execution_context = ExecutionContext::From(script_state); - Document* document = ToDocument(execution_context); + Document* document = To<Document>(execution_context); - if (!document->GetFrame() || - !document->GetFrame()->IsFeatureEnabled( - mojom::FeaturePolicyFeature::kEncryptedMedia)) { + if (!document->IsFeatureEnabled(mojom::FeaturePolicyFeature::kEncryptedMedia, + ReportOptions::kReportOnFailure)) { UseCounter::Count(document, WebFeature::kEncryptedMediaDisabledByFeaturePolicy); document->AddConsoleMessage( diff --git a/chromium/third_party/blink/renderer/modules/event_target_modules_names.json5 b/chromium/third_party/blink/renderer/modules/event_target_modules_names.json5 index 65975c81c70..dc4b6094fd4 100644 --- a/chromium/third_party/blink/renderer/modules/event_target_modules_names.json5 +++ b/chromium/third_party/blink/renderer/modules/event_target_modules_names.json5 @@ -31,6 +31,8 @@ "modules/notifications/Notification", "modules/payments/PaymentRequest", "modules/peerconnection/RTCIceTransport", + "modules/peerconnection/RTCQuicStream", + "modules/peerconnection/RTCQuicTransport", "modules/permissions/PermissionStatus", "modules/picture_in_picture/HTMLVideoElementPictureInPicture", "modules/picture_in_picture/PictureInPictureWindow", @@ -41,6 +43,7 @@ "modules/remoteplayback/RemotePlayback", "modules/screen_orientation/ScreenOrientation", "modules/sensor/Sensor", + "modules/serial/Serial", "modules/service_worker/ServiceWorker", "modules/service_worker/ServiceWorkerContainer", "modules/service_worker/ServiceWorkerGlobalScope", @@ -57,6 +60,7 @@ "modules/webmidi/MIDIInput", "modules/webmidi/MIDIPort", "modules/xr/XR", + "modules/xr/XRCoordinateSystem", "modules/xr/XRSession", { name: "modules/websockets/WebSocket", diff --git a/chromium/third_party/blink/renderer/modules/eventsource/event_source.cc b/chromium/third_party/blink/renderer/modules/eventsource/event_source.cc index 8c68e3c1bd2..90eff457dd4 100644 --- a/chromium/third_party/blink/renderer/modules/eventsource/event_source.cc +++ b/chromium/third_party/blink/renderer/modules/eventsource/event_source.cc @@ -79,10 +79,9 @@ EventSource* EventSource::Create(ExecutionContext* context, const String& url, const EventSourceInit& event_source_init, ExceptionState& exception_state) { - if (context->IsDocument()) - UseCounter::Count(ToDocument(context), WebFeature::kEventSourceDocument); - else - UseCounter::Count(context, WebFeature::kEventSourceWorker); + UseCounter::Count(context, IsA<Document>(context) + ? WebFeature::kEventSourceDocument + : WebFeature::kEventSourceWorker); if (url.IsEmpty()) { exception_state.ThrowDOMException( @@ -127,7 +126,7 @@ void EventSource::Connect() { request.SetHTTPMethod(HTTPNames::GET); request.SetHTTPHeaderField(HTTPNames::Accept, "text/event-stream"); request.SetHTTPHeaderField(HTTPNames::Cache_Control, "no-cache"); - request.SetRequestContext(WebURLRequest::kRequestContextEventSource); + request.SetRequestContext(mojom::RequestContextType::EVENT_SOURCE); request.SetFetchRequestMode(network::mojom::FetchRequestMode::kCORS); request.SetFetchCredentialsMode( with_credentials_ ? network::mojom::FetchCredentialsMode::kInclude @@ -149,11 +148,8 @@ void EventSource::Connect() { last_event_id_utf8.length())); } - const SecurityOrigin* origin = execution_context.GetSecurityOrigin(); - ResourceLoaderOptions resource_loader_options; resource_loader_options.data_buffering_policy = kDoNotBufferData; - resource_loader_options.security_origin = origin; probe::willSendEventSourceRequest(&execution_context, this); loader_ = diff --git a/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser.cc b/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser.cc index dfca4c749a7..39b80f10bec 100644 --- a/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser.cc +++ b/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser.cc @@ -22,12 +22,12 @@ EventSourceParser::EventSourceParser(const AtomicString& last_event_id, client_(client), codec_(NewTextCodec(UTF8Encoding())) {} -void EventSourceParser::AddBytes(const char* bytes, size_t size) { +void EventSourceParser::AddBytes(const char* bytes, uint32_t size) { // A line consists of |m_line| followed by // |bytes[start..(next line break)]|. - size_t start = 0; + uint32_t start = 0; const unsigned char kBOM[] = {0xef, 0xbb, 0xbf}; - for (size_t i = 0; i < size && !is_stopped_; ++i) { + for (uint32_t i = 0; i < size && !is_stopped_; ++i) { // As kBOM contains neither CR nor LF, we can think BOM and the line // break separately. if (is_recognizing_bom_ && line_.size() + (i - start) == arraysize(kBOM)) { @@ -77,8 +77,8 @@ void EventSourceParser::ParseLine() { event_type_ = g_null_atom; return; } - size_t field_name_end = line_.Find(':'); - size_t field_value_start; + wtf_size_t field_name_end = line_.Find(':'); + wtf_size_t field_value_start; if (field_name_end == WTF::kNotFound) { field_name_end = line_.size(); field_value_start = field_name_end; @@ -88,7 +88,7 @@ void EventSourceParser::ParseLine() { ++field_value_start; } } - size_t field_value_size = line_.size() - field_value_start; + wtf_size_t field_value_size = line_.size() - field_value_start; String field_name = FromUTF8(line_.data(), field_name_end); if (field_name == "event") { event_type_ = AtomicString( @@ -109,7 +109,8 @@ void EventSourceParser::ParseLine() { } if (field_name == "retry") { bool has_only_digits = true; - for (size_t i = field_value_start; i < line_.size() && has_only_digits; ++i) + for (wtf_size_t i = field_value_start; i < line_.size() && has_only_digits; + ++i) has_only_digits = IsASCIIDigit(line_[i]); if (field_value_start == line_.size()) { client_->OnReconnectionTimeSet(EventSource::kDefaultReconnectDelay); @@ -126,7 +127,7 @@ void EventSourceParser::ParseLine() { // Unrecognized field name. Ignore! } -String EventSourceParser::FromUTF8(const char* bytes, size_t size) { +String EventSourceParser::FromUTF8(const char* bytes, uint32_t size) { return codec_->Decode(bytes, size, WTF::FlushBehavior::kDataEOF); } diff --git a/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser.h b/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser.h index 8c4ab1e72aa..e3eb4e08d8e 100644 --- a/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser.h +++ b/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser.h @@ -31,7 +31,7 @@ class MODULES_EXPORT EventSourceParser final EventSourceParser(const AtomicString& last_event_id, Client*); - void AddBytes(const char*, size_t); + void AddBytes(const char*, uint32_t); const AtomicString& LastEventId() const { return last_event_id_; } // Stop parsing. This can be called from Client::onMessageEvent. void Stop() { is_stopped_ = true; } @@ -39,7 +39,7 @@ class MODULES_EXPORT EventSourceParser final private: void ParseLine(); - String FromUTF8(const char* bytes, size_t); + String FromUTF8(const char* bytes, uint32_t); Vector<char> line_; diff --git a/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser_test.cc b/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser_test.cc index 5da6ce1918b..2370a04f252 100644 --- a/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser_test.cc +++ b/chromium/third_party/blink/renderer/modules/eventsource/event_source_parser_test.cc @@ -6,6 +6,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/modules/eventsource/event_source.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/text/character_names.h" #include <string.h> @@ -94,7 +95,9 @@ class EventSourceParserTest : public testing::Test { parser_(new EventSourceParser(AtomicString(), client_)) {} ~EventSourceParserTest() override = default; - void Enqueue(const char* data) { parser_->AddBytes(data, strlen(data)); } + void Enqueue(const char* data) { + parser_->AddBytes(data, static_cast<uint32_t>(strlen(data))); + } void EnqueueOneByOne(const char* data) { const char* p = data; while (*p != '\0') diff --git a/chromium/third_party/blink/renderer/modules/exported/web_ax_object.cc b/chromium/third_party/blink/renderer/modules/exported/web_ax_object.cc index 28a9aa8b13a..4f763635342 100644 --- a/chromium/third_party/blink/renderer/modules/exported/web_ax_object.cc +++ b/chromium/third_party/blink/renderer/modules/exported/web_ax_object.cc @@ -90,8 +90,7 @@ class WebAXSparseAttributeClientAdapter : public AXSparseAttributeClient { void AddObjectVectorAttribute(AXObjectVectorAttribute attribute, HeapVector<Member<AXObject>>& value) override { WebVector<WebAXObject> result(value.size()); - for (size_t i = 0; i < value.size(); i++) - result[i] = WebAXObject(value[i]); + std::copy(value.begin(), value.end(), result.begin()); attribute_map_.AddObjectVectorAttribute( static_cast<WebAXObjectVectorAttribute>(attribute), result); } @@ -156,11 +155,11 @@ bool WebAXObject::UpdateLayoutAndCheckValidity() { return !IsDetached(); } -WebAXDefaultActionVerb WebAXObject::Action() const { +ax::mojom::DefaultActionVerb WebAXObject::Action() const { if (IsDetached()) - return WebAXDefaultActionVerb::kNone; + return ax::mojom::DefaultActionVerb::kNone; - return static_cast<WebAXDefaultActionVerb>(private_->Action()); + return private_->Action(); } bool WebAXObject::CanPress() const { @@ -239,18 +238,18 @@ WebString WebAXObject::AriaAutoComplete() const { return private_->AriaAutoComplete(); } -WebAXAriaCurrentState WebAXObject::AriaCurrentState() const { +ax::mojom::AriaCurrentState WebAXObject::AriaCurrentState() const { if (IsDetached()) - return kWebAXAriaCurrentStateUndefined; + return ax::mojom::AriaCurrentState::kNone; - return static_cast<WebAXAriaCurrentState>(private_->GetAriaCurrentState()); + return private_->GetAriaCurrentState(); } -WebAXCheckedState WebAXObject::CheckedState() const { +ax::mojom::CheckedState WebAXObject::CheckedState() const { if (IsDetached()) - return kWebAXCheckedUndefined; + return ax::mojom::CheckedState::kNone; - return static_cast<WebAXCheckedState>(private_->CheckedState()); + return private_->CheckedState(); } bool WebAXObject::IsClickable() const { @@ -260,13 +259,6 @@ bool WebAXObject::IsClickable() const { return private_->IsClickable(); } -bool WebAXObject::IsCollapsed() const { - if (IsDetached()) - return false; - - return private_->IsCollapsed(); -} - bool WebAXObject::IsControl() const { if (IsDetached()) return false; @@ -428,11 +420,11 @@ WebAXObject WebAXObject::AriaActiveDescendant() const { return WebAXObject(private_->ActiveDescendant()); } -WebAXHasPopup WebAXObject::HasPopup() const { +ax::mojom::HasPopup WebAXObject::HasPopup() const { if (IsDetached()) - return kWebAXHasPopupFalse; + return ax::mojom::HasPopup::kFalse; - return static_cast<WebAXHasPopup>(private_->HasPopup()); + return private_->HasPopup(); } bool WebAXObject::IsEditableRoot() const { @@ -581,11 +573,11 @@ WebString WebAXObject::ImageDataUrl(const WebSize& max_size) const { return private_->ImageDataUrl(max_size); } -WebAXInvalidState WebAXObject::InvalidState() const { +ax::mojom::InvalidState WebAXObject::InvalidState() const { if (IsDetached()) - return kWebAXInvalidStateUndefined; + return ax::mojom::InvalidState::kNone; - return static_cast<WebAXInvalidState>(private_->GetInvalidState()); + return private_->GetInvalidState(); } // Only used when invalidState() returns WebAXInvalidStateOther. @@ -725,42 +717,53 @@ WebVector<WebAXObject> WebAXObject::RadioButtonsInGroup() const { AXObject::AXObjectVector radio_buttons = private_->RadioButtonsInGroup(); WebVector<WebAXObject> web_radio_buttons(radio_buttons.size()); - for (size_t i = 0; i < radio_buttons.size(); ++i) - web_radio_buttons[i] = WebAXObject(radio_buttons[i]); + std::copy(radio_buttons.begin(), radio_buttons.end(), + web_radio_buttons.begin()); return web_radio_buttons; } -WebAXRole WebAXObject::Role() const { +ax::mojom::Role WebAXObject::Role() const { if (IsDetached()) - return kWebAXRoleUnknown; + return ax::mojom::Role::kUnknown; - return static_cast<WebAXRole>(private_->RoleValue()); + return private_->RoleValue(); +} + +static ax::mojom::TextAffinity ToAXAffinity(TextAffinity affinity) { + switch (affinity) { + case TextAffinity::kUpstream: + return ax::mojom::TextAffinity::kUpstream; + case TextAffinity::kDownstream: + return ax::mojom::TextAffinity::kDownstream; + default: + NOTREACHED(); + return ax::mojom::TextAffinity::kDownstream; + } } void WebAXObject::Selection(WebAXObject& anchor_object, int& anchor_offset, - WebAXTextAffinity& anchor_affinity, + ax::mojom::TextAffinity& anchor_affinity, WebAXObject& focus_object, int& focus_offset, - WebAXTextAffinity& focus_affinity) const { + ax::mojom::TextAffinity& focus_affinity) const { if (IsDetached()) { anchor_object = WebAXObject(); anchor_offset = -1; - anchor_affinity = kWebAXTextAffinityDownstream; + anchor_affinity = ax::mojom::TextAffinity::kDownstream; focus_object = WebAXObject(); focus_offset = -1; - focus_affinity = kWebAXTextAffinityDownstream; + focus_affinity = ax::mojom::TextAffinity::kDownstream; return; } AXObject::AXSelection ax_selection = private_->Selection(); anchor_object = WebAXObject(ax_selection.anchor_object); anchor_offset = ax_selection.anchor_offset; - anchor_affinity = - static_cast<WebAXTextAffinity>(ax_selection.anchor_affinity); + anchor_affinity = ToAXAffinity(ax_selection.anchor_affinity); focus_object = WebAXObject(ax_selection.focus_object); focus_offset = ax_selection.focus_offset; - focus_affinity = static_cast<WebAXTextAffinity>(ax_selection.focus_affinity); + focus_affinity = ToAXAffinity(ax_selection.focus_affinity); return; } @@ -873,18 +876,18 @@ WebString WebAXObject::StringValue() const { return private_->StringValue(); } -WebAXTextDirection WebAXObject::GetTextDirection() const { +ax::mojom::TextDirection WebAXObject::GetTextDirection() const { if (IsDetached()) - return kWebAXTextDirectionLR; + return ax::mojom::TextDirection::kLtr; - return static_cast<WebAXTextDirection>(private_->GetTextDirection()); + return private_->GetTextDirection(); } -WebAXTextPosition WebAXObject::GetTextPosition() const { +ax::mojom::TextPosition WebAXObject::GetTextPosition() const { if (IsDetached()) - return kWebAXTextPositionNone; + return ax::mojom::TextPosition::kNone; - return static_cast<WebAXTextPosition>(private_->GetTextPosition()); + return private_->GetTextPosition(); } WebAXTextStyle WebAXObject::TextStyle() const { @@ -901,20 +904,19 @@ WebURL WebAXObject::Url() const { return private_->Url(); } -WebString WebAXObject::GetName(WebAXNameFrom& out_name_from, +WebString WebAXObject::GetName(ax::mojom::NameFrom& out_name_from, WebVector<WebAXObject>& out_name_objects) const { if (IsDetached()) return WebString(); - AXNameFrom name_from = kAXNameFromUninitialized; + ax::mojom::NameFrom name_from = ax::mojom::NameFrom::kUninitialized; HeapVector<Member<AXObject>> name_objects; WebString result = private_->GetName(name_from, &name_objects); - out_name_from = static_cast<WebAXNameFrom>(name_from); + out_name_from = name_from; - WebVector<WebAXObject> web_name_objects(name_objects.size()); - for (size_t i = 0; i < name_objects.size(); i++) - web_name_objects[i] = WebAXObject(name_objects[i]); - out_name_objects.Swap(web_name_objects); + out_name_objects.reserve(name_objects.size()); + out_name_objects.resize(name_objects.size()); + std::copy(name_objects.begin(), name_objects.end(), out_name_objects.begin()); return result; } @@ -923,37 +925,38 @@ WebString WebAXObject::GetName() const { if (IsDetached()) return WebString(); - AXNameFrom name_from; + ax::mojom::NameFrom name_from; HeapVector<Member<AXObject>> name_objects; return private_->GetName(name_from, &name_objects); } WebString WebAXObject::Description( - WebAXNameFrom name_from, - WebAXDescriptionFrom& out_description_from, + ax::mojom::NameFrom name_from, + ax::mojom::DescriptionFrom& out_description_from, WebVector<WebAXObject>& out_description_objects) const { if (IsDetached()) return WebString(); - AXDescriptionFrom description_from = kAXDescriptionFromUninitialized; + ax::mojom::DescriptionFrom description_from = + ax::mojom::DescriptionFrom::kUninitialized; HeapVector<Member<AXObject>> description_objects; - String result = private_->Description(static_cast<AXNameFrom>(name_from), - description_from, &description_objects); - out_description_from = static_cast<WebAXDescriptionFrom>(description_from); + String result = + private_->Description(name_from, description_from, &description_objects); + out_description_from = description_from; - WebVector<WebAXObject> web_description_objects(description_objects.size()); - for (size_t i = 0; i < description_objects.size(); i++) - web_description_objects[i] = WebAXObject(description_objects[i]); - out_description_objects.Swap(web_description_objects); + out_description_objects.reserve(description_objects.size()); + out_description_objects.resize(description_objects.size()); + std::copy(description_objects.begin(), description_objects.end(), + out_description_objects.begin()); return result; } -WebString WebAXObject::Placeholder(WebAXNameFrom name_from) const { +WebString WebAXObject::Placeholder(ax::mojom::NameFrom name_from) const { if (IsDetached()) return WebString(); - return private_->Placeholder(static_cast<AXNameFrom>(name_from)); + return private_->Placeholder(name_from); } bool WebAXObject::SupportsRangeValue() const { @@ -1071,13 +1074,7 @@ bool WebAXObject::LineBreaks(WebVector<int>& result) const { Vector<int> line_breaks_vector; private_->LineBreaks(line_breaks_vector); - - size_t vector_size = line_breaks_vector.size(); - WebVector<int> line_breaks_web_vector(vector_size); - for (size_t i = 0; i < vector_size; i++) - line_breaks_web_vector[i] = line_breaks_vector[i]; - result.Swap(line_breaks_web_vector); - + result = line_breaks_vector; return true; } @@ -1164,21 +1161,16 @@ void WebAXObject::RowHeaders( AXObject::AXObjectVector headers; private_->RowHeaders(headers); - - size_t header_count = headers.size(); - WebVector<WebAXObject> result(header_count); - - for (size_t i = 0; i < header_count; i++) - result[i] = WebAXObject(headers[i]); - - row_header_elements.Swap(result); + row_header_elements.reserve(headers.size()); + row_header_elements.resize(headers.size()); + std::copy(headers.begin(), headers.end(), row_header_elements.begin()); } unsigned WebAXObject::ColumnIndex() const { if (IsDetached()) return 0; - if (private_->RoleValue() != kColumnRole) + if (private_->RoleValue() != ax::mojom::Role::kColumn) return 0; return private_->ColumnIndex(); @@ -1188,7 +1180,7 @@ WebAXObject WebAXObject::ColumnHeader() const { if (IsDetached()) return WebAXObject(); - if (private_->RoleValue() != kColumnRole) + if (private_->RoleValue() != ax::mojom::Role::kColumn) return WebAXObject(); return WebAXObject(private_->HeaderObject()); @@ -1204,14 +1196,9 @@ void WebAXObject::ColumnHeaders( AXObject::AXObjectVector headers; private_->ColumnHeaders(headers); - - size_t header_count = headers.size(); - WebVector<WebAXObject> result(header_count); - - for (size_t i = 0; i < header_count; i++) - result[i] = WebAXObject(headers[i]); - - column_header_elements.Swap(result); + column_header_elements.reserve(headers.size()); + column_header_elements.resize(headers.size()); + std::copy(headers.begin(), headers.end(), column_header_elements.begin()); } unsigned WebAXObject::CellColumnIndex() const { @@ -1242,11 +1229,11 @@ unsigned WebAXObject::CellRowSpan() const { return private_->IsTableCellLikeRole() ? private_->RowSpan() : 0; } -WebAXSortDirection WebAXObject::SortDirection() const { +ax::mojom::SortDirection WebAXObject::SortDirection() const { if (IsDetached()) - return kWebAXSortDirectionUndefined; + return ax::mojom::SortDirection::kNone; - return static_cast<WebAXSortDirection>(private_->GetSortDirection()); + return private_->GetSortDirection(); } void WebAXObject::LoadInlineTextBoxes() const { @@ -1270,7 +1257,25 @@ WebAXObject WebAXObject::PreviousOnLine() const { return WebAXObject(private_.Get()->PreviousOnLine()); } -void WebAXObject::Markers(WebVector<WebAXMarkerType>& types, +static ax::mojom::MarkerType ToAXMarkerType( + DocumentMarker::MarkerType marker_type) { + switch (marker_type) { + case DocumentMarker::kSpelling: + return ax::mojom::MarkerType::kSpelling; + case DocumentMarker::kGrammar: + return ax::mojom::MarkerType::kGrammar; + case DocumentMarker::kTextMatch: + return ax::mojom::MarkerType::kTextMatch; + case DocumentMarker::kActiveSuggestion: + return ax::mojom::MarkerType::kActiveSuggestion; + case DocumentMarker::kSuggestion: + return ax::mojom::MarkerType::kSuggestion; + default: + return ax::mojom::MarkerType::kNone; + } +} + +void WebAXObject::Markers(WebVector<ax::mojom::MarkerType>& types, WebVector<int>& starts, WebVector<int>& ends) const { if (IsDetached()) @@ -1281,11 +1286,11 @@ void WebAXObject::Markers(WebVector<WebAXMarkerType>& types, private_->Markers(marker_types, marker_ranges); DCHECK_EQ(marker_types.size(), marker_ranges.size()); - WebVector<WebAXMarkerType> web_marker_types(marker_types.size()); + WebVector<ax::mojom::MarkerType> web_marker_types(marker_types.size()); WebVector<int> start_offsets(marker_ranges.size()); WebVector<int> end_offsets(marker_ranges.size()); - for (size_t i = 0; i < marker_types.size(); ++i) { - web_marker_types[i] = static_cast<WebAXMarkerType>(marker_types[i]); + for (wtf_size_t i = 0; i < marker_types.size(); ++i) { + web_marker_types[i] = ToAXMarkerType(marker_types[i]); DCHECK(marker_ranges[i].IsValid()); DCHECK_EQ(marker_ranges[i].Start().ContainerObject(), marker_ranges[i].End().ContainerObject()); @@ -1304,12 +1309,7 @@ void WebAXObject::CharacterOffsets(WebVector<int>& offsets) const { Vector<int> offsets_vector; private_->TextCharacterOffsets(offsets_vector); - - size_t vector_size = offsets_vector.size(); - WebVector<int> offsets_web_vector(vector_size); - for (size_t i = 0; i < vector_size; i++) - offsets_web_vector[i] = offsets_vector[i]; - offsets.Swap(offsets_web_vector); + offsets = offsets_vector; } void WebAXObject::GetWordBoundaries(WebVector<int>& starts, @@ -1322,7 +1322,7 @@ void WebAXObject::GetWordBoundaries(WebVector<int>& starts, WebVector<int> word_start_offsets(word_boundaries.size()); WebVector<int> word_end_offsets(word_boundaries.size()); - for (size_t i = 0; i < word_boundaries.size(); ++i) { + for (wtf_size_t i = 0; i < word_boundaries.size(); ++i) { DCHECK(word_boundaries[i].IsValid()); DCHECK_EQ(word_boundaries[i].Start().ContainerObject(), word_boundaries[i].End().ContainerObject()); diff --git a/chromium/third_party/blink/renderer/modules/exported/web_dom_file_system.cc b/chromium/third_party/blink/renderer/modules/exported/web_dom_file_system.cc index 7c24cfabb2a..fed359691e4 100644 --- a/chromium/third_party/blink/renderer/modules/exported/web_dom_file_system.cc +++ b/chromium/third_party/blink/renderer/modules/exported/web_dom_file_system.cc @@ -89,20 +89,20 @@ WebString WebDOMFileSystem::GetName() const { return private_->name(); } -WebFileSystem::Type WebDOMFileSystem::GetType() const { +WebFileSystemType WebDOMFileSystem::GetType() const { DCHECK(private_.Get()); switch (private_->GetType()) { case blink::mojom::FileSystemType::kTemporary: - return WebFileSystem::kTypeTemporary; + return WebFileSystemType::kWebFileSystemTypeTemporary; case blink::mojom::FileSystemType::kPersistent: - return WebFileSystem::kTypePersistent; + return WebFileSystemType::kWebFileSystemTypePersistent; case blink::mojom::FileSystemType::kIsolated: - return WebFileSystem::kTypeIsolated; + return WebFileSystemType::kWebFileSystemTypeIsolated; case blink::mojom::FileSystemType::kExternal: - return WebFileSystem::kTypeExternal; + return WebFileSystemType::kWebFileSystemTypeExternal; default: NOTREACHED(); - return WebFileSystem::kTypeTemporary; + return WebFileSystemType::kWebFileSystemTypeTemporary; } } diff --git a/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc b/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc index 360d0299fe6..cd9cda55dd5 100644 --- a/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc +++ b/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc @@ -32,8 +32,10 @@ #include <memory> #include "services/network/public/cpp/shared_url_loader_factory.h" +#include "third_party/blink/public/mojom/service_worker/service_worker_installed_scripts_manager.mojom-blink.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h" +#include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/public/platform/web_url_request.h" #include "third_party/blink/public/platform/web_worker_fetch_context.h" @@ -55,7 +57,6 @@ #include "third_party/blink/renderer/core/workers/worker_global_scope.h" #include "third_party/blink/renderer/core/workers/worker_inspector_proxy.h" #include "third_party/blink/renderer/modules/indexeddb/indexed_db_client.h" -#include "third_party/blink/renderer/modules/service_worker/service_worker_container_client.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.h" @@ -66,22 +67,25 @@ #include "third_party/blink/renderer/platform/network/network_utils.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/shared_buffer.h" +#include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/referrer_policy.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/weborigin/security_policy.h" #include "third_party/blink/renderer/platform/wtf/functional.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { +// static std::unique_ptr<WebEmbeddedWorker> WebEmbeddedWorker::Create( std::unique_ptr<WebServiceWorkerContextClient> client, - std::unique_ptr<WebServiceWorkerInstalledScriptsManager> - installed_scripts_manager, + std::unique_ptr<WebServiceWorkerInstalledScriptsManagerParams> + installed_scripts_manager_params, mojo::ScopedMessagePipeHandle content_settings_handle, mojo::ScopedMessagePipeHandle cache_storage, mojo::ScopedMessagePipeHandle interface_provider) { return std::make_unique<WebEmbeddedWorkerImpl>( - std::move(client), std::move(installed_scripts_manager), + std::move(client), std::move(installed_scripts_manager_params), std::make_unique<ServiceWorkerContentSettingsProxy>( // Chrome doesn't use interface versioning. // TODO(falken): Is that comment about versioning correct? @@ -94,10 +98,25 @@ std::unique_ptr<WebEmbeddedWorker> WebEmbeddedWorker::Create( service_manager::mojom::blink::InterfaceProvider::Version_)); } +// static +std::unique_ptr<WebEmbeddedWorkerImpl> WebEmbeddedWorkerImpl::CreateForTesting( + std::unique_ptr<WebServiceWorkerContextClient> client, + std::unique_ptr<ServiceWorkerInstalledScriptsManager> + installed_scripts_manager) { + auto worker_impl = std::make_unique<WebEmbeddedWorkerImpl>( + std::move(client), nullptr /* installed_scripts_manager_params */, + std::make_unique<ServiceWorkerContentSettingsProxy>( + nullptr /* host_info */), + nullptr /* cache_storage_info */, nullptr /* interface_provider_info */); + worker_impl->installed_scripts_manager_ = + std::move(installed_scripts_manager); + return worker_impl; +} + WebEmbeddedWorkerImpl::WebEmbeddedWorkerImpl( std::unique_ptr<WebServiceWorkerContextClient> client, - std::unique_ptr<WebServiceWorkerInstalledScriptsManager> - installed_scripts_manager, + std::unique_ptr<WebServiceWorkerInstalledScriptsManagerParams> + installed_scripts_manager_params, std::unique_ptr<ServiceWorkerContentSettingsProxy> content_settings_client, mojom::blink::CacheStoragePtrInfo cache_storage_info, service_manager::mojom::blink::InterfaceProviderPtrInfo @@ -109,10 +128,22 @@ WebEmbeddedWorkerImpl::WebEmbeddedWorkerImpl( waiting_for_debugger_state_(kNotWaitingForDebugger), cache_storage_info_(std::move(cache_storage_info)), interface_provider_info_(std::move(interface_provider_info)) { - if (installed_scripts_manager) { - installed_scripts_manager_ = - std::make_unique<ServiceWorkerInstalledScriptsManager>( - std::move(installed_scripts_manager)); + if (installed_scripts_manager_params) { + DCHECK(installed_scripts_manager_params->manager_request.is_valid()); + DCHECK(installed_scripts_manager_params->manager_host_ptr.is_valid()); + Vector<KURL> installed_scripts_urls; + installed_scripts_urls.AppendRange( + installed_scripts_manager_params->installed_scripts_urls.begin(), + installed_scripts_manager_params->installed_scripts_urls.end()); + installed_scripts_manager_ = std::make_unique< + ServiceWorkerInstalledScriptsManager>( + installed_scripts_urls, + mojom::blink::ServiceWorkerInstalledScriptsManagerRequest( + std::move(installed_scripts_manager_params->manager_request)), + mojom::blink::ServiceWorkerInstalledScriptsManagerHostPtrInfo( + std::move(installed_scripts_manager_params->manager_host_ptr), + mojom::blink::ServiceWorkerInstalledScriptsManagerHost::Version_), + Platform::Current()->GetIOTaskRunner()); } } @@ -239,9 +270,14 @@ void WebEmbeddedWorkerImpl::AddMessageToConsole( } void WebEmbeddedWorkerImpl::BindDevToolsAgent( + mojo::ScopedInterfaceEndpointHandle devtools_agent_host_ptr_info, mojo::ScopedInterfaceEndpointHandle devtools_agent_request) { - shadow_page_->BindDevToolsAgent(mojom::blink::DevToolsAgentAssociatedRequest( - std::move(devtools_agent_request))); + shadow_page_->DevToolsAgent()->BindRequest( + mojom::blink::DevToolsAgentHostAssociatedPtrInfo( + std::move(devtools_agent_host_ptr_info), + mojom::blink::DevToolsAgentHost::Version_), + mojom::blink::DevToolsAgentAssociatedRequest( + std::move(devtools_agent_request))); } void WebEmbeddedWorkerImpl::PostMessageToPageInspector(int session_id, @@ -280,7 +316,7 @@ void WebEmbeddedWorkerImpl::OnShadowPageInitialized() { main_script_loader_ = WorkerClassicScriptLoader::Create(); main_script_loader_->LoadTopLevelScriptAsynchronously( *shadow_page_->GetDocument(), worker_start_data_.script_url, - WebURLRequest::kRequestContextServiceWorker, + mojom::RequestContextType::SERVICE_WORKER, network::mojom::FetchRequestMode::kSameOrigin, network::mojom::FetchCredentialsMode::kSameOrigin, worker_start_data_.address_space, base::OnceClosure(), @@ -340,8 +376,6 @@ void WebEmbeddedWorkerImpl::StartWorkerThread() { ProvideServiceWorkerGlobalScopeClientToWorker( worker_clients, new ServiceWorkerGlobalScopeClient(*worker_context_client_)); - ProvideServiceWorkerContainerClientToWorker( - worker_clients, worker_context_client_->CreateServiceWorkerProvider()); std::unique_ptr<WebWorkerFetchContext> web_worker_fetch_context = worker_context_client_->CreateServiceWorkerFetchContext( @@ -359,9 +393,13 @@ void WebEmbeddedWorkerImpl::StartWorkerThread() { String source_code; std::unique_ptr<Vector<char>> cached_meta_data; - // TODO(nhiroki); Set |script_type| to ScriptType::kModule for module fetch. - // (https://crbug.com/824647) - ScriptType script_type = ScriptType::kClassic; + // TODO(https://crbug.com/824647): Use blink::mojom::ScriptType everywhere + // and deprecate blink::ScriptType. + // Remove this line after removed all blink::ScriptType. + ScriptType script_type = + (worker_start_data_.script_type == mojom::ScriptType::kModule) + ? ScriptType::kModule + : ScriptType::kClassic; // |main_script_loader_| isn't created if the InstalledScriptsManager had the // script. @@ -426,13 +464,34 @@ void WebEmbeddedWorkerImpl::StartWorkerThread() { worker_inspector_proxy_->WorkerThreadCreated(document, worker_thread_.get(), worker_start_data_.script_url); - // TODO(nhiroki): Support module workers (https://crbug.com/680046). - // Note that this doesn't really start the script evaluation until - // ReadyToEvaluateScript() is called on the WebServiceWorkerContextProxy - // on the worker thread. - worker_thread_->EvaluateClassicScript( - worker_start_data_.script_url, source_code, std::move(cached_meta_data), - v8_inspector::V8StackTraceId()); + // > Switching on job’s worker type, run these substeps with the following + // > options: + // https://w3c.github.io/ServiceWorker/#update-algorithm + if (script_type == ScriptType::kClassic) { + // > "classic": Fetch a classic worker script given job’s serialized script + // > url, job’s client, "serviceworker", and the to-be-created environment + // > settings object for this service worker. + // Service worker is origin-bound, so use kSharableCrossOrigin. + worker_thread_->EvaluateClassicScript( + worker_start_data_.script_url, kSharableCrossOrigin, source_code, + std::move(cached_meta_data), v8_inspector::V8StackTraceId()); + } else { + // > "module": Fetch a module worker script graph given job’s serialized + // > script url, job’s client, "serviceworker", "omit", and the + // > to-be-created environment settings object for this service worker. + + // TODO(asamidoi): Currently, we use the shadow page's Document as an + // outside_settings_object as a workaround. This should be the Document that + // called navigator.ServiceWorker.register(). To do it, we need to make a + // way to pass the settings object over mojo IPCs. + auto* outside_settings_object = + document->CreateFetchClientSettingsObjectSnapshot(); + network::mojom::FetchCredentialsMode credentials_mode = + network::mojom::FetchCredentialsMode::kOmit; + worker_thread_->ImportModuleScript(worker_start_data_.script_url, + outside_settings_object, + credentials_mode); + } } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h b/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h index ffb8994e780..7c73402d511 100644 --- a/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h +++ b/chromium/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h @@ -59,7 +59,7 @@ class MODULES_EXPORT WebEmbeddedWorkerImpl final public: WebEmbeddedWorkerImpl( std::unique_ptr<WebServiceWorkerContextClient>, - std::unique_ptr<WebServiceWorkerInstalledScriptsManager>, + std::unique_ptr<WebServiceWorkerInstalledScriptsManagerParams>, std::unique_ptr<ServiceWorkerContentSettingsProxy>, mojom::blink::CacheStoragePtrInfo, service_manager::mojom::blink::InterfaceProviderPtrInfo); @@ -71,6 +71,7 @@ class MODULES_EXPORT WebEmbeddedWorkerImpl final void ResumeAfterDownload() override; void AddMessageToConsole(const WebConsoleMessage&) override; void BindDevToolsAgent( + mojo::ScopedInterfaceEndpointHandle devtools_agent_host_ptr_info, mojo::ScopedInterfaceEndpointHandle devtools_agent_request) override; void PostMessageToPageInspector(int session_id, const WTF::String&); @@ -80,6 +81,10 @@ class MODULES_EXPORT WebEmbeddedWorkerImpl final WebApplicationCacheHostClient*) override; void OnShadowPageInitialized() override; + static std::unique_ptr<WebEmbeddedWorkerImpl> CreateForTesting( + std::unique_ptr<WebServiceWorkerContextClient>, + std::unique_ptr<ServiceWorkerInstalledScriptsManager>); + private: // WebDevToolsAgentImpl::Client overrides. void ResumeStartup() override; diff --git a/chromium/third_party/blink/renderer/modules/exported/web_idb_key.cc b/chromium/third_party/blink/renderer/modules/exported/web_idb_key.cc index 9b183328b2b..600bfce5080 100644 --- a/chromium/third_party/blink/renderer/modules/exported/web_idb_key.cc +++ b/chromium/third_party/blink/renderer/modules/exported/web_idb_key.cc @@ -28,6 +28,7 @@ #include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h" #include "third_party/blink/renderer/modules/indexeddb/idb_key.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" namespace blink { @@ -36,7 +37,7 @@ size_t WebIDBKeyArrayView::size() const { } WebIDBKeyView WebIDBKeyArrayView::operator[](size_t index) const { - return WebIDBKeyView(private_->Array()[index].get()); + return WebIDBKeyView(private_->Array()[SafeCast<wtf_size_t>(index)].get()); } WebIDBKeyType WebIDBKeyView::KeyType() const { @@ -69,7 +70,7 @@ double WebIDBKeyView::Number() const { WebIDBKey WebIDBKey::CreateArray(WebVector<WebIDBKey> array) { IDBKey::KeyArray keys; - keys.ReserveCapacity(array.size()); + keys.ReserveCapacity(SafeCast<wtf_size_t>(array.size())); for (WebIDBKey& key : array) { DCHECK(key.View().KeyType() != kWebIDBKeyTypeNull); keys.emplace_back(key.ReleaseIdbKey()); diff --git a/chromium/third_party/blink/renderer/modules/filesystem/BUILD.gn b/chromium/third_party/blink/renderer/modules/filesystem/BUILD.gn index 2e158d69650..021534621b5 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/filesystem/BUILD.gn @@ -49,6 +49,10 @@ blink_modules_sources("filesystem") { "file_system_client.h", "file_system_directory_handle.cc", "file_system_directory_handle.h", + "file_system_directory_iterator.cc", + "file_system_directory_iterator.h", + "file_system_dispatcher.cc", + "file_system_dispatcher.h", "file_system_file_handle.cc", "file_system_file_handle.h", "file_system_writer.cc", @@ -70,4 +74,9 @@ blink_modules_sources("filesystem") { "worker_global_scope_file_system.cc", "worker_global_scope_file_system.h", ] + + deps = [ + "//components/services/filesystem/public/interfaces:interfaces_blink", + "//third_party/blink/renderer/platform", + ] } diff --git a/chromium/third_party/blink/renderer/modules/filesystem/DEPS b/chromium/third_party/blink/renderer/modules/filesystem/DEPS index 6bec426b0d2..e8bdd831680 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/DEPS +++ b/chromium/third_party/blink/renderer/modules/filesystem/DEPS @@ -1,4 +1,5 @@ include_rules = [ + "+base/files/file.h", "-third_party/blink/renderer/modules", "+third_party/blink/renderer/modules/event_target_modules.h", "+third_party/blink/renderer/modules/filesystem", diff --git a/chromium/third_party/blink/renderer/modules/filesystem/OWNERS b/chromium/third_party/blink/renderer/modules/filesystem/OWNERS index a4c6d78bad6..373163caefd 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/OWNERS +++ b/chromium/third_party/blink/renderer/modules/filesystem/OWNERS @@ -1,3 +1,4 @@ +mek@chromium.org jsbell@chromium.org kinuko@chromium.org pwnall@chromium.org diff --git a/chromium/third_party/blink/renderer/modules/filesystem/README.md b/chromium/third_party/blink/renderer/modules/filesystem/README.md new file mode 100644 index 00000000000..6e3f3df6d52 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/filesystem/README.md @@ -0,0 +1,74 @@ +# FileSystem API + +This directory contains the renderer side implementation of various filesystem +related APIs. + +## Related directories + +[`//storage/browser/fileapi/`](../../../storage/browser/fileapi) contains part +of the browser side implementation, while +[`//content/browser/fileapi/`](../../../content/browser/fileapi) contains the +rest of the browser side implementation and +[`blink/public/mojom/filesystem`](../../../third_party/blink/public/mojom/filesystem) +contains the mojom interfaces for these APIs. + +## APIs In this directory + +### File and Directory Entries API + +First of all this directory contains the implementation of the +[Entries API](https://wicg.github.io/entries-api). This API consists of +types to expose read-only access to file and directory entries to the web, +primarily used by drag-and-drop and `<input type=file>`. Our implementation +doesn't match the interface names of the spec, but otherwise should be pretty +close to the spec. + +TODO(mek): More details + +### File API: Directories and FileSystem + +Secondly this directory contains the implementation of something similar to the +deprecated [w3c file-system-api](https://www.w3.org/TR/2012/WD-file-system-api-20120417/). +This API is very similar to the previous Entries API, but it also adds support +for writing and modifying to files and directories, as well as a way to get +access to a origin scoped sandboxed filesystem. + +TODO(mek): More details + +### Writable Files + +Finally this directory contains the implementation of the new and still under +development [Writable Files API](https://github.com/WICG/writable-files/blob/master/EXPLAINER.md). +This API is mostly implemented on top of the same backend as the previous two +APIs, but hopes to eventually replace both of those, while also adding new +functionality. + +It consists of the following parts: + + * `FileSystemBaseHandle`, `FileSystemFileHandle` and `FileSystemDirectoryHandle`: + these interfaces mimic the old `Entry` interfaces (and inherit from `EntryBase` + to share as much of the implementation as possible), but expose a more modern + promisified API. + + * `getSystemDirectory`: An entry point (exposed via `FileSystemDirectoryHandle`) + that today only gives access to the same sandboxed filesystem as what was + available through the old API. In the future this could get extended to add + support for other directories as well. + + * `FileSystemWriter`: a more modern API with similar functionality to the + old `FileWriter` API. The implementation of this actually does make use of + a different mojom interface than the old API. But since the functionality is + mostly the same, hopefully we will be able to migrate the old implementation + to the new mojom API as well. + + * `chooseFileSystemEntries`: An entry point, currently on `window`, that lets + a website pop-up a file picker, prompting the user to select one or more + files or directories, to which the website than gets access. + +Since the `Handle` interfaces are based on the implementation of the `Entry` +interfaces, internally and across IPC these are still represented by +`filesystem://` URLs. Hopefully in the future we will be able to change this and +turn it into a more capabilities based API (where having a mojo handle gives you +access to specific files or directories), as with the current implementation it +is very hard to properly support transferring handles to other processes via +postMessage (which is something we do want to support in the future). diff --git a/chromium/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.idl b/chromium/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.idl new file mode 100644 index 00000000000..9907820a2af --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.idl @@ -0,0 +1,14 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://wicg.github.io/writable-files/#enumdef-choosefilesystementriestype +enum ChooseFileSystemEntriesType { "openFile", "saveFile", "openDirectory" }; + +// https://wicg.github.io/writable-files/#dictdef-choosefilesystementriesoptions +dictionary ChooseFileSystemEntriesOptions { + ChooseFileSystemEntriesType type = "openFile"; + boolean multiple = false; + sequence<ChooseFileSystemEntriesOptionsAccepts> accepts; + boolean excludeAcceptAllOption = false; +}; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options_accepts.idl b/chromium/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options_accepts.idl new file mode 100644 index 00000000000..6b95a2b240d --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options_accepts.idl @@ -0,0 +1,10 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +dictionary ChooseFileSystemEntriesOptionsAccepts { + DOMString description; + sequence<DOMString> mimeTypes; + sequence<DOMString> extensions; +}; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/directory_reader.cc b/chromium/third_party/blink/renderer/modules/filesystem/directory_reader.cc index 607b4444dae..e234149591b 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/directory_reader.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/directory_reader.cc @@ -77,7 +77,7 @@ class DirectoryReader::ErrorCallbackHelper final : public ErrorCallbackBase { return new ErrorCallbackHelper(reader); } - void Invoke(FileError::ErrorCode error) override { reader_->OnError(error); } + void Invoke(base::File::Error error) override { reader_->OnError(error); } void Trace(blink::Visitor* visitor) override { visitor->Trace(reader_); @@ -103,7 +103,7 @@ void DirectoryReader::readEntries(V8EntriesCallback* entries_callback, ErrorCallbackHelper::Create(this)); } - if (error_) { + if (error_ != base::File::FILE_OK) { Filesystem()->ReportError(ScriptErrorCallback::Wrap(error_callback), error_); return; @@ -113,7 +113,7 @@ void DirectoryReader::readEntries(V8EntriesCallback* entries_callback, // Non-null entries_callback_ means multiple readEntries() calls are made // concurrently. We don't allow doing it. Filesystem()->ReportError(ScriptErrorCallback::Wrap(error_callback), - FileError::kInvalidStateErr); + base::File::FILE_ERROR_FAILED); return; } @@ -142,7 +142,7 @@ void DirectoryReader::AddEntries(const EntryHeapVector& entries) { } } -void DirectoryReader::OnError(FileError::ErrorCode error) { +void DirectoryReader::OnError(base::File::Error error) { error_ = error; entries_callback_ = nullptr; if (auto* error_callback = error_callback_.Release()) { diff --git a/chromium/third_party/blink/renderer/modules/filesystem/directory_reader.h b/chromium/third_party/blink/renderer/modules/filesystem/directory_reader.h index c0e5240abdb..aa741253d1d 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/directory_reader.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/directory_reader.h @@ -67,11 +67,11 @@ class DirectoryReader : public DirectoryReaderBase { void AddEntries(const EntryHeapVector& entries); - void OnError(FileError::ErrorCode); + void OnError(base::File::Error error); bool is_reading_; EntryHeapVector entries_; - FileError::ErrorCode error_ = FileError::ErrorCode::kOK; + base::File::Error error_ = base::File::FILE_OK; Member<V8PersistentCallbackInterface<V8EntriesCallback>> entries_callback_; Member<V8PersistentCallbackInterface<V8ErrorCallback>> error_callback_; }; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/directory_reader_sync.cc b/chromium/third_party/blink/renderer/modules/filesystem/directory_reader_sync.cc index 7bed6982573..1e7d48d50cb 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/directory_reader_sync.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/directory_reader_sync.cc @@ -78,7 +78,7 @@ class DirectoryReaderSync::ErrorCallbackHelper final ErrorCallbackBase::Trace(visitor); } - void Invoke(FileError::ErrorCode error) override { + void Invoke(base::File::Error error) override { reader_->error_code_ = error; } @@ -94,15 +94,16 @@ DirectoryReaderSync::DirectoryReaderSync(DOMFileSystemBase* file_system, EntrySyncHeapVector DirectoryReaderSync::readEntries( ExceptionState& exception_state) { - if (!callbacks_id_) { - callbacks_id_ = Filesystem()->ReadDirectory( + if (!has_called_read_directory_) { + Filesystem()->ReadDirectory( this, full_path_, EntriesCallbackHelper::Create(this), ErrorCallbackHelper::Create(this), DOMFileSystemBase::kSynchronous); + has_called_read_directory_ = true; } DCHECK(!has_more_entries_); - if (error_code_ != FileError::kOK) { + if (error_code_ != base::File::FILE_OK) { FileError::ThrowDOMException(exception_state, error_code_); return EntrySyncHeapVector(); } diff --git a/chromium/third_party/blink/renderer/modules/filesystem/directory_reader_sync.h b/chromium/third_party/blink/renderer/modules/filesystem/directory_reader_sync.h index 3e97b4e59b1..92b1bedab3f 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/directory_reader_sync.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/directory_reader_sync.h @@ -64,9 +64,9 @@ class DirectoryReaderSync : public DirectoryReaderBase { DirectoryReaderSync(DOMFileSystemBase*, const String& full_path); - int callbacks_id_ = 0; + bool has_called_read_directory_ = false; EntrySyncHeapVector entries_; - FileError::ErrorCode error_code_ = FileError::kOK; + base::File::Error error_code_ = base::File::FILE_OK; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_path.cc b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_path.cc index c50c536d052..d1ca3514469 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_path.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_path.cc @@ -83,22 +83,22 @@ String DOMFilePath::RemoveExtraParentReferences(const String& path) { Vector<String> components; Vector<String> canonicalized; path.Split(DOMFilePath::kSeparator, components); - for (size_t i = 0; i < components.size(); ++i) { - if (components[i] == ".") + for (const auto& component : components) { + if (component == ".") continue; - if (components[i] == "..") { + if (component == "..") { if (canonicalized.size() > 0) canonicalized.pop_back(); continue; } - canonicalized.push_back(components[i]); + canonicalized.push_back(component); } if (canonicalized.IsEmpty()) return DOMFilePath::kRoot; StringBuilder result; - for (size_t i = 0; i < canonicalized.size(); ++i) { + for (const auto& component : canonicalized) { result.Append(DOMFilePath::kSeparator); - result.Append(canonicalized[i]); + result.Append(component); } return result.ToString(); } @@ -120,13 +120,10 @@ bool DOMFilePath::IsValidPath(const String& path) { // ".." or "." is likely an attempt to break out of the sandbox. Vector<String> components; path.Split(DOMFilePath::kSeparator, components); - for (size_t i = 0; i < components.size(); ++i) { - if (components[i] == ".") - return false; - if (components[i] == "..") - return false; - } - return true; + return std::none_of(components.begin(), components.end(), + [](const String& component) { + return component == "." || component == ".."; + }); } bool DOMFilePath::IsValidName(const String& name) { diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.cc b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.cc index 5e5f3e8e37b..9d079872924 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.cc @@ -33,14 +33,13 @@ #include <memory> #include "third_party/blink/public/platform/platform.h" -#include "third_party/blink/public/platform/web_file_system.h" -#include "third_party/blink/public/platform/web_file_system_callbacks.h" #include "third_party/blink/public/platform/web_security_origin.h" #include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/modules/filesystem/directory_entry.h" #include "third_party/blink/renderer/modules/filesystem/dom_file_path.h" #include "third_party/blink/renderer/modules/filesystem/file_entry.h" #include "third_party/blink/renderer/modules/filesystem/file_system_callbacks.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h" #include "third_party/blink/renderer/modules/filesystem/file_writer.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" @@ -126,18 +125,18 @@ bool DOMFileSystem::HasPendingActivity() const { } void DOMFileSystem::ReportError(ErrorCallbackBase* error_callback, - FileError::ErrorCode file_error) { - ReportError(GetExecutionContext(), error_callback, file_error); + base::File::Error error) { + ReportError(GetExecutionContext(), error_callback, error); } void DOMFileSystem::ReportError(ExecutionContext* execution_context, ErrorCallbackBase* error_callback, - FileError::ErrorCode file_error) { + base::File::Error error) { if (!error_callback) return; ScheduleCallback(execution_context, WTF::Bind(&ErrorCallbackBase::Invoke, - WrapPersistent(error_callback), file_error)); + WrapPersistent(error_callback), error)); } void DOMFileSystem::CreateWriter( @@ -146,17 +145,12 @@ void DOMFileSystem::CreateWriter( ErrorCallbackBase* error_callback) { DCHECK(file_entry); - if (!FileSystem()) { - ReportError(error_callback, FileError::kAbortErr); - return; - } - FileWriter* file_writer = FileWriter::Create(GetExecutionContext()); std::unique_ptr<AsyncFileSystemCallbacks> callbacks = FileWriterCallbacks::Create(file_writer, success_callback, error_callback, context_); - FileSystem()->CreateFileWriter(CreateFileSystemURL(file_entry), file_writer, - std::move(callbacks)); + FileSystemDispatcher::From(context_).InitializeFileWriter( + CreateFileSystemURL(file_entry), std::move(callbacks)); } void DOMFileSystem::CreateFile( @@ -164,12 +158,8 @@ void DOMFileSystem::CreateFile( SnapshotFileCallback::OnDidCreateSnapshotFileCallback* success_callback, ErrorCallbackBase* error_callback) { KURL file_system_url = CreateFileSystemURL(file_entry); - if (!FileSystem()) { - ReportError(error_callback, FileError::kAbortErr); - return; - } - FileSystem()->CreateSnapshotFileAndReadMetadata( + FileSystemDispatcher::From(context_).CreateSnapshotFile( file_system_url, SnapshotFileCallback::Create(this, file_entry->name(), file_system_url, success_callback, error_callback, context_)); diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.h b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.h index a1e90d31579..465c3f5776e 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system.h @@ -67,11 +67,11 @@ class MODULES_EXPORT DOMFileSystem final // DOMFileSystemBase overrides. void AddPendingCallbacks() override; void RemovePendingCallbacks() override; - void ReportError(ErrorCallbackBase*, FileError::ErrorCode) override; + void ReportError(ErrorCallbackBase*, base::File::Error error) override; static void ReportError(ExecutionContext*, ErrorCallbackBase*, - FileError::ErrorCode); + base::File::Error error); // ScriptWrappable overrides. bool HasPendingActivity() const final; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_base.cc b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_base.cc index c8e148aad92..98e1a6566c8 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_base.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_base.cc @@ -32,8 +32,6 @@ #include <memory> #include "third_party/blink/public/platform/platform.h" -#include "third_party/blink/public/platform/web_file_system.h" -#include "third_party/blink/public/platform/web_file_system_callbacks.h" #include "third_party/blink/public/platform/web_security_origin.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/fileapi/file.h" @@ -44,6 +42,7 @@ #include "third_party/blink/renderer/modules/filesystem/entry.h" #include "third_party/blink/renderer/modules/filesystem/entry_base.h" #include "third_party/blink/renderer/modules/filesystem/file_system_callbacks.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" @@ -73,13 +72,6 @@ void DOMFileSystemBase::Trace(blink::Visitor* visitor) { ScriptWrappable::Trace(visitor); } -WebFileSystem* DOMFileSystemBase::FileSystem() const { - Platform* platform = Platform::Current(); - if (!platform) - return nullptr; - return platform->FileSystem(); -} - const SecurityOrigin* DOMFileSystemBase::GetSecurityOrigin() const { return context_->GetSecurityOrigin(); } @@ -217,15 +209,16 @@ void DOMFileSystemBase::GetMetadata( MetadataCallbacks::OnDidReadMetadataCallback* success_callback, ErrorCallbackBase* error_callback, SynchronousType synchronous_type) { - if (!FileSystem()) { - ReportError(error_callback, FileError::kAbortErr); - return; - } - std::unique_ptr<AsyncFileSystemCallbacks> callbacks(MetadataCallbacks::Create( success_callback, error_callback, context_, this)); - callbacks->SetShouldBlockUntilCompletion(synchronous_type == kSynchronous); - FileSystem()->ReadMetadata(CreateFileSystemURL(entry), std::move(callbacks)); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); + + if (synchronous_type == kSynchronous) { + dispatcher.ReadMetadataSync(CreateFileSystemURL(entry), + std::move(callbacks)); + } else { + dispatcher.ReadMetadata(CreateFileSystemURL(entry), std::move(callbacks)); + } } static bool VerifyAndGetDestinationPathForCopyOrMove(const EntryBase* source, @@ -272,27 +265,25 @@ void DOMFileSystemBase::Move( EntryCallbacks::OnDidGetEntryCallback* success_callback, ErrorCallbackBase* error_callback, SynchronousType synchronous_type) { - if (!FileSystem()) { - ReportError(error_callback, FileError::kAbortErr); - return; - } - String destination_path; if (!VerifyAndGetDestinationPathForCopyOrMove(source, parent, new_name, destination_path)) { - ReportError(error_callback, FileError::kInvalidModificationErr); + ReportError(error_callback, base::File::FILE_ERROR_INVALID_OPERATION); return; } std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntryCallbacks::Create( success_callback, error_callback, context_, parent->filesystem(), destination_path, source->isDirectory())); - callbacks->SetShouldBlockUntilCompletion(synchronous_type == kSynchronous); - FileSystem()->Move( - CreateFileSystemURL(source), - parent->filesystem()->CreateFileSystemURL(destination_path), - std::move(callbacks)); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); + const KURL& src = CreateFileSystemURL(source); + const KURL& dest = + parent->filesystem()->CreateFileSystemURL(destination_path); + if (synchronous_type == kSynchronous) + dispatcher.MoveSync(src, dest, std::move(callbacks)); + else + dispatcher.Move(src, dest, std::move(callbacks)); } void DOMFileSystemBase::Copy( @@ -302,27 +293,25 @@ void DOMFileSystemBase::Copy( EntryCallbacks::OnDidGetEntryCallback* success_callback, ErrorCallbackBase* error_callback, SynchronousType synchronous_type) { - if (!FileSystem()) { - ReportError(error_callback, FileError::kAbortErr); - return; - } - String destination_path; if (!VerifyAndGetDestinationPathForCopyOrMove(source, parent, new_name, destination_path)) { - ReportError(error_callback, FileError::kInvalidModificationErr); + ReportError(error_callback, base::File::FILE_ERROR_INVALID_OPERATION); return; } std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntryCallbacks::Create( success_callback, error_callback, context_, parent->filesystem(), destination_path, source->isDirectory())); - callbacks->SetShouldBlockUntilCompletion(synchronous_type == kSynchronous); - FileSystem()->Copy( - CreateFileSystemURL(source), - parent->filesystem()->CreateFileSystemURL(destination_path), - std::move(callbacks)); + const KURL& src = CreateFileSystemURL(source); + const KURL& dest = + parent->filesystem()->CreateFileSystemURL(destination_path); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); + if (synchronous_type == kSynchronous) + dispatcher.CopySync(src, dest, std::move(callbacks)); + else + dispatcher.Copy(src, dest, std::move(callbacks)); } void DOMFileSystemBase::Remove( @@ -330,23 +319,21 @@ void DOMFileSystemBase::Remove( VoidCallbacks::OnDidSucceedCallback* success_callback, ErrorCallbackBase* error_callback, SynchronousType synchronous_type) { - if (!FileSystem()) { - ReportError(error_callback, FileError::kAbortErr); - return; - } - DCHECK(entry); // We don't allow calling remove() on the root directory. if (entry->fullPath() == String(DOMFilePath::kRoot)) { - ReportError(error_callback, FileError::kInvalidModificationErr); + ReportError(error_callback, base::File::FILE_ERROR_INVALID_OPERATION); return; } std::unique_ptr<AsyncFileSystemCallbacks> callbacks( VoidCallbacks::Create(success_callback, error_callback, context_, this)); - callbacks->SetShouldBlockUntilCompletion(synchronous_type == kSynchronous); - - FileSystem()->Remove(CreateFileSystemURL(entry), std::move(callbacks)); + const KURL& url = CreateFileSystemURL(entry); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); + if (synchronous_type == kSynchronous) + dispatcher.RemoveSync(url, /*recursive=*/false, std::move(callbacks)); + else + dispatcher.Remove(url, /*recursive=*/false, std::move(callbacks)); } void DOMFileSystemBase::RemoveRecursively( @@ -354,41 +341,33 @@ void DOMFileSystemBase::RemoveRecursively( VoidCallbacks::OnDidSucceedCallback* success_callback, ErrorCallbackBase* error_callback, SynchronousType synchronous_type) { - if (!FileSystem()) { - ReportError(error_callback, FileError::kAbortErr); - return; - } - DCHECK(entry); DCHECK(entry->isDirectory()); // We don't allow calling remove() on the root directory. if (entry->fullPath() == String(DOMFilePath::kRoot)) { - ReportError(error_callback, FileError::kInvalidModificationErr); + ReportError(error_callback, base::File::FILE_ERROR_INVALID_OPERATION); return; } std::unique_ptr<AsyncFileSystemCallbacks> callbacks( VoidCallbacks::Create(success_callback, error_callback, context_, this)); - callbacks->SetShouldBlockUntilCompletion(synchronous_type == kSynchronous); - - FileSystem()->RemoveRecursively(CreateFileSystemURL(entry), - std::move(callbacks)); + const KURL& url = CreateFileSystemURL(entry); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); + if (synchronous_type == kSynchronous) + dispatcher.RemoveSync(url, /*recursive=*/true, std::move(callbacks)); + else + dispatcher.Remove(url, /*recursive=*/true, std::move(callbacks)); } void DOMFileSystemBase::GetParent( const EntryBase* entry, EntryCallbacks::OnDidGetEntryCallback* success_callback, ErrorCallbackBase* error_callback) { - if (!FileSystem()) { - ReportError(error_callback, FileError::kAbortErr); - return; - } - DCHECK(entry); String path = DOMFilePath::GetDirectory(entry->fullPath()); - FileSystem()->DirectoryExists( - CreateFileSystemURL(path), + FileSystemDispatcher::From(context_).Exists( + CreateFileSystemURL(path), /*is_directory=*/true, EntryCallbacks::Create(success_callback, error_callback, context_, this, path, true)); } @@ -400,27 +379,29 @@ void DOMFileSystemBase::GetFile( EntryCallbacks::OnDidGetEntryCallback* success_callback, ErrorCallbackBase* error_callback, SynchronousType synchronous_type) { - if (!FileSystem()) { - ReportError(error_callback, FileError::kAbortErr); - return; - } - String absolute_path; if (!PathToAbsolutePath(type_, entry, path, absolute_path)) { - ReportError(error_callback, FileError::kInvalidModificationErr); + ReportError(error_callback, base::File::FILE_ERROR_INVALID_OPERATION); return; } std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntryCallbacks::Create( success_callback, error_callback, context_, this, absolute_path, false)); - callbacks->SetShouldBlockUntilCompletion(synchronous_type == kSynchronous); - - if (flags.createFlag()) - FileSystem()->CreateFile(CreateFileSystemURL(absolute_path), - flags.exclusive(), std::move(callbacks)); - else - FileSystem()->FileExists(CreateFileSystemURL(absolute_path), - std::move(callbacks)); + const KURL& url = CreateFileSystemURL(absolute_path); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); + + if (flags.createFlag()) { + if (synchronous_type == kSynchronous) + dispatcher.CreateFileSync(url, flags.exclusive(), std::move(callbacks)); + else + dispatcher.CreateFile(url, flags.exclusive(), std::move(callbacks)); + } else { + if (synchronous_type == kSynchronous) { + dispatcher.ExistsSync(url, /*is_directory=*/false, std::move(callbacks)); + } else { + dispatcher.Exists(url, /*is_directory=*/false, std::move(callbacks)); + } + } } void DOMFileSystemBase::GetDirectory( @@ -430,57 +411,51 @@ void DOMFileSystemBase::GetDirectory( EntryCallbacks::OnDidGetEntryCallback* success_callback, ErrorCallbackBase* error_callback, SynchronousType synchronous_type) { - if (!FileSystem()) { - ReportError(error_callback, FileError::kAbortErr); - return; - } - String absolute_path; if (!PathToAbsolutePath(type_, entry, path, absolute_path)) { - ReportError(error_callback, FileError::kInvalidModificationErr); + ReportError(error_callback, base::File::FILE_ERROR_INVALID_OPERATION); return; } std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntryCallbacks::Create( success_callback, error_callback, context_, this, absolute_path, true)); - callbacks->SetShouldBlockUntilCompletion(synchronous_type == kSynchronous); - - if (flags.createFlag()) - FileSystem()->CreateDirectory(CreateFileSystemURL(absolute_path), - flags.exclusive(), std::move(callbacks)); - else - FileSystem()->DirectoryExists(CreateFileSystemURL(absolute_path), - std::move(callbacks)); + const KURL& url = CreateFileSystemURL(absolute_path); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); + + if (flags.createFlag()) { + if (synchronous_type == kSynchronous) { + dispatcher.CreateDirectorySync(url, flags.exclusive(), + /*recursive=*/false, std::move(callbacks)); + } else { + dispatcher.CreateDirectory(url, flags.exclusive(), /*recursive=*/false, + std::move(callbacks)); + } + } else { + if (synchronous_type == kSynchronous) { + dispatcher.ExistsSync(url, /*is_directory=*/true, std::move(callbacks)); + } else { + dispatcher.Exists(url, /*is_directory=*/true, std::move(callbacks)); + } + } } -int DOMFileSystemBase::ReadDirectory( +void DOMFileSystemBase::ReadDirectory( DirectoryReaderBase* reader, const String& path, EntriesCallbacks::OnDidGetEntriesCallback* success_callback, ErrorCallbackBase* error_callback, SynchronousType synchronous_type) { - if (!FileSystem()) { - ReportError(error_callback, FileError::kAbortErr); - return 0; - } - DCHECK(DOMFilePath::IsAbsolute(path)); std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntriesCallbacks::Create( success_callback, error_callback, context_, reader, path)); - callbacks->SetShouldBlockUntilCompletion(synchronous_type == kSynchronous); - - return FileSystem()->ReadDirectory(CreateFileSystemURL(path), - std::move(callbacks)); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_); + const KURL& url = CreateFileSystemURL(path); + if (synchronous_type == kSynchronous) { + dispatcher.ReadDirectorySync(url, std::move(callbacks)); + } else { + dispatcher.ReadDirectory(url, std::move(callbacks)); + } } -STATIC_ASSERT_ENUM(WebFileSystem::kTypeTemporary, - mojom::blink::FileSystemType::kTemporary); -STATIC_ASSERT_ENUM(WebFileSystem::kTypePersistent, - mojom::blink::FileSystemType::kPersistent); -STATIC_ASSERT_ENUM(WebFileSystem::kTypeExternal, - mojom::blink::FileSystemType::kExternal); -STATIC_ASSERT_ENUM(WebFileSystem::kTypeIsolated, - mojom::blink::FileSystemType::kIsolated); - } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_base.h b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_base.h index 76496faac03..83452e2aa1b 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_base.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_base.h @@ -42,10 +42,6 @@ #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { -class WebFileSystem; -} // namespace blink - -namespace blink { class DirectoryReaderBase; class EntryBase; @@ -78,12 +74,11 @@ class MODULES_EXPORT DOMFileSystemBase : public ScriptWrappable { virtual void RemovePendingCallbacks() {} // Overridden by subclasses to handle sync vs async error-handling. - virtual void ReportError(ErrorCallbackBase*, FileError::ErrorCode) = 0; + virtual void ReportError(ErrorCallbackBase*, base::File::Error error) = 0; const String& name() const { return name_; } mojom::blink::FileSystemType GetType() const { return type_; } KURL RootURL() const { return filesystem_root_url_; } - WebFileSystem* FileSystem() const; const SecurityOrigin* GetSecurityOrigin() const; // The clonable flag is used in the structured clone algorithm to test @@ -150,11 +145,11 @@ class MODULES_EXPORT DOMFileSystemBase : public ScriptWrappable { EntryCallbacks::OnDidGetEntryCallback*, ErrorCallbackBase*, SynchronousType = kAsynchronous); - int ReadDirectory(DirectoryReaderBase*, - const String& path, - EntriesCallbacks::OnDidGetEntriesCallback*, - ErrorCallbackBase*, - SynchronousType = kAsynchronous); + void ReadDirectory(DirectoryReaderBase*, + const String& path, + EntriesCallbacks::OnDidGetEntriesCallback*, + ErrorCallbackBase*, + SynchronousType = kAsynchronous); void Trace(blink::Visitor*) override; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc index e560d7ae23b..1d1b6e1008c 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc @@ -33,14 +33,13 @@ #include <memory> #include "base/memory/ptr_util.h" -#include "third_party/blink/public/platform/web_file_system.h" -#include "third_party/blink/public/platform/web_file_system_callbacks.h" #include "third_party/blink/renderer/core/fileapi/file.h" #include "third_party/blink/renderer/core/fileapi/file_error.h" #include "third_party/blink/renderer/modules/filesystem/directory_entry_sync.h" #include "third_party/blink/renderer/modules/filesystem/dom_file_path.h" #include "third_party/blink/renderer/modules/filesystem/file_entry_sync.h" #include "third_party/blink/renderer/modules/filesystem/file_system_callbacks.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h" #include "third_party/blink/renderer/modules/filesystem/file_writer_sync.h" #include "third_party/blink/renderer/modules/filesystem/sync_callback_helper.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" @@ -65,8 +64,8 @@ DOMFileSystemSync::DOMFileSystemSync(ExecutionContext* context, DOMFileSystemSync::~DOMFileSystemSync() = default; void DOMFileSystemSync::ReportError(ErrorCallbackBase* error_callback, - FileError::ErrorCode file_error) { - error_callback->Invoke(file_error); + base::File::Error error) { + error_callback->Invoke(error); } DirectoryEntrySync* DOMFileSystemSync::root() { @@ -82,13 +81,13 @@ class CreateFileHelper final : public AsyncFileSystemCallbacks { static CreateFileResult* Create() { return new CreateFileResult(); } bool failed_; - int code_; + base::File::Error error_; Member<File> file_; void Trace(blink::Visitor* visitor) { visitor->Trace(file_); } private: - CreateFileResult() : failed_(false), code_(0) {} + CreateFileResult() : failed_(false), error_(base::File::FILE_OK) {} }; static std::unique_ptr<AsyncFileSystemCallbacks> Create( @@ -100,9 +99,9 @@ class CreateFileHelper final : public AsyncFileSystemCallbacks { new CreateFileHelper(result, name, url, type))); } - void DidFail(int code) override { + void DidFail(base::File::Error error) override { result_->failed_ = true; - result_->code_ = code; + result_->error_ = error; } ~CreateFileHelper() override = default; @@ -120,8 +119,6 @@ class CreateFileHelper final : public AsyncFileSystemCallbacks { DOMFileSystemBase::CreateFile(metadata, url_, type_, name_); } - bool ShouldBlockUntilCompletion() const override { return true; } - private: CreateFileHelper(CreateFileResult* result, const String& name, @@ -142,12 +139,12 @@ File* DOMFileSystemSync::CreateFile(const FileEntrySync* file_entry, KURL file_system_url = CreateFileSystemURL(file_entry); CreateFileHelper::CreateFileResult* result( CreateFileHelper::CreateFileResult::Create()); - FileSystem()->CreateSnapshotFileAndReadMetadata( + FileSystemDispatcher::From(context_).CreateSnapshotFileSync( file_system_url, CreateFileHelper::Create(result, file_entry->name(), file_system_url, GetType())); if (result->failed_) { FileError::ThrowDOMException( - exception_state, static_cast<FileError::ErrorCode>(result->code_), + exception_state, result->error_, "Could not create '" + file_entry->name() + "'."); return nullptr; } @@ -159,7 +156,7 @@ FileWriterSync* DOMFileSystemSync::CreateWriter( ExceptionState& exception_state) { DCHECK(file_entry); - FileWriterSync* file_writer = FileWriterSync::Create(); + FileWriterSync* file_writer = FileWriterSync::Create(context_); FileWriterCallbacksSyncHelper* sync_helper = FileWriterCallbacksSyncHelper::Create(); @@ -167,10 +164,9 @@ FileWriterSync* DOMFileSystemSync::CreateWriter( FileWriterCallbacks::Create(file_writer, sync_helper->GetSuccessCallback(), sync_helper->GetErrorCallback(), context_); - callbacks->SetShouldBlockUntilCompletion(true); - FileSystem()->CreateFileWriter(CreateFileSystemURL(file_entry), file_writer, - std::move(callbacks)); + FileSystemDispatcher::From(context_).InitializeFileWriterSync( + CreateFileSystemURL(file_entry), std::move(callbacks)); FileWriterBase* success = sync_helper->GetResultOrThrow(exception_state); return success ? file_writer : nullptr; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.h b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.h index b4d4f863f78..228b3e0b211 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.h @@ -57,7 +57,7 @@ class DOMFileSystemSync final : public DOMFileSystemBase { ~DOMFileSystemSync() override; - void ReportError(ErrorCallbackBase*, FileError::ErrorCode) override; + void ReportError(ErrorCallbackBase*, base::File::Error error) override; DirectoryEntrySync* root(); diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc b/chromium/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc index cf8d2aa0ef2..52b1e87c04d 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc @@ -25,6 +25,8 @@ #include "third_party/blink/renderer/modules/filesystem/dom_window_file_system.h" +#include "base/feature_list.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/mojom/filesystem/file_system.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/dom/document.h" @@ -32,8 +34,11 @@ #include "third_party/blink/renderer/core/fileapi/file_error.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/use_counter.h" +#include "third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.h" +#include "third_party/blink/renderer/modules/filesystem/directory_entry.h" #include "third_party/blink/renderer/modules/filesystem/dom_file_system.h" #include "third_party/blink/renderer/modules/filesystem/file_system_callbacks.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h" #include "third_party/blink/renderer/modules/filesystem/local_file_system.h" #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" @@ -60,7 +65,7 @@ void DOMWindowFileSystem::webkitRequestFileSystem( if (!document->GetSecurityOrigin()->CanAccessFileSystem()) { DOMFileSystem::ReportError(document, ScriptErrorCallback::Wrap(error_callback), - FileError::kSecurityErr); + base::File::FILE_ERROR_SECURITY); return; } else if (document->GetSecurityOrigin()->IsLocal()) { UseCounter::Count(document, WebFeature::kFileAccessedFileSystem); @@ -71,7 +76,7 @@ void DOMWindowFileSystem::webkitRequestFileSystem( if (!DOMFileSystemBase::IsValidType(file_system_type)) { DOMFileSystem::ReportError(document, ScriptErrorCallback::Wrap(error_callback), - FileError::kInvalidModificationErr); + base::File::FILE_ERROR_INVALID_OPERATION); return; } @@ -81,7 +86,8 @@ void DOMWindowFileSystem::webkitRequestFileSystem( FileSystemCallbacks::OnDidOpenFileSystemV8Impl::Create( success_callback), ScriptErrorCallback::Wrap(error_callback), document, - file_system_type)); + file_system_type), + LocalFileSystem::kAsynchronous); } void DOMWindowFileSystem::webkitResolveLocalFileSystemURL( @@ -102,7 +108,7 @@ void DOMWindowFileSystem::webkitResolveLocalFileSystemURL( !security_origin->CanRequest(completed_url)) { DOMFileSystem::ReportError(document, ScriptErrorCallback::Wrap(error_callback), - FileError::kSecurityErr); + base::File::FILE_ERROR_SECURITY); return; } else if (document->GetSecurityOrigin()->IsLocal()) { UseCounter::Count(document, WebFeature::kFileAccessedFileSystem); @@ -111,7 +117,7 @@ void DOMWindowFileSystem::webkitResolveLocalFileSystemURL( if (!completed_url.IsValid()) { DOMFileSystem::ReportError(document, ScriptErrorCallback::Wrap(error_callback), - FileError::kEncodingErr); + base::File::FILE_ERROR_INVALID_URL); return; } @@ -119,7 +125,8 @@ void DOMWindowFileSystem::webkitResolveLocalFileSystemURL( document, completed_url, ResolveURICallbacks::Create( ResolveURICallbacks::OnDidGetEntryV8Impl::Create(success_callback), - ScriptErrorCallback::Wrap(error_callback), document)); + ScriptErrorCallback::Wrap(error_callback), document), + LocalFileSystem::kAsynchronous); } static_assert( @@ -131,9 +138,69 @@ static_assert( static_cast<int>(mojom::blink::FileSystemType::kPersistent), "DOMWindowFileSystem::kPersistent should match FileSystemTypePersistent"); +namespace { + +mojom::blink::ChooseFileSystemEntryType ConvertChooserType(const String& input, + bool multiple) { + if (input == "openFile") { + return multiple + ? mojom::blink::ChooseFileSystemEntryType::kOpenMultipleFiles + : mojom::blink::ChooseFileSystemEntryType::kOpenFile; + } + if (input == "saveFile") + return mojom::blink::ChooseFileSystemEntryType::kSaveFile; + if (input == "openDirectory") + return mojom::blink::ChooseFileSystemEntryType::kOpenDirectory; + NOTREACHED(); + return mojom::blink::ChooseFileSystemEntryType::kOpenFile; +} + +Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> ConvertAccepts( + const HeapVector<ChooseFileSystemEntriesOptionsAccepts>& accepts) { + Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> result; + result.ReserveInitialCapacity(accepts.size()); + for (const auto& a : accepts) { + result.emplace_back( + blink::mojom::blink::ChooseFileSystemEntryAcceptsOption::New( + a.hasDescription() ? a.description() : g_empty_string, + a.hasMimeTypes() ? a.mimeTypes() : Vector<String>(), + a.hasExtensions() ? a.extensions() : Vector<String>())); + } + return result; +} + +ScriptPromise CreateFileHandle(ScriptState* script_state, + const mojom::blink::FileSystemEntryPtr& entry, + bool is_directory) { + auto* new_resolver = ScriptPromiseResolver::Create(script_state); + ScriptPromise result = new_resolver->Promise(); + auto* fs = DOMFileSystem::CreateIsolatedFileSystem( + ExecutionContext::From(script_state), entry->file_system_id); + // TODO(mek): Try to create handle directly rather than having to do more + // IPCs to get the actual entries. + if (is_directory) { + fs->GetDirectory(fs->root(), entry->base_name, FileSystemFlags(), + new EntryCallbacks::OnDidGetEntryPromiseImpl(new_resolver), + new PromiseErrorCallback(new_resolver)); + } else { + fs->GetFile(fs->root(), entry->base_name, FileSystemFlags(), + new EntryCallbacks::OnDidGetEntryPromiseImpl(new_resolver), + new PromiseErrorCallback(new_resolver)); + } + return result; +} + +} // namespace + ScriptPromise DOMWindowFileSystem::chooseFileSystemEntries( ScriptState* script_state, - LocalDOMWindow& window) { + LocalDOMWindow& window, + const ChooseFileSystemEntriesOptions& options) { + if (!base::FeatureList::IsEnabled(blink::features::kWritableFilesAPI)) { + return ScriptPromise::RejectWithDOMException( + script_state, DOMException::Create(DOMExceptionCode::kAbortError)); + } + if (!window.IsCurrentlyDisplayedInFrame()) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kAbortError)); @@ -145,7 +212,7 @@ ScriptPromise DOMWindowFileSystem::chooseFileSystemEntries( script_state, DOMException::Create(DOMExceptionCode::kAbortError)); } - if (!Frame::HasTransientUserActivation(window.GetFrame())) { + if (!LocalFrame::HasTransientUserActivation(window.GetFrame())) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create( @@ -153,9 +220,44 @@ ScriptPromise DOMWindowFileSystem::chooseFileSystemEntries( "Must be handling a user gesture to show a file picker.")); } + Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> accepts; + if (options.hasAccepts()) + accepts = ConvertAccepts(options.accepts()); + auto* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise result = resolver->Promise(); - LocalFileSystem::From(*document)->ChooseEntry(resolver); + FileSystemDispatcher::From(document).GetFileSystemManager().ChooseEntry( + ConvertChooserType(options.type(), options.multiple()), + std::move(accepts), !options.excludeAcceptAllOption(), + WTF::Bind( + [](ScriptPromiseResolver* resolver, + const ChooseFileSystemEntriesOptions& options, + base::File::Error result, + Vector<mojom::blink::FileSystemEntryPtr> entries) { + if (result != base::File::FILE_OK) { + resolver->Reject(FileError::CreateDOMException(result)); + return; + } + bool is_directory = options.type() == "openDirectory"; + ScriptState* script_state = resolver->GetScriptState(); + ScriptState::Scope scope(script_state); + if (options.multiple()) { + Vector<ScriptPromise> result; + result.ReserveInitialCapacity(entries.size()); + for (const auto& entry : entries) { + result.emplace_back( + CreateFileHandle(script_state, entry, is_directory)); + } + resolver->Resolve( + ScriptPromise::All(script_state, result).GetScriptValue()); + } else { + DCHECK_EQ(1u, entries.size()); + resolver->Resolve( + CreateFileHandle(script_state, entries[0], is_directory) + .GetScriptValue()); + } + }, + WrapPersistent(resolver), options)); return result; } diff --git a/chromium/third_party/blink/renderer/modules/filesystem/dom_window_file_system.h b/chromium/third_party/blink/renderer/modules/filesystem/dom_window_file_system.h index a12e3beeb9b..8d4264d1f39 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/dom_window_file_system.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/dom_window_file_system.h @@ -32,6 +32,7 @@ namespace blink { +class ChooseFileSystemEntriesOptions; class LocalDOMWindow; class ScriptPromise; class ScriptState; @@ -60,7 +61,10 @@ class DOMWindowFileSystem { kPersistent, }; - static ScriptPromise chooseFileSystemEntries(ScriptState*, LocalDOMWindow&); + static ScriptPromise chooseFileSystemEntries( + ScriptState*, + LocalDOMWindow&, + const ChooseFileSystemEntriesOptions&); }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.cc index f991bfb05f4..1fcaa2f115c 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.cc @@ -7,6 +7,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/modules/filesystem/dom_file_system_base.h" #include "third_party/blink/renderer/modules/filesystem/file_system_callbacks.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_directory_handle.h" namespace blink { @@ -23,4 +24,35 @@ ScriptPromise FileSystemBaseHandle::getParent(ScriptState* script_state) { return result; } +ScriptPromise FileSystemBaseHandle::moveTo(ScriptState* script_state, + FileSystemDirectoryHandle* parent, + const String& name) { + auto* resolver = ScriptPromiseResolver::Create(script_state); + ScriptPromise result = resolver->Promise(); + filesystem()->Move(this, parent, name, + new EntryCallbacks::OnDidGetEntryPromiseImpl(resolver), + new PromiseErrorCallback(resolver)); + return result; +} + +ScriptPromise FileSystemBaseHandle::copyTo(ScriptState* script_state, + FileSystemDirectoryHandle* parent, + const String& name) { + auto* resolver = ScriptPromiseResolver::Create(script_state); + ScriptPromise result = resolver->Promise(); + filesystem()->Copy(this, parent, name, + new EntryCallbacks::OnDidGetEntryPromiseImpl(resolver), + new PromiseErrorCallback(resolver)); + return result; +} + +ScriptPromise FileSystemBaseHandle::remove(ScriptState* script_state) { + auto* resolver = ScriptPromiseResolver::Create(script_state); + ScriptPromise result = resolver->Promise(); + filesystem()->Remove(this, + new VoidCallbacks::OnDidSucceedPromiseImpl(resolver), + new PromiseErrorCallback(resolver)); + return result; +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.h b/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.h index 991b19dbc71..c1585c93625 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.h @@ -8,6 +8,7 @@ #include "third_party/blink/renderer/modules/filesystem/entry_base.h" namespace blink { +class FileSystemDirectoryHandle; class ScriptPromise; class ScriptState; @@ -18,6 +19,13 @@ class FileSystemBaseHandle : public EntryBase { explicit FileSystemBaseHandle(DOMFileSystemBase*, const String& full_path); ScriptPromise getParent(ScriptState*); + ScriptPromise moveTo(ScriptState*, + FileSystemDirectoryHandle* parent, + const String& name = String()); + ScriptPromise copyTo(ScriptState*, + FileSystemDirectoryHandle* parent, + const String& name = String()); + ScriptPromise remove(ScriptState*); }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.idl b/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.idl index 70d7786e194..20008ad4737 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.idl +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_base_handle.idl @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://wicg.github.io/writable-files/#filesystemhandle [ RuntimeEnabled=WritableFiles, NoInterfaceObject @@ -16,5 +16,10 @@ readonly attribute USVString name; [CallWith=ScriptState] Promise<FileSystemDirectoryHandle> getParent(); - // TODO(mek): Other methods to move/copy/delete entries. + + [CallWith=ScriptState] Promise<FileSystemBaseHandle> moveTo( + FileSystemDirectoryHandle parent, optional USVString name); + [CallWith=ScriptState] Promise<FileSystemBaseHandle> copyTo( + FileSystemDirectoryHandle parent, optional USVString name); + [CallWith=ScriptState] Promise<void> remove(); }; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_callbacks.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_system_callbacks.cc index 139e795f2d0..06bde35238c 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_callbacks.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_callbacks.cc @@ -33,7 +33,6 @@ #include <memory> #include "base/memory/ptr_util.h" -#include "third_party/blink/public/platform/web_file_writer.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" @@ -72,17 +71,15 @@ FileSystemCallbacksBase::~FileSystemCallbacksBase() { file_system_->RemovePendingCallbacks(); } -void FileSystemCallbacksBase::DidFail(int code) { +void FileSystemCallbacksBase::DidFail(base::File::Error error) { if (error_callback_) { InvokeOrScheduleCallback(&ErrorCallbackBase::Invoke, - error_callback_.Release(), - static_cast<FileError::ErrorCode>(code)); + error_callback_.Release(), error); } } bool FileSystemCallbacksBase::ShouldScheduleCallback() const { - return !ShouldBlockUntilCompletion() && execution_context_ && - execution_context_->IsContextPaused(); + return execution_context_ && execution_context_->IsContextPaused(); } template <typename CallbackMemberFunction, @@ -122,7 +119,7 @@ void ScriptErrorCallback::Trace(blink::Visitor* visitor) { visitor->Trace(callback_); } -void ScriptErrorCallback::Invoke(FileError::ErrorCode error) { +void ScriptErrorCallback::Invoke(base::File::Error error) { callback_->InvokeAndReportException(nullptr, FileError::CreateDOMException(error)); }; @@ -140,7 +137,7 @@ void PromiseErrorCallback::Trace(Visitor* visitor) { visitor->Trace(resolver_); } -void PromiseErrorCallback::Invoke(FileError::ErrorCode error) { +void PromiseErrorCallback::Invoke(base::File::Error error) { resolver_->Reject(FileError::CreateDOMException(error)); } @@ -265,6 +262,21 @@ void FileSystemCallbacks::OnDidOpenFileSystemV8Impl::OnSuccess( callback_->InvokeAndReportException(nullptr, file_system); } +FileSystemCallbacks::OnDidOpenFileSystemPromiseImpl:: + OnDidOpenFileSystemPromiseImpl(ScriptPromiseResolver* resolver) + : resolver_(resolver) {} + +void FileSystemCallbacks::OnDidOpenFileSystemPromiseImpl::Trace( + Visitor* visitor) { + OnDidOpenFileSystemCallback::Trace(visitor); + visitor->Trace(resolver_); +} + +void FileSystemCallbacks::OnDidOpenFileSystemPromiseImpl::OnSuccess( + DOMFileSystem* file_system) { + resolver_->Resolve(file_system->root()->asFileSystemHandle()); +} + std::unique_ptr<AsyncFileSystemCallbacks> FileSystemCallbacks::Create( OnDidOpenFileSystemCallback* success_callback, ErrorCallbackBase* error_callback, @@ -324,7 +336,7 @@ void ResolveURICallbacks::DidResolveURL(const String& name, String absolute_path; if (!DOMFileSystemBase::PathToAbsolutePath(type, root, file_path, absolute_path)) { - DidFail(FileError::kInvalidModificationErr); + DidFail(base::File::FILE_ERROR_INVALID_OPERATION); return; } @@ -408,16 +420,13 @@ FileWriterCallbacks::FileWriterCallbacks( file_writer_(file_writer), success_callback_(success_callback) {} -void FileWriterCallbacks::DidCreateFileWriter( - std::unique_ptr<WebFileWriter> file_writer, - long long length) { - file_writer_->Initialize(std::move(file_writer), length); - +void FileWriterCallbacks::DidCreateFileWriter(const KURL& path, + long long length) { if (!success_callback_) return; - + file_writer_->Initialize(path, length); InvokeOrScheduleCallback(&OnDidCreateFileWriterCallback::OnSuccess, - success_callback_.Release(), file_writer_.Release()); + success_callback_.Release(), file_writer_); } // SnapshotFileCallback ------------------------------------------------------- @@ -487,6 +496,19 @@ void VoidCallbacks::OnDidSucceedV8Impl::OnSuccess( callback_->InvokeAndReportException(nullptr); } +VoidCallbacks::OnDidSucceedPromiseImpl::OnDidSucceedPromiseImpl( + ScriptPromiseResolver* resolver) + : resolver_(resolver) {} + +void VoidCallbacks::OnDidSucceedPromiseImpl::Trace(Visitor* visitor) { + OnDidSucceedCallback::Trace(visitor); + visitor->Trace(resolver_); +} + +void VoidCallbacks::OnDidSucceedPromiseImpl::OnSuccess(ExecutionContext*) { + resolver_->Resolve(); +} + std::unique_ptr<AsyncFileSystemCallbacks> VoidCallbacks::Create( OnDidSucceedCallback* success_callback, ErrorCallbackBase* error_callback, diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_callbacks.h b/chromium/third_party/blink/renderer/modules/filesystem/file_system_callbacks.h index b14c82c7fab..04ab209a9d8 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_callbacks.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_callbacks.h @@ -68,7 +68,7 @@ class ErrorCallbackBase : public GarbageCollectedFinalized<ErrorCallbackBase> { public: virtual ~ErrorCallbackBase() {} virtual void Trace(blink::Visitor* visitor) {} - virtual void Invoke(FileError::ErrorCode) = 0; + virtual void Invoke(base::File::Error error) = 0; }; class FileSystemCallbacksBase : public AsyncFileSystemCallbacks { @@ -76,7 +76,7 @@ class FileSystemCallbacksBase : public AsyncFileSystemCallbacks { ~FileSystemCallbacksBase() override; // For ErrorCallback. - void DidFail(int code) final; + void DidFail(base::File::Error error) final; // Other callback methods are implemented by each subclass. @@ -111,7 +111,7 @@ class ScriptErrorCallback final : public ErrorCallbackBase { ~ScriptErrorCallback() override {} void Trace(blink::Visitor*) override; - void Invoke(FileError::ErrorCode) override; + void Invoke(base::File::Error error) override; private: explicit ScriptErrorCallback(V8ErrorCallback*); @@ -122,7 +122,7 @@ class PromiseErrorCallback final : public ErrorCallbackBase { public: explicit PromiseErrorCallback(ScriptPromiseResolver*); void Trace(Visitor*) override; - void Invoke(FileError::ErrorCode) override; + void Invoke(base::File::Error error) override; private: Member<ScriptPromiseResolver> resolver_; @@ -249,6 +249,16 @@ class FileSystemCallbacks final : public FileSystemCallbacksBase { Member<V8PersistentCallbackInterface<V8FileSystemCallback>> callback_; }; + class OnDidOpenFileSystemPromiseImpl : public OnDidOpenFileSystemCallback { + public: + explicit OnDidOpenFileSystemPromiseImpl(ScriptPromiseResolver*); + void Trace(Visitor*) override; + void OnSuccess(DOMFileSystem*) override; + + private: + Member<ScriptPromiseResolver> resolver_; + }; + static std::unique_ptr<AsyncFileSystemCallbacks> Create( OnDidOpenFileSystemCallback*, ErrorCallbackBase*, @@ -361,8 +371,7 @@ class FileWriterCallbacks final : public FileSystemCallbacksBase { OnDidCreateFileWriterCallback*, ErrorCallbackBase*, ExecutionContext*); - void DidCreateFileWriter(std::unique_ptr<WebFileWriter>, - long long length) override; + void DidCreateFileWriter(const KURL& path, long long length) override; private: FileWriterCallbacks(FileWriterBase*, @@ -451,6 +460,16 @@ class VoidCallbacks final : public FileSystemCallbacksBase { Member<V8PersistentCallbackInterface<V8VoidCallback>> callback_; }; + class OnDidSucceedPromiseImpl : public OnDidSucceedCallback { + public: + OnDidSucceedPromiseImpl(ScriptPromiseResolver*); + void Trace(Visitor*) override; + void OnSuccess(ExecutionContext*) override; + + private: + Member<ScriptPromiseResolver> resolver_; + }; + static std::unique_ptr<AsyncFileSystemCallbacks> Create(OnDidSucceedCallback*, ErrorCallbackBase*, ExecutionContext*, diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.cc index c10c7a481db..4bc2d834eda 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.cc @@ -7,6 +7,8 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/modules/filesystem/dom_file_system_base.h" #include "third_party/blink/renderer/modules/filesystem/file_system_callbacks.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.h" +#include "third_party/blink/renderer/modules/filesystem/local_file_system.h" namespace blink { @@ -15,23 +17,83 @@ FileSystemDirectoryHandle::FileSystemDirectoryHandle( const String& full_path) : FileSystemBaseHandle(file_system, full_path) {} -ScriptPromise FileSystemDirectoryHandle::getFile(ScriptState* script_state, - const String& name) { +ScriptPromise FileSystemDirectoryHandle::getFile( + ScriptState* script_state, + const String& name, + const FileSystemGetFileOptions& options) { + FileSystemFlags flags; + flags.setCreateFlag(options.create()); auto* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise result = resolver->Promise(); - filesystem()->GetFile(this, name, FileSystemFlags(), + filesystem()->GetFile(this, name, flags, new EntryCallbacks::OnDidGetEntryPromiseImpl(resolver), new PromiseErrorCallback(resolver)); return result; } -ScriptPromise FileSystemDirectoryHandle::getDirectory(ScriptState* script_state, - const String& name) { +ScriptPromise FileSystemDirectoryHandle::getDirectory( + ScriptState* script_state, + const String& name, + const FileSystemGetDirectoryOptions& options) { + FileSystemFlags flags; + flags.setCreateFlag(options.create()); auto* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise result = resolver->Promise(); filesystem()->GetDirectory( - this, name, FileSystemFlags(), - new EntryCallbacks::OnDidGetEntryPromiseImpl(resolver), + this, name, flags, new EntryCallbacks::OnDidGetEntryPromiseImpl(resolver), + new PromiseErrorCallback(resolver)); + return result; +} + +// static +ScriptPromise FileSystemDirectoryHandle::getSystemDirectory( + ScriptState* script_state, + const GetSystemDirectoryOptions& options) { + auto* context = ExecutionContext::From(script_state); + + auto* resolver = ScriptPromiseResolver::Create(script_state); + ScriptPromise result = resolver->Promise(); + + LocalFileSystem::From(*context)->RequestFileSystem( + context, mojom::blink::FileSystemType::kTemporary, /*size=*/0, + FileSystemCallbacks::Create( + new FileSystemCallbacks::OnDidOpenFileSystemPromiseImpl(resolver), + new PromiseErrorCallback(resolver), context, + mojom::blink::FileSystemType::kTemporary), + LocalFileSystem::kAsynchronous); + return result; +} + +namespace { + +void ReturnDataFunction(const v8::FunctionCallbackInfo<v8::Value>& info) { + V8SetReturnValue(info, info.Data()); +} + +} // namespace + +ScriptValue FileSystemDirectoryHandle::getEntries(ScriptState* script_state) { + auto* iterator = new FileSystemDirectoryIterator(filesystem(), fullPath()); + auto* isolate = script_state->GetIsolate(); + auto context = script_state->GetContext(); + v8::Local<v8::Object> result = v8::Object::New(isolate); + if (!result + ->Set(context, v8::Symbol::GetAsyncIterator(isolate), + v8::Function::New(context, &ReturnDataFunction, + ToV8(iterator, script_state)) + .ToLocalChecked()) + .ToChecked()) { + return ScriptValue(); + } + return ScriptValue(script_state, result); +} + +ScriptPromise FileSystemDirectoryHandle::removeRecursively( + ScriptState* script_state) { + auto* resolver = ScriptPromiseResolver::Create(script_state); + ScriptPromise result = resolver->Promise(); + filesystem()->RemoveRecursively( + this, new VoidCallbacks::OnDidSucceedPromiseImpl(resolver), new PromiseErrorCallback(resolver)); return result; } diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.h b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.h index cd3fd96fc8c..3dfc770d4b0 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.h @@ -5,7 +5,11 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_SYSTEM_DIRECTORY_HANDLE_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_SYSTEM_DIRECTORY_HANDLE_H_ +#include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/modules/filesystem/file_system_base_handle.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_get_directory_options.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_get_file_options.h" +#include "third_party/blink/renderer/modules/filesystem/get_system_directory_options.h" namespace blink { @@ -16,8 +20,18 @@ class FileSystemDirectoryHandle : public FileSystemBaseHandle { FileSystemDirectoryHandle(DOMFileSystemBase*, const String& full_path); bool isDirectory() const override { return true; } - ScriptPromise getFile(ScriptState*, const String& name); - ScriptPromise getDirectory(ScriptState*, const String& name); + ScriptPromise getFile(ScriptState*, + const String& name, + const FileSystemGetFileOptions&); + ScriptPromise getDirectory(ScriptState*, + const String& name, + const FileSystemGetDirectoryOptions&); + ScriptValue getEntries(ScriptState*); + ScriptPromise removeRecursively(ScriptState*); + + static ScriptPromise getSystemDirectory( + ScriptState*, + const GetSystemDirectoryOptions& options); }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.idl b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.idl index 1b13904a04c..5e2309e925a 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.idl +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.idl @@ -2,11 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://wicg.github.io/writable-files/#filesystemdirectoryhandle [ RuntimeEnabled=WritableFiles ] interface FileSystemDirectoryHandle : FileSystemBaseHandle { - [CallWith=ScriptState] Promise<FileSystemFileHandle> getFile(USVString name); - [CallWith=ScriptState] Promise<FileSystemDirectoryHandle> getDirectory(USVString name); - // TODO(mek): Other methods such as getEntries etc. + [CallWith=ScriptState] Promise<FileSystemFileHandle> getFile(USVString name, optional FileSystemGetFileOptions options); + [CallWith=ScriptState] Promise<FileSystemDirectoryHandle> getDirectory(USVString name, optional FileSystemGetDirectoryOptions options); + [CallWith=ScriptState] object getEntries(); + + [CallWith=ScriptState] Promise<void> removeRecursively(); + + [CallWith=ScriptState] + static Promise<FileSystemDirectoryHandle> getSystemDirectory(GetSystemDirectoryOptions options); }; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.cc new file mode 100644 index 00000000000..d7fa8b6cebe --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.cc @@ -0,0 +1,110 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.h" + +#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" +#include "third_party/blink/renderer/core/dom/dom_exception.h" +#include "third_party/blink/renderer/core/fileapi/file_error.h" +#include "third_party/blink/renderer/modules/filesystem/entry.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_base_handle.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_directory_iterator_entry.h" + +namespace blink { + +class FileSystemDirectoryIterator::EntriesCallbackHelper + : public EntriesCallbacks::OnDidGetEntriesCallback { + public: + explicit EntriesCallbackHelper(FileSystemDirectoryIterator* reader) + : reader_(reader) {} + + void Trace(Visitor* visitor) override { + EntriesCallbacks::OnDidGetEntriesCallback::Trace(visitor); + visitor->Trace(reader_); + } + + void OnSuccess(EntryHeapVector* entries) override { + reader_->AddEntries(*entries); + } + + private: + // TODO(https://crbug.com/350285): This Member keeps the reader alive until + // all of the readDirectory results are received. + Member<FileSystemDirectoryIterator> reader_; +}; + +class FileSystemDirectoryIterator::ErrorCallbackHelper final + : public ErrorCallbackBase { + public: + explicit ErrorCallbackHelper(FileSystemDirectoryIterator* reader) + : reader_(reader) {} + + void Invoke(base::File::Error error) override { reader_->OnError(error); } + + void Trace(Visitor* visitor) override { + ErrorCallbackBase::Trace(visitor); + visitor->Trace(reader_); + } + + private: + Member<FileSystemDirectoryIterator> reader_; +}; + +FileSystemDirectoryIterator::FileSystemDirectoryIterator( + DOMFileSystemBase* file_system, + const String& full_path) + : DirectoryReaderBase(file_system, full_path) { + Filesystem()->ReadDirectory(this, full_path_, new EntriesCallbackHelper(this), + new ErrorCallbackHelper(this)); +} + +ScriptPromise FileSystemDirectoryIterator::next(ScriptState* script_state) { + if (error_ != base::File::FILE_OK) { + return ScriptPromise::RejectWithDOMException( + script_state, FileError::CreateDOMException(error_)); + } + + if (!entries_.IsEmpty()) { + FileSystemDirectoryIteratorEntry result; + result.setValue(entries_.TakeFirst()->asFileSystemHandle()); + return ScriptPromise::Cast(script_state, ToV8(result, script_state)); + } + + if (has_more_entries_) { + DCHECK(!pending_next_); + pending_next_ = ScriptPromiseResolver::Create(script_state); + return pending_next_->Promise(); + } + + FileSystemDirectoryIteratorEntry result; + result.setDone(true); + return ScriptPromise::Cast(script_state, ToV8(result, script_state)); +} + +void FileSystemDirectoryIterator::Trace(Visitor* visitor) { + DirectoryReaderBase::Trace(visitor); + visitor->Trace(entries_); + visitor->Trace(pending_next_); +} + +void FileSystemDirectoryIterator::AddEntries(const EntryHeapVector& entries) { + for (const auto& e : entries) + entries_.emplace_back(e); + if (pending_next_) { + ScriptState::Scope scope(pending_next_->GetScriptState()); + pending_next_->Resolve( + next(pending_next_->GetScriptState()).GetScriptValue()); + pending_next_ = nullptr; + } +} + +void FileSystemDirectoryIterator::OnError(base::File::Error error) { + error_ = error; + if (pending_next_) { + pending_next_->Reject(FileError::CreateDOMException(error)); + pending_next_ = nullptr; + } +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.h b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.h new file mode 100644 index 00000000000..2f851333a2a --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.h @@ -0,0 +1,42 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_SYSTEM_DIRECTORY_ITERATOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_SYSTEM_DIRECTORY_ITERATOR_H_ + +#include "base/files/file.h" +#include "third_party/blink/renderer/modules/filesystem/directory_reader_base.h" +#include "third_party/blink/renderer/modules/filesystem/dom_file_system.h" + +namespace blink { +class ScriptPromise; +class ScriptPromiseResolver; +class ScriptState; + +class FileSystemDirectoryIterator : public DirectoryReaderBase { + DEFINE_WRAPPERTYPEINFO(); + public: + FileSystemDirectoryIterator(DOMFileSystemBase*, const String& full_path); + + ScriptPromise next(ScriptState*); + // TODO(mek): This return method should cancel the backend directory iteration + // operation, to avoid doing useless work. + void IteratorReturn() {} + + void Trace(Visitor*) override; + + private: + class EntriesCallbackHelper; + class ErrorCallbackHelper; + void AddEntries(const EntryHeapVector& entries); + void OnError(base::File::Error); + + base::File::Error error_ = base::File::FILE_OK; + HeapDeque<Member<Entry>> entries_; + Member<ScriptPromiseResolver> pending_next_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_SYSTEM_DIRECTORY_ITERATOR_H_ diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.idl b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.idl new file mode 100644 index 00000000000..bb376bb9220 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator.idl @@ -0,0 +1,14 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Async iterator returned by FileSystemDirectoryHandle.getEntries(). +// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-asynciterator-interface +[ + NoInterfaceObject, + RuntimeEnabled=WritableFiles +] interface FileSystemDirectoryIterator { + [CallWith=ScriptState] Promise next(); + [ImplementedAs=IteratorReturn] void return(); +}; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator_entry.idl b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator_entry.idl new file mode 100644 index 00000000000..3e37520931f --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_directory_iterator_entry.idl @@ -0,0 +1,11 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Used by FileSystemDirectoryIterator to represents results of next() calls. +// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-iteratorresult-interface +dictionary FileSystemDirectoryIteratorEntry { + FileSystemBaseHandle value; + boolean done = false; +}; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc new file mode 100644 index 00000000000..a910df063c9 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc @@ -0,0 +1,585 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h" + +#include "build/build_config.h" +#include "services/service_manager/public/cpp/interface_provider.h" +#include "third_party/blink/public/platform/file_path_conversion.h" +#include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/platform/wtf/functional.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace blink { + +class FileSystemDispatcher::WriteListener + : public mojom::blink::FileSystemOperationListener { + public: + WriteListener(const WriteCallback& success_callback, + StatusCallback error_callback) + : error_callback_(std::move(error_callback)), + write_callback_(success_callback) {} + + void ResultsRetrieved( + Vector<filesystem::mojom::blink::DirectoryEntryPtr> entries, + bool has_more) override { + NOTREACHED(); + } + + void ErrorOccurred(base::File::Error error_code) override { + std::move(error_callback_).Run(error_code); + } + + void DidWrite(int64_t byte_count, bool complete) override { + write_callback_.Run(byte_count, complete); + } + + private: + StatusCallback error_callback_; + WriteCallback write_callback_; +}; + +class FileSystemDispatcher::ReadDirectoryListener + : public mojom::blink::FileSystemOperationListener { + public: + explicit ReadDirectoryListener( + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) + : callbacks_(std::move(callbacks)) {} + + void ResultsRetrieved( + Vector<filesystem::mojom::blink::DirectoryEntryPtr> entries, + bool has_more) override { + for (const auto& entry : entries) { + callbacks_->DidReadDirectoryEntry( + FilePathToWebString(entry->name), + entry->type == filesystem::mojom::blink::FsFileType::DIRECTORY); + } + callbacks_->DidReadDirectoryEntries(has_more); + } + + void ErrorOccurred(base::File::Error error_code) override { + callbacks_->DidFail(error_code); + } + + void DidWrite(int64_t byte_count, bool complete) override { NOTREACHED(); } + + private: + std::unique_ptr<AsyncFileSystemCallbacks> callbacks_; +}; + +FileSystemDispatcher::FileSystemDispatcher(ExecutionContext& context) + : Supplement<ExecutionContext>(context), next_operation_id_(1) {} + +// static +const char FileSystemDispatcher::kSupplementName[] = "FileSystemDispatcher"; + +// static +FileSystemDispatcher& FileSystemDispatcher::From(ExecutionContext* context) { + DCHECK(context); + FileSystemDispatcher* dispatcher = + Supplement<ExecutionContext>::From<FileSystemDispatcher>(context); + if (!dispatcher) { + dispatcher = new FileSystemDispatcher(*context); + Supplement<ExecutionContext>::ProvideTo(*context, dispatcher); + } + return *dispatcher; +} + +FileSystemDispatcher::~FileSystemDispatcher() = default; + +mojom::blink::FileSystemManager& FileSystemDispatcher::GetFileSystemManager() { + if (!file_system_manager_ptr_) { + mojom::blink::FileSystemManagerRequest request = + mojo::MakeRequest(&file_system_manager_ptr_); + // Document::GetInterfaceProvider() can return null if the frame is + // detached. + if (GetSupplementable()->GetInterfaceProvider()) { + GetSupplementable()->GetInterfaceProvider()->GetInterface( + std::move(request)); + } + } + DCHECK(file_system_manager_ptr_); + return *file_system_manager_ptr_; +} + +void FileSystemDispatcher::OpenFileSystem( + const KURL& origin_url, + mojom::blink::FileSystemType type, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + GetFileSystemManager().Open( + origin_url, type, + WTF::Bind(&FileSystemDispatcher::DidOpenFileSystem, + WrapWeakPersistent(this), std::move(callbacks))); +} + +void FileSystemDispatcher::OpenFileSystemSync( + const KURL& origin_url, + mojom::blink::FileSystemType type, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + String name; + KURL root_url; + base::File::Error error_code = base::File::FILE_ERROR_FAILED; + GetFileSystemManager().Open(origin_url, type, &name, &root_url, &error_code); + DidOpenFileSystem(std::move(callbacks), std::move(name), root_url, + error_code); +} + +void FileSystemDispatcher::ResolveURL( + const KURL& filesystem_url, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + GetFileSystemManager().ResolveURL( + filesystem_url, + WTF::Bind(&FileSystemDispatcher::DidResolveURL, WrapWeakPersistent(this), + std::move(callbacks))); +} + +void FileSystemDispatcher::ResolveURLSync( + const KURL& filesystem_url, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + mojom::blink::FileSystemInfoPtr info; + base::FilePath file_path; + bool is_directory; + base::File::Error error_code = base::File::FILE_ERROR_FAILED; + GetFileSystemManager().ResolveURL(filesystem_url, &info, &file_path, + &is_directory, &error_code); + DidResolveURL(std::move(callbacks), std::move(info), std::move(file_path), + is_directory, error_code); +} + +void FileSystemDispatcher::Move( + const KURL& src_path, + const KURL& dest_path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + GetFileSystemManager().Move( + src_path, dest_path, + WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this), + std::move(callbacks))); +} + +void FileSystemDispatcher::MoveSync( + const KURL& src_path, + const KURL& dest_path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + base::File::Error error_code = base::File::FILE_ERROR_FAILED; + GetFileSystemManager().Move(src_path, dest_path, &error_code); + DidFinish(std::move(callbacks), error_code); +} + +void FileSystemDispatcher::Copy( + const KURL& src_path, + const KURL& dest_path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + GetFileSystemManager().Copy( + src_path, dest_path, + WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this), + std::move(callbacks))); +} + +void FileSystemDispatcher::CopySync( + const KURL& src_path, + const KURL& dest_path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + base::File::Error error_code = base::File::FILE_ERROR_FAILED; + GetFileSystemManager().Copy(src_path, dest_path, &error_code); + DidFinish(std::move(callbacks), error_code); +} + +void FileSystemDispatcher::Remove( + const KURL& path, + bool recursive, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + GetFileSystemManager().Remove( + path, recursive, + WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this), + std::move(callbacks))); +} + +void FileSystemDispatcher::RemoveSync( + const KURL& path, + bool recursive, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + base::File::Error error_code = base::File::FILE_ERROR_FAILED; + GetFileSystemManager().Remove(path, recursive, &error_code); + DidFinish(std::move(callbacks), error_code); +} + +void FileSystemDispatcher::ReadMetadata( + const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + GetFileSystemManager().ReadMetadata( + path, WTF::Bind(&FileSystemDispatcher::DidReadMetadata, + WrapWeakPersistent(this), std::move(callbacks))); +} + +void FileSystemDispatcher::ReadMetadataSync( + const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + base::File::Info file_info; + base::File::Error error_code = base::File::FILE_ERROR_FAILED; + GetFileSystemManager().ReadMetadata(path, &file_info, &error_code); + DidReadMetadata(std::move(callbacks), std::move(file_info), error_code); +} + +void FileSystemDispatcher::CreateFile( + const KURL& path, + bool exclusive, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + GetFileSystemManager().Create( + path, exclusive, /*is_directory=*/false, /*is_recursive=*/false, + WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this), + std::move(callbacks))); +} + +void FileSystemDispatcher::CreateFileSync( + const KURL& path, + bool exclusive, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + base::File::Error error_code = base::File::FILE_ERROR_FAILED; + GetFileSystemManager().Create(path, exclusive, /*is_directory=*/false, + /*is_recursive=*/false, &error_code); + DidFinish(std::move(callbacks), error_code); +} + +void FileSystemDispatcher::CreateDirectory( + const KURL& path, + bool exclusive, + bool recursive, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + GetFileSystemManager().Create( + path, exclusive, /*is_directory=*/true, recursive, + WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this), + std::move(callbacks))); +} + +void FileSystemDispatcher::CreateDirectorySync( + const KURL& path, + bool exclusive, + bool recursive, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + base::File::Error error_code = base::File::FILE_ERROR_FAILED; + GetFileSystemManager().Create(path, exclusive, /*is_directory=*/true, + recursive, &error_code); + DidFinish(std::move(callbacks), error_code); +} + +void FileSystemDispatcher::Exists( + const KURL& path, + bool is_directory, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + GetFileSystemManager().Exists( + path, is_directory, + WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this), + std::move(callbacks))); +} + +void FileSystemDispatcher::ExistsSync( + const KURL& path, + bool is_directory, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + base::File::Error error_code = base::File::FILE_ERROR_FAILED; + GetFileSystemManager().Exists(path, is_directory, &error_code); + DidFinish(std::move(callbacks), error_code); +} + +void FileSystemDispatcher::ReadDirectory( + const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + mojom::blink::FileSystemOperationListenerPtr ptr; + mojom::blink::FileSystemOperationListenerRequest request = + mojo::MakeRequest(&ptr); + op_listeners_.AddBinding( + std::make_unique<ReadDirectoryListener>(std::move(callbacks)), + std::move(request)); + GetFileSystemManager().ReadDirectory(path, std::move(ptr)); +} + +void FileSystemDispatcher::ReadDirectorySync( + const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + Vector<filesystem::mojom::blink::DirectoryEntryPtr> entries; + base::File::Error result = base::File::FILE_ERROR_FAILED; + GetFileSystemManager().ReadDirectorySync(path, &entries, &result); + if (result == base::File::FILE_OK) { + DidReadDirectory(std::move(callbacks), std::move(entries), + std::move(result)); + } +} + +void FileSystemDispatcher::InitializeFileWriter( + const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + GetFileSystemManager().ReadMetadata( + path, WTF::Bind(&FileSystemDispatcher::InitializeFileWriterCallback, + WrapWeakPersistent(this), path, std::move(callbacks))); +} + +void FileSystemDispatcher::InitializeFileWriterSync( + const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + base::File::Info file_info; + base::File::Error error_code = base::File::FILE_ERROR_FAILED; + GetFileSystemManager().ReadMetadata(path, &file_info, &error_code); + InitializeFileWriterCallback(path, std::move(callbacks), file_info, + error_code); +} + +void FileSystemDispatcher::Truncate(const KURL& path, + int64_t offset, + int* request_id_out, + StatusCallback callback) { + mojom::blink::FileSystemCancellableOperationPtr op_ptr; + mojom::blink::FileSystemCancellableOperationRequest op_request = + mojo::MakeRequest(&op_ptr); + int operation_id = next_operation_id_++; + op_ptr.set_connection_error_handler( + WTF::Bind(&FileSystemDispatcher::RemoveOperationPtr, + WrapWeakPersistent(this), operation_id)); + cancellable_operations_.insert(operation_id, std::move(op_ptr)); + GetFileSystemManager().Truncate( + path, offset, std::move(op_request), + WTF::Bind(&FileSystemDispatcher::DidTruncate, WrapWeakPersistent(this), + operation_id, std::move(callback))); + + if (request_id_out) + *request_id_out = operation_id; +} + +void FileSystemDispatcher::TruncateSync(const KURL& path, + int64_t offset, + StatusCallback callback) { + base::File::Error error_code = base::File::FILE_ERROR_FAILED; + GetFileSystemManager().TruncateSync(path, offset, &error_code); + std::move(callback).Run(error_code); +} + +void FileSystemDispatcher::Write(const KURL& path, + const String& blob_id, + int64_t offset, + int* request_id_out, + const WriteCallback& success_callback, + StatusCallback error_callback) { + mojom::blink::FileSystemCancellableOperationPtr op_ptr; + mojom::blink::FileSystemCancellableOperationRequest op_request = + mojo::MakeRequest(&op_ptr); + int operation_id = next_operation_id_++; + op_ptr.set_connection_error_handler( + WTF::Bind(&FileSystemDispatcher::RemoveOperationPtr, + WrapWeakPersistent(this), operation_id)); + cancellable_operations_.insert(operation_id, std::move(op_ptr)); + + mojom::blink::FileSystemOperationListenerPtr listener_ptr; + mojom::blink::FileSystemOperationListenerRequest request = + mojo::MakeRequest(&listener_ptr); + op_listeners_.AddBinding( + std::make_unique<WriteListener>( + WTF::BindRepeating(&FileSystemDispatcher::DidWrite, + WrapWeakPersistent(this), success_callback, + operation_id), + WTF::Bind(&FileSystemDispatcher::WriteErrorCallback, + WrapWeakPersistent(this), std::move(error_callback), + operation_id)), + std::move(request)); + + GetFileSystemManager().Write(path, blob_id, offset, std::move(op_request), + std::move(listener_ptr)); + + if (request_id_out) + *request_id_out = operation_id; +} + +void FileSystemDispatcher::WriteSync(const KURL& path, + const String& blob_id, + int64_t offset, + const WriteCallback& success_callback, + StatusCallback error_callback) { + int64_t byte_count; + base::File::Error error_code = base::File::FILE_ERROR_FAILED; + GetFileSystemManager().WriteSync(path, blob_id, offset, &byte_count, + &error_code); + if (error_code == base::File::FILE_OK) + std::move(success_callback).Run(byte_count, /*complete=*/true); + else + std::move(error_callback).Run(error_code); +} + +void FileSystemDispatcher::Cancel(int request_id_to_cancel, + StatusCallback callback) { + if (cancellable_operations_.find(request_id_to_cancel) == + cancellable_operations_.end()) { + std::move(callback).Run(base::File::FILE_ERROR_INVALID_OPERATION); + return; + } + cancellable_operations_.find(request_id_to_cancel) + ->value->Cancel(WTF::Bind(&FileSystemDispatcher::DidCancel, + WrapWeakPersistent(this), std::move(callback), + request_id_to_cancel)); +} + +void FileSystemDispatcher::CreateSnapshotFile( + const KURL& file_path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + GetFileSystemManager().CreateSnapshotFile( + file_path, WTF::Bind(&FileSystemDispatcher::DidCreateSnapshotFile, + WrapWeakPersistent(this), std::move(callbacks))); +} + +void FileSystemDispatcher::CreateSnapshotFileSync( + const KURL& file_path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + base::File::Info file_info; + base::FilePath platform_path; + base::File::Error error_code = base::File::FILE_ERROR_FAILED; + mojom::blink::ReceivedSnapshotListenerPtr listener; + GetFileSystemManager().CreateSnapshotFile( + file_path, &file_info, &platform_path, &error_code, &listener); + DidCreateSnapshotFile(std::move(callbacks), std::move(file_info), + std::move(platform_path), error_code, + std::move(listener)); +} + +void FileSystemDispatcher::DidOpenFileSystem( + std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + const String& name, + const KURL& root, + base::File::Error error_code) { + if (error_code == base::File::Error::FILE_OK) { + callbacks->DidOpenFileSystem(name, root); + } else { + callbacks->DidFail(error_code); + } +} + +void FileSystemDispatcher::DidResolveURL( + std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + mojom::blink::FileSystemInfoPtr info, + const base::FilePath& file_path, + bool is_directory, + base::File::Error error_code) { + if (error_code == base::File::Error::FILE_OK) { + DCHECK(info->root_url.IsValid()); + callbacks->DidResolveURL(info->name, info->root_url, info->mount_type, + FilePathToWebString(file_path), is_directory); + } else { + callbacks->DidFail(error_code); + } +} + +void FileSystemDispatcher::DidFinish( + std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + base::File::Error error_code) { + if (error_code == base::File::Error::FILE_OK) + callbacks->DidSucceed(); + else + callbacks->DidFail(error_code); +} + +void FileSystemDispatcher::DidReadMetadata( + std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + const base::File::Info& file_info, + base::File::Error error_code) { + if (error_code == base::File::Error::FILE_OK) { + callbacks->DidReadMetadata(FileMetadata::From(file_info)); + } else { + callbacks->DidFail(error_code); + } +} + +void FileSystemDispatcher::DidReadDirectory( + std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + Vector<filesystem::mojom::blink::DirectoryEntryPtr> entries, + base::File::Error error_code) { + if (error_code == base::File::Error::FILE_OK) { + for (const auto& entry : entries) { + callbacks->DidReadDirectoryEntry( + FilePathToWebString(entry->name), + entry->type == filesystem::mojom::blink::FsFileType::DIRECTORY); + } + callbacks->DidReadDirectoryEntries(false); + } else { + callbacks->DidFail(error_code); + } +} + +void FileSystemDispatcher::InitializeFileWriterCallback( + const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + const base::File::Info& file_info, + base::File::Error error_code) { + if (error_code == base::File::Error::FILE_OK) { + if (file_info.is_directory || file_info.size < 0) { + callbacks->DidFail(base::File::FILE_ERROR_FAILED); + return; + } + callbacks->DidCreateFileWriter(path, file_info.size); + } else { + callbacks->DidFail(error_code); + } +} + +void FileSystemDispatcher::DidTruncate(int operation_id, + StatusCallback callback, + base::File::Error error_code) { + if (error_code != base::File::FILE_ERROR_ABORT) + RemoveOperationPtr(operation_id); + std::move(callback).Run(error_code); +} + +void FileSystemDispatcher::DidWrite(const WriteCallback& callback, + int operation_id, + int64_t bytes, + bool complete) { + callback.Run(bytes, complete); + if (complete) + RemoveOperationPtr(operation_id); +} + +void FileSystemDispatcher::WriteErrorCallback(StatusCallback callback, + int operation_id, + base::File::Error error) { + std::move(callback).Run(error); + if (error != base::File::FILE_ERROR_ABORT) + RemoveOperationPtr(operation_id); +} + +void FileSystemDispatcher::DidCancel(StatusCallback callback, + int cancelled_operation_id, + base::File::Error error_code) { + if (error_code == base::File::FILE_OK) + RemoveOperationPtr(cancelled_operation_id); + std::move(callback).Run(error_code); +} + +void FileSystemDispatcher::DidCreateSnapshotFile( + std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + const base::File::Info& file_info, + const base::FilePath& platform_path, + base::File::Error error_code, + mojom::blink::ReceivedSnapshotListenerPtr listener) { + if (error_code == base::File::FILE_OK) { + FileMetadata file_metadata = FileMetadata::From(file_info); + file_metadata.platform_path = FilePathToWebString(platform_path); + + std::unique_ptr<BlobData> blob_data = BlobData::Create(); + blob_data->AppendFile(file_metadata.platform_path, 0, file_metadata.length, + InvalidFileTime()); + scoped_refptr<BlobDataHandle> snapshot_blob = + BlobDataHandle::Create(std::move(blob_data), file_metadata.length); + + callbacks->DidCreateSnapshotFile(file_metadata, snapshot_blob); + + if (listener) + listener->DidReceiveSnapshotFile(); + } else { + callbacks->DidFail(error_code); + } +} + +void FileSystemDispatcher::RemoveOperationPtr(int operation_id) { + DCHECK(cancellable_operations_.find(operation_id) != + cancellable_operations_.end()); + cancellable_operations_.erase(operation_id); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h b/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h new file mode 100644 index 00000000000..ec5f5e8c77b --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h @@ -0,0 +1,203 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_SYSTEM_DISPATCHER_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_SYSTEM_DISPATCHER_H_ + +#include "mojo/public/cpp/bindings/strong_binding_set.h" +#include "third_party/blink/public/mojom/filesystem/file_system.mojom-blink.h" +#include "third_party/blink/public/platform/web_callbacks.h" +#include "third_party/blink/renderer/platform/async_file_system_callbacks.h" +#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/supplementable.h" + +namespace WTF { +class String; +} + +namespace blink { + +class KURL; +class ExecutionContext; + +// Sends messages via mojo to the blink::mojom::FileSystemManager service +// running in the browser process. It is owned by ExecutionContext, and +// instances are created lazily by calling FileSystemDispatcher::From(). +class FileSystemDispatcher + : public GarbageCollectedFinalized<FileSystemDispatcher>, + public Supplement<ExecutionContext> { + USING_GARBAGE_COLLECTED_MIXIN(FileSystemDispatcher); + + public: + using StatusCallback = base::OnceCallback<void(base::File::Error error)>; + using WriteCallback = + base::RepeatingCallback<void(int64_t bytes, bool complete)>; + + static const char kSupplementName[]; + + static FileSystemDispatcher& From(ExecutionContext* context); + virtual ~FileSystemDispatcher(); + + mojom::blink::FileSystemManager& GetFileSystemManager(); + + void OpenFileSystem(const KURL& url, + mojom::blink::FileSystemType type, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + void OpenFileSystemSync(const KURL& url, + mojom::blink::FileSystemType type, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + + void ResolveURL(const KURL& filesystem_url, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + void ResolveURLSync(const KURL& filesystem_url, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + + void Move(const KURL& src_path, + const KURL& dest_path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + void MoveSync(const KURL& src_path, + const KURL& dest_path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + + void Copy(const KURL& src_path, + const KURL& dest_path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + void CopySync(const KURL& src_path, + const KURL& dest_path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + + void Remove(const KURL& path, + bool recursive, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + void RemoveSync(const KURL& path, + bool recursive, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + + void ReadMetadata(const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + void ReadMetadataSync(const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + + void CreateFile(const KURL& path, + bool exclusive, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + void CreateFileSync(const KURL& path, + bool exclusive, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + + void CreateDirectory(const KURL& path, + bool exclusive, + bool recursive, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + void CreateDirectorySync(const KURL& path, + bool exclusive, + bool recursive, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + + void Exists(const KURL& path, + bool for_directory, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + void ExistsSync(const KURL& path, + bool for_directory, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + + void ReadDirectory(const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + void ReadDirectorySync(const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + + void InitializeFileWriter(const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks>); + void InitializeFileWriterSync(const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks>); + + void Truncate(const KURL& path, + int64_t offset, + int* request_id_out, + StatusCallback callback); + void TruncateSync(const KURL& path, int64_t offset, StatusCallback callback); + + void Write(const KURL& path, + const String& blob_id, + int64_t offset, + int* request_id_out, + const WriteCallback& success_callback, + StatusCallback error_callback); + void WriteSync(const KURL& path, + const String& blob_id, + int64_t offset, + const WriteCallback& success_callback, + StatusCallback error_callback); + + void Cancel(int request_id_to_cancel, StatusCallback callback); + + void CreateSnapshotFile(const KURL& file_path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + void CreateSnapshotFileSync( + const KURL& file_path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks); + + private: + class WriteListener; + class ReadDirectoryListener; + + explicit FileSystemDispatcher(ExecutionContext& context); + + void DidOpenFileSystem(std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + const String& name, + const KURL& root, + base::File::Error error_code); + void DidResolveURL(std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + mojom::blink::FileSystemInfoPtr info, + const base::FilePath& file_path, + bool is_directory, + base::File::Error error_code); + void DidFinish(std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + base::File::Error error_code); + void DidReadMetadata(std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + const base::File::Info& file_info, + base::File::Error error); + void DidReadDirectory( + std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + Vector<filesystem::mojom::blink::DirectoryEntryPtr> entries, + base::File::Error error_code); + void InitializeFileWriterCallback( + const KURL& path, + std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + const base::File::Info& file_info, + base::File::Error error); + void DidTruncate(int operation_id, + StatusCallback callback, + base::File::Error error_code); + void DidWrite(const WriteCallback& callback, + int operation_id, + int64_t bytes, + bool complete); + void WriteErrorCallback(StatusCallback callback, + int operation_id, + base::File::Error error); + void DidCancel(StatusCallback callback, + int cancelled_operation_id, + base::File::Error error_code); + void DidCreateSnapshotFile( + std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + const base::File::Info& file_info, + const base::FilePath& platform_path, + base::File::Error error_code, + mojom::blink::ReceivedSnapshotListenerPtr listener); + + void RemoveOperationPtr(int operation_id); + + mojom::blink::FileSystemManagerPtr file_system_manager_ptr_; + using OperationsMap = + HashMap<int, mojom::blink::FileSystemCancellableOperationPtr>; + OperationsMap cancellable_operations_; + int next_operation_id_; + mojo::StrongBindingSet<mojom::blink::FileSystemOperationListener> + op_listeners_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_SYSTEM_DISPATCHER_H_ diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc index 91deae419cf..9bf62daa4fc 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc @@ -5,38 +5,19 @@ #include "third_party/blink/renderer/modules/filesystem/file_system_file_handle.h" #include "third_party/blink/public/mojom/filesystem/file_writer.mojom-blink.h" -#include "third_party/blink/public/platform/web_file_system.h" +#include "third_party/blink/public/platform/web_callbacks.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/fileapi/file.h" #include "third_party/blink/renderer/modules/filesystem/dom_file_system.h" #include "third_party/blink/renderer/modules/filesystem/file_system_callbacks.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h" #include "third_party/blink/renderer/modules/filesystem/file_system_writer.h" namespace blink { namespace { -class CreateWriterCallbacks - : public WebCallbacks<mojo::ScopedMessagePipeHandle, base::File::Error> { - public: - explicit CreateWriterCallbacks(ScriptPromiseResolver* resolver) - : resolver_(resolver) {} - - void OnSuccess(mojo::ScopedMessagePipeHandle handle) override { - mojom::blink::FileWriterPtr mojo_writer(mojom::blink::FileWriterPtrInfo( - std::move(handle), mojom::blink::FileWriter::Version_)); - resolver_->Resolve(new FileSystemWriter(std::move(mojo_writer))); - } - - void OnError(base::File::Error error) override { - resolver_->Reject(FileError::CreateDOMException(error)); - } - - private: - Persistent<ScriptPromiseResolver> resolver_; -}; - class OnDidCreateSnapshotFilePromise : public SnapshotFileCallback::OnDidCreateSnapshotFileCallback { public: @@ -59,34 +40,36 @@ FileSystemFileHandle::FileSystemFileHandle(DOMFileSystemBase* file_system, : FileSystemBaseHandle(file_system, full_path) {} ScriptPromise FileSystemFileHandle::createWriter(ScriptState* script_state) { - if (!filesystem()->FileSystem()) { - return ScriptPromise::RejectWithDOMException( - script_state, FileError::CreateDOMException(FileError::kAbortErr)); - } - auto* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise result = resolver->Promise(); - filesystem()->FileSystem()->CreateFileWriter( - filesystem()->CreateFileSystemURL(this), - std::make_unique<CreateWriterCallbacks>(resolver)); + FileSystemDispatcher::From(ExecutionContext::From(script_state)) + .GetFileSystemManager() + .CreateWriter( + filesystem()->CreateFileSystemURL(this), + WTF::Bind( + [](ScriptPromiseResolver* resolver, base::File::Error result, + mojom::blink::FileWriterPtr writer) { + if (result == base::File::FILE_OK) { + resolver->Resolve(new FileSystemWriter(std::move(writer))); + } else { + resolver->Reject(FileError::CreateDOMException(result)); + } + }, + WrapPersistent(resolver))); return result; } ScriptPromise FileSystemFileHandle::getFile(ScriptState* script_state) { - if (!filesystem()->FileSystem()) { - return ScriptPromise::RejectWithDOMException( - script_state, FileError::CreateDOMException(FileError::kAbortErr)); - } - auto* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise result = resolver->Promise(); KURL file_system_url = filesystem()->CreateFileSystemURL(this); - filesystem()->FileSystem()->CreateSnapshotFileAndReadMetadata( - file_system_url, - SnapshotFileCallback::Create(filesystem(), name(), file_system_url, - new OnDidCreateSnapshotFilePromise(resolver), - new PromiseErrorCallback(resolver), - ExecutionContext::From(script_state))); + FileSystemDispatcher::From(ExecutionContext::From(script_state)) + .CreateSnapshotFile(file_system_url, + SnapshotFileCallback::Create( + filesystem(), name(), file_system_url, + new OnDidCreateSnapshotFilePromise(resolver), + new PromiseErrorCallback(resolver), + ExecutionContext::From(script_state))); return result; } diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_file_handle.idl b/chromium/third_party/blink/renderer/modules/filesystem/file_system_file_handle.idl index 7b554909e65..74f5582f547 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_file_handle.idl +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_file_handle.idl @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://wicg.github.io/writable-files/#filesystemfilehandle [ RuntimeEnabled=WritableFiles ] interface FileSystemFileHandle : FileSystemBaseHandle { diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_get_directory_options.idl b/chromium/third_party/blink/renderer/modules/filesystem/file_system_get_directory_options.idl new file mode 100644 index 00000000000..246e8108b53 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_get_directory_options.idl @@ -0,0 +1,8 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://wicg.github.io/writable-files/#dictdef-filesystemgetdirectoryoptions +dictionary FileSystemGetDirectoryOptions { + boolean create = false; +}; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_get_file_options.idl b/chromium/third_party/blink/renderer/modules/filesystem/file_system_get_file_options.idl new file mode 100644 index 00000000000..19c7978f439 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_get_file_options.idl @@ -0,0 +1,8 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://wicg.github.io/writable-files/#dictdef-filesystemgetfileoptions +dictionary FileSystemGetFileOptions { + boolean create = false; +}; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.cc index ab254de4e6e..89ec9b3f123 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.cc @@ -5,9 +5,13 @@ #include "third_party/blink/renderer/modules/filesystem/file_system_writer.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_blob.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" +#include "third_party/blink/renderer/core/fetch/fetch_data_loader.h" +#include "third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.h" #include "third_party/blink/renderer/core/fileapi/blob.h" #include "third_party/blink/renderer/core/fileapi/file_error.h" +#include "third_party/blink/renderer/core/streams/readable_stream_operations.h" #include "third_party/blink/renderer/platform/wtf/functional.h" namespace blink { @@ -19,7 +23,26 @@ FileSystemWriter::FileSystemWriter(mojom::blink::FileWriterPtr writer) ScriptPromise FileSystemWriter::write(ScriptState* script_state, uint64_t position, - Blob* blob) { + ScriptValue data, + ExceptionState& exception_state) { + v8::Isolate* isolate = script_state->GetIsolate(); + if (V8Blob::hasInstance(data.V8Value(), isolate)) { + Blob* blob = V8Blob::ToImpl(data.V8Value().As<v8::Object>()); + return WriteBlob(script_state, position, blob); + } + if (!ReadableStreamOperations::IsReadableStream(script_state, data, + exception_state) + .value_or(false)) { + if (!exception_state.HadException()) + exception_state.ThrowTypeError("data should be a Blob or ReadableStream"); + return ScriptPromise(); + } + return WriteStream(script_state, position, data, exception_state); +} + +ScriptPromise FileSystemWriter::WriteBlob(ScriptState* script_state, + uint64_t position, + Blob* blob) { if (!writer_ || pending_operation_) { return ScriptPromise::RejectWithDOMException( script_state, @@ -33,6 +56,121 @@ ScriptPromise FileSystemWriter::write(ScriptState* script_state, return result; } +class FileSystemWriter::StreamWriterClient + : public GarbageCollectedFinalized<StreamWriterClient>, + public FetchDataLoader::Client { + USING_GARBAGE_COLLECTED_MIXIN(StreamWriterClient); + + public: + explicit StreamWriterClient(FileSystemWriter* writer) : writer_(writer) {} + + void DidFetchDataStartedDataPipe( + mojo::ScopedDataPipeConsumerHandle data_pipe) override { + data_pipe_ = std::move(data_pipe); + } + + mojo::ScopedDataPipeConsumerHandle TakeDataPipe() { + DCHECK(data_pipe_); + return std::move(data_pipe_); + } + + void DidFetchDataLoadedDataPipe() override { + // WriteComplete could have been called with an error before we reach this + // point, in that case just return. + if (did_complete_) + return; + DCHECK(!did_finish_writing_to_pipe_); + DCHECK(writer_->pending_operation_); + did_finish_writing_to_pipe_ = true; + } + + void DidFetchDataLoadFailed() override { + // WriteComplete could have been called with an error before we reach this + // point, in that case just return. + if (did_complete_) + return; + DCHECK(writer_->pending_operation_); + did_complete_ = true; + writer_->pending_operation_->Reject( + FileError::CreateDOMException(base::File::FILE_ERROR_FAILED)); + Reset(); + } + + void Abort() override { + // WriteComplete could have been called with an error before we reach this + // point, in that case just return. + if (did_complete_) + return; + DCHECK(writer_->pending_operation_); + did_complete_ = true; + writer_->pending_operation_->Reject( + FileError::CreateDOMException(base::File::FILE_ERROR_ABORT)); + Reset(); + } + + void WriteComplete(base::File::Error result, uint64_t bytes_written) { + // Early return if we already completed (with an error) before. + if (did_complete_) + return; + DCHECK(writer_->pending_operation_); + did_complete_ = true; + if (result != base::File::FILE_OK) { + writer_->pending_operation_->Reject( + FileError::CreateDOMException(result)); + } else { + DCHECK(did_finish_writing_to_pipe_); + writer_->pending_operation_->Resolve(); + } + Reset(); + } + + void Trace(Visitor* visitor) override { + Client::Trace(visitor); + visitor->Trace(writer_); + } + + private: + void Reset() { + writer_->pending_operation_ = nullptr; + writer_->stream_loader_ = nullptr; + } + + Member<FileSystemWriter> writer_; + mojo::ScopedDataPipeConsumerHandle data_pipe_; + bool did_finish_writing_to_pipe_ = false; + bool did_complete_ = false; +}; + +ScriptPromise FileSystemWriter::WriteStream(ScriptState* script_state, + uint64_t position, + ScriptValue stream, + ExceptionState& exception_state) { + if (!writer_ || pending_operation_) { + return ScriptPromise::RejectWithDOMException( + script_state, + DOMException::Create(DOMExceptionCode::kInvalidStateError)); + } + DCHECK(!stream_loader_); + + auto reader = ReadableStreamOperations::GetReader(script_state, stream, + exception_state); + if (exception_state.HadException()) + return ScriptPromise(); + auto* consumer = new ReadableStreamBytesConsumer(script_state, reader); + + stream_loader_ = FetchDataLoader::CreateLoaderAsDataPipe( + ExecutionContext::From(script_state) + ->GetTaskRunner(TaskType::kInternalDefault)); + pending_operation_ = ScriptPromiseResolver::Create(script_state); + ScriptPromise result = pending_operation_->Promise(); + auto* client = new StreamWriterClient(this); + stream_loader_->Start(consumer, client); + writer_->WriteStream( + position, client->TakeDataPipe(), + WTF::Bind(&StreamWriterClient::WriteComplete, WrapPersistent(client))); + return result; +} + ScriptPromise FileSystemWriter::truncate(ScriptState* script_state, uint64_t size) { if (!writer_ || pending_operation_) { @@ -60,6 +198,7 @@ ScriptPromise FileSystemWriter::close(ScriptState* script_state) { void FileSystemWriter::Trace(Visitor* visitor) { ScriptWrappable::Trace(visitor); visitor->Trace(pending_operation_); + visitor->Trace(stream_loader_); } void FileSystemWriter::WriteComplete(base::File::Error result, diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.h b/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.h index f00cd9f417f..6fa00725759 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.h @@ -7,13 +7,17 @@ #include "third_party/blink/public/mojom/filesystem/file_writer.mojom-blink.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h" namespace blink { class Blob; +class ExceptionState; +class FetchDataLoader; class ScriptPromise; class ScriptPromiseResolver; class ScriptState; +class ScriptValue; class FileSystemWriter final : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); @@ -21,19 +25,31 @@ class FileSystemWriter final : public ScriptWrappable { public: explicit FileSystemWriter(mojom::blink::FileWriterPtr); - ScriptPromise write(ScriptState*, uint64_t position, Blob*); + ScriptPromise write(ScriptState*, + uint64_t position, + ScriptValue data, + ExceptionState&); ScriptPromise truncate(ScriptState*, uint64_t size); ScriptPromise close(ScriptState*); void Trace(Visitor*) override; private: + class StreamWriterClient; + + ScriptPromise WriteBlob(ScriptState*, uint64_t position, Blob*); + ScriptPromise WriteStream(ScriptState*, + uint64_t position, + ScriptValue stream, + ExceptionState&); + void WriteComplete(base::File::Error result, uint64_t bytes_written); void TruncateComplete(base::File::Error result); mojom::blink::FileWriterPtr writer_; Member<ScriptPromiseResolver> pending_operation_; + TraceWrapperMember<FetchDataLoader> stream_loader_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.idl b/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.idl index c4362be6e59..b1cf94195ac 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.idl +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_system_writer.idl @@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://wicg.github.io/writable-files/#filesystemwriter [ NoInterfaceObject, RuntimeEnabled=WritableFiles ] interface FileSystemWriter { - // TODO(mek): Support other types, such as ReadableStream, by using 'any'. - [CallWith=ScriptState] Promise<void> write(unsigned long long position, Blob data); + // TODO(mek): 'any' really is 'Blob or ReadableStream', but that's not + // currently supported by our bindings. + [CallWith=ScriptState, RaisesException] Promise<void> write(unsigned long long position, any data); [CallWith=ScriptState] Promise<void> truncate(unsigned long long size); [CallWith=ScriptState] Promise<void> close(); diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_writer.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_writer.cc index b8f8bb66861..5ad31e6b662 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_writer.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_writer.cc @@ -30,11 +30,11 @@ #include "third_party/blink/renderer/modules/filesystem/file_writer.h" -#include "third_party/blink/public/platform/web_file_writer.h" #include "third_party/blink/public/platform/web_url.h" #include "third_party/blink/renderer/core/events/progress_event.h" #include "third_party/blink/renderer/core/fileapi/blob.h" #include "third_party/blink/renderer/core/probe/core_probes.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/wtf/time.h" @@ -57,11 +57,11 @@ FileWriter::FileWriter(ExecutionContext* context) truncate_length_(-1), num_aborts_(0), recursion_depth_(0), - last_progress_notification_time_ms_(0) {} + last_progress_notification_time_ms_(0), + request_id_(0) {} FileWriter::~FileWriter() { DCHECK(!recursion_depth_); - DCHECK(!Writer()); } const AtomicString& FileWriter::InterfaceName() const { @@ -81,7 +81,6 @@ void FileWriter::write(Blob* data, ExceptionState& exception_state) { if (!GetExecutionContext()) return; DCHECK(data); - DCHECK(Writer()); DCHECK_EQ(truncate_length_, -1); if (ready_state_ == kWriting) { SetError(FileError::kInvalidStateErr, exception_state); @@ -111,7 +110,6 @@ void FileWriter::write(Blob* data, ExceptionState& exception_state) { void FileWriter::seek(long long position, ExceptionState& exception_state) { if (!GetExecutionContext()) return; - DCHECK(Writer()); if (ready_state_ == kWriting) { SetError(FileError::kInvalidStateErr, exception_state); return; @@ -125,7 +123,6 @@ void FileWriter::seek(long long position, ExceptionState& exception_state) { void FileWriter::truncate(long long position, ExceptionState& exception_state) { if (!GetExecutionContext()) return; - DCHECK(Writer()); DCHECK_EQ(truncate_length_, -1); if (ready_state_ == kWriting || position < 0) { SetError(FileError::kInvalidStateErr, exception_state); @@ -154,16 +151,15 @@ void FileWriter::truncate(long long position, ExceptionState& exception_state) { void FileWriter::abort(ExceptionState& exception_state) { if (!GetExecutionContext()) return; - DCHECK(Writer()); if (ready_state_ != kWriting) return; ++num_aborts_; DoOperation(kOperationAbort); - SignalCompletion(FileError::kAbortErr); + SignalCompletion(base::File::FILE_ERROR_ABORT); } -void FileWriter::DidWrite(long long bytes, bool complete) { +void FileWriter::DidWriteImpl(int64_t bytes, bool complete) { if (operation_in_progress_ == kOperationAbort) { CompleteAbort(); return; @@ -183,7 +179,7 @@ void FileWriter::DidWrite(long long bytes, bool complete) { operation_in_progress_ = kOperationNone; } - int num_aborts = num_aborts_; + long long num_aborts = num_aborts_; // We could get an abort in the handler for this event. If we do, it's // already handled the cleanup and signalCompletion call. double now = CurrentTimeMS(); @@ -196,11 +192,11 @@ void FileWriter::DidWrite(long long bytes, bool complete) { if (complete) { if (num_aborts == num_aborts_) - SignalCompletion(FileError::kOK); + SignalCompletion(base::File::FILE_OK); } } -void FileWriter::DidTruncate() { +void FileWriter::DidTruncateImpl() { if (operation_in_progress_ == kOperationAbort) { CompleteAbort(); return; @@ -211,12 +207,12 @@ void FileWriter::DidTruncate() { if (position() > length()) SetPosition(length()); operation_in_progress_ = kOperationNone; - SignalCompletion(FileError::kOK); + SignalCompletion(base::File::FILE_OK); } -void FileWriter::DidFail(WebFileError code) { +void FileWriter::DidFailImpl(base::File::Error error) { DCHECK_NE(kOperationNone, operation_in_progress_); - DCHECK_NE(FileError::kOK, static_cast<FileError::ErrorCode>(code)); + DCHECK_NE(base::File::FILE_OK, error); if (operation_in_progress_ == kOperationAbort) { CompleteAbort(); return; @@ -225,7 +221,29 @@ void FileWriter::DidFail(WebFileError code) { DCHECK_EQ(kWriting, ready_state_); blob_being_written_.Clear(); operation_in_progress_ = kOperationNone; - SignalCompletion(static_cast<FileError::ErrorCode>(code)); + SignalCompletion(error); +} + +void FileWriter::DoTruncate(const KURL& path, int64_t offset) { + FileSystemDispatcher::From(GetExecutionContext()) + .Truncate(path, offset, &request_id_, + WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this))); +} + +void FileWriter::DoWrite(const KURL& path, + const String& blob_id, + int64_t offset) { + FileSystemDispatcher::From(GetExecutionContext()) + .Write( + path, blob_id, offset, &request_id_, + WTF::BindRepeating(&FileWriter::DidWrite, WrapWeakPersistent(this)), + WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this))); +} + +void FileWriter::DoCancel() { + FileSystemDispatcher::From(GetExecutionContext()) + .Cancel(request_id_, + WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this))); } void FileWriter::CompleteAbort() { @@ -244,13 +262,13 @@ void FileWriter::DoOperation(Operation operation) { DCHECK_EQ(-1, truncate_length_); DCHECK(blob_being_written_.Get()); DCHECK_EQ(kWriting, ready_state_); - Writer()->Write(position(), blob_being_written_->Uuid()); + Write(position(), blob_being_written_->Uuid()); break; case kOperationTruncate: DCHECK_EQ(kOperationNone, operation_in_progress_); DCHECK_GE(truncate_length_, 0); DCHECK_EQ(kWriting, ready_state_); - Writer()->Truncate(truncate_length_); + Truncate(truncate_length_); break; case kOperationNone: DCHECK_EQ(kOperationNone, operation_in_progress_); @@ -261,7 +279,7 @@ void FileWriter::DoOperation(Operation operation) { case kOperationAbort: if (operation_in_progress_ == kOperationWrite || operation_in_progress_ == kOperationTruncate) - Writer()->Cancel(); + Cancel(); else if (operation_in_progress_ != kOperationAbort) operation = kOperationNone; queued_operation_ = kOperationNone; @@ -273,12 +291,12 @@ void FileWriter::DoOperation(Operation operation) { operation_in_progress_ = operation; } -void FileWriter::SignalCompletion(FileError::ErrorCode code) { +void FileWriter::SignalCompletion(base::File::Error error) { ready_state_ = kDone; truncate_length_ = -1; - if (FileError::kOK != code) { - error_ = FileError::CreateDOMException(code); - if (FileError::kAbortErr == code) + if (error != base::File::FILE_OK) { + error_ = FileError::CreateDOMException(error); + if (base::File::FILE_ERROR_ABORT == error) FireEvent(EventTypeNames::abort); else FireEvent(EventTypeNames::error); @@ -308,11 +326,12 @@ void FileWriter::SetError(FileError::ErrorCode error_code, void FileWriter::Dispose() { // Make sure we've actually got something to stop, and haven't already called // abort(). - if (Writer() && ready_state_ == kWriting) { + if (ready_state_ == kWriting) { DoOperation(kOperationAbort); ready_state_ = kDone; } - ResetWriter(); + // Prevents any queued operations from running after abort completes. + queued_operation_ = kOperationNone; } void FileWriter::Trace(blink::Visitor* visitor) { diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_writer.h b/chromium/third_party/blink/renderer/modules/filesystem/file_writer.h index e8215bd1f97..69c38d342df 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_writer.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_writer.h @@ -31,7 +31,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_WRITER_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_WRITER_H_ -#include "third_party/blink/public/platform/web_file_writer_client.h" #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" #include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" @@ -49,8 +48,7 @@ class ExecutionContext; class FileWriter final : public EventTargetWithInlineData, public FileWriterBase, public ActiveScriptWrappable<FileWriter>, - public ContextLifecycleObserver, - public WebFileWriterClient { + public ContextLifecycleObserver { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(FileWriter); USING_PRE_FINALIZER(FileWriter, Dispose); @@ -68,10 +66,15 @@ class FileWriter final : public EventTargetWithInlineData, ReadyState getReadyState() const { return ready_state_; } DOMException* error() const { return error_.Get(); } - // WebFileWriterClient - void DidWrite(long long bytes, bool complete) override; - void DidTruncate() override; - void DidFail(WebFileError) override; + // FileWriterBase + void DidWriteImpl(int64_t bytes, bool complete) override; + void DidTruncateImpl() override; + void DidFailImpl(base::File::Error error) override; + void DoTruncate(const KURL& path, int64_t offset) override; + void DoWrite(const KURL& path, + const String& blob_id, + int64_t offset) override; + void DoCancel() override; // ContextLifecycleObserver void ContextDestroyed(ExecutionContext*) override; @@ -108,7 +111,7 @@ class FileWriter final : public EventTargetWithInlineData, void DoOperation(Operation); - void SignalCompletion(FileError::ErrorCode); + void SignalCompletion(base::File::Error error_code); void FireEvent(const AtomicString& type); @@ -127,6 +130,7 @@ class FileWriter final : public EventTargetWithInlineData, long long recursion_depth_; double last_progress_notification_time_ms_; Member<Blob> blob_being_written_; + int request_id_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_writer_base.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_base.cc index 42d7dbd107f..5e01937d035 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_writer_base.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_base.cc @@ -31,7 +31,6 @@ #include "third_party/blink/renderer/modules/filesystem/file_writer_base.h" #include <memory> -#include "third_party/blink/public/platform/web_file_writer.h" #include "third_party/blink/renderer/core/events/progress_event.h" #include "third_party/blink/renderer/core/fileapi/blob.h" #include "third_party/blink/renderer/core/fileapi/file_error.h" @@ -40,15 +39,16 @@ namespace blink { FileWriterBase::~FileWriterBase() = default; -void FileWriterBase::Initialize(std::unique_ptr<WebFileWriter> writer, - long long length) { - DCHECK(!writer_); +void FileWriterBase::Initialize(const KURL& path, long long length) { DCHECK_GE(length, 0); - writer_ = std::move(writer); length_ = length; + path_ = path; } -FileWriterBase::FileWriterBase() : position_(0) {} +FileWriterBase::FileWriterBase() + : position_(0), + operation_(kOperationNone), + cancel_state_(kCancelNotInProgress) {} void FileWriterBase::SeekInternal(long long position) { if (position > length_) @@ -60,14 +60,129 @@ void FileWriterBase::SeekInternal(long long position) { position_ = position; } -void FileWriterBase::ResetWriter() { - writer_ = nullptr; +void FileWriterBase::Truncate(long long length) { + DCHECK_EQ(kOperationNone, operation_); + DCHECK_EQ(kCancelNotInProgress, cancel_state_); + operation_ = kOperationTruncate; + DoTruncate(path_, length); } -void FileWriterBase::Dispose() { - // Need to explicitly destroy m_writer in pre-finalizer, because otherwise it - // may attempt to call methods on the FileWriter before we are finalized. - ResetWriter(); +void FileWriterBase::Write(long long position, const String& id) { + DCHECK_EQ(kOperationNone, operation_); + DCHECK_EQ(kCancelNotInProgress, cancel_state_); + operation_ = kOperationWrite; + DoWrite(path_, id, position); +} + +// When we cancel a write/truncate, we always get back the result of the write +// before the result of the cancel, no matter what happens. +// So we'll get back either +// success [of the write/truncate, in a DidWrite(XXX, true)/DidSucceed() call] +// followed by failure [of the cancel]; or +// failure [of the write, either from cancel or other reasons] followed by +// the result of the cancel. +// In the write case, there could also be queued up non-terminal DidWrite calls +// before any of that comes back, but there will always be a terminal write +// response [success or failure] after them, followed by the cancel result, so +// we can ignore non-terminal write responses, take the terminal write success +// or the first failure as the last write response, then know that the next +// thing to come back is the cancel response. We only notify the +// AsyncFileWriterClient when it's all over. +void FileWriterBase::Cancel() { + // Check for the cancel passing the previous operation's return in-flight. + if (operation_ != kOperationWrite && operation_ != kOperationTruncate) + return; + if (cancel_state_ != kCancelNotInProgress) + return; + cancel_state_ = kCancelSent; + DoCancel(); +} + +void FileWriterBase::DidFinish(base::File::Error error_code) { + if (error_code == base::File::FILE_OK) + DidSucceed(); + else + DidFail(error_code); +} + +void FileWriterBase::DidWrite(int64_t bytes, bool complete) { + DCHECK_EQ(kOperationWrite, operation_); + switch (cancel_state_) { + case kCancelNotInProgress: + if (complete) + operation_ = kOperationNone; + DidWriteImpl(bytes, complete); + break; + case kCancelSent: + // This is the success call of the write, which we'll eat, even though + // it succeeded before the cancel got there. We accepted the cancel call, + // so the write will eventually return an error. + if (complete) + cancel_state_ = kCancelReceivedWriteResponse; + break; + case kCancelReceivedWriteResponse: + default: + NOTREACHED(); + } +} + +void FileWriterBase::DidSucceed() { + // Write never gets a DidSucceed call, so this is either a cancel or truncate + // response. + switch (cancel_state_) { + case kCancelNotInProgress: + // A truncate succeeded, with no complications. + DCHECK_EQ(kOperationTruncate, operation_); + operation_ = kOperationNone; + DidTruncateImpl(); + break; + case kCancelSent: + DCHECK_EQ(kOperationTruncate, operation_); + // This is the success call of the truncate, which we'll eat, even though + // it succeeded before the cancel got there. We accepted the cancel call, + // so the truncate will eventually return an error. + cancel_state_ = kCancelReceivedWriteResponse; + break; + case kCancelReceivedWriteResponse: + // This is the success of the cancel operation. + FinishCancel(); + break; + default: + NOTREACHED(); + } +} + +void FileWriterBase::DidFail(base::File::Error error_code) { + DCHECK_NE(kOperationNone, operation_); + switch (cancel_state_) { + case kCancelNotInProgress: + // A write or truncate failed. + operation_ = kOperationNone; + DidFailImpl(error_code); + break; + case kCancelSent: + // This is the failure of a write or truncate; the next message should be + // the result of the cancel. We don't assume that it'll be a success, as + // the write/truncate could have failed for other reasons. + cancel_state_ = kCancelReceivedWriteResponse; + break; + case kCancelReceivedWriteResponse: + // The cancel reported failure, meaning that the write or truncate + // finished before the cancel got there. But we suppressed the + // write/truncate's response, and will now report that it was cancelled. + FinishCancel(); + break; + default: + NOTREACHED(); + } +} + +void FileWriterBase::FinishCancel() { + DCHECK_EQ(kCancelReceivedWriteResponse, cancel_state_); + DCHECK_NE(kOperationNone, operation_); + cancel_state_ = kCancelNotInProgress; + operation_ = kOperationNone; + DidFailImpl(base::File::FILE_ERROR_ABORT); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_writer_base.h b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_base.h index 0e608ce3fb1..03e1b25cf82 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_writer_base.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_base.h @@ -32,43 +32,72 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_WRITER_BASE_H_ #include <memory> +#include "base/files/file.h" +#include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/weborigin/kurl.h" namespace blink { -class WebFileWriter; - -class FileWriterBase : public GarbageCollectedMixin { - USING_PRE_FINALIZER(FileWriterBase, Dispose); - +class MODULES_EXPORT FileWriterBase : public GarbageCollectedMixin { public: virtual ~FileWriterBase(); - void Initialize(std::unique_ptr<WebFileWriter>, long long length); + void Initialize(const KURL& path, long long length); long long position() const { return position_; } long long length() const { return length_; } void Trace(blink::Visitor* visitor) override {} + virtual void Truncate(long long length); + virtual void Write(long long position, const String& id); + virtual void Cancel(); + protected: FileWriterBase(); - WebFileWriter* Writer() { return writer_.get(); } - void SetPosition(long long position) { position_ = position; } void SetLength(long long length) { length_ = length; } void SeekInternal(long long position); - void ResetWriter(); + // This calls DidSucceed() or DidFail() based on the value of |error_code|. + void DidFinish(base::File::Error error_code); + void DidSucceed(); + void DidWrite(int64_t bytes, bool complete); + void DidFail(base::File::Error error_code); + + // Derived classes must provide these methods to asynchronously perform + // the requested operation, and they must call the appropriate DidSomething + // method upon completion and as progress is made in the Write case. + virtual void DoTruncate(const KURL& path, int64_t offset) = 0; + virtual void DoWrite(const KURL& path, + const String& blob_id, + int64_t offset) = 0; + virtual void DoCancel() = 0; + + // These are conditionally called by the Did* methods. + virtual void DidWriteImpl(int64_t bytes, bool complete) = 0; + virtual void DidFailImpl(base::File::Error error_code) = 0; + virtual void DidTruncateImpl() = 0; private: - void Dispose(); + enum OperationType { kOperationNone, kOperationWrite, kOperationTruncate }; + + enum CancelState { + kCancelNotInProgress, + kCancelSent, + kCancelReceivedWriteResponse, + }; + + void FinishCancel(); - std::unique_ptr<WebFileWriter> writer_; long long position_; long long length_; + KURL path_; + OperationType operation_; + CancelState cancel_state_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_writer_sync.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_sync.cc index 85377d37a0e..e9c20b16cc1 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_writer_sync.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_sync.cc @@ -30,20 +30,19 @@ #include "third_party/blink/renderer/modules/filesystem/file_writer_sync.h" -#include "third_party/blink/public/platform/web_file_writer.h" #include "third_party/blink/public/platform/web_url.h" #include "third_party/blink/renderer/core/fileapi/blob.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" namespace blink { void FileWriterSync::write(Blob* data, ExceptionState& exception_state) { DCHECK(data); - DCHECK(Writer()); DCHECK(complete_); PrepareForWrite(); - Writer()->Write(position(), data->Uuid()); + Write(position(), data->Uuid()); DCHECK(complete_); if (error_) { FileError::ThrowDOMException(exception_state, error_); @@ -55,14 +54,12 @@ void FileWriterSync::write(Blob* data, ExceptionState& exception_state) { } void FileWriterSync::seek(long long position, ExceptionState& exception_state) { - DCHECK(Writer()); DCHECK(complete_); SeekInternal(position); } void FileWriterSync::truncate(long long offset, ExceptionState& exception_state) { - DCHECK(Writer()); DCHECK(complete_); if (offset < 0) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, @@ -70,7 +67,7 @@ void FileWriterSync::truncate(long long offset, return; } PrepareForWrite(); - Writer()->Truncate(offset); + Truncate(offset); DCHECK(complete_); if (error_) { FileError::ThrowDOMException(exception_state, error_); @@ -81,30 +78,57 @@ void FileWriterSync::truncate(long long offset, SetLength(offset); } -void FileWriterSync::DidWrite(long long bytes, bool complete) { - DCHECK_EQ(FileError::kOK, error_); +void FileWriterSync::DidWriteImpl(int64_t bytes, bool complete) { + DCHECK_EQ(base::File::FILE_OK, error_); DCHECK(!complete_); complete_ = complete; } -void FileWriterSync::DidTruncate() { - DCHECK_EQ(FileError::kOK, error_); +void FileWriterSync::DidTruncateImpl() { + DCHECK_EQ(base::File::FILE_OK, error_); DCHECK(!complete_); complete_ = true; } -void FileWriterSync::DidFail(WebFileError error) { - DCHECK_EQ(FileError::kOK, error_); - error_ = static_cast<FileError::ErrorCode>(error); +void FileWriterSync::DidFailImpl(base::File::Error error) { + DCHECK_EQ(base::File::FILE_OK, error_); + error_ = error; DCHECK(!complete_); complete_ = true; } -FileWriterSync::FileWriterSync() : error_(FileError::kOK), complete_(true) {} +void FileWriterSync::DoTruncate(const KURL& path, int64_t offset) { + if (!GetExecutionContext()) + return; + FileSystemDispatcher::From(GetExecutionContext()) + .TruncateSync( + path, offset, + WTF::Bind(&FileWriterSync::DidFinish, WrapWeakPersistent(this))); +} + +void FileWriterSync::DoWrite(const KURL& path, + const String& blob_id, + int64_t offset) { + if (!GetExecutionContext()) + return; + FileSystemDispatcher::From(GetExecutionContext()) + .WriteSync( + path, blob_id, offset, + WTF::BindRepeating(&FileWriterSync::DidWrite, + WrapWeakPersistent(this)), + WTF::Bind(&FileWriterSync::DidFinish, WrapWeakPersistent(this))); +} + +void FileWriterSync::DoCancel() { + NOTREACHED(); +} + +FileWriterSync::FileWriterSync(ExecutionContext* context) + : ContextClient(context), error_(base::File::FILE_OK), complete_(true) {} void FileWriterSync::PrepareForWrite() { DCHECK(complete_); - error_ = FileError::kOK; + error_ = base::File::FILE_OK; complete_ = false; } @@ -113,6 +137,7 @@ FileWriterSync::~FileWriterSync() = default; void FileWriterSync::Trace(blink::Visitor* visitor) { ScriptWrappable::Trace(visitor); FileWriterBase::Trace(visitor); + ContextClient::Trace(visitor); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_writer_sync.h b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_sync.h index 1d6bf25fb73..656160699d8 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/file_writer_sync.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_sync.h @@ -31,7 +31,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_WRITER_SYNC_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_WRITER_SYNC_H_ -#include "third_party/blink/public/platform/web_file_writer_client.h" +#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" #include "third_party/blink/renderer/core/fileapi/file_error.h" #include "third_party/blink/renderer/modules/filesystem/file_writer_base.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" @@ -44,30 +44,36 @@ class ExceptionState; class FileWriterSync final : public ScriptWrappable, public FileWriterBase, - public WebFileWriterClient { + public ContextClient { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(FileWriterSync); public: - static FileWriterSync* Create() { return new FileWriterSync(); } + static FileWriterSync* Create(ExecutionContext* context) { + return new FileWriterSync(context); + } ~FileWriterSync() override; void Trace(blink::Visitor*) override; - // FileWriterBase void write(Blob*, ExceptionState&); void seek(long long position, ExceptionState&); void truncate(long long length, ExceptionState&); - // WebFileWriterClient, via FileWriterBase - void DidWrite(long long bytes, bool complete) override; - void DidTruncate() override; - void DidFail(WebFileError) override; + // FileWriterBase + void DidWriteImpl(int64_t bytes, bool complete) override; + void DidTruncateImpl() override; + void DidFailImpl(base::File::Error error) override; + void DoTruncate(const KURL& path, int64_t offset) override; + void DoWrite(const KURL& path, + const String& blob_id, + int64_t offset) override; + void DoCancel() override; private: - FileWriterSync(); + explicit FileWriterSync(ExecutionContext* context); void PrepareForWrite(); - FileError::ErrorCode error_; + base::File::Error error_; bool complete_; }; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/file_writer_test.cc b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_test.cc new file mode 100644 index 00000000000..efd3679bafa --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/filesystem/file_writer_test.cc @@ -0,0 +1,353 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/filesystem/file_writer_base.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { + +namespace { + +// We use particular offsets to trigger particular behaviors +// in the TestableFileWriter. +const int kNoOffset = -1; +const int kBasicFileTruncate_Offset = 1; +const int kErrorFileTruncate_Offset = 2; +const int kCancelFileTruncate_Offset = 3; +const int kCancelFailedTruncate_Offset = 4; +const int kBasicFileWrite_Offset = 1; +const int kErrorFileWrite_Offset = 2; +const int kMultiFileWrite_Offset = 3; +const int kCancelFileWriteBeforeCompletion_Offset = 4; +const int kCancelFileWriteAfterCompletion_Offset = 5; + +KURL mock_path_as_kurl() { + return KURL("MockPath"); +} + +} // namespace + +class TestableFileWriter : public GarbageCollectedFinalized<TestableFileWriter>, + public FileWriterBase { + USING_GARBAGE_COLLECTED_MIXIN(TestableFileWriter); + + public: + explicit TestableFileWriter() { reset(); } + + void reset() { + received_truncate_ = false; + received_truncate_path_ = KURL(); + received_truncate_offset_ = kNoOffset; + received_write_ = false; + received_write_path_ = KURL(); + received_write_offset_ = kNoOffset; + received_write_blob_uuid_ = String(); + received_cancel_ = false; + + received_did_write_count_ = 0; + received_did_write_bytes_total_ = 0; + received_did_write_complete_ = false; + received_did_truncate_ = false; + received_did_fail_ = false; + fail_error_received_ = static_cast<base::File::Error>(0); + } + + void Trace(Visitor* visitor) override { FileWriterBase::Trace(visitor); } + + bool received_truncate_; + KURL received_truncate_path_; + int64_t received_truncate_offset_; + bool received_write_; + KURL received_write_path_; + String received_write_blob_uuid_; + int64_t received_write_offset_; + bool received_cancel_; + + int received_did_write_count_; + long long received_did_write_bytes_total_; + bool received_did_write_complete_; + bool received_did_truncate_; + bool received_did_fail_; + base::File::Error fail_error_received_; + + protected: + void DoTruncate(const KURL& path, int64_t offset) override { + received_truncate_ = true; + received_truncate_path_ = path; + received_truncate_offset_ = offset; + + if (offset == kBasicFileTruncate_Offset) { + DidSucceed(); + } else if (offset == kErrorFileTruncate_Offset) { + DidFail(base::File::FILE_ERROR_NOT_FOUND); + } else if (offset == kCancelFileTruncate_Offset) { + Cancel(); + DidSucceed(); // truncate completion + DidSucceed(); // cancel completion + } else if (offset == kCancelFailedTruncate_Offset) { + Cancel(); + DidFail(base::File::FILE_ERROR_NOT_FOUND); // truncate completion + DidSucceed(); // cancel completion + } else { + FAIL(); + } + } + + void DoWrite(const KURL& path, + const String& blob_uuid, + int64_t offset) override { + received_write_ = true; + received_write_path_ = path; + received_write_offset_ = offset; + received_write_blob_uuid_ = blob_uuid; + + if (offset == kBasicFileWrite_Offset) { + DidWrite(1, true); + } else if (offset == kErrorFileWrite_Offset) { + DidFail(base::File::FILE_ERROR_NOT_FOUND); + } else if (offset == kMultiFileWrite_Offset) { + DidWrite(1, false); + DidWrite(1, false); + DidWrite(1, true); + } else if (offset == kCancelFileWriteBeforeCompletion_Offset) { + DidWrite(1, false); + Cancel(); + DidWrite(1, false); + DidWrite(1, false); + DidFail(base::File::FILE_ERROR_NOT_FOUND); // write completion + DidSucceed(); // cancel completion + } else if (offset == kCancelFileWriteAfterCompletion_Offset) { + DidWrite(1, false); + Cancel(); + DidWrite(1, false); + DidWrite(1, false); + DidWrite(1, true); // write completion + DidFail(base::File::FILE_ERROR_NOT_FOUND); // cancel completion + } else { + FAIL(); + } + } + + void DoCancel() override { received_cancel_ = true; } + + void DidWriteImpl(int64_t bytes, bool complete) override { + EXPECT_FALSE(received_did_write_complete_); + ++received_did_write_count_; + received_did_write_bytes_total_ += bytes; + if (complete) + received_did_write_complete_ = true; + } + + void DidTruncateImpl() override { + EXPECT_FALSE(received_did_truncate_); + received_did_truncate_ = true; + } + + void DidFailImpl(base::File::Error error) override { + EXPECT_FALSE(received_did_fail_); + received_did_fail_ = true; + fail_error_received_ = error; + } +}; + +class FileWriterTest : public testing::Test { + public: + FileWriterTest() = default; + + FileWriterBase* writer() { return testable_writer_.Get(); } + + protected: + void SetUp() override { + testable_writer_ = new TestableFileWriter(); + testable_writer_->Initialize(mock_path_as_kurl(), 10); + } + + Persistent<TestableFileWriter> testable_writer_; + + DISALLOW_COPY_AND_ASSIGN(FileWriterTest); +}; + +TEST_F(FileWriterTest, BasicFileWrite) { + const String kBlobId("1234"); + writer()->Write(kBasicFileWrite_Offset, kBlobId); + + // Check that the Do* methods of the derived class get called correctly. + EXPECT_TRUE(testable_writer_->received_write_); + EXPECT_EQ(testable_writer_->received_write_path_, mock_path_as_kurl()); + EXPECT_EQ(kBasicFileWrite_Offset, testable_writer_->received_write_offset_); + EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); + EXPECT_FALSE(testable_writer_->received_truncate_); + EXPECT_FALSE(testable_writer_->received_cancel_); + + // Check that the Did*Impl methods of the client gets called correctly. + EXPECT_EQ(1, testable_writer_->received_did_write_count_); + EXPECT_TRUE(testable_writer_->received_did_write_complete_); + EXPECT_EQ(1, testable_writer_->received_did_write_bytes_total_); + EXPECT_FALSE(testable_writer_->received_did_truncate_); + EXPECT_FALSE(testable_writer_->received_did_fail_); +} + +TEST_F(FileWriterTest, BasicFileTruncate) { + writer()->Truncate(kBasicFileTruncate_Offset); + + // Check that the Do* methods of the derived class get called correctly. + EXPECT_TRUE(testable_writer_->received_truncate_); + EXPECT_EQ(mock_path_as_kurl(), testable_writer_->received_truncate_path_); + EXPECT_EQ(kBasicFileTruncate_Offset, + testable_writer_->received_truncate_offset_); + EXPECT_FALSE(testable_writer_->received_write_); + EXPECT_FALSE(testable_writer_->received_cancel_); + + // Check that the Did*Impl methods of the client gets called correctly. + EXPECT_TRUE(testable_writer_->received_did_truncate_); + EXPECT_EQ(0, testable_writer_->received_did_write_count_); + EXPECT_FALSE(testable_writer_->received_did_fail_); +} + +TEST_F(FileWriterTest, ErrorFileWrite) { + const String kBlobId("1234"); + writer()->Write(kErrorFileWrite_Offset, kBlobId); + + // Check that the Do* methods of the derived class get called correctly. + EXPECT_TRUE(testable_writer_->received_write_); + EXPECT_EQ(testable_writer_->received_write_path_, mock_path_as_kurl()); + EXPECT_EQ(kErrorFileWrite_Offset, testable_writer_->received_write_offset_); + EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); + EXPECT_FALSE(testable_writer_->received_truncate_); + EXPECT_FALSE(testable_writer_->received_cancel_); + + // Check that the Did*Impl methods of the client gets called correctly. + EXPECT_TRUE(testable_writer_->received_did_fail_); + EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, + testable_writer_->fail_error_received_); + EXPECT_EQ(0, testable_writer_->received_did_write_count_); + EXPECT_FALSE(testable_writer_->received_did_truncate_); +} + +TEST_F(FileWriterTest, ErrorFileTruncate) { + writer()->Truncate(kErrorFileTruncate_Offset); + + // Check that the Do* methods of the derived class get called correctly. + EXPECT_TRUE(testable_writer_->received_truncate_); + EXPECT_EQ(mock_path_as_kurl(), testable_writer_->received_truncate_path_); + EXPECT_EQ(kErrorFileTruncate_Offset, + testable_writer_->received_truncate_offset_); + EXPECT_FALSE(testable_writer_->received_write_); + EXPECT_FALSE(testable_writer_->received_cancel_); + + // Check that the Did*Impl methods of the client gets called correctly. + EXPECT_TRUE(testable_writer_->received_did_fail_); + EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, + testable_writer_->fail_error_received_); + EXPECT_FALSE(testable_writer_->received_did_truncate_); + EXPECT_EQ(0, testable_writer_->received_did_write_count_); +} + +TEST_F(FileWriterTest, MultiFileWrite) { + const String kBlobId("1234"); + writer()->Write(kMultiFileWrite_Offset, kBlobId); + + // Check that the Do* methods of the derived class get called correctly. + EXPECT_TRUE(testable_writer_->received_write_); + EXPECT_EQ(testable_writer_->received_write_path_, mock_path_as_kurl()); + EXPECT_EQ(kMultiFileWrite_Offset, testable_writer_->received_write_offset_); + EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); + EXPECT_FALSE(testable_writer_->received_truncate_); + EXPECT_FALSE(testable_writer_->received_cancel_); + + // Check that the Did*Impl methods of the client gets called correctly. + EXPECT_EQ(3, testable_writer_->received_did_write_count_); + EXPECT_TRUE(testable_writer_->received_did_write_complete_); + EXPECT_EQ(3, testable_writer_->received_did_write_bytes_total_); + EXPECT_FALSE(testable_writer_->received_did_truncate_); + EXPECT_FALSE(testable_writer_->received_did_fail_); +} + +TEST_F(FileWriterTest, CancelFileWriteBeforeCompletion) { + const String kBlobId("1234"); + writer()->Write(kCancelFileWriteBeforeCompletion_Offset, kBlobId); + + // Check that the Do* methods of the derived class get called correctly. + EXPECT_TRUE(testable_writer_->received_write_); + EXPECT_EQ(testable_writer_->received_write_path_, mock_path_as_kurl()); + EXPECT_EQ(kCancelFileWriteBeforeCompletion_Offset, + testable_writer_->received_write_offset_); + EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); + EXPECT_TRUE(testable_writer_->received_cancel_); + EXPECT_FALSE(testable_writer_->received_truncate_); + + // Check that the Did*Impl methods of the client gets called correctly. + EXPECT_TRUE(testable_writer_->received_did_fail_); + EXPECT_EQ(base::File::FILE_ERROR_ABORT, + testable_writer_->fail_error_received_); + EXPECT_EQ(1, testable_writer_->received_did_write_count_); + EXPECT_FALSE(testable_writer_->received_did_write_complete_); + EXPECT_EQ(1, testable_writer_->received_did_write_bytes_total_); + EXPECT_FALSE(testable_writer_->received_did_truncate_); +} + +TEST_F(FileWriterTest, CancelFileWriteAfterCompletion) { + const String kBlobId("1234"); + writer()->Write(kCancelFileWriteAfterCompletion_Offset, kBlobId); + + // Check that the Do* methods of the derived class get called correctly. + EXPECT_TRUE(testable_writer_->received_write_); + EXPECT_EQ(testable_writer_->received_write_path_, mock_path_as_kurl()); + EXPECT_EQ(kCancelFileWriteAfterCompletion_Offset, + testable_writer_->received_write_offset_); + EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_); + EXPECT_TRUE(testable_writer_->received_cancel_); + EXPECT_FALSE(testable_writer_->received_truncate_); + + // Check that the Did*Impl methods of the client gets called correctly. + EXPECT_TRUE(testable_writer_->received_did_fail_); + EXPECT_EQ(base::File::FILE_ERROR_ABORT, + testable_writer_->fail_error_received_); + EXPECT_EQ(1, testable_writer_->received_did_write_count_); + EXPECT_FALSE(testable_writer_->received_did_write_complete_); + EXPECT_EQ(1, testable_writer_->received_did_write_bytes_total_); + EXPECT_FALSE(testable_writer_->received_did_truncate_); +} + +TEST_F(FileWriterTest, CancelFileTruncate) { + writer()->Truncate(kCancelFileTruncate_Offset); + + // Check that the Do* methods of the derived class get called correctly. + EXPECT_TRUE(testable_writer_->received_truncate_); + EXPECT_EQ(mock_path_as_kurl(), testable_writer_->received_truncate_path_); + EXPECT_EQ(kCancelFileTruncate_Offset, + testable_writer_->received_truncate_offset_); + EXPECT_TRUE(testable_writer_->received_cancel_); + EXPECT_FALSE(testable_writer_->received_write_); + + // Check that the Did*Impl methods of the client gets called correctly. + EXPECT_TRUE(testable_writer_->received_did_fail_); + EXPECT_EQ(base::File::FILE_ERROR_ABORT, + testable_writer_->fail_error_received_); + EXPECT_FALSE(testable_writer_->received_did_truncate_); + EXPECT_EQ(0, testable_writer_->received_did_write_count_); +} + +TEST_F(FileWriterTest, CancelFailedTruncate) { + writer()->Truncate(kCancelFailedTruncate_Offset); + + // Check that the Do* methods of the derived class get called correctly. + EXPECT_TRUE(testable_writer_->received_truncate_); + EXPECT_EQ(mock_path_as_kurl(), testable_writer_->received_truncate_path_); + EXPECT_EQ(kCancelFailedTruncate_Offset, + testable_writer_->received_truncate_offset_); + EXPECT_TRUE(testable_writer_->received_cancel_); + EXPECT_FALSE(testable_writer_->received_write_); + + // Check that the Did*Impl methods of the client gets called correctly. + EXPECT_TRUE(testable_writer_->received_did_fail_); + EXPECT_EQ(base::File::FILE_ERROR_ABORT, + testable_writer_->fail_error_received_); + EXPECT_FALSE(testable_writer_->received_did_truncate_); + EXPECT_EQ(0, testable_writer_->received_did_write_count_); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/filesystem/get_system_directory_options.idl b/chromium/third_party/blink/renderer/modules/filesystem/get_system_directory_options.idl new file mode 100644 index 00000000000..831ac3560fa --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/filesystem/get_system_directory_options.idl @@ -0,0 +1,13 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://wicg.github.io/writable-files/#enumdef-systemdirectorytype +enum SystemDirectoryType { + "sandbox" +}; + +// https://wicg.github.io/writable-files/#dictdef-getsystemdirectoryoptions +dictionary GetSystemDirectoryOptions { + required SystemDirectoryType type; +}; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/local_file_system.cc b/chromium/third_party/blink/renderer/modules/filesystem/local_file_system.cc index 4eb2801f037..c14ff58d913 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/local_file_system.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/local_file_system.cc @@ -35,7 +35,6 @@ #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/task_type.h" -#include "third_party/blink/public/platform/web_file_system.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" @@ -44,19 +43,20 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_client.h" #include "third_party/blink/renderer/core/workers/worker_global_scope.h" -#include "third_party/blink/renderer/modules/filesystem/directory_entry.h" #include "third_party/blink/renderer/modules/filesystem/dom_file_system.h" #include "third_party/blink/renderer/modules/filesystem/file_system_client.h" +#include "third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h" #include "third_party/blink/renderer/platform/async_file_system_callbacks.h" #include "third_party/blink/renderer/platform/content_setting_callbacks.h" #include "third_party/blink/renderer/platform/wtf/functional.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" namespace blink { namespace { void ReportFailure(std::unique_ptr<AsyncFileSystemCallbacks> callbacks, - FileError::ErrorCode error) { + base::File::Error error) { callbacks->DidFail(error); } @@ -83,13 +83,14 @@ LocalFileSystem::~LocalFileSystem() = default; void LocalFileSystem::ResolveURL( ExecutionContext* context, const KURL& file_system_url, - std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + SynchronousType type) { CallbackWrapper* wrapper = new CallbackWrapper(std::move(callbacks)); RequestFileSystemAccessInternal( context, WTF::Bind(&LocalFileSystem::ResolveURLInternal, WrapCrossThreadPersistent(this), WrapPersistent(context), - file_system_url, WrapPersistent(wrapper)), + file_system_url, WrapPersistent(wrapper), type), WTF::Bind(&LocalFileSystem::FileSystemNotAllowedInternal, WrapCrossThreadPersistent(this), WrapPersistent(context), WrapPersistent(wrapper))); @@ -99,90 +100,19 @@ void LocalFileSystem::RequestFileSystem( ExecutionContext* context, mojom::blink::FileSystemType type, long long size, - std::unique_ptr<AsyncFileSystemCallbacks> callbacks) { + std::unique_ptr<AsyncFileSystemCallbacks> callbacks, + SynchronousType sync_type) { CallbackWrapper* wrapper = new CallbackWrapper(std::move(callbacks)); RequestFileSystemAccessInternal( context, WTF::Bind(&LocalFileSystem::FileSystemAllowedInternal, WrapCrossThreadPersistent(this), WrapPersistent(context), type, - WrapPersistent(wrapper)), + WrapPersistent(wrapper), sync_type), WTF::Bind(&LocalFileSystem::FileSystemNotAllowedInternal, WrapCrossThreadPersistent(this), WrapPersistent(context), WrapPersistent(wrapper))); } -namespace { - -class ChooseEntryCallbacks : public WebFileSystem::ChooseEntryCallbacks { - public: - ChooseEntryCallbacks(ScriptPromiseResolver* resolver, bool return_multiple) - : resolver_(resolver), return_multiple_(return_multiple) {} - - void OnSuccess(WebVector<WebFileSystem::FileSystemEntry> entries) override { - ScriptState::Scope scope(resolver_->GetScriptState()); - if (return_multiple_) { - Vector<ScriptPromise> result; - result.ReserveInitialCapacity(entries.size()); - for (const auto& entry : entries) - result.emplace_back(CreateFileHandle(entry)); - resolver_->Resolve(ScriptPromise::All(resolver_->GetScriptState(), result) - .GetScriptValue()); - } else { - DCHECK_EQ(1u, entries.size()); - resolver_->Resolve(CreateFileHandle(entries[0]).GetScriptValue()); - } - } - - void OnError(base::File::Error error) override { - resolver_->Reject(FileError::CreateDOMException(error)); - } - - private: - ScriptPromise CreateFileHandle(const WebFileSystem::FileSystemEntry& entry) { - auto* new_resolver = - ScriptPromiseResolver::Create(resolver_->GetScriptState()); - ScriptPromise result = new_resolver->Promise(); - auto* fs = DOMFileSystem::CreateIsolatedFileSystem( - resolver_->GetExecutionContext(), entry.file_system_id); - // TODO(mek): Try to create handle directly rather than having to do more - // IPCs to get the actual entries. - fs->GetFile(fs->root(), entry.base_name, FileSystemFlags(), - new EntryCallbacks::OnDidGetEntryPromiseImpl(new_resolver), - new PromiseErrorCallback(new_resolver)); - return result; - } - - Persistent<ScriptPromiseResolver> resolver_; - bool return_multiple_; -}; - -} // namespace - -void LocalFileSystem::ChooseEntry(ScriptPromiseResolver* resolver) { - if (!base::FeatureList::IsEnabled(blink::features::kWritableFilesAPI)) { - resolver->Reject(FileError::CreateDOMException(FileError::kAbortErr)); - return; - } - - WebFileSystem* file_system = GetFileSystem(); - if (!file_system) { - resolver->Reject(FileError::CreateDOMException(FileError::kAbortErr)); - return; - } - - file_system->ChooseEntry( - Supplement<LocalFrame>::GetSupplementable()->Client()->GetWebFrame(), - std::make_unique<ChooseEntryCallbacks>(resolver, false)); -} - -WebFileSystem* LocalFileSystem::GetFileSystem() const { - Platform* platform = Platform::Current(); - if (!platform) - return nullptr; - - return platform->FileSystem(); -} - void LocalFileSystem::RequestFileSystemAccessInternal( ExecutionContext* context, base::OnceClosure allowed, @@ -205,7 +135,7 @@ void LocalFileSystem::FileSystemNotAvailable(ExecutionContext* context, context->GetTaskRunner(TaskType::kFileReading) ->PostTask(FROM_HERE, WTF::Bind(&ReportFailure, WTF::Passed(callbacks->Release()), - FileError::kAbortErr)); + base::File::FILE_ERROR_ABORT)); } void LocalFileSystem::FileSystemNotAllowedInternal(ExecutionContext* context, @@ -213,34 +143,40 @@ void LocalFileSystem::FileSystemNotAllowedInternal(ExecutionContext* context, context->GetTaskRunner(TaskType::kFileReading) ->PostTask(FROM_HERE, WTF::Bind(&ReportFailure, WTF::Passed(callbacks->Release()), - FileError::kAbortErr)); + base::File::FILE_ERROR_ABORT)); } void LocalFileSystem::FileSystemAllowedInternal( ExecutionContext* context, mojom::blink::FileSystemType type, - CallbackWrapper* callbacks) { - WebFileSystem* file_system = GetFileSystem(); - if (!file_system) { - FileSystemNotAvailable(context, callbacks); - return; - } + CallbackWrapper* callbacks, + SynchronousType sync_type) { KURL storage_partition = KURL(NullURL(), context->GetSecurityOrigin()->ToString()); - file_system->OpenFileSystem(storage_partition, - static_cast<WebFileSystemType>(type), - callbacks->Release()); + std::unique_ptr<AsyncFileSystemCallbacks> async_callbacks = + callbacks->Release(); + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context); + if (sync_type == kSynchronous) { + dispatcher.OpenFileSystemSync(storage_partition, type, + std::move(async_callbacks)); + } else { + dispatcher.OpenFileSystem(storage_partition, type, + std::move(async_callbacks)); + } } void LocalFileSystem::ResolveURLInternal(ExecutionContext* context, const KURL& file_system_url, - CallbackWrapper* callbacks) { - WebFileSystem* file_system = GetFileSystem(); - if (!file_system) { - FileSystemNotAvailable(context, callbacks); - return; + CallbackWrapper* callbacks, + SynchronousType sync_type) { + FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context); + std::unique_ptr<AsyncFileSystemCallbacks> async_callbacks = + callbacks->Release(); + if (sync_type == kSynchronous) { + dispatcher.ResolveURLSync(file_system_url, std::move(async_callbacks)); + } else { + dispatcher.ResolveURL(file_system_url, std::move(async_callbacks)); } - file_system->ResolveURL(file_system_url, callbacks->Release()); } LocalFileSystem::LocalFileSystem(LocalFrame& frame, @@ -263,10 +199,9 @@ void LocalFileSystem::Trace(blink::Visitor* visitor) { const char LocalFileSystem::kSupplementName[] = "LocalFileSystem"; LocalFileSystem* LocalFileSystem::From(ExecutionContext& context) { - if (context.IsDocument()) { + if (auto* document = DynamicTo<Document>(context)) { LocalFileSystem* file_system = - Supplement<LocalFrame>::From<LocalFileSystem>( - ToDocument(context).GetFrame()); + Supplement<LocalFrame>::From<LocalFileSystem>(document->GetFrame()); DCHECK(file_system); return file_system; } diff --git a/chromium/third_party/blink/renderer/modules/filesystem/local_file_system.h b/chromium/third_party/blink/renderer/modules/filesystem/local_file_system.h index f62847ca161..d58080d2066 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/local_file_system.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/local_file_system.h @@ -48,8 +48,6 @@ class CallbackWrapper; class FileSystemClient; class ExecutionContext; class KURL; -class ScriptPromiseResolver; -class WebFileSystem; class LocalFileSystem final : public GarbageCollectedFinalized<LocalFileSystem>, public Supplement<LocalFrame>, @@ -59,6 +57,8 @@ class LocalFileSystem final : public GarbageCollectedFinalized<LocalFileSystem>, WTF_MAKE_NONCOPYABLE(LocalFileSystem); public: + enum SynchronousType { kAsynchronous, kSynchronous }; + static const char kSupplementName[]; LocalFileSystem(LocalFrame&, std::unique_ptr<FileSystemClient>); @@ -67,13 +67,13 @@ class LocalFileSystem final : public GarbageCollectedFinalized<LocalFileSystem>, void ResolveURL(ExecutionContext*, const KURL&, - std::unique_ptr<AsyncFileSystemCallbacks>); + std::unique_ptr<AsyncFileSystemCallbacks>, + SynchronousType sync_type); void RequestFileSystem(ExecutionContext*, mojom::blink::FileSystemType, long long size, - std::unique_ptr<AsyncFileSystemCallbacks>); - - void ChooseEntry(ScriptPromiseResolver*); + std::unique_ptr<AsyncFileSystemCallbacks>, + SynchronousType sync_type); FileSystemClient& Client() const { return *client_; } @@ -83,7 +83,6 @@ class LocalFileSystem final : public GarbageCollectedFinalized<LocalFileSystem>, const char* NameInHeapSnapshot() const override { return "LocalFileSystem"; } private: - WebFileSystem* GetFileSystem() const; void FileSystemNotAvailable(ExecutionContext*, CallbackWrapper*); void RequestFileSystemAccessInternal(ExecutionContext*, @@ -92,8 +91,12 @@ class LocalFileSystem final : public GarbageCollectedFinalized<LocalFileSystem>, void FileSystemNotAllowedInternal(ExecutionContext*, CallbackWrapper*); void FileSystemAllowedInternal(ExecutionContext*, mojom::blink::FileSystemType, - CallbackWrapper*); - void ResolveURLInternal(ExecutionContext*, const KURL&, CallbackWrapper*); + CallbackWrapper*, + SynchronousType sync_type); + void ResolveURLInternal(ExecutionContext*, + const KURL&, + CallbackWrapper*, + SynchronousType sync_type); const std::unique_ptr<FileSystemClient> client_; }; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/local_file_system_client.cc b/chromium/third_party/blink/renderer/modules/filesystem/local_file_system_client.cc index 06df6256824..ab6d6ec45b5 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/local_file_system_client.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/local_file_system_client.cc @@ -54,7 +54,8 @@ LocalFileSystemClient::~LocalFileSystemClient() = default; bool LocalFileSystemClient::RequestFileSystemAccessSync( ExecutionContext* context) { DCHECK(context); - if (context->IsDocument()) { + if (IsA<Document>(context)) { + // TODO(dcheng): Why is this NOTREACHED and handled? NOTREACHED(); return false; } @@ -68,12 +69,13 @@ void LocalFileSystemClient::RequestFileSystemAccessAsync( ExecutionContext* context, std::unique_ptr<ContentSettingCallbacks> callbacks) { DCHECK(context); - if (!context->IsDocument()) { + auto* document = DynamicTo<Document>(context); + if (!document) { + // TODO(dcheng): Why is this NOTREACHED and handled? NOTREACHED(); return; } - Document* document = ToDocument(context); DCHECK(document->GetFrame()); document->GetFrame() ->GetContentSettingsClient() diff --git a/chromium/third_party/blink/renderer/modules/filesystem/sync_callback_helper.h b/chromium/third_party/blink/renderer/modules/filesystem/sync_callback_helper.h index 4a5335d2835..c01ed1c6d63 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/sync_callback_helper.h +++ b/chromium/third_party/blink/renderer/modules/filesystem/sync_callback_helper.h @@ -56,7 +56,7 @@ class DOMFileSystemCallbacksSyncHelper final ErrorCallbackBase* GetErrorCallback() { return new ErrorCallbackImpl(this); } CallbackArg* GetResultOrThrow(ExceptionState& exception_state) { - if (error_code_ != FileError::ErrorCode::kOK) { + if (error_code_ != base::File::FILE_OK) { FileError::ThrowDOMException(exception_state, error_code_); return nullptr; } @@ -90,8 +90,8 @@ class DOMFileSystemCallbacksSyncHelper final visitor->Trace(helper_); ErrorCallbackBase::Trace(visitor); } - void Invoke(FileError::ErrorCode error_code) override { - DCHECK_NE(error_code, FileError::ErrorCode::kOK); + void Invoke(base::File::Error error_code) override { + DCHECK_NE(error_code, base::File::FILE_OK); helper_->error_code_ = error_code; } @@ -106,7 +106,7 @@ class DOMFileSystemCallbacksSyncHelper final DOMFileSystemCallbacksSyncHelper() = default; Member<CallbackArg> result_; - FileError::ErrorCode error_code_ = FileError::ErrorCode::kOK; + base::File::Error error_code_ = base::File::FILE_OK; friend class SuccessCallbackImpl; friend class ErrorCallbackImpl; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/window_file_system.idl b/chromium/third_party/blink/renderer/modules/filesystem/window_file_system.idl index 39bd2744cfb..935f48bcb00 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/window_file_system.idl +++ b/chromium/third_party/blink/renderer/modules/filesystem/window_file_system.idl @@ -38,10 +38,8 @@ [RuntimeEnabled=FileSystem] void webkitResolveLocalFileSystemURL(DOMString url, EntryCallback successCallback, optional ErrorCallback? errorCallback); - // https://github.com/WICG/writable-files/blob/master/EXPLAINER.md - // TODO(crbug.com/878581): This needs some kind of options dictionary. - // TODO(crbug.com/878566): This should be SecureContext, but that is - // currently broken. - [RuntimeEnabled=WritableFiles, CallWith=ScriptState] - Promise<(FileSystemBaseHandle or sequence<FileSystemBaseHandle>)> chooseFileSystemEntries(); + // https://wicg.github.io/writable-files/#api-choosefilesystementries + [RuntimeEnabled=WritableFiles, CallWith=ScriptState, SecureContext] + Promise<(FileSystemBaseHandle or sequence<FileSystemBaseHandle>)> + chooseFileSystemEntries(optional ChooseFileSystemEntriesOptions options); }; diff --git a/chromium/third_party/blink/renderer/modules/filesystem/worker_global_scope_file_system.cc b/chromium/third_party/blink/renderer/modules/filesystem/worker_global_scope_file_system.cc index 26b2ce2eeea..713954c0e53 100644 --- a/chromium/third_party/blink/renderer/modules/filesystem/worker_global_scope_file_system.cc +++ b/chromium/third_party/blink/renderer/modules/filesystem/worker_global_scope_file_system.cc @@ -55,7 +55,7 @@ void WorkerGlobalScopeFileSystem::webkitRequestFileSystem( if (!secure_context->GetSecurityOrigin()->CanAccessFileSystem()) { DOMFileSystem::ReportError(&worker, ScriptErrorCallback::Wrap(error_callback), - FileError::kSecurityErr); + base::File::FILE_ERROR_SECURITY); return; } else if (secure_context->GetSecurityOrigin()->IsLocal()) { UseCounter::Count(secure_context, WebFeature::kFileAccessedFileSystem); @@ -66,7 +66,7 @@ void WorkerGlobalScopeFileSystem::webkitRequestFileSystem( if (!DOMFileSystemBase::IsValidType(file_system_type)) { DOMFileSystem::ReportError(&worker, ScriptErrorCallback::Wrap(error_callback), - FileError::kInvalidModificationErr); + base::File::FILE_ERROR_INVALID_OPERATION); return; } @@ -75,8 +75,8 @@ void WorkerGlobalScopeFileSystem::webkitRequestFileSystem( FileSystemCallbacks::Create( FileSystemCallbacks::OnDidOpenFileSystemV8Impl::Create( success_callback), - ScriptErrorCallback::Wrap(error_callback), &worker, - file_system_type)); + ScriptErrorCallback::Wrap(error_callback), &worker, file_system_type), + LocalFileSystem::kAsynchronous); } DOMFileSystemSync* WorkerGlobalScopeFileSystem::webkitRequestFileSystemSync( @@ -107,10 +107,10 @@ DOMFileSystemSync* WorkerGlobalScopeFileSystem::webkitRequestFileSystemSync( FileSystemCallbacks::Create(sync_helper->GetSuccessCallback(), sync_helper->GetErrorCallback(), &worker, file_system_type); - callbacks->SetShouldBlockUntilCompletion(true); - LocalFileSystem::From(worker)->RequestFileSystem(&worker, file_system_type, - size, std::move(callbacks)); + LocalFileSystem::From(worker)->RequestFileSystem( + &worker, file_system_type, size, std::move(callbacks), + LocalFileSystem::kSynchronous); DOMFileSystem* file_system = sync_helper->GetResultOrThrow(exception_state); return file_system ? DOMFileSystemSync::Create(file_system) : nullptr; } @@ -126,7 +126,7 @@ void WorkerGlobalScopeFileSystem::webkitResolveLocalFileSystemURL( !secure_context->GetSecurityOrigin()->CanRequest(completed_url)) { DOMFileSystem::ReportError(&worker, ScriptErrorCallback::Wrap(error_callback), - FileError::kSecurityErr); + base::File::FILE_ERROR_SECURITY); return; } else if (secure_context->GetSecurityOrigin()->IsLocal()) { UseCounter::Count(secure_context, WebFeature::kFileAccessedFileSystem); @@ -135,7 +135,7 @@ void WorkerGlobalScopeFileSystem::webkitResolveLocalFileSystemURL( if (!completed_url.IsValid()) { DOMFileSystem::ReportError(&worker, ScriptErrorCallback::Wrap(error_callback), - FileError::kEncodingErr); + base::File::FILE_ERROR_INVALID_URL); return; } @@ -143,7 +143,8 @@ void WorkerGlobalScopeFileSystem::webkitResolveLocalFileSystemURL( &worker, completed_url, ResolveURICallbacks::Create( ResolveURICallbacks::OnDidGetEntryV8Impl::Create(success_callback), - ScriptErrorCallback::Wrap(error_callback), &worker)); + ScriptErrorCallback::Wrap(error_callback), &worker), + LocalFileSystem::kAsynchronous); } EntrySync* WorkerGlobalScopeFileSystem::webkitResolveLocalFileSystemSyncURL( @@ -170,10 +171,10 @@ EntrySync* WorkerGlobalScopeFileSystem::webkitResolveLocalFileSystemSyncURL( std::unique_ptr<AsyncFileSystemCallbacks> callbacks = ResolveURICallbacks::Create(sync_helper->GetSuccessCallback(), sync_helper->GetErrorCallback(), &worker); - callbacks->SetShouldBlockUntilCompletion(true); LocalFileSystem::From(worker)->ResolveURL(&worker, completed_url, - std::move(callbacks)); + std::move(callbacks), + LocalFileSystem::kSynchronous); Entry* entry = sync_helper->GetResultOrThrow(exception_state); return entry ? EntrySync::Create(entry) : nullptr; diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc index f3771a13499..78725b41274 100644 --- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc +++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc @@ -14,9 +14,9 @@ namespace blink { using device::mojom::blink::GamepadHapticsManager; GamepadDispatcher& GamepadDispatcher::Instance() { - DEFINE_STATIC_LOCAL(GamepadDispatcher, gamepad_dispatcher, + DEFINE_STATIC_LOCAL(Persistent<GamepadDispatcher>, gamepad_dispatcher, (new GamepadDispatcher)); - return gamepad_dispatcher; + return *gamepad_dispatcher; } void GamepadDispatcher::SampleGamepads(device::Gamepads& gamepads) { diff --git a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.cc b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.cc index 54491f6ad98..c819b8b2456 100644 --- a/chromium/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.cc +++ b/chromium/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.cc @@ -93,7 +93,7 @@ void GamepadSharedMemoryReader::SampleGamepads(device::Gamepads& gamepads) { if (contention_count == kMaximumContentionCount) break; } while (gamepad_hardware_buffer_->seqlock.ReadRetry(version)); - UMA_HISTOGRAM_COUNTS("Gamepad.ReadContentionCount", contention_count); + UMA_HISTOGRAM_COUNTS_1M("Gamepad.ReadContentionCount", contention_count); if (contention_count >= kMaximumContentionCount) { // We failed to successfully read, presumably because the hardware diff --git a/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc b/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc index 71e9b2285ec..66209e12b2f 100644 --- a/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc +++ b/chromium/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc @@ -71,12 +71,12 @@ bool HasUserActivation(GamepadList* gamepads) { // A button press counts as a user activation if the button's value is greater // than the activation threshold. A threshold is used so that analog buttons // or triggers do not generate an activation from a light touch. - for (size_t pad_index = 0; pad_index < gamepads->length(); ++pad_index) { + for (wtf_size_t pad_index = 0; pad_index < gamepads->length(); ++pad_index) { Gamepad* pad = gamepads->item(pad_index); if (pad) { const GamepadButtonVector& buttons = pad->buttons(); - for (size_t i = 0; i < buttons.size(); ++i) { - double value = buttons.at(i)->value(); + for (auto button : buttons) { + double value = button->value(); if (value > kButtonActivationThreshold) return true; } @@ -88,7 +88,7 @@ bool HasUserActivation(GamepadList* gamepads) { } // namespace template <typename T> -static void SampleGamepad(size_t index, +static void SampleGamepad(unsigned index, T& gamepad, const device::Gamepad& device_gamepad, const TimeTicks& navigation_start) { @@ -108,6 +108,12 @@ static void SampleGamepad(size_t index, gamepad.SetPose(device_gamepad.pose); gamepad.SetHand(device_gamepad.hand); + if (device_gamepad.is_xr) { + TimeTicks now = TimeTicks::Now(); + TRACE_COUNTER1("input", "XR gamepad pose age (ms)", + (now - last_updated).InMilliseconds()); + } + bool newly_connected; HasGamepadConnectionChanged(old_id, gamepad.id(), old_was_connected, gamepad.connected(), &newly_connected, nullptr); @@ -138,7 +144,7 @@ static void SampleGamepads(ListType* into, GamepadDispatcher::Instance().SampleGamepads(gamepads); - for (size_t i = 0; i < device::Gamepads::kItemsLengthCap; ++i) { + for (unsigned i = 0; i < device::Gamepads::kItemsLengthCap; ++i) { device::Gamepad& web_gamepad = gamepads.items[i]; bool hide_xr_gamepad = false; @@ -210,7 +216,7 @@ GamepadList* NavigatorGamepad::Gamepads() { // visible. if (RuntimeEnabledFeatures::UserActivationV2Enabled() && GetFrame() && GetPage() && GetPage()->IsPageVisible() && HasUserActivation(gamepads_)) { - Frame::NotifyUserActivation(GetFrame(), UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(GetFrame(), UserGestureToken::kNewGesture); } return gamepads_.Get(); @@ -384,7 +390,7 @@ void NavigatorGamepad::SampleAndCheckConnectedGamepads() { bool NavigatorGamepad::CheckConnectedGamepads(GamepadList* old_gamepads, GamepadList* new_gamepads) { int disconnection_count = 0; - for (size_t i = 0; i < device::Gamepads::kItemsLengthCap; ++i) { + for (unsigned i = 0; i < device::Gamepads::kItemsLengthCap; ++i) { Gamepad* old_gamepad = old_gamepads ? old_gamepads->item(i) : nullptr; Gamepad* new_gamepad = new_gamepads->item(i); bool connected, disconnected; diff --git a/chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc b/chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc index b5b03638b30..87bd0323537 100644 --- a/chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc +++ b/chromium/third_party/blink/renderer/modules/geolocation/geolocation.cc @@ -85,11 +85,12 @@ PositionError* CreatePositionError( return PositionError::Create(error_code, error); } -static void ReportGeolocationViolation(ExecutionContext* context) { - Document* doc = ToDocumentOrNull(context); - if (!Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr)) { +static void ReportGeolocationViolation(Document* doc) { + // TODO(dcheng): |doc| probably can't be null here. + if (!LocalFrame::HasTransientUserActivation(doc ? doc->GetFrame() + : nullptr)) { PerformanceMonitor::ReportGenericViolation( - context, PerformanceMonitor::kDiscouragedAPIUse, + doc, PerformanceMonitor::kDiscouragedAPIUse, "Only request geolocation information in response to a user gesture.", base::TimeDelta(), nullptr); } @@ -121,7 +122,7 @@ void Geolocation::Trace(blink::Visitor* visitor) { } Document* Geolocation::GetDocument() const { - return ToDocument(GetExecutionContext()); + return To<Document>(GetExecutionContext()); } LocalFrame* Geolocation::GetFrame() const { @@ -224,8 +225,9 @@ void Geolocation::StartRequest(GeoNotifier* notifier) { return; } - if (!GetFrame()->IsFeatureEnabled(mojom::FeaturePolicyFeature::kGeolocation, - ReportOptions::kReportOnFailure)) { + if (!GetDocument()->IsFeatureEnabled( + mojom::FeaturePolicyFeature::kGeolocation, + ReportOptions::kReportOnFailure)) { UseCounter::Count(GetDocument(), WebFeature::kGeolocationDisabledByFeaturePolicy); GetDocument()->AddConsoleMessage(ConsoleMessage::Create( @@ -463,7 +465,7 @@ void Geolocation::UpdateGeolocationConnection() { invalidator); geolocation_service_->CreateGeolocation( MakeRequest(&geolocation_, invalidator), - Frame::HasTransientUserActivation(GetFrame())); + LocalFrame::HasTransientUserActivation(GetFrame())); geolocation_.set_connection_error_handler(WTF::Bind( &Geolocation::OnGeolocationConnectionError, WrapWeakPersistent(this))); diff --git a/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc b/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc index e76a6b3f4cd..6cb4156980d 100644 --- a/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc +++ b/chromium/third_party/blink/renderer/modules/imagecapture/image_capture.cc @@ -345,6 +345,7 @@ void ImageCapture::SetMediaTrackConstraints( (constraints.hasFocusMode() && !capabilities_.hasFocusMode()) || (constraints.hasExposureCompensation() && !capabilities_.hasExposureCompensation()) || + (constraints.hasExposureTime() && !capabilities_.hasExposureTime()) || (constraints.hasColorTemperature() && !capabilities_.hasColorTemperature()) || (constraints.hasIso() && !capabilities_.hasIso()) || @@ -352,6 +353,7 @@ void ImageCapture::SetMediaTrackConstraints( (constraints.hasContrast() && !capabilities_.hasContrast()) || (constraints.hasSaturation() && !capabilities_.hasSaturation()) || (constraints.hasSharpness() && !capabilities_.hasSharpness()) || + (constraints.hasFocusDistance() && !capabilities_.hasFocusDistance()) || (constraints.hasZoom() && !capabilities_.hasZoom()) || (constraints.hasTorch() && !capabilities_.hasTorch())) { resolver->Reject(DOMException::Create(DOMExceptionCode::kNotSupportedError, @@ -436,6 +438,20 @@ void ImageCapture::SetMediaTrackConstraints( constraints.exposureCompensation()); settings->exposure_compensation = exposure_compensation; } + settings->has_exposure_time = + constraints.hasExposureTime() && constraints.exposureTime().IsDouble(); + if (settings->has_exposure_time) { + const auto exposure_time = constraints.exposureTime().GetAsDouble(); + if (exposure_time < capabilities_.exposureTime()->min() || + exposure_time > capabilities_.exposureTime()->max()) { + resolver->Reject( + DOMException::Create(DOMExceptionCode::kNotSupportedError, + "exposureTime setting out of range")); + return; + } + temp_constraints.setExposureTime(constraints.exposureTime()); + settings->exposure_time = exposure_time; + } settings->has_color_temperature = constraints.hasColorTemperature() && constraints.colorTemperature().IsDouble(); if (settings->has_color_temperature) { @@ -519,6 +535,21 @@ void ImageCapture::SetMediaTrackConstraints( settings->sharpness = sharpness; } + settings->has_focus_distance = + constraints.hasFocusDistance() && constraints.focusDistance().IsDouble(); + if (settings->has_focus_distance) { + const auto focus_distance = constraints.focusDistance().GetAsDouble(); + if (focus_distance < capabilities_.focusDistance()->min() || + focus_distance > capabilities_.focusDistance()->max()) { + resolver->Reject( + DOMException::Create(DOMExceptionCode::kNotSupportedError, + "focusDistance setting out of range")); + return; + } + temp_constraints.setFocusDistance(constraints.focusDistance()); + settings->focus_distance = focus_distance; + } + settings->has_zoom = constraints.hasZoom() && constraints.zoom().IsDouble(); if (settings->has_zoom) { const auto zoom = constraints.zoom().GetAsDouble(); @@ -585,6 +616,8 @@ void ImageCapture::GetMediaTrackSettings(MediaTrackSettings& settings) const { if (settings_.hasExposureCompensation()) settings.setExposureCompensation(settings_.exposureCompensation()); + if (settings_.hasExposureTime()) + settings.setExposureTime(settings_.exposureTime()); if (settings_.hasColorTemperature()) settings.setColorTemperature(settings_.colorTemperature()); if (settings_.hasIso()) @@ -599,6 +632,8 @@ void ImageCapture::GetMediaTrackSettings(MediaTrackSettings& settings) const { if (settings_.hasSharpness()) settings.setSharpness(settings_.sharpness()); + if (settings_.hasFocusDistance()) + settings.setFocusDistance(settings_.focusDistance()); if (settings_.hasZoom()) settings.setZoom(settings_.zoom()); if (settings_.hasTorch()) @@ -772,6 +807,11 @@ void ImageCapture::UpdateMediaTrackCapabilities( settings_.setExposureCompensation( photo_state->exposure_compensation->current); } + if (photo_state->exposure_time->max != photo_state->exposure_time->min) { + capabilities_.setExposureTime( + MediaSettingsRange::Create(*photo_state->exposure_time)); + settings_.setExposureTime(photo_state->exposure_time->current); + } if (photo_state->color_temperature->max != photo_state->color_temperature->min) { capabilities_.setColorTemperature( @@ -804,6 +844,11 @@ void ImageCapture::UpdateMediaTrackCapabilities( settings_.setSharpness(photo_state->sharpness->current); } + if (photo_state->focus_distance->max != photo_state->focus_distance->min) { + capabilities_.setFocusDistance( + MediaSettingsRange::Create(*photo_state->focus_distance)); + settings_.setFocusDistance(photo_state->focus_distance->current); + } if (photo_state->zoom->max != photo_state->zoom->min) { capabilities_.setZoom(MediaSettingsRange::Create(*photo_state->zoom)); settings_.setZoom(photo_state->zoom->current); diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/README.md b/chromium/third_party/blink/renderer/modules/indexeddb/README.md index 39c3c33a6db..d38cacc99e7 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/README.md +++ b/chromium/third_party/blink/renderer/modules/indexeddb/README.md @@ -28,4 +28,14 @@ Please add documents below as you write it. Please complete the list below with new or existing design docs. -* [Handling Large Values in IndexedDB](https://goo.gl/VncHrw) +* [Handling Large Values in IndexedDB](https://docs.google.com/document/d/1wmbLb91Se4OIp3Z0eKkAJEHG4YHgq75WUH2mqazrnik/) +* [IndexedDB Tombstone Sweeper](https://docs.google.com/document/d/1BWy0aT_hWrmc3umCxas6-7ofDmT8CSgK4sv1s4VwTeA/) +* [LevelDB Scopes: Special Transactions for IndexedDB](https://docs.google.com/document/d/16_igCI15Gfzb6UYqeuJTmJPrzEtawz6Y1tVOKNtYgiU/) +* [IndexedDB: Onion Soup](https://docs.google.com/document/d/12nwW3mLxVBximpIt9IS0h7hoaB5fcIAl4zHdhuOVKLg/) + +## Obsoleted Design Docs + +These documents are no longer current, but are still the best documentation we +have in their area. + +* [Blob Storage in IndexedDB](https://docs.google.com/document/d/1Kdr4pcFt4QBDLLQn-fY4kZgw6ptmK23lthGZdQMVh2Y/)
\ No newline at end of file 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 6a1da96df88..db3a230190b 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_database.cc @@ -50,6 +50,7 @@ #include "third_party/blink/renderer/platform/histogram.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" #include "third_party/blink/renderer/platform/wtf/atomics.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include <limits> #include <memory> @@ -192,7 +193,8 @@ void IDBDatabase::OnChanges( WebVector<WebIDBObservation> web_observations, const WebIDBDatabaseCallbacks::TransactionMap& transactions) { HeapVector<Member<IDBObservation>> observations; - observations.ReserveInitialCapacity(web_observations.size()); + observations.ReserveInitialCapacity( + SafeCast<wtf_size_t>(web_observations.size())); for (WebIDBObservation& web_observation : web_observations) { observations.emplace_back( IDBObservation::Create(std::move(web_observation), isolate_)); diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_event_dispatcher.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_event_dispatcher.cc index 67f5ea8fdb2..5504e123547 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_event_dispatcher.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_event_dispatcher.cc @@ -30,17 +30,18 @@ #include "third_party/blink/renderer/modules/event_modules.h" #include "third_party/blink/renderer/modules/event_target_modules.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" namespace blink { DispatchEventResult IDBEventDispatcher::Dispatch( Event& event, HeapVector<Member<EventTarget>>& event_targets) { - size_t size = event_targets.size(); + wtf_size_t size = event_targets.size(); DCHECK(size); event.SetEventPhase(Event::kCapturingPhase); - for (size_t i = size - 1; i; --i) { // Don't do the first element. + for (wtf_size_t i = size - 1; i; --i) { // Don't do the first element. event.SetCurrentTarget(event_targets[i].Get()); event_targets[i]->FireEventListeners(event); if (event.PropagationStopped()) @@ -54,7 +55,7 @@ DispatchEventResult IDBEventDispatcher::Dispatch( goto doneDispatching; event.SetEventPhase(Event::kBubblingPhase); - for (size_t i = 1; i < size; ++i) { // Don't do the first element. + for (wtf_size_t i = 1; i < size; ++i) { // Don't do the first element. event.SetCurrentTarget(event_targets[i].Get()); event_targets[i]->FireEventListeners(event); if (event.PropagationStopped() || event.cancelBubble()) diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc index 4dd5232c63f..3f70fecdb98 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_factory.cc @@ -56,11 +56,9 @@ static const char kPermissionDeniedErrorMessage[] = IDBFactory::IDBFactory() = default; static bool IsContextValid(ExecutionContext* context) { - DCHECK(context->IsDocument() || context->IsWorkerGlobalScope()); - if (context->IsDocument()) { - Document* document = ToDocument(context); + DCHECK(IsA<Document>(context) || context->IsWorkerGlobalScope()); + if (auto* document = DynamicTo<Document>(context)) return document->GetFrame() && document->GetPage(); - } return true; } diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.cc index 114db34fb2a..8ed421c8c74 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key.cc @@ -41,8 +41,8 @@ bool IDBKey::IsValid() const { return false; if (type_ == kArrayType) { - for (size_t i = 0; i < array_.size(); i++) { - if (!array_[i]->IsValid()) + for (const auto& element : array_) { + if (!element->IsValid()) return false; } } @@ -67,7 +67,8 @@ int IDBKey::Compare(const IDBKey* other) const { switch (type_) { case kArrayType: - for (size_t i = 0; i < array_.size() && i < other->array_.size(); ++i) { + for (wtf_size_t i = 0; i < array_.size() && i < other->array_.size(); + ++i) { if (int result = array_[i]->Compare(other->array_[i].get())) return result; } @@ -123,7 +124,7 @@ WebVector<WebIDBKey> IDBKey::ToMultiEntryArray( return static_cast<IDBKey*>(a)->IsLessThan(static_cast<IDBKey*>(b)); }); const auto end = std::unique(result.begin(), result.end()); - DCHECK_LE(static_cast<size_t>(end - result.begin()), result.size()); + DCHECK_LE(static_cast<wtf_size_t>(end - result.begin()), result.size()); result.resize(end - result.begin()); return result; diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.cc index 3e1c12b4acf..af493f274a8 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path.cc @@ -61,12 +61,12 @@ static inline bool IsIdentifierCharacter(UChar c) { } bool IsIdentifier(const String& s) { - size_t length = s.length(); + wtf_size_t length = s.length(); if (!length) return false; if (!IsIdentifierStartCharacter(s[0])) return false; - for (size_t i = 1; i < length; ++i) { + for (wtf_size_t i = 1; i < length; ++i) { if (!IsIdentifierCharacter(s[i])) return false; } @@ -93,8 +93,8 @@ void IDBParseKeyPath(const String& key_path, } key_path.Split('.', /*allow_empty_entries=*/true, elements); - for (size_t i = 0; i < elements.size(); ++i) { - if (!IsIdentifier(elements[i])) { + for (const auto& element : elements) { + if (!IsIdentifier(element)) { error = kIDBKeyPathParseErrorIdentifier; return; } @@ -110,8 +110,8 @@ IDBKeyPath::IDBKeyPath(const class String& string) IDBKeyPath::IDBKeyPath(const Vector<class String>& array) : type_(kArrayType), array_(array) { #if DCHECK_IS_ON() - for (size_t i = 0; i < array_.size(); ++i) - DCHECK(!array_[i].IsNull()); + for (const auto& element : array_) + DCHECK(!element.IsNull()); #endif } @@ -127,8 +127,8 @@ IDBKeyPath::IDBKeyPath(const StringOrStringSequence& key_path) { type_ = kArrayType; array_ = key_path.GetAsStringSequence(); #if DCHECK_IS_ON() - for (size_t i = 0; i < array_.size(); ++i) - DCHECK(!array_[i].IsNull()); + for (const auto& element : array_) + DCHECK(!element.IsNull()); #endif } } @@ -177,8 +177,8 @@ bool IDBKeyPath::IsValid() const { case kArrayType: if (array_.IsEmpty()) return false; - for (size_t i = 0; i < array_.size(); ++i) { - if (!IDBIsValidKeyPath(array_[i])) + for (const auto& element : array_) { + if (!IDBIsValidKeyPath(element)) return false; } return true; diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path_test.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path_test.cc index 62dfa5829e7..92e1f492f9d 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path_test.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_key_path_test.cc @@ -49,7 +49,7 @@ void CheckKeyPath(const String& key_path, if (error != kIDBKeyPathParseErrorNone) return; ASSERT_EQ(expected.size(), key_path_elements.size()); - for (size_t i = 0; i < expected.size(); ++i) + for (wtf_size_t i = 0; i < expected.size(); ++i) ASSERT_TRUE(expected[i] == key_path_elements[i]) << i; } diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc index edacac192e5..722fa6d674f 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc @@ -29,6 +29,7 @@ #include "base/feature_list.h" #include "base/memory/scoped_refptr.h" +#include "base/numerics/safe_conversions.h" #include "third_party/blink/public/platform/modules/indexeddb/web_idb_database.h" #include "third_party/blink/public/platform/modules/indexeddb/web_idb_key.h" #include "third_party/blink/public/platform/modules/indexeddb/web_idb_key_range.h" @@ -557,19 +558,20 @@ IDBRequest* IDBObjectStore::DoPut(ScriptState* script_state, key_type_histogram.Count(static_cast<int>(key->GetType())); } - Vector<int64_t> index_ids; - WebVector<WebVector<WebIDBKey>> index_keys; + WebVector<WebIDBIndexKeys> index_keys; index_keys.reserve(Metadata().indexes.size()); for (const auto& it : Metadata().indexes) { if (clone.IsEmpty()) value_wrapper.Clone(script_state, &clone); - index_ids.push_back(it.key); - index_keys.emplace_back(GenerateIndexKeysForValue( - script_state->GetIsolate(), *it.value, clone)); + index_keys.emplace_back( + it.key, GenerateIndexKeysForValue(script_state->GetIsolate(), *it.value, + clone)); } // Records 1KB to 1GB. - UMA_HISTOGRAM_COUNTS_1M("WebCore.IndexedDB.PutValueSize2", - value_wrapper.DataLengthBeforeWrapInBytes() / 1024); + UMA_HISTOGRAM_COUNTS_1M( + "WebCore.IndexedDB.PutValueSize2", + base::saturated_cast<base::HistogramBase::Sample>( + value_wrapper.DataLengthBeforeWrapInBytes() / 1024)); IDBRequest* request = IDBRequest::Create( script_state, source, transaction_.Get(), std::move(metrics)); @@ -584,8 +586,7 @@ IDBRequest* IDBObjectStore::DoPut(ScriptState* script_state, transaction_->Id(), Id(), WebData(value_wrapper.TakeWireBytes()), value_wrapper.TakeBlobInfo(), WebIDBKeyView(key), static_cast<WebIDBPutMode>(put_mode), - request->CreateWebCallbacks().release(), index_ids, - WebVector<WebIDBDatabase::WebIndexKeys>(std::move(index_keys))); + request->CreateWebCallbacks().release(), std::move(index_keys)); return request; } @@ -746,8 +747,6 @@ class IndexPopulator final : public EventListener { if (cursor_any->GetType() == IDBAny::kIDBCursorWithValueType) cursor = cursor_any->IdbCursorWithValue(); - Vector<int64_t> index_ids; - index_ids.push_back(IndexMetadata().id); if (cursor && !cursor->IsDeleted()) { cursor->Continue(nullptr, nullptr, IDBRequest::AsyncTraceState(), ASSERT_NO_EXCEPTION); @@ -755,18 +754,21 @@ class IndexPopulator final : public EventListener { const IDBKey* primary_key = cursor->IdbPrimaryKey(); ScriptValue value = cursor->value(script_state_); - WebVector<WebVector<WebIDBKey>> index_keys_list; - index_keys_list.reserve(1); - index_keys_list.emplace_back(GenerateIndexKeysForValue( - script_state_->GetIsolate(), IndexMetadata(), value)); + WebVector<WebIDBIndexKeys> index_keys; + index_keys.reserve(1); + index_keys.emplace_back( + IndexMetadata().id, + GenerateIndexKeysForValue(script_state_->GetIsolate(), + IndexMetadata(), value)); - database_->Backend()->SetIndexKeys( - transaction_id_, object_store_id_, WebIDBKeyView(primary_key), - index_ids, - WebVector<WebIDBDatabase::WebIndexKeys>(std::move(index_keys_list))); + database_->Backend()->SetIndexKeys(transaction_id_, object_store_id_, + WebIDBKeyView(primary_key), + std::move(index_keys)); } else { // Now that we are done indexing, tell the backend to go // back to processing tasks of type NormalTask. + Vector<int64_t> index_ids; + index_ids.push_back(IndexMetadata().id); database_->Backend()->SetIndexesReady(transaction_id_, object_store_id_, index_ids); database_.Clear(); diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc index 9729f0d46e3..765b6267942 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request.cc @@ -430,8 +430,8 @@ void IDBRequest::EnqueueResponse(const Vector<String>& string_list) { } DOMStringList* dom_string_list = DOMStringList::Create(); - for (size_t i = 0; i < string_list.size(); ++i) - dom_string_list->Append(string_list[i]); + for (const auto& item : string_list) + dom_string_list->Append(item); EnqueueResultInternal(IDBAny::Create(dom_string_list)); metrics_.RecordAndReset(); } diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.h b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.h index 2cb8f84ed02..16b7ca15502 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.h +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.h @@ -8,7 +8,7 @@ #include <memory> #include "base/callback.h" -#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/vector.h" diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_test_helper.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_test_helper.cc index 7e8b391c681..cf37a961664 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_test_helper.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_test_helper.cc @@ -36,9 +36,9 @@ std::unique_ptr<IDBValue> CreateNullIDBValueForTesting(v8::Isolate* isolate) { std::unique_ptr<IDBValue> CreateIDBValueForTesting(v8::Isolate* isolate, bool create_wrapped_value) { - size_t element_count = create_wrapped_value ? 16 : 2; + uint32_t element_count = create_wrapped_value ? 16 : 2; v8::Local<v8::Array> v8_array = v8::Array::New(isolate, element_count); - for (size_t i = 0; i < element_count; ++i) + for (uint32_t i = 0; i < element_count; ++i) v8_array->Set(i, v8::True(isolate)); NonThrowableExceptionState non_throwable_exception_state; diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc index 732ed6a1157..6e0e414b36f 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_transaction_test.cc @@ -122,11 +122,13 @@ TEST_F(IDBTransactionTest, ContextDestroyedEarlyDeath) { EXPECT_CALL(*backend, Close()).Times(1); BuildTransaction(scope, std::move(backend)); - PersistentHeapHashSet<WeakMember<IDBTransaction>> live_transactions; - live_transactions.insert(transaction_); + Persistent<HeapHashSet<WeakMember<IDBTransaction>>> live_transactions = + new HeapHashSet<WeakMember<IDBTransaction>>; + ; + live_transactions->insert(transaction_); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(1u, live_transactions.size()); + EXPECT_EQ(1u, live_transactions->size()); Persistent<IDBRequest> request = IDBRequest::Create(scope.GetScriptState(), store_.Get(), @@ -136,7 +138,7 @@ TEST_F(IDBTransactionTest, ContextDestroyedEarlyDeath) { request.Clear(); // The transaction is holding onto the request. ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(1u, live_transactions.size()); + EXPECT_EQ(1u, live_transactions->size()); // This will generate an Abort() call to the back end which is dropped by the // fake proxy, so an explicit OnAbort call is made. @@ -147,7 +149,7 @@ TEST_F(IDBTransactionTest, ContextDestroyedEarlyDeath) { store_.Clear(); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(0U, live_transactions.size()); + EXPECT_EQ(0U, live_transactions->size()); } TEST_F(IDBTransactionTest, ContextDestroyedAfterDone) { @@ -156,11 +158,13 @@ TEST_F(IDBTransactionTest, ContextDestroyedAfterDone) { EXPECT_CALL(*backend, Close()).Times(1); BuildTransaction(scope, std::move(backend)); - PersistentHeapHashSet<WeakMember<IDBTransaction>> live_transactions; - live_transactions.insert(transaction_); + Persistent<HeapHashSet<WeakMember<IDBTransaction>>> live_transactions = + new HeapHashSet<WeakMember<IDBTransaction>>; + ; + live_transactions->insert(transaction_); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(1U, live_transactions.size()); + EXPECT_EQ(1U, live_transactions->size()); Persistent<IDBRequest> request = IDBRequest::Create(scope.GetScriptState(), store_.Get(), @@ -172,7 +176,7 @@ TEST_F(IDBTransactionTest, ContextDestroyedAfterDone) { request.Clear(); // The transaction is holding onto the request. ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(1U, live_transactions.size()); + EXPECT_EQ(1U, live_transactions->size()); // This will generate an Abort() call to the back end which is dropped by the // fake proxy, so an explicit OnAbort call is made. @@ -184,10 +188,10 @@ TEST_F(IDBTransactionTest, ContextDestroyedAfterDone) { // The request completed, so it has enqueued a success event. Discard the // event, so that the transaction can go away. - EXPECT_EQ(1U, live_transactions.size()); + EXPECT_EQ(1U, live_transactions->size()); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(0U, live_transactions.size()); + EXPECT_EQ(0U, live_transactions->size()); } TEST_F(IDBTransactionTest, ContextDestroyedWithQueuedResult) { @@ -196,11 +200,13 @@ TEST_F(IDBTransactionTest, ContextDestroyedWithQueuedResult) { EXPECT_CALL(*backend, Close()).Times(1); BuildTransaction(scope, std::move(backend)); - PersistentHeapHashSet<WeakMember<IDBTransaction>> live_transactions; - live_transactions.insert(transaction_); + Persistent<HeapHashSet<WeakMember<IDBTransaction>>> live_transactions = + new HeapHashSet<WeakMember<IDBTransaction>>; + ; + live_transactions->insert(transaction_); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(1U, live_transactions.size()); + EXPECT_EQ(1U, live_transactions->size()); Persistent<IDBRequest> request = IDBRequest::Create(scope.GetScriptState(), store_.Get(), @@ -211,7 +217,7 @@ TEST_F(IDBTransactionTest, ContextDestroyedWithQueuedResult) { request.Clear(); // The transaction is holding onto the request. ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(1U, live_transactions.size()); + EXPECT_EQ(1U, live_transactions->size()); // This will generate an Abort() call to the back end which is dropped by the // fake proxy, so an explicit OnAbort call is made. @@ -224,7 +230,7 @@ TEST_F(IDBTransactionTest, ContextDestroyedWithQueuedResult) { url_loader_mock_factory_->ServeAsynchronousRequests(); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(0U, live_transactions.size()); + EXPECT_EQ(0U, live_transactions->size()); } TEST_F(IDBTransactionTest, ContextDestroyedWithTwoQueuedResults) { @@ -233,11 +239,13 @@ TEST_F(IDBTransactionTest, ContextDestroyedWithTwoQueuedResults) { EXPECT_CALL(*backend, Close()).Times(1); BuildTransaction(scope, std::move(backend)); - PersistentHeapHashSet<WeakMember<IDBTransaction>> live_transactions; - live_transactions.insert(transaction_); + Persistent<HeapHashSet<WeakMember<IDBTransaction>>> live_transactions = + new HeapHashSet<WeakMember<IDBTransaction>>; + ; + live_transactions->insert(transaction_); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(1U, live_transactions.size()); + EXPECT_EQ(1U, live_transactions->size()); Persistent<IDBRequest> request1 = IDBRequest::Create(scope.GetScriptState(), store_.Get(), @@ -253,7 +261,7 @@ TEST_F(IDBTransactionTest, ContextDestroyedWithTwoQueuedResults) { request1.Clear(); // The transaction is holding onto the requests. request2.Clear(); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(1U, live_transactions.size()); + EXPECT_EQ(1U, live_transactions->size()); // This will generate an Abort() call to the back end which is dropped by the // fake proxy, so an explicit OnAbort call is made. @@ -266,7 +274,7 @@ TEST_F(IDBTransactionTest, ContextDestroyedWithTwoQueuedResults) { url_loader_mock_factory_->ServeAsynchronousRequests(); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(0U, live_transactions.size()); + EXPECT_EQ(0U, live_transactions->size()); } TEST_F(IDBTransactionTest, DocumentShutdownWithQueuedAndBlockedResults) { @@ -277,11 +285,13 @@ TEST_F(IDBTransactionTest, DocumentShutdownWithQueuedAndBlockedResults) { EXPECT_CALL(*backend, Close()).Times(1); BuildTransaction(scope, std::move(backend)); - PersistentHeapHashSet<WeakMember<IDBTransaction>> live_transactions; - live_transactions.insert(transaction_); + Persistent<HeapHashSet<WeakMember<IDBTransaction>>> live_transactions = + new HeapHashSet<WeakMember<IDBTransaction>>; + ; + live_transactions->insert(transaction_); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(1U, live_transactions.size()); + EXPECT_EQ(1U, live_transactions->size()); Persistent<IDBRequest> request1 = IDBRequest::Create(scope.GetScriptState(), store_.Get(), @@ -297,7 +307,7 @@ TEST_F(IDBTransactionTest, DocumentShutdownWithQueuedAndBlockedResults) { request1.Clear(); // The transaction is holding onto the requests. request2.Clear(); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(1U, live_transactions.size()); + EXPECT_EQ(1U, live_transactions->size()); // This will generate an Abort() call to the back end which is dropped by the // fake proxy, so an explicit OnAbort call is made. @@ -310,7 +320,7 @@ TEST_F(IDBTransactionTest, DocumentShutdownWithQueuedAndBlockedResults) { url_loader_mock_factory_->ServeAsynchronousRequests(); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(0U, live_transactions.size()); + EXPECT_EQ(0U, live_transactions->size()); } TEST_F(IDBTransactionTest, TransactionFinish) { @@ -320,22 +330,24 @@ TEST_F(IDBTransactionTest, TransactionFinish) { EXPECT_CALL(*backend, Close()).Times(1); BuildTransaction(scope, std::move(backend)); - PersistentHeapHashSet<WeakMember<IDBTransaction>> live_transactions; - live_transactions.insert(transaction_); + Persistent<HeapHashSet<WeakMember<IDBTransaction>>> live_transactions = + new HeapHashSet<WeakMember<IDBTransaction>>; + ; + live_transactions->insert(transaction_); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(1U, live_transactions.size()); + EXPECT_EQ(1U, live_transactions->size()); DeactivateNewTransactions(scope.GetIsolate()); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(1U, live_transactions.size()); + EXPECT_EQ(1U, live_transactions->size()); transaction_.Clear(); store_.Clear(); ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(1U, live_transactions.size()); + EXPECT_EQ(1U, live_transactions->size()); // Stop the context, so events don't get queued (which would keep the // transaction alive). @@ -348,7 +360,7 @@ TEST_F(IDBTransactionTest, TransactionFinish) { // OnAbort() should have cleared the transaction's reference to the database. ThreadState::Current()->CollectAllGarbage(); - EXPECT_EQ(0U, live_transactions.size()); + EXPECT_EQ(0U, live_transactions->size()); } } // namespace diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc index cf13a66dd43..21626735dde 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value.cc @@ -13,6 +13,7 @@ #include "third_party/blink/public/platform/web_blob_info.h" #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h" #include "third_party/blink/renderer/platform/blob/blob_data.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "v8/include/v8.h" namespace blink { @@ -20,7 +21,7 @@ namespace blink { IDBValue::IDBValue(const WebData& data, const WebVector<WebBlobInfo>& web_blob_info) : data_(data) { - blob_info_.ReserveInitialCapacity(web_blob_info.size()); + blob_info_.ReserveInitialCapacity(SafeCast<wtf_size_t>(web_blob_info.size())); for (const WebBlobInfo& info : web_blob_info) { blob_info_.push_back(info); diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.cc index 7630571fa49..5ab0aacad0c 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.cc @@ -13,6 +13,7 @@ #include "third_party/blink/renderer/modules/indexeddb/idb_request.h" #include "third_party/blink/renderer/modules/indexeddb/idb_value.h" #include "third_party/blink/renderer/platform/blob/blob_data.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { @@ -136,7 +137,7 @@ bool IDBValueWrapper::WrapIfBiggerThan(unsigned max_bytes) { DCHECK(owns_wire_bytes_) << __func__ << " called after TakeWireBytes()"; #endif // DCHECK_IS_ON() - unsigned wire_data_size = wire_data_.size(); + size_t wire_data_size = wire_data_.size(); if (wire_data_size <= max_bytes) return false; @@ -154,7 +155,8 @@ bool IDBValueWrapper::WrapIfBiggerThan(unsigned max_bytes) { wire_data_buffer_.push_back(kVersionTag); wire_data_buffer_.push_back(kRequiresProcessingSSVPseudoVersion); wire_data_buffer_.push_back(kReplaceWithBlob); - IDBValueWrapper::WriteVarInt(wire_data_size, wire_data_buffer_); + IDBValueWrapper::WriteVarInt(SafeCast<unsigned>(wire_data_size), + wire_data_buffer_); IDBValueWrapper::WriteVarInt(serialized_value_->BlobDataHandles().size(), wire_data_buffer_); diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping_test.cc b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping_test.cc index e52b0d133e9..f78b2600392 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping_test.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping_test.cc @@ -184,7 +184,7 @@ TEST(IDBValueWrapperTest, WriteBytes) { // Friend class of IDBValueUnwrapper with access to its internals. class IDBValueUnwrapperReadTestHelper { public: - void ReadVarInt(const char* start, size_t buffer_size) { + void ReadVarInt(const char* start, uint32_t buffer_size) { IDBValueUnwrapper unwrapper; const uint8_t* buffer_start = reinterpret_cast<const uint8_t*>(start); @@ -197,10 +197,10 @@ class IDBValueUnwrapperReadTestHelper { << "ReadVarInt should not change end_"; ASSERT_LE(unwrapper.current_, unwrapper.end_) << "ReadVarInt should not move current_ past end_"; - consumed_bytes_ = unwrapper.current_ - buffer_start; + consumed_bytes_ = static_cast<uint32_t>(unwrapper.current_ - buffer_start); } - void ReadBytes(const char* start, size_t buffer_size) { + void ReadBytes(const char* start, uint32_t buffer_size) { IDBValueUnwrapper unwrapper; const uint8_t* buffer_start = reinterpret_cast<const uint8_t*>(start); @@ -212,7 +212,7 @@ class IDBValueUnwrapperReadTestHelper { ASSERT_EQ(unwrapper.end_, buffer_end) << "ReadBytes should not change end_"; ASSERT_LE(unwrapper.current_, unwrapper.end_) << "ReadBytes should not move current_ past end_"; - consumed_bytes_ = unwrapper.current_ - buffer_start; + consumed_bytes_ = static_cast<uint32_t>(unwrapper.current_ - buffer_start); } bool success() { return success_; } @@ -488,7 +488,8 @@ TEST(IDBValueUnwrapperTest, IsWrapped) { wrapped_value->SetIsolate(scope.GetIsolate()); EXPECT_TRUE(IDBValueUnwrapper::IsWrapped(wrapped_value.get())); - Vector<char> wrapped_marker_bytes(wrapped_marker_buffer->size()); + Vector<char> wrapped_marker_bytes( + static_cast<wtf_size_t>(wrapped_marker_buffer->size())); ASSERT_TRUE(wrapped_marker_buffer->GetBytes(wrapped_marker_bytes.data(), wrapped_marker_bytes.size())); @@ -496,7 +497,7 @@ TEST(IDBValueUnwrapperTest, IsWrapped) { // Truncating the array to fewer than 3 bytes should cause IsWrapped() to // return false. ASSERT_LT(3U, wrapped_marker_bytes.size()); - for (size_t i = 0; i < 3; ++i) { + for (wtf_size_t i = 0; i < 3; ++i) { std::unique_ptr<IDBValue> mutant_value = IDBValue::Create( SharedBuffer::Create(wrapped_marker_bytes.data(), i), blob_infos); mutant_value->SetIsolate(scope.GetIsolate()); @@ -507,7 +508,7 @@ TEST(IDBValueUnwrapperTest, IsWrapped) { // IsWrapped() looks at the first 3 bytes in the value. Flipping any bit in // these 3 bytes should cause IsWrapped() to return false. ASSERT_LT(3U, wrapped_marker_bytes.size()); - for (size_t i = 0; i < 3; ++i) { + for (wtf_size_t i = 0; i < 3; ++i) { for (int j = 0; j < 8; ++j) { char mask = 1 << j; wrapped_marker_bytes[i] ^= mask; diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_client.cc b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_client.cc index b92e3a87e24..40640a0a548 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_client.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/indexed_db_client.cc @@ -32,9 +32,8 @@ IndexedDBClient::IndexedDBClient(WorkerClients& clients) : Supplement<WorkerClients>(clients) {} IndexedDBClient* IndexedDBClient::From(ExecutionContext* context) { - if (context->IsDocument()) { - return Supplement<LocalFrame>::From<IndexedDBClient>( - ToDocument(*context).GetFrame()); + if (auto* document = DynamicTo<Document>(context)) { + return Supplement<LocalFrame>::From<IndexedDBClient>(document->GetFrame()); } WorkerClients* clients = ToWorkerGlobalScope(*context).Clients(); @@ -47,8 +46,7 @@ bool IndexedDBClient::AllowIndexedDB(ExecutionContext* context, DCHECK(context->IsContextThread()); SECURITY_DCHECK(context->IsDocument() || context->IsWorkerGlobalScope()); - if (context->IsDocument()) { - Document* document = ToDocument(context); + if (auto* document = DynamicTo<Document>(context)) { LocalFrame* frame = document->GetFrame(); if (!frame) return false; diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc b/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc index d0776114b01..00ff7182645 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc @@ -141,7 +141,7 @@ class GetDatabaseNamesCallback final : public EventListener { DOMStringList* database_names_list = request_result->DomStringList(); std::unique_ptr<protocol::Array<String>> database_names = protocol::Array<String>::create(); - for (size_t i = 0; i < database_names_list->length(); ++i) + for (uint32_t i = 0; i < database_names_list->length(); ++i) database_names->addItem(database_names_list->item(i)); request_callback_->sendSuccess(std::move(database_names)); } @@ -401,7 +401,7 @@ std::unique_ptr<KeyPath> KeyPathFromIDBKeyPath(const IDBKeyPath& idb_key_path) { std::unique_ptr<protocol::Array<String>> array = protocol::Array<String>::create(); const Vector<String>& string_array = idb_key_path.Array(); - for (size_t i = 0; i < string_array.size(); ++i) + for (wtf_size_t i = 0; i < string_array.size(); ++i) array->addItem(string_array[i]); key_path->setArray(std::move(array)); break; @@ -463,7 +463,7 @@ class DatabaseLoader final std::unique_ptr<DatabaseWithObjectStores> result = DatabaseWithObjectStores::create() .setName(idb_database->name()) - .setVersion(idb_database->version()) + .setVersion(static_cast<int>(idb_database->version())) .setObjectStores(std::move(object_stores)) .build(); @@ -608,7 +608,7 @@ class OpenCursorCallback final : public EventListener { return; } - Document* document = ToDocument(ExecutionContext::From(script_state_)); + Document* document = To<Document>(ExecutionContext::From(script_state_)); if (!document) return; ScriptState::Scope scope(script_state_); diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h index 0aac12d21d1..a7325498632 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h +++ b/chromium/third_party/blink/renderer/modules/indexeddb/mock_web_idb_database.h @@ -84,7 +84,7 @@ class MockWebIDBDatabase : public testing::StrictMock<WebIDBDatabase> { bool key_only, WebIDBCallbacks*)); - MOCK_METHOD9(Put, + MOCK_METHOD8(Put, void(long long transaction_id, long long object_store_id, const WebData& value, @@ -92,15 +92,13 @@ class MockWebIDBDatabase : public testing::StrictMock<WebIDBDatabase> { WebIDBKeyView primary_key, WebIDBPutMode, WebIDBCallbacks*, - const WebVector<long long>& index_ids, - const WebVector<WebIndexKeys>)); + const WebVector<WebIDBIndexKeys>&)); - MOCK_METHOD5(SetIndexKeys, + MOCK_METHOD4(SetIndexKeys, void(long long transaction_id, long long object_store_id, WebIDBKeyView primary_key, - const WebVector<long long>& index_ids, - const WebVector<WebIndexKeys>&)); + const WebVector<WebIDBIndexKeys>&)); MOCK_METHOD3(SetIndexesReady, void(long long transaction_id, long long object_store_id, diff --git a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc index bebb7e661d8..fe63972adb0 100644 --- a/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc +++ b/chromium/third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.cc @@ -43,6 +43,7 @@ #include "third_party/blink/renderer/modules/indexeddb/idb_request.h" #include "third_party/blink/renderer/modules/indexeddb/idb_value.h" #include "third_party/blink/renderer/platform/shared_buffer.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" using blink::WebIDBCursor; using blink::WebIDBDatabase; @@ -154,7 +155,7 @@ void WebIDBCallbacksImpl::OnSuccess(WebVector<WebIDBValue> values) { probe::AsyncTask async_task(request_->GetExecutionContext(), this, "success"); Vector<std::unique_ptr<IDBValue>> idb_values; - idb_values.ReserveInitialCapacity(values.size()); + idb_values.ReserveInitialCapacity(SafeCast<wtf_size_t>(values.size())); for (WebIDBValue& value : values) { std::unique_ptr<IDBValue> idb_value = value.ReleaseIdbValue(); idb_value->SetIsolate(request_->GetIsolate()); diff --git a/chromium/third_party/blink/renderer/modules/keyboard/keyboard_layout_map.h b/chromium/third_party/blink/renderer/modules/keyboard/keyboard_layout_map.h index d332924c37b..d6980c28019 100644 --- a/chromium/third_party/blink/renderer/modules/keyboard/keyboard_layout_map.h +++ b/chromium/third_party/blink/renderer/modules/keyboard/keyboard_layout_map.h @@ -23,7 +23,7 @@ class KeyboardLayoutMap final : public ScriptWrappable, const HashMap<String, String>& Map() const { return layout_map_; } // IDL attributes / methods - size_t size() const { return layout_map_.size(); } + uint32_t size() const { return layout_map_.size(); } void Trace(blink::Visitor* visitor) override { ScriptWrappable::Trace(visitor); diff --git a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc index 503294aafe3..93c78e5b9c5 100644 --- a/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc +++ b/chromium/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc @@ -43,7 +43,7 @@ double ComputeFrameRate(const String& fps_str) { if (std::isfinite(result)) return result > 0 ? result : std::numeric_limits<double>::quiet_NaN(); - size_t slash_position = fps_str.find('/'); + wtf_size_t slash_position = fps_str.find('/'); if (slash_position == kNotFound) return std::numeric_limits<double>::quiet_NaN(); diff --git a/chromium/third_party/blink/renderer/modules/media_controls/BUILD.gn b/chromium/third_party/blink/renderer/modules/media_controls/BUILD.gn index f15b852a55a..5c8e0de3a8a 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/media_controls/BUILD.gn @@ -7,6 +7,8 @@ import("//tools/grit/grit_rule.gni") blink_modules_sources("media_controls") { sources = [ + "elements/media_control_animated_arrow_container_element.cc", + "elements/media_control_animated_arrow_container_element.h", "elements/media_control_animation_event_listener.cc", "elements/media_control_animation_event_listener.h", "elements/media_control_button_panel_element.cc", diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.cc new file mode 100644 index 00000000000..0848f2d8cce --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.cc @@ -0,0 +1,124 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.h" + +#include "third_party/blink/renderer/core/dom/shadow_root.h" +#include "third_party/blink/renderer/core/html/html_style_element.h" +#include "third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.h" + +namespace blink { + +MediaControlAnimatedArrowContainerElement::AnimatedArrow::AnimatedArrow( + const AtomicString& id, + Document& document) + : HTMLDivElement(document) { + setAttribute("id", id); +} + +void MediaControlAnimatedArrowContainerElement::AnimatedArrow::HideInternal() { + DCHECK(!hidden_); + svg_container_->SetInlineStyleProperty(CSSPropertyDisplay, CSSValueNone); + hidden_ = true; +} + +void MediaControlAnimatedArrowContainerElement::AnimatedArrow::ShowInternal() { + DCHECK(hidden_); + hidden_ = false; + + if (svg_container_) { + svg_container_->RemoveInlineStyleProperty(CSSPropertyDisplay); + return; + } + + SetInnerHTMLFromString(MediaControlsResourceLoader::GetJumpSVGImage()); + + last_arrow_ = getElementById("arrow-3"); + svg_container_ = getElementById("jump"); + + event_listener_ = new MediaControlAnimationEventListener(this); +} + +void MediaControlAnimatedArrowContainerElement::AnimatedArrow:: + OnAnimationIteration() { + counter_--; + + if (counter_ == 0) + HideInternal(); +} + +void MediaControlAnimatedArrowContainerElement::AnimatedArrow::Show() { + if (hidden_) + ShowInternal(); + + counter_++; +} + +Element& MediaControlAnimatedArrowContainerElement::AnimatedArrow:: + WatchedAnimationElement() const { + return *last_arrow_; +} + +void MediaControlAnimatedArrowContainerElement::AnimatedArrow::Trace( + Visitor* visitor) { + MediaControlAnimationEventListener::Observer::Trace(visitor); + HTMLDivElement::Trace(visitor); + visitor->Trace(last_arrow_); + visitor->Trace(svg_container_); + visitor->Trace(event_listener_); +} + +MediaControlAnimatedArrowContainerElement:: + MediaControlAnimatedArrowContainerElement(MediaControlsImpl& media_controls) + : MediaControlDivElement(media_controls, kMediaAnimatedArrowContainer), + left_jump_arrow_(nullptr), + right_jump_arrow_(nullptr) { + EnsureUserAgentShadowRoot(); + SetShadowPseudoId( + AtomicString("-internal-media-controls-animated-arrow-container")); +} + +void MediaControlAnimatedArrowContainerElement::ShowArrowAnimation( + MediaControlAnimatedArrowContainerElement::ArrowDirection direction) { + // Load the arrow icons and associate CSS the first time we jump. + if (!left_jump_arrow_) { + DCHECK(!right_jump_arrow_); + ShadowRoot* shadow_root = GetShadowRoot(); + + // This stylesheet element and will contain rules that are specific to the + // jump arrows. The shadow DOM protects these rules from the parent DOM + // from bleeding across the shadow DOM boundary. + auto* style = HTMLStyleElement::Create(GetDocument(), CreateElementFlags()); + style->setTextContent( + MediaControlsResourceLoader::GetAnimatedArrowStyleSheet()); + shadow_root->ParserAppendChild(style); + + left_jump_arrow_ = + new MediaControlAnimatedArrowContainerElement::AnimatedArrow( + "left-arrow", GetDocument()); + shadow_root->ParserAppendChild(left_jump_arrow_); + + right_jump_arrow_ = + new MediaControlAnimatedArrowContainerElement::AnimatedArrow( + "right-arrow", GetDocument()); + shadow_root->ParserAppendChild(right_jump_arrow_); + } + + DCHECK(left_jump_arrow_ && right_jump_arrow_); + + if (direction == + MediaControlAnimatedArrowContainerElement::ArrowDirection::kLeft) { + left_jump_arrow_->Show(); + } else { + right_jump_arrow_->Show(); + } +} + +void MediaControlAnimatedArrowContainerElement::Trace(blink::Visitor* visitor) { + MediaControlDivElement::Trace(visitor); + visitor->Trace(left_jump_arrow_); + visitor->Trace(right_jump_arrow_); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.h new file mode 100644 index 00000000000..ea60c72ed80 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.h @@ -0,0 +1,75 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_ANIMATED_ARROW_CONTAINER_ELEMENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_ANIMATED_ARROW_CONTAINER_ELEMENT_H_ + +#include "third_party/blink/renderer/core/html/html_div_element.h" +#include "third_party/blink/renderer/modules/media_controls/elements/media_control_animation_event_listener.h" +#include "third_party/blink/renderer/modules/media_controls/elements/media_control_div_element.h" +#include "third_party/blink/renderer/modules/modules_export.h" + +namespace WTF { +class AtomicString; +} + +namespace blink { + +class MediaControlsImpl; + +class MODULES_EXPORT MediaControlAnimatedArrowContainerElement final + : public MediaControlDivElement { + public: + enum class ArrowDirection { kLeft, kRight }; + + explicit MediaControlAnimatedArrowContainerElement(MediaControlsImpl&); + + void ShowArrowAnimation(ArrowDirection); + + void Trace(blink::Visitor*) override; + + private: + friend class MediaControlAnimatedArrowContainerElementTest; + + // This class is responible for displaying the arrow animation when a jump is + // triggered by the user. + class MODULES_EXPORT AnimatedArrow final + : public HTMLDivElement, + public MediaControlAnimationEventListener::Observer { + USING_GARBAGE_COLLECTED_MIXIN(AnimatedArrow); + + public: + AnimatedArrow(const AtomicString& id, Document& document); + + // MediaControlAnimationEventListener::Observer overrides + void OnAnimationIteration() override; + void OnAnimationEnd() override{}; + Element& WatchedAnimationElement() const override; + + // Shows the animated arrows for a single animation iteration. If the + // arrows are already shown it will show them for another animation + // iteration. + void Show(); + + void Trace(Visitor*) override; + + private: + void HideInternal(); + void ShowInternal(); + + int counter_ = 0; + bool hidden_ = true; + + Member<Element> last_arrow_; + Member<Element> svg_container_; + Member<MediaControlAnimationEventListener> event_listener_; + }; + + Member<AnimatedArrow> left_jump_arrow_; + Member<AnimatedArrow> right_jump_arrow_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_ANIMATED_ARROW_CONTAINER_ELEMENT_H_ diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element_test.cc new file mode 100644 index 00000000000..584e6c168f4 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element_test.cc @@ -0,0 +1,83 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/core/css/css_property_value_set.h" +#include "third_party/blink/renderer/core/dom/events/event.h" +#include "third_party/blink/renderer/core/event_type_names.h" +#include "third_party/blink/renderer/core/testing/page_test_base.h" + +namespace blink { + +class MediaControlAnimatedArrowContainerElementTest : public PageTestBase { + public: + void SetUp() final { + // Create page and instance of AnimatedArrow to run tests on. + PageTestBase::SetUp(); + arrow_element_ = + new MediaControlAnimatedArrowContainerElement::AnimatedArrow( + "test", GetDocument()); + GetDocument().body()->AppendChild(arrow_element_); + } + + protected: + void ExpectNotPresent() { EXPECT_FALSE(SVGElementIsPresent()); } + + void ExpectPresentAndShown() { + EXPECT_TRUE(SVGElementIsPresent()); + EXPECT_FALSE(SVGElementHasDisplayValue()); + } + + void ExpectPresentAndHidden() { + EXPECT_TRUE(SVGElementIsPresent()); + EXPECT_TRUE(SVGElementHasDisplayValue()); + } + + void SimulateShow() { arrow_element_->Show(); } + + void SimulateAnimationIteration() { + Event* event = Event::Create(EventTypeNames::animationiteration); + GetElementById("arrow-3")->DispatchEvent(*event); + } + + private: + bool SVGElementHasDisplayValue() { + return GetElementById("jump")->InlineStyle()->HasProperty( + CSSPropertyDisplay); + } + + bool SVGElementIsPresent() { return GetElementById("jump"); } + + Element* GetElementById(const AtomicString& id) { + return GetDocument().body()->getElementById(id); + } + + Persistent<MediaControlAnimatedArrowContainerElement::AnimatedArrow> + arrow_element_; +}; + +TEST_F(MediaControlAnimatedArrowContainerElementTest, ShowIncrementsCounter) { + ExpectNotPresent(); + + // Start a new show. + SimulateShow(); + ExpectPresentAndShown(); + + // Increment the counter and finish the first show. + SimulateShow(); + SimulateAnimationIteration(); + ExpectPresentAndShown(); + + // Finish the second show. + SimulateAnimationIteration(); + ExpectPresentAndHidden(); + + // Start a new show. + SimulateShow(); + ExpectPresentAndShown(); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc index cf3cd3b40ae..6f9fd45dd93 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc @@ -63,7 +63,7 @@ class MediaControlDisplayCutoutFullscreenButtonElementTest void SimulateEnterFullscreen() { { std::unique_ptr<UserGestureIndicator> gesture = - Frame::NotifyUserActivation(GetDocument().GetFrame()); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame()); Fullscreen::RequestFullscreen(*video_); } diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc index 50c19e07bc6..a240eac3b84 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc @@ -77,7 +77,7 @@ void MediaControlDownloadButtonElement::DefaultEventHandler(Event& event) { UserMetricsAction("Media.Controls.Download")); ResourceRequest request(url); request.SetSuggestedFilename(MediaElement().title()); - request.SetRequestContext(WebURLRequest::kRequestContextDownload); + request.SetRequestContext(mojom::RequestContextType::DOWNLOAD); request.SetRequestorOrigin(SecurityOrigin::Create(GetDocument().Url())); GetDocument().GetFrame()->Client()->DownloadURL( request, DownloadCrossOriginRedirects::kFollow); diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h index d5a73cc191b..06df6aa5204 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h @@ -39,6 +39,7 @@ enum MediaControlElementType { kMediaEnterPictureInPictureButton, kMediaExitPictureInPictureButton, kMediaDisplayCutoutFullscreenButton, + kMediaAnimatedArrowContainer, }; #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_ELEMENT_TYPE_H_ diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.cc index 088518dbaba..7a6b6ac02f8 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.cc @@ -128,4 +128,14 @@ void MediaControlElementsHelper::NotifyMediaControlAccessibleFocus( ->OnAccessibleFocus(); } +void MediaControlElementsHelper::NotifyMediaControlAccessibleBlur( + Element* element) { + const HTMLMediaElement* media_element = ToParentMediaElement(element); + if (!media_element || !media_element->GetMediaControls()) + return; + + static_cast<MediaControlsImpl*>(media_element->GetMediaControls()) + ->OnAccessibleBlur(); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h index adc67d95da1..0e39ac3550e 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h @@ -64,6 +64,7 @@ class MediaControlElementsHelper final { // Utility function that notifies the media controls in which the element is // that it was focused by an accessibility tool. static void NotifyMediaControlAccessibleFocus(Element*); + static void NotifyMediaControlAccessibleBlur(Element*); }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.cc index 34f2affb6ad..da173711dda 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.cc @@ -64,6 +64,18 @@ void MediaControlMuteButtonElement::DefaultEventHandler(Event& event) { event.SetDefaultHandled(); } + if (!IsOverflowElement()) { + if (event.type() == EventTypeNames::mouseover || + event.type() == EventTypeNames::focus) { + GetMediaControls().OpenVolumeSliderIfNecessary(); + } + + if (event.type() == EventTypeNames::mouseout || + event.type() == EventTypeNames::blur) { + GetMediaControls().CloseVolumeSliderIfNecessary(); + } + } + MediaControlInputElement::DefaultEventHandler(event); } diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc index 485796cea4b..aa454a87048 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc @@ -5,44 +5,21 @@ #include "third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.h" #include "third_party/blink/public/platform/platform.h" -#include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/public/platform/web_size.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/dom/shadow_root.h" -#include "third_party/blink/renderer/core/events/mouse_event.h" -#include "third_party/blink/renderer/core/geometry/dom_rect.h" -#include "third_party/blink/renderer/core/html/html_style_element.h" #include "third_party/blink/renderer/core/html/media/html_media_element.h" #include "third_party/blink/renderer/core/html/media/html_media_source.h" #include "third_party/blink/renderer/core/input_type_names.h" -#include "third_party/blink/renderer/core/layout/layout_view.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" -#include "third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" -#include "third_party/blink/renderer/platform/wtf/time.h" namespace { // The size of the inner circle button in pixels. constexpr int kInnerButtonSize = 56; -// The touch padding of the inner circle button in pixels. -constexpr int kInnerButtonTouchPaddingSize = 20; - -// Check if a point is based within the boundary of a DOMRect with a margin. -bool IsPointInRect(blink::DOMRect& rect, int margin, int x, int y) { - return ((x >= (rect.left() - margin)) && (x <= (rect.right() + margin)) && - (y >= (rect.top() - margin)) && (y <= (rect.bottom() + margin))); -} - -// The delay between two taps to be recognized as a double tap gesture. -constexpr WTF::TimeDelta kDoubleTapDelay = TimeDelta::FromMilliseconds(300); - -// The number of seconds to jump when double tapping. -constexpr int kNumberOfSecondsToJump = 10; - // The CSS class to add to hide the element. const char kHiddenClassName[] = "hidden"; @@ -50,66 +27,6 @@ const char kHiddenClassName[] = "hidden"; namespace blink { -MediaControlOverlayPlayButtonElement::AnimatedArrow::AnimatedArrow( - const AtomicString& id, - Document& document) - : HTMLDivElement(document) { - setAttribute("id", id); -} - -void MediaControlOverlayPlayButtonElement::AnimatedArrow::HideInternal() { - DCHECK(!hidden_); - svg_container_->SetInlineStyleProperty(CSSPropertyDisplay, CSSValueNone); - hidden_ = true; -} - -void MediaControlOverlayPlayButtonElement::AnimatedArrow::ShowInternal() { - DCHECK(hidden_); - hidden_ = false; - - if (svg_container_) { - svg_container_->RemoveInlineStyleProperty(CSSPropertyDisplay); - return; - } - - SetInnerHTMLFromString(MediaControlsResourceLoader::GetJumpSVGImage()); - - last_arrow_ = getElementById("arrow-3"); - svg_container_ = getElementById("jump"); - - event_listener_ = new MediaControlAnimationEventListener(this); -} - -void MediaControlOverlayPlayButtonElement::AnimatedArrow:: - OnAnimationIteration() { - counter_--; - - if (counter_ == 0) - HideInternal(); -} - -void MediaControlOverlayPlayButtonElement::AnimatedArrow::Show() { - if (hidden_) - ShowInternal(); - - counter_++; -} - -Element& -MediaControlOverlayPlayButtonElement::AnimatedArrow::WatchedAnimationElement() - const { - return *last_arrow_; -} - -void MediaControlOverlayPlayButtonElement::AnimatedArrow::Trace( - Visitor* visitor) { - MediaControlAnimationEventListener::Observer::Trace(visitor); - HTMLDivElement::Trace(visitor); - visitor->Trace(last_arrow_); - visitor->Trace(svg_container_); - visitor->Trace(event_listener_); -} - // The DOM structure looks like: // // MediaControlOverlayPlayButtonElement @@ -120,12 +37,7 @@ void MediaControlOverlayPlayButtonElement::AnimatedArrow::Trace( MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement( MediaControlsImpl& media_controls) : MediaControlInputElement(media_controls, kMediaPlayButton), - tap_timer_(GetDocument().GetTaskRunner(TaskType::kMediaElementEvent), - this, - &MediaControlOverlayPlayButtonElement::TapTimerFired), - internal_button_(nullptr), - left_jump_arrow_(nullptr), - right_jump_arrow_(nullptr) { + internal_button_(nullptr) { EnsureUserAgentShadowRoot(); setType(InputTypeNames::button); SetShadowPseudoId(AtomicString("-webkit-media-controls-overlay-play-button")); @@ -179,146 +91,17 @@ void MediaControlOverlayPlayButtonElement::MaybePlayPause() { UpdateDisplayType(); } -void MediaControlOverlayPlayButtonElement::MaybeJump(int seconds) { - // Load the arrow icons and associate CSS the first time we jump. - if (!left_jump_arrow_) { - DCHECK(!right_jump_arrow_); - ShadowRoot* shadow_root = GetShadowRoot(); - - // This stylesheet element and will contain rules that are specific to the - // jump arrows. The shadow DOM protects these rules from the parent DOM - // from bleeding across the shadow DOM boundary. - auto* style = HTMLStyleElement::Create(GetDocument(), CreateElementFlags()); - style->setTextContent( - MediaControlsResourceLoader::GetOverlayPlayStyleSheet()); - shadow_root->ParserAppendChild(style); - - // Insert the left jump arrow to the left of the play button. - left_jump_arrow_ = new MediaControlOverlayPlayButtonElement::AnimatedArrow( - "left-arrow", GetDocument()); - shadow_root->ParserInsertBefore(left_jump_arrow_, - *shadow_root->firstChild()); - - // Insert the right jump arrow to the right of the play button. - right_jump_arrow_ = new MediaControlOverlayPlayButtonElement::AnimatedArrow( - "right-arrow", GetDocument()); - shadow_root->ParserAppendChild(right_jump_arrow_); - } - - DCHECK(left_jump_arrow_ && right_jump_arrow_); - double new_time = std::max(0.0, MediaElement().currentTime() + seconds); - new_time = std::min(new_time, MediaElement().duration()); - MediaElement().setCurrentTime(new_time); - - if (seconds > 0) - right_jump_arrow_->Show(); - else - left_jump_arrow_->Show(); -} - void MediaControlOverlayPlayButtonElement::DefaultEventHandler(Event& event) { - if (ShouldCausePlayPause(event)) { + if (event.type() == EventTypeNames::click) { event.SetDefaultHandled(); MaybePlayPause(); - } else if (event.type() == EventTypeNames::click) { - event.SetDefaultHandled(); - - DCHECK(event.IsMouseEvent()); - auto& mouse_event = ToMouseEvent(event); - DCHECK(mouse_event.HasPosition()); - - if (!tap_timer_.IsActive()) { - // If there was not a previous touch and this was outside of the button - // then we should toggle visibility with a small unnoticeable delay in - // case their is a second tap. - if (tap_timer_.IsActive()) - return; - tap_was_touch_event_ = MediaControlsImpl::IsTouchEvent(&event); - tap_timer_.StartOneShot(kDoubleTapDelay, FROM_HERE); - } else { - // Cancel the play pause event. - tap_timer_.Stop(); - - // If both taps were touch events, then jump. - if (tap_was_touch_event_.value() && - MediaControlsImpl::IsTouchEvent(&event)) { - // Jump forwards or backwards based on the position of the tap. - WebSize element_size = - MediaControlElementsHelper::GetSizeOrDefault(*this, WebSize(0, 0)); - - if (mouse_event.clientX() >= element_size.width / 2) { - MaybeJump(kNumberOfSecondsToJump); - } else { - MaybeJump(kNumberOfSecondsToJump * -1); - } - } else { - if (GetMediaControls().IsFullscreenEnabled()) { - // Enter or exit fullscreen. - if (MediaElement().IsFullscreen()) - GetMediaControls().ExitFullscreen(); - else - GetMediaControls().EnterFullscreen(); - } - } - - tap_was_touch_event_.reset(); - } } MediaControlInputElement::DefaultEventHandler(event); } bool MediaControlOverlayPlayButtonElement::KeepEventInNode( const Event& event) const { - // We only care about user interaction events. - if (!MediaControlElementsHelper::IsUserInteractionEvent(event)) - return false; - - // For mouse events, only keep in node if they're on the internal button. - if (event.IsMouseEvent() && MediaControlsImpl::IsModern()) - return IsMouseEventOnInternalButton(ToMouseEvent(event)); - - return true; -} - -bool MediaControlOverlayPlayButtonElement::ShouldCausePlayPause( - const Event& event) const { - // Only click events cause a play/pause. - if (event.type() != EventTypeNames::click) - return false; - - // Double tap to navigate should only be available on modern controls. - if (!MediaControlsImpl::IsModern() || !event.IsMouseEvent()) - return true; - - // TODO(beccahughes): Move to PointerEvent. - return IsMouseEventOnInternalButton(ToMouseEvent(event)); -} - -bool MediaControlOverlayPlayButtonElement::IsMouseEventOnInternalButton( - const MouseEvent& mouse_event) const { - // If we don't have the necessary pieces to calculate whether the event is - // within the bounds of the button, default to yes. - if (!mouse_event.HasPosition() || !isConnected() || - !GetDocument().GetLayoutView() || !MediaElement().ShouldShowControls()) { - return true; - } - - // If there is no layout view, default to yes. - if (!GetDocument().GetLayoutView()) - return true; - - // Find the zoom-adjusted internal button bounding box. - DOMRect* box = internal_button_->getBoundingClientRect(); - float zoom = ComputedStyleRef().EffectiveZoom() / - GetDocument().GetLayoutView()->ZoomFactor(); - box->setX(box->x() * zoom); - box->setY(box->y() * zoom); - box->setWidth(box->width() * zoom); - box->setHeight(box->height() * zoom); - - // Check the button and a margin around it. - return IsPointInRect(*box, kInnerButtonTouchPaddingSize, - mouse_event.clientX(), mouse_event.clientY()); + return MediaControlElementsHelper::IsUserInteractionEvent(event); } WebSize MediaControlOverlayPlayButtonElement::GetSizeOrDefault() const { @@ -336,17 +119,9 @@ void MediaControlOverlayPlayButtonElement::SetIsDisplayed(bool displayed) { displayed_ = displayed; } -void MediaControlOverlayPlayButtonElement::TapTimerFired(TimerBase*) { - if (tap_was_touch_event_.value()) - GetMediaControls().MaybeToggleControlsFromTap(); - tap_was_touch_event_.reset(); -} - void MediaControlOverlayPlayButtonElement::Trace(blink::Visitor* visitor) { MediaControlInputElement::Trace(visitor); visitor->Trace(internal_button_); - visitor->Trace(left_jump_arrow_); - visitor->Trace(right_jump_arrow_); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.h index d2eec864f5b..e7ef4575925 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.h @@ -6,20 +6,13 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_ELEMENTS_MEDIA_CONTROL_OVERLAY_PLAY_BUTTON_ELEMENT_H_ #include "third_party/blink/renderer/core/html/html_div_element.h" -#include "third_party/blink/renderer/modules/media_controls/elements/media_control_animation_event_listener.h" #include "third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.h" #include "third_party/blink/renderer/modules/modules_export.h" -#include "third_party/blink/renderer/platform/timer.h" - -namespace WTF { -class AtomicString; -} namespace blink { class Event; class MediaControlsImpl; -class MouseEvent; class MODULES_EXPORT MediaControlOverlayPlayButtonElement final : public MediaControlInputElement { @@ -41,58 +34,12 @@ class MODULES_EXPORT MediaControlOverlayPlayButtonElement final const char* GetNameForHistograms() const override; private: - friend class MediaControlOverlayPlayButtonElementTest; - - // This class is responible for displaying the arrow animation when a jump is - // triggered by the user. - class MODULES_EXPORT AnimatedArrow final - : public HTMLDivElement, - public MediaControlAnimationEventListener::Observer { - USING_GARBAGE_COLLECTED_MIXIN(AnimatedArrow); - - public: - AnimatedArrow(const AtomicString& id, Document& document); - - // MediaControlAnimationEventListener::Observer overrides - void OnAnimationIteration() override; - void OnAnimationEnd() override{}; - Element& WatchedAnimationElement() const override; - - // Shows the animated arrows for a single animation iteration. If the - // arrows are already shown it will show them for another animation - // iteration. - void Show(); - - void Trace(Visitor*) override; - - private: - void HideInternal(); - void ShowInternal(); - - int counter_ = 0; - bool hidden_ = true; - - Member<Element> last_arrow_; - Member<Element> svg_container_; - Member<MediaControlAnimationEventListener> event_listener_; - }; - - void TapTimerFired(TimerBase*); - void DefaultEventHandler(Event&) override; bool KeepEventInNode(const Event&) const override; - bool ShouldCausePlayPause(const Event&) const; - bool IsMouseEventOnInternalButton(const MouseEvent&) const; void MaybePlayPause(); - void MaybeJump(int); - - TaskRunnerTimer<MediaControlOverlayPlayButtonElement> tap_timer_; - base::Optional<bool> tap_was_touch_event_; Member<HTMLDivElement> internal_button_; - Member<AnimatedArrow> left_jump_arrow_; - Member<AnimatedArrow> right_jump_arrow_; bool displayed_ = true; }; diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element_test.cc deleted file mode 100644 index a6cf60699f9..00000000000 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element_test.cc +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.h" - -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/renderer/core/css/css_property_value_set.h" -#include "third_party/blink/renderer/core/dom/events/event.h" -#include "third_party/blink/renderer/core/event_type_names.h" -#include "third_party/blink/renderer/core/events/mouse_event.h" -#include "third_party/blink/renderer/core/frame/local_dom_window.h" -#include "third_party/blink/renderer/core/html/html_html_element.h" -#include "third_party/blink/renderer/core/html/media/html_video_element.h" -#include "third_party/blink/renderer/core/testing/page_test_base.h" -#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h" -#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" - -namespace blink { - -class MediaControlOverlayPlayButtonElementTest : public PageTestBase { - public: - void SetUp() final { - // Create page and instance of AnimatedArrow to run tests on. - PageTestBase::SetUp(); - arrow_element_ = new MediaControlOverlayPlayButtonElement::AnimatedArrow( - "test", GetDocument()); - GetDocument().body()->AppendChild(arrow_element_); - } - - protected: - void ExpectNotPresent() { EXPECT_FALSE(SVGElementIsPresent()); } - - void ExpectPresentAndShown() { - EXPECT_TRUE(SVGElementIsPresent()); - EXPECT_FALSE(SVGElementHasDisplayValue()); - } - - void ExpectPresentAndHidden() { - EXPECT_TRUE(SVGElementIsPresent()); - EXPECT_TRUE(SVGElementHasDisplayValue()); - } - - void SimulateShow() { arrow_element_->Show(); } - - void SimulateAnimationIteration() { - Event* event = Event::Create(EventTypeNames::animationiteration); - GetElementById("arrow-3")->DispatchEvent(*event); - } - - Document& CreateTestDocumentWithBody() { - Document* document = Document::CreateForTest(); - HTMLHtmlElement* html = HTMLHtmlElement::Create(*document); - document->AppendChild(html); - document->documentElement()->SetInnerHTMLFromString("<body></body>"); - return *document; - } - - void CreateTestOverlayPlayButton(Document& test_document) { - // Create a video element so that a MediaControlsImpl is created. - HTMLVideoElement* media_element = HTMLVideoElement::Create(test_document); - media_element->SetBooleanAttribute(HTMLNames::controlsAttr, true); - test_document.body()->AppendChild(media_element); - - MediaControlsImpl* media_controls = - static_cast<MediaControlsImpl*>(media_element->GetMediaControls()); - ASSERT_NE(nullptr, media_controls); - - // Create a MediaControlOverlayPlayButtonElement for testing. - overlay_play_button_ = - new MediaControlOverlayPlayButtonElement(*media_controls); - } - - void SimulateKeepEventInNode() { - MouseEventInit mouse_initializer; - mouse_initializer.setView(GetDocument().domWindow()); - mouse_initializer.setButton(1); - - MouseEvent* mouse_event = - MouseEvent::Create(nullptr, EventTypeNames::click, mouse_initializer); - overlay_play_button_->KeepEventInNode(*mouse_event); - } - - private: - bool SVGElementHasDisplayValue() { - return GetElementById("jump")->InlineStyle()->HasProperty( - CSSPropertyDisplay); - } - - bool SVGElementIsPresent() { return GetElementById("jump"); } - - Element* GetElementById(const AtomicString& id) { - return GetDocument().body()->getElementById(id); - } - - Persistent<MediaControlOverlayPlayButtonElement> overlay_play_button_; - Persistent<MediaControlOverlayPlayButtonElement::AnimatedArrow> - arrow_element_; -}; - -TEST_F(MediaControlOverlayPlayButtonElementTest, ShowIncrementsCounter) { - ExpectNotPresent(); - - // Start a new show. - SimulateShow(); - ExpectPresentAndShown(); - - // Increment the counter and finish the first show. - SimulateShow(); - SimulateAnimationIteration(); - ExpectPresentAndShown(); - - // Finish the second show. - SimulateAnimationIteration(); - ExpectPresentAndHidden(); - - // Start a new show. - SimulateShow(); - ExpectPresentAndShown(); -} - -TEST_F(MediaControlOverlayPlayButtonElementTest, - KeepEventInNodeWithoutLayoutViewDoesntCrash) { - ScopedModernMediaControlsForTest enable_modern_media_controls(true); - Document& document_without_layout_view = CreateTestDocumentWithBody(); - CreateTestOverlayPlayButton(document_without_layout_view); - SimulateKeepEventInNode(); -} - -} // 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 b4d02b11036..22848fc0ddd 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 @@ -125,7 +125,8 @@ void MediaControlPanelElement::MakeTransparent() { opaque_ = false; } -void MediaControlPanelElement::RemovedFrom(ContainerNode&) { +void MediaControlPanelElement::RemovedFrom(ContainerNode& insertion_point) { + MediaControlDivElement::RemovedFrom(insertion_point); DetachTransitionEventListener(); } @@ -134,6 +135,10 @@ void MediaControlPanelElement::Trace(blink::Visitor* visitor) { visitor->Trace(event_listener_); } +bool MediaControlPanelElement::KeepDisplayedForAccessibility() { + return keep_displayed_for_accessibility_; +} + void MediaControlPanelElement::SetKeepDisplayedForAccessibility(bool value) { keep_displayed_for_accessibility_ = value; } @@ -168,7 +173,7 @@ void MediaControlPanelElement::DetachTransitionEventListener() { void MediaControlPanelElement::DefaultEventHandler(Event& event) { // Suppress the media element activation behavior (toggle play/pause) when // any part of the control panel is clicked. - if (event.type() == EventTypeNames::click) { + if (event.type() == EventTypeNames::click && !MediaControlsImpl::IsModern()) { event.SetDefaultHandled(); return; } @@ -176,7 +181,8 @@ void MediaControlPanelElement::DefaultEventHandler(Event& event) { } bool MediaControlPanelElement::KeepEventInNode(const Event& event) const { - return !MediaControlsImpl::IsModern() && + return (!MediaControlsImpl::IsModern() || + GetMediaControls().ShouldShowAudioControls()) && MediaControlElementsHelper::IsUserInteractionEvent(event); } 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 301e1a26722..ccb43bbb8fa 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 @@ -26,6 +26,7 @@ class MODULES_EXPORT MediaControlPanelElement final void MakeOpaque(); void MakeTransparent(); + bool KeepDisplayedForAccessibility(); void SetKeepDisplayedForAccessibility(bool); // Node override; diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element_test.cc index d158961a2b5..f44fe39f8cb 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element_test.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element_test.cc @@ -49,6 +49,7 @@ class MediaControlPanelElementTest : public PageTestBase { } MediaControlPanelElement& GetPanel() { return *panel_element_.Get(); } + HTMLMediaElement& GetMediaElement() { return *media_element_.Get(); } private: void TriggerEvent(const AtomicString& name) { @@ -89,4 +90,12 @@ TEST_F(MediaControlPanelElementTest, StateTransitions) { ExpectPanelIsDisplayed(); } +TEST_F(MediaControlPanelElementTest, isConnected) { + EXPECT_TRUE( + GetMediaElement().GetMediaControls()->PanelElement()->isConnected()); + GetMediaElement().remove(); + EXPECT_FALSE( + GetMediaElement().GetMediaControls()->PanelElement()->isConnected()); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc index 03276daaf1d..0cb0d29c3a1 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc @@ -13,6 +13,7 @@ #include "third_party/blink/renderer/core/frame/local_dom_window.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/modules/media_controls/elements/media_control_elements_helper.h" #include "third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.h" #include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h" #include "third_party/blink/renderer/platform/keyboard_codes.h" @@ -161,6 +162,11 @@ void MediaControlPopupMenuElement::DefaultEventHandler(Event& event) { MediaControlDivElement::DefaultEventHandler(event); } +bool MediaControlPopupMenuElement::KeepEventInNode(const Event& event) const { + return MediaControlsImpl::IsModern() && + MediaControlElementsHelper::IsUserInteractionEvent(event); +} + void MediaControlPopupMenuElement::RemovedFrom(ContainerNode& container) { if (IsWanted()) SetIsWanted(false); diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h index 691f301be7d..a538d3ee566 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h @@ -26,6 +26,7 @@ class MediaControlPopupMenuElement : public MediaControlDivElement { // Node override. void DefaultEventHandler(Event&) override; + bool KeepEventInNode(const Event&) const override; void RemovedFrom(ContainerNode&) override; void Trace(blink::Visitor*) override; diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc index afc97376393..2ffacc5f603 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc @@ -5,6 +5,7 @@ #include "third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.h" #include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/renderer/core/dom/dom_token_list.h" #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/html/media/html_media_element.h" #include "third_party/blink/renderer/core/html_names.h" @@ -14,12 +15,22 @@ namespace blink { +namespace { + +const char kClosedCSSClass[] = "closed"; + +} // anonymous namespace + MediaControlVolumeSliderElement::MediaControlVolumeSliderElement( MediaControlsImpl& media_controls) : MediaControlSliderElement(media_controls, kMediaVolumeSlider) { setAttribute(HTMLNames::maxAttr, "1"); SetShadowPseudoId(AtomicString("-webkit-media-controls-volume-slider")); SetVolumeInternal(MediaElement().volume()); + + // The slider starts closed in modern media controls. + if (MediaControlsImpl::IsModern()) + CloseSlider(); } void MediaControlVolumeSliderElement::SetVolume(double volume) { @@ -30,6 +41,14 @@ void MediaControlVolumeSliderElement::SetVolume(double volume) { SetVolumeInternal(volume); } +void MediaControlVolumeSliderElement::OpenSlider() { + classList().Remove(kClosedCSSClass); +} + +void MediaControlVolumeSliderElement::CloseSlider() { + classList().Add(kClosedCSSClass); +} + bool MediaControlVolumeSliderElement::WillRespondToMouseMoveEvents() { if (!isConnected() || !GetDocument().IsActive()) return false; @@ -75,6 +94,16 @@ void MediaControlVolumeSliderElement::DefaultEventHandler(Event& event) { MediaElement().setMuted(false); SetVolumeInternal(volume); } + + if (event.type() == EventTypeNames::mouseover || + event.type() == EventTypeNames::focus) { + GetMediaControls().OpenVolumeSliderIfNecessary(); + } + + if (event.type() == EventTypeNames::mouseout || + event.type() == EventTypeNames::blur) { + GetMediaControls().CloseVolumeSliderIfNecessary(); + } } void MediaControlVolumeSliderElement::SetVolumeInternal(double volume) { diff --git a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.h b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.h index 2e9962f5c25..dc37b48d74f 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.h @@ -19,6 +19,9 @@ class MediaControlVolumeSliderElement final : public MediaControlSliderElement { // TODO: who calls this? void SetVolume(double); + void OpenSlider(); + void CloseSlider(); + // MediaControlInputElement overrides. bool WillRespondToMouseMoveEvents() override; bool WillRespondToMouseClickEvents() override; diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate_test.cc index bd53ac69e41..04eb76ab939 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate_test.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate_test.cc @@ -55,7 +55,7 @@ class MediaControlsDisplayCutoutDelegateTest : public PageTestBase { void SimulateEnterFullscreen() { { std::unique_ptr<UserGestureIndicator> gesture = - Frame::NotifyUserActivation(GetDocument().GetFrame()); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame()); Fullscreen::RequestFullscreen(GetVideoElement()); } 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 fa2415ecb14..43a10f53557 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 @@ -29,7 +29,6 @@ #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/public/platform/web_size.h" #include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_html.h" -#include "third_party/blink/renderer/core/css/css_style_declaration.h" #include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h" #include "third_party/blink/renderer/core/dom/mutation_observer.h" #include "third_party/blink/renderer/core/dom/mutation_observer_init.h" @@ -40,6 +39,7 @@ #include "third_party/blink/renderer/core/frame/settings.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/geometry/dom_rect.h" #include "third_party/blink/renderer/core/html/media/autoplay_policy.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" @@ -51,6 +51,7 @@ #include "third_party/blink/renderer/core/page/spatial_navigation.h" #include "third_party/blink/renderer/core/resize_observer/resize_observer.h" #include "third_party/blink/renderer/core/resize_observer/resize_observer_entry.h" +#include "third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.h" #include "third_party/blink/renderer/modules/media_controls/elements/media_control_button_panel_element.h" #include "third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.h" #include "third_party/blink/renderer/modules/media_controls/elements/media_control_current_time_display_element.h" @@ -131,14 +132,11 @@ const char kScrubbingMessageCSSClass[] = "scrubbing-message"; const char kTestModeCSSClass[] = "test-mode"; const char kImmersiveModeCSSClass[] = "immersive-mode"; -// The ratio of video width/height to use for play button size. -constexpr float kSizingSmallOverlayPlayButtonSizeRatio = 0.25; -constexpr float kSizingMediumOverlayPlayButtonSizeRatio = 0.15; -constexpr float kSizingLargeOverlayPlayButtonSizeRatio = 0.11; +// The delay between two taps to be recognized as a double tap gesture. +constexpr WTF::TimeDelta kDoubleTapDelay = TimeDelta::FromMilliseconds(300); -// Used for setting overlay play button width CSS variable. -constexpr double kMinOverlayPlayButtonWidth = 48; -const char kOverlayPlayButtonWidthCSSVar[] = "--overlay-play-button-width"; +// 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 @@ -368,6 +366,7 @@ MediaControlsImpl::MediaControlsImpl(HTMLMediaElement& media_element) media_button_panel_(nullptr), loading_panel_(nullptr), picture_in_picture_button_(nullptr), + animated_arrow_container_element_(nullptr), cast_button_(nullptr), fullscreen_button_(nullptr), display_cutout_fullscreen_button_(nullptr), @@ -390,7 +389,11 @@ MediaControlsImpl::MediaControlsImpl(HTMLMediaElement& media_element) media_element.GetDocument().GetTaskRunner(TaskType::kInternalMedia), this, &MediaControlsImpl::ElementSizeChangedTimerFired), - keep_showing_until_timer_fires_(false) { + keep_showing_until_timer_fires_(false), + tap_timer_( + media_element.GetDocument().GetTaskRunner(TaskType::kInternalMedia), + this, + &MediaControlsImpl::TapTimerFired) { // On touch devices, start with the assumption that the user will interact via // touch events. Settings* settings = media_element.GetDocument().GetSettings(); @@ -525,8 +528,7 @@ void MediaControlsImpl::InitializeControls() { overlay_enclosure_ = new MediaControlOverlayEnclosureElement(*this); - if (RuntimeEnabledFeatures::MediaControlsOverlayPlayButtonEnabled() || - IsModern()) { + if (RuntimeEnabledFeatures::MediaControlsOverlayPlayButtonEnabled()) { overlay_play_button_ = new MediaControlOverlayPlayButtonElement(*this); if (!IsModern()) @@ -560,12 +562,9 @@ void MediaControlsImpl::InitializeControls() { timeline_ = new MediaControlTimelineElement(*this); mute_button_ = new MediaControlMuteButtonElement(*this); - // The volume slider should be shown if we are using the legacy controls. - if (!IsModern()) { - volume_slider_ = new MediaControlVolumeSliderElement(*this); - if (PreferHiddenVolumeControls(GetDocument())) - volume_slider_->SetIsWanted(false); - } + volume_slider_ = new MediaControlVolumeSliderElement(*this); + if (PreferHiddenVolumeControls(GetDocument())) + volume_slider_->SetIsWanted(false); if (RuntimeEnabledFeatures::PictureInPictureEnabled() && GetDocument().GetSettings() && @@ -640,7 +639,7 @@ void MediaControlsImpl::PopulatePanel() { if (display_cutout_fullscreen_button_) panel_->ParserAppendChild(display_cutout_fullscreen_button_); - panel_->ParserAppendChild(overlay_play_button_); + MaybeParserAppendChild(panel_, overlay_play_button_); panel_->ParserAppendChild(media_button_panel_); button_panel = media_button_panel_; } @@ -656,9 +655,15 @@ void MediaControlsImpl::PopulatePanel() { panel_->ParserAppendChild(timeline_); - button_panel->ParserAppendChild(mute_button_); + // On modern controls, the volume slider is to the left of the mute button. + if (IsModern()) { + MaybeParserAppendChild(button_panel, volume_slider_); + button_panel->ParserAppendChild(mute_button_); + } else { + button_panel->ParserAppendChild(mute_button_); + MaybeParserAppendChild(button_panel, volume_slider_); + } - MaybeParserAppendChild(button_panel, volume_slider_); MaybeParserAppendChild(button_panel, picture_in_picture_button_); button_panel->ParserAppendChild(fullscreen_button_); @@ -754,18 +759,35 @@ void MediaControlsImpl::UpdateCSSClassFromState() { // If we are in the "no-source" state we should show the overflow menu on a // video element. if (IsModern()) { + bool updated = false; + if (state == kNoSource) { - // Check if the overflow menu has the "disabled" attribute set so we avoid - // unnecessarily resetting it. + // Check if the play button or overflow menu has the "disabled" attribute + // set so we avoid unnecessarily resetting it. + if (!play_button_->hasAttribute(HTMLNames::disabledAttr)) { + play_button_->setAttribute(HTMLNames::disabledAttr, ""); + updated = true; + } + if (ShouldShowVideoControls() && !overflow_menu_->hasAttribute(HTMLNames::disabledAttr)) { overflow_menu_->setAttribute(HTMLNames::disabledAttr, ""); - UpdateOverflowMenuWanted(); + updated = true; + } + } else { + if (play_button_->hasAttribute(HTMLNames::disabledAttr)) { + play_button_->removeAttribute(HTMLNames::disabledAttr); + updated = true; + } + + if (overflow_menu_->hasAttribute(HTMLNames::disabledAttr)) { + overflow_menu_->removeAttribute(HTMLNames::disabledAttr); + updated = true; } - } else if (overflow_menu_->hasAttribute(HTMLNames::disabledAttr)) { - overflow_menu_->removeAttribute(HTMLNames::disabledAttr); - UpdateOverflowMenuWanted(); } + + if (updated) + UpdateOverflowMenuWanted(); } } @@ -813,8 +835,7 @@ void MediaControlsImpl::RemovedFrom(ContainerNode& insertion_point) { HTMLDivElement::RemovedFrom(insertion_point); - // TODO(mlamouri): we hide show the controls instead of having - // HTMLMediaElement do it. + Hide(); media_event_listener_->Detach(); if (orientation_lock_delegate_) @@ -1040,6 +1061,10 @@ bool MediaControlsImpl::ShouldHideMediaControls(unsigned behavior_flags) const { if (download_iph_manager_ && download_iph_manager_->IsShowingInProductHelp()) return false; + // Don't hide if we have accessiblity focus. + if (panel_->KeepDisplayedForAccessibility()) + return false; + return true; } @@ -1246,13 +1271,16 @@ void MediaControlsImpl::UpdateOverflowMenuWanted() const { // room and hide the overlay play button if there is not enough room. if (ShouldShowVideoControls()) { // Allocate vertical room for overlay play button if necessary. - WebSize overlay_play_button_size = overlay_play_button_->GetSizeOrDefault(); - if (controls_size.height >= overlay_play_button_size.height && - controls_size.width >= kModernMinWidthForOverlayPlayButton) { - overlay_play_button_->SetDoesFit(true); - controls_size.height -= overlay_play_button_size.height; - } else { - overlay_play_button_->SetDoesFit(false); + if (overlay_play_button_) { + WebSize overlay_play_button_size = + overlay_play_button_->GetSizeOrDefault(); + if (controls_size.height >= overlay_play_button_size.height && + controls_size.width >= kModernMinWidthForOverlayPlayButton) { + overlay_play_button_->SetDoesFit(true); + controls_size.height -= overlay_play_button_size.height; + } else { + overlay_play_button_->SetDoesFit(false); + } } controls_size.width -= kModernControlsVideoButtonPadding; @@ -1269,7 +1297,8 @@ void MediaControlsImpl::UpdateOverflowMenuWanted() const { } // If we cannot show the overlay play button, show the normal one. - play_button_->SetIsWanted(!overlay_play_button_->DoesFit()); + play_button_->SetIsWanted(!overlay_play_button_ || + !overlay_play_button_->DoesFit()); } else { controls_size.width -= kModernControlsAudioButtonPadding; @@ -1360,42 +1389,6 @@ void MediaControlsImpl::UpdateSizingCSSClass() { SetClass(kMediaControlsSizingLargeCSSClass, ShouldShowVideoControls() && sizing_class == MediaControlsSizingClass::kLarge); - - UpdateOverlayPlayButtonWidthCSSVar(); -} - -void MediaControlsImpl::UpdateOverlayPlayButtonWidthCSSVar() { - // The logic for sizing the overlay play button and its use inside the - // controls is a bit too complex for CSS alone (the sizing is a min of two - // values maxed with another, and then that needs to be used in calculations - // for the spinner as well). To work around this, we're using a CSS variable - // set here and used inside the controls CSS. - int width = size_.Width(); - int height = size_.Height(); - double minDimension = std::min(width, height); - - MediaControlsSizingClass sizing_class = MediaControls::GetSizingClass(width); - double sizingRatio; - if (sizing_class == MediaControlsSizingClass::kLarge) { - sizingRatio = kSizingLargeOverlayPlayButtonSizeRatio; - } else if (sizing_class == MediaControlsSizingClass::kMedium) { - sizingRatio = kSizingMediumOverlayPlayButtonSizeRatio; - } else { - sizingRatio = kSizingSmallOverlayPlayButtonSizeRatio; - } - - double play_button_width = - std::max(kMinOverlayPlayButtonWidth, minDimension * sizingRatio); - - WTF::String play_button_css_value = WTF::String::Number(play_button_width); - play_button_css_value.append("px"); - - if (!overlay_play_button_width_.has_value() || - overlay_play_button_width_.value() != play_button_width) { - overlay_play_button_width_ = play_button_width; - style()->setProperty(&GetDocument(), kOverlayPlayButtonWidthCSSVar, - play_button_css_value, "", ASSERT_NO_EXCEPTION); - } } void MediaControlsImpl::MaybeToggleControlsFromTap() { @@ -1416,16 +1409,33 @@ void MediaControlsImpl::MaybeToggleControlsFromTap() { } void MediaControlsImpl::OnAccessibleFocus() { + if (panel_->KeepDisplayedForAccessibility()) + return; + panel_->SetKeepDisplayedForAccessibility(true); if (!MediaElement().ShouldShowControls()) return; + OpenVolumeSliderIfNecessary(); + keep_showing_until_timer_fires_ = true; StartHideMediaControlsTimer(); MaybeShow(); } +void MediaControlsImpl::OnAccessibleBlur() { + panel_->SetKeepDisplayedForAccessibility(false); + + if (MediaElement().ShouldShowControls()) + return; + + CloseVolumeSliderIfNecessary(); + + keep_showing_until_timer_fires_ = false; + ResetHideMediaControlsTimer(); +} + void MediaControlsImpl::DefaultEventHandler(Event& event) { HTMLDivElement::DefaultEventHandler(event); @@ -1458,6 +1468,9 @@ void MediaControlsImpl::DefaultEventHandler(Event& event) { HandlePointerEvent(&event); } + if (event.type() == EventTypeNames::click && !is_touch_interaction_) + HandleClickEvent(&event); + // If the user is interacting with the controls via the keyboard, don't hide // the controls. This will fire when the user tabs between controls (focusin) // or when they seek either the timeline or volume sliders (input). @@ -1470,7 +1483,7 @@ void MediaControlsImpl::DefaultEventHandler(Event& event) { !IsSpatialNavigationEnabled(GetDocument().GetFrame())) { const String& key = ToKeyboardEvent(event).key(); if (key == "Enter" || ToKeyboardEvent(event).keyCode() == ' ') { - if (IsModern()) { + if (IsModern() && overlay_play_button_) { overlay_play_button_->OnMediaKeyboardEvent(&event); } else { play_button_->OnMediaKeyboardEvent(&event); @@ -1482,8 +1495,7 @@ void MediaControlsImpl::DefaultEventHandler(Event& event) { timeline_->OnMediaKeyboardEvent(&event); return; } - // We don't allow the user to change the volume on modern media controls. - if (!IsModern() && (key == "ArrowDown" || key == "ArrowUp")) { + if (volume_slider_ && (key == "ArrowDown" || key == "ArrowUp")) { for (int i = 0; i < 5; i++) volume_slider_->OnMediaKeyboardEvent(&event); return; @@ -1515,10 +1527,46 @@ void MediaControlsImpl::HandlePointerEvent(Event* event) { } } +void MediaControlsImpl::HandleClickEvent(Event* event) { + if (!IsModern() || ContainsRelatedTarget(event) || !IsFullscreenEnabled()) + return; + + if (tap_timer_.IsActive()) { + tap_timer_.Stop(); + + // Toggle fullscreen. + if (MediaElement().IsFullscreen()) + ExitFullscreen(); + else + EnterFullscreen(); + } else { + tap_timer_.StartOneShot(kDoubleTapDelay, FROM_HERE); + } +} + void MediaControlsImpl::HandleTouchEvent(Event* event) { if (IsModern()) { is_mouse_over_controls_ = false; is_touch_interaction_ = true; + + if (event->type() == EventTypeNames::click && + !ContainsRelatedTarget(event)) { + event->SetDefaultHandled(); + + if (tap_timer_.IsActive()) { + // Cancel the visibility toggle event. + tap_timer_.Stop(); + + if (IsOnLeftSide(event)) { + MaybeJump(kNumberOfSecondsToJump * -1); + } else { + MaybeJump(kNumberOfSecondsToJump); + } + } else { + tap_timer_.StartOneShot(kDoubleTapDelay, FROM_HERE); + } + } + return; } if (event->type() == EventTypeNames::gesturetap && @@ -1536,6 +1584,47 @@ void MediaControlsImpl::HandleTouchEvent(Event* event) { } } +void MediaControlsImpl::EnsureAnimatedArrowContainer() { + if (!animated_arrow_container_element_) { + animated_arrow_container_element_ = + new MediaControlAnimatedArrowContainerElement(*this); + ParserAppendChild(animated_arrow_container_element_); + } +} + +void MediaControlsImpl::MaybeJump(int seconds) { + // Update the current time. + double new_time = std::max(0.0, MediaElement().currentTime() + seconds); + new_time = std::min(new_time, MediaElement().duration()); + MediaElement().setCurrentTime(new_time); + + // Show the arrow animation. + EnsureAnimatedArrowContainer(); + MediaControlAnimatedArrowContainerElement::ArrowDirection direction = + (seconds > 0) + ? MediaControlAnimatedArrowContainerElement::ArrowDirection::kRight + : MediaControlAnimatedArrowContainerElement::ArrowDirection::kLeft; + animated_arrow_container_element_->ShowArrowAnimation(direction); +} + +bool MediaControlsImpl::IsOnLeftSide(Event* event) { + if (!event->IsMouseEvent()) + return false; + + MouseEvent* mouse_event = ToMouseEvent(event); + if (!mouse_event->HasPosition()) + return false; + + DOMRect* rect = getBoundingClientRect(); + double middle = rect->x() + (rect->width() / 2); + return mouse_event->clientX() < middle; +} + +void MediaControlsImpl::TapTimerFired(TimerBase*) { + if (is_touch_interaction_) + MaybeToggleControlsFromTap(); +} + void MediaControlsImpl::HideMediaControlsTimerFired(TimerBase*) { unsigned behavior_flags = hide_timer_behavior_flags_ | kIgnoreFocus | kIgnoreVideoHover; @@ -1591,7 +1680,6 @@ void MediaControlsImpl::OnVolumeChange() { // Update visibility of volume controls. // TODO(mlamouri): it should not be part of the volumechange handling because // it is using audio availability as input. - BatchedControlUpdate batch(this); if (volume_slider_) { volume_slider_->SetVolume(MediaElement().muted() ? 0 : MediaElement().volume()); @@ -1607,6 +1695,12 @@ void MediaControlsImpl::OnVolumeChange() { mute_button_->SetIsWanted(MediaElement().HasAudio()); mute_button_->removeAttribute(HTMLNames::disabledAttr); } + + // On modern media controls, if the volume slider is being used we don't want + // to update controls visiblity, since this can shift the position of the + // volume slider and make it unusable. + if (!IsModern() || !volume_slider_ || !volume_slider_->IsHovered()) + BatchedControlUpdate batch(this); } void MediaControlsImpl::OnFocusIn() { @@ -2021,6 +2115,30 @@ void MediaControlsImpl::StartHideMediaControlsIfNecessary() { StartHideMediaControlsTimer(); } +void MediaControlsImpl::OpenVolumeSliderIfNecessary() { + if (ShouldOpenVolumeSlider()) + volume_slider_->OpenSlider(); +} + +void MediaControlsImpl::CloseVolumeSliderIfNecessary() { + if (ShouldCloseVolumeSlider()) + volume_slider_->CloseSlider(); +} + +bool MediaControlsImpl::ShouldOpenVolumeSlider() const { + if (!volume_slider_ || !IsModern()) + return false; + + return !PreferHiddenVolumeControls(GetDocument()); +} + +bool MediaControlsImpl::ShouldCloseVolumeSlider() const { + if (!volume_slider_ || !IsModern()) + return false; + + return !(volume_slider_->IsHovered() || mute_button_->IsHovered()); +} + const MediaControlDownloadButtonElement& MediaControlsImpl::DownloadButton() const { return *download_button_; @@ -2069,6 +2187,7 @@ void MediaControlsImpl::Trace(blink::Visitor* visitor) { visitor->Trace(mute_button_); visitor->Trace(volume_slider_); visitor->Trace(picture_in_picture_button_); + visitor->Trace(animated_arrow_container_element_); visitor->Trace(toggle_closed_captions_button_); visitor->Trace(fullscreen_button_); visitor->Trace(download_button_); diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h index e87c133017e..53e85b7e9e4 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl.h @@ -42,6 +42,7 @@ class MediaControlsDisplayCutoutDelegate; class MediaControlsOrientationLockDelegate; class MediaControlsRotateToFullscreenDelegate; class MediaControlsWindowEventListener; +class MediaControlAnimatedArrowContainerElement; class MediaControlButtonPanelElement; class MediaControlCastButtonElement; class MediaControlCurrentTimeDisplayElement; @@ -136,6 +137,9 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement, void ToggleOverflowMenu(); bool OverflowMenuVisible(); + void OpenVolumeSliderIfNecessary(); + void CloseVolumeSliderIfNecessary(); + void ShowOverlayCastButtonIfNeeded(); // Methods call by the scrubber. @@ -189,6 +193,10 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement, // accessibility tool. This is meant to be replaced by AOM when the event will // be exposed to the platform. void OnAccessibleFocus(); + void OnAccessibleBlur(); + + // Returns true/false based on which set of controls to display. + bool ShouldShowAudioControls() const; private: // MediaControlsMediaEventListener is a component that is listening to events @@ -262,6 +270,9 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement, void HideCursor(); void ShowCursor(); + bool ShouldOpenVolumeSlider() const; + bool ShouldCloseVolumeSlider() const; + void ElementSizeChangedTimerFired(TimerBase*); // Hide elements that don't fit, and show those things that we want which @@ -272,7 +283,6 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement, void UpdateOverflowMenuWanted() const; void UpdateScrubbingMessageFits() const; void UpdateSizingCSSClass(); - void UpdateOverlayPlayButtonWidthCSSVar(); void MaybeRecordElementsDisplayed() const; // Takes a popup menu (caption, overflow) and position on the screen. This is @@ -288,7 +298,6 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement, void UpdateActingAsAudioControls(); // Returns true/false based on which set of controls to display. - bool ShouldShowAudioControls() const; bool ShouldShowVideoControls() const; // Node @@ -298,8 +307,14 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement, bool ContainsRelatedTarget(Event*); void HandlePointerEvent(Event*); + void HandleClickEvent(Event*); void HandleTouchEvent(Event*); + void EnsureAnimatedArrowContainer(); + void MaybeJump(int); + bool IsOnLeftSide(Event*); + void TapTimerFired(TimerBase*); + // Internal cast related methods. void RemotePlaybackStateChanged(); void RefreshCastButtonVisibility(); @@ -347,6 +362,8 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement, Member<MediaControlButtonPanelElement> media_button_panel_; Member<MediaControlLoadingPanelElement> loading_panel_; Member<MediaControlPictureInPictureButtonElement> picture_in_picture_button_; + Member<MediaControlAnimatedArrowContainerElement> + animated_arrow_container_element_; Member<MediaControlCastButtonElement> cast_button_; Member<MediaControlFullscreenButtonElement> fullscreen_button_; @@ -389,9 +406,8 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement, // touch events, we want to ignore pointerover/pointerout/pointermove events. bool is_touch_interaction_ = false; - // Holds the currently set --overlay-play-button-width value. Used to check if - // we need to update. - base::Optional<double> overlay_play_button_width_; + // Timer for distinguishing double-taps. + TaskRunnerTimer<MediaControlsImpl> tap_timer_; bool is_test_mode_ = false; }; diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc index a772b25a7f5..f636b810f95 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc @@ -72,6 +72,9 @@ class MockWebMediaPlayerForImpl : public EmptyWebMediaPlayer { // WebMediaPlayer overrides: WebTimeRanges Seekable() const override { return seekable_; } bool HasVideo() const override { return true; } + SurfaceLayerMode GetVideoSurfaceLayerMode() const override { + return SurfaceLayerMode::kAlways; + } WebTimeRanges seekable_; }; @@ -1095,34 +1098,13 @@ TEST_F(MediaControlsImplTestWithMockScheduler, AccessibleFocusShowsControls) { EXPECT_TRUE(IsElementVisible(*panel)); platform()->RunForPeriodSeconds(2); - EXPECT_FALSE(IsElementVisible(*panel)); - - MediaControls().OnAccessibleFocus(); - platform()->RunForPeriodSeconds(2); - EXPECT_TRUE(IsElementVisible(*panel)); -} - -TEST_F(MediaControlsImplTestWithMockScheduler, - AccessibleFocusKeepsControlsHiddenButDisplayed) { - EnsureSizing(); - - Element* panel = MediaControls().PanelElement(); - - MediaControls().MediaElement().SetSrc("http://example.com"); - MediaControls().MediaElement().Play(); - - platform()->RunForPeriodSeconds(2); + SimulateHideMediaControlsTimerFired(); EXPECT_TRUE(IsElementVisible(*panel)); - MediaControls().OnAccessibleFocus(); + MediaControls().OnAccessibleBlur(); platform()->RunForPeriodSeconds(4); + SimulateHideMediaControlsTimerFired(); EXPECT_FALSE(IsElementVisible(*panel)); - - // Display is none but can't be checked via InlineStyle. Adding checks of this - // to make sure that any one changing this assumption will have to update this - // test. - EXPECT_FALSE(panel->InlineStyle()); - EXPECT_NE(EDisplay::kNone, panel->EnsureComputedStyle()->Display()); } TEST_F(MediaControlsImplTest, diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.cc index f11ee556b5a..0f49a4bc3a0 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.cc @@ -377,7 +377,7 @@ MediaControlsOrientationLockDelegate::ComputeDeviceOrientation( // device_orientation_angle snapped to nearest multiple of 90. int device_orientation_angle90 = - std::lround(device_orientation_angle / 90) * 90; + static_cast<int>(std::lround(device_orientation_angle / 90) * 90); // To be considered portrait or landscape, allow the device to be rotated 23 // degrees (chosen to approximately match Android's behavior) to either side diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc index b591afcf2e2..4b2a3176e41 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc @@ -202,7 +202,7 @@ class MediaControlsOrientationLockDelegateTest void SimulateEnterFullscreen() { std::unique_ptr<UserGestureIndicator> gesture = - Frame::NotifyUserActivation(GetDocument().GetFrame()); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame()); Fullscreen::RequestFullscreen(Video()); test::RunPendingTasks(); } @@ -405,7 +405,7 @@ class MediaControlsOrientationLockAndRotateToFullscreenDelegateTest void PlayVideo() { { std::unique_ptr<UserGestureIndicator> gesture = - Frame::NotifyUserActivation(GetDocument().GetFrame()); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame()); Video().Play(); } test::RunPendingTasks(); diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.cc index 7eef1d4d899..3b05144a1e5 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.cc @@ -81,9 +81,9 @@ String MediaControlsResourceLoader::GetScrubbingMessageStyleSheet() { }; // static -String MediaControlsResourceLoader::GetOverlayPlayStyleSheet() { +String MediaControlsResourceLoader::GetAnimatedArrowStyleSheet() { return ResourceBundleHelper::UncompressResourceAsString( - IDR_SHADOWSTYLE_MODERN_MEDIA_CONTROLS_OVERLAY_PLAY_CSS); + IDR_SHADOWSTYLE_MODERN_MEDIA_CONTROLS_ANIMATED_ARROW_CSS); }; // static diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.h b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.h index 2f5c2491444..40d99ace82f 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.h +++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.h @@ -37,8 +37,8 @@ class MediaControlsResourceLoader // Returns the scrubbing message stylesheet content as a string. static String GetScrubbingMessageStyleSheet(); - // Returns the overlay play button stylesheet content as a string. - static String GetOverlayPlayStyleSheet(); + // Returns the animated arrow stylesheet content as a string. + static String GetAnimatedArrowStyleSheet(); // Returns the specific stylesheet used for media related interstitials. static String GetMediaInterstitialsStyleSheet(); diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc index 66992a77f56..ad5161cf1b7 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc @@ -12,6 +12,7 @@ #include "third_party/blink/renderer/core/dom/user_gesture_indicator.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/fullscreen/fullscreen.h" +#include "third_party/blink/renderer/core/html/media/html_media_element_controls_list.h" #include "third_party/blink/renderer/core/html/media/html_video_element.h" #include "third_party/blink/renderer/core/page/chrome_client.h" #include "third_party/blink/renderer/modules/device_orientation/device_orientation_data.h" @@ -184,6 +185,10 @@ void MediaControlsRotateToFullscreenDelegate::OnScreenOrientationChange() { if (!video_element_->ShouldShowControls()) return; + // Do not enable if controlsList=nofullscreen is used. + if (video_element_->ControlsListInternal()->ShouldHideFullscreen()) + return; + // Only enable if the Device Orientation API can provide beta and gamma values // that will be needed for MediaControlsOrientationLockDelegate to // automatically unlock, such that it will be possible to exit fullscreen by @@ -228,7 +233,8 @@ void MediaControlsRotateToFullscreenDelegate::OnScreenOrientationChange() { { std::unique_ptr<UserGestureIndicator> gesture = - Frame::NotifyUserActivation(video_element_->GetDocument().GetFrame()); + LocalFrame::NotifyUserActivation( + video_element_->GetDocument().GetFrame()); bool should_be_fullscreen = current_screen_orientation_ == video_orientation; diff --git a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc index ee2a82dbb4c..e36f5176532 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc +++ b/chromium/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc @@ -220,7 +220,7 @@ void MediaControlsRotateToFullscreenDelegateTest::InitScreenAndVideo( void MediaControlsRotateToFullscreenDelegateTest::PlayVideo() { { std::unique_ptr<UserGestureIndicator> gesture = - Frame::NotifyUserActivation(GetDocument().GetFrame()); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame()); GetVideo().Play(); } test::RunPendingTasks(); @@ -307,7 +307,7 @@ TEST_F(MediaControlsRotateToFullscreenDelegateTest, // Should start observing visibility when played. { std::unique_ptr<UserGestureIndicator> gesture = - Frame::NotifyUserActivation(GetDocument().GetFrame()); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame()); GetVideo().Play(); } test::RunPendingTasks(); @@ -328,7 +328,7 @@ TEST_F(MediaControlsRotateToFullscreenDelegateTest, // Should resume observing visibility when playback resumes. { std::unique_ptr<UserGestureIndicator> gesture = - Frame::NotifyUserActivation(GetDocument().GetFrame()); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame()); GetVideo().Play(); } test::RunPendingTasks(); @@ -622,7 +622,7 @@ TEST_F(MediaControlsRotateToFullscreenDelegateTest, // video (in this case document.body). { std::unique_ptr<UserGestureIndicator> gesture = - Frame::NotifyUserActivation(GetDocument().GetFrame()); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame()); Fullscreen::RequestFullscreen(*GetDocument().body()); } test::RunPendingTasks(); @@ -653,7 +653,7 @@ TEST_F(MediaControlsRotateToFullscreenDelegateTest, // Start in fullscreen. { std::unique_ptr<UserGestureIndicator> gesture = - Frame::NotifyUserActivation(GetDocument().GetFrame()); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame()); GetMediaControls().EnterFullscreen(); } // n.b. omit to call Fullscreen::From(GetDocument()).DidEnterFullscreen() so @@ -684,7 +684,7 @@ TEST_F(MediaControlsRotateToFullscreenDelegateTest, // Start in fullscreen. { std::unique_ptr<UserGestureIndicator> gesture = - Frame::NotifyUserActivation(GetDocument().GetFrame()); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame()); GetMediaControls().EnterFullscreen(); } // n.b. omit to call Fullscreen::From(GetDocument()).DidEnterFullscreen() so @@ -716,7 +716,7 @@ TEST_F(MediaControlsRotateToFullscreenDelegateTest, // video (in this case document.body). { std::unique_ptr<UserGestureIndicator> gesture = - Frame::NotifyUserActivation(GetDocument().GetFrame()); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame()); Fullscreen::RequestFullscreen(*GetDocument().body()); } test::RunPendingTasks(); @@ -735,4 +735,50 @@ TEST_F(MediaControlsRotateToFullscreenDelegateTest, EXPECT_FALSE(GetVideo().IsFullscreen()); } +TEST_F(MediaControlsRotateToFullscreenDelegateTest, + EnterFailControlsListNoFullscreen) { + // Portrait screen, landscape video. + InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(640, 480)); + EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + + EXPECT_FALSE(ObservedVisibility()); + + GetVideo().setAttribute("controlslist", "nofullscreen"); + + PlayVideo(); + UpdateVisibilityObserver(); + + EXPECT_TRUE(ObservedVisibility()); + + // Rotate screen to landscape. + RotateTo(kWebScreenOrientationLandscapePrimary); + + // Should not enter fullscreen when controlsList=nofullscreen. + EXPECT_FALSE(GetVideo().IsFullscreen()); +} + +TEST_F(MediaControlsRotateToFullscreenDelegateTest, + EnterSuccessControlsListNoDownload) { + // Portrait screen, landscape video. + InitScreenAndVideo(kWebScreenOrientationPortraitPrimary, WebSize(640, 480)); + EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation()); + EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation()); + + EXPECT_FALSE(ObservedVisibility()); + + GetVideo().setAttribute("controlslist", "nodownload"); + + PlayVideo(); + UpdateVisibilityObserver(); + + EXPECT_TRUE(ObservedVisibility()); + + // Rotate screen to landscape. + RotateTo(kWebScreenOrientationLandscapePrimary); + + // Should enter fullscreen when controlsList is not set to nofullscreen. + EXPECT_TRUE(GetVideo().IsFullscreen()); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/media_controls/resources/media_controls_resources.grd b/chromium/third_party/blink/renderer/modules/media_controls/resources/media_controls_resources.grd index 6da1783bcc0..ff832b58baf 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/resources/media_controls_resources.grd +++ b/chromium/third_party/blink/renderer/modules/media_controls/resources/media_controls_resources.grd @@ -17,7 +17,7 @@ <includes> <include name="IDR_UASTYLE_LEGACY_MEDIA_CONTROLS_ANDROID_CSS" file="legacyMediaControlsAndroid.css" type="BINDATA" compress="gzip" /> <include name="IDR_SHADOWSTYLE_MODERN_MEDIA_CONTROLS_TIMELINE_CSS" file="modernMediaControls_timeline.css" type="BINDATA" compress="gzip" /> - <include name="IDR_SHADOWSTYLE_MODERN_MEDIA_CONTROLS_OVERLAY_PLAY_CSS" file="modernMediaControls_overlay_play.css" type="BINDATA" compress="gzip" /> + <include name="IDR_SHADOWSTYLE_MODERN_MEDIA_CONTROLS_ANIMATED_ARROW_CSS" file="modernMediaControls_animated_arrow.css" type="BINDATA" compress="gzip" /> <include name="IDR_SHADOWSTYLE_MODERN_MEDIA_CONTROLS_SCRUBBING_MESSAGE_CSS" file="modernMediaControls_scrubbing_message.css" type="BINDATA" compress="gzip" /> <include name="IDR_MODERN_MEDIA_CONTROLS_JUMP_SVG" file="jump_image.svg" type="BINDATA" compress="gzip" /> <include name="IDR_MODERN_MEDIA_CONTROLS_ARROW_RIGHT_SVG" file="ic_arrow_right.svg" type="BINDATA" compress="gzip" /> 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 ba69e49f0e7..9d6ecde1cef 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 @@ -250,30 +250,14 @@ video::-webkit-media-controls.sizing-small div[pseudo="-internal-media-controls- video::-webkit-media-controls.sizing-medium div[pseudo="-internal-media-controls-button-panel" i] { height: 64px; line-height: 64px; - padding: 0 32px 0 32px; + padding: 0 16px 0 32px; } /* TODO(https://crbug.com/857120): remove these rules and the sizing-large CSS class. */ video::-webkit-media-controls.sizing-large div[pseudo="-internal-media-controls-button-panel" i] { height: 64px; line-height: 64px; - padding: 0 32px 0 32px; -} - -/* TODO(https://crbug.com/857120): All these are the same, so these are unnecessary. */ -video::-webkit-media-controls.sizing-small [pseudo="-webkit-media-controls-current-time-display"], -video::-webkit-media-controls.sizing-small [pseudo="-webkit-media-controls-time-remaining-display"] { - font-size: 16px; -} - -video::-webkit-media-controls.sizing-medium [pseudo="-webkit-media-controls-current-time-display"], -video::-webkit-media-controls.sizing-medium [pseudo="-webkit-media-controls-time-remaining-display"] { - font-size: 16px; -} - -video::-webkit-media-controls.sizing-large [pseudo="-webkit-media-controls-current-time-display"], -video::-webkit-media-controls.sizing-large [pseudo="-webkit-media-controls-time-remaining-display"] { - font-size: 16px; + padding: 0 16px 0 32px; } audio::-webkit-media-controls-play-button, @@ -325,8 +309,10 @@ video::-webkit-media-controls:not(.audio-only) [pseudo="-webkit-media-controls-p } audio::-webkit-media-controls-mute-button:disabled, +audio::-webkit-media-controls-play-button:disabled, video::-internal-media-controls-overflow-button:disabled, video::-webkit-media-controls-mute-button:disabled, +video::-webkit-media-controls-play-button:disabled, video::-webkit-media-controls-fullscreen-button:disabled { background-color: initial; opacity: 0.3; @@ -380,19 +366,19 @@ video::-webkit-media-controls:not(.audio-only) [pseudo="-webkit-media-controls-p video::-webkit-media-controls-overlay-play-button { -webkit-appearance: -internal-media-control; - display: flex; - justify-content: center; - align-items: center; - flex: 1; + position: absolute; + left: 50%; + top: 50%; + margin-left: -56px /* (72px play button width / -2) - 20px padding */; + margin-top: -68px /* ((72px play button width + 24px timeline height + padding-bottom) / -2) - 20px padding */; min-height: 0; - width: 100%; - box-sizing: border-box; + width: fit-content; overflow: hidden; background: transparent; - margin-bottom: -48px; - position: relative; opacity: 1; transition: opacity 0.25s cubic-bezier(0.25, 0.1, 0.25, 1); + padding: 20px; + border: 0; } /** @@ -410,8 +396,8 @@ video::-webkit-media-controls-overlay-play-button.hidden { } input[pseudo="-webkit-media-controls-overlay-play-button" i]::-internal-media-controls-overlay-play-button-internal { - width: var(--overlay-play-button-width, 48px); - height: var(--overlay-play-button-width, 48px); + width: 72px; + height: 72px; border-radius: 50%; background-size: 50%; @@ -437,17 +423,11 @@ video::-webkit-media-controls.state-playing:not(.audio-only) input[pseudo="-webk background-image: -webkit-image-set(url(ic_pause_white.svg) 1x); } -video::-webkit-media-controls.sizing-small input[pseudo="-webkit-media-controls-overlay-play-button" i] { - margin-bottom: -48px; -} - -video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-overlay-play-button" i] { - margin-bottom: -64px; -} - -/* TODO(https://crbug.com/857120): remove these rules and the sizing-large CSS class. */ -video::-webkit-media-controls.sizing-large input[pseudo="-webkit-media-controls-overlay-play-button" i] { - margin-bottom: -64px; +video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-play-button"] { + /* Undo the extra 16px of left padding on the button panel. We only want that + * extra padding when the current time is the leftmost item, and not when the + * play button is leftmost. */ + margin-left: -16px; } /** @@ -478,95 +458,53 @@ video::-webkit-media-controls-timeline { } video::-webkit-media-controls.sizing-small input[pseudo="-webkit-media-controls-timeline" i] { - padding: 0 16px 12px 16px; + padding: 0 16px 20px 16px; } video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-timeline" i] { - padding: 0 32px 36px 32px; + padding: 0 32px 20px 32px; } /* TODO(https://crbug.com/857120): remove these rules and the sizing-large CSS class. */ video::-webkit-media-controls.sizing-large input[pseudo="-webkit-media-controls-timeline" i] { - padding: 0 32px 36px 32px; -} - -/* TODO(https://crbug.com/857120): All these are the same, so these are unnecessary. */ -video::-webkit-media-controls.sizing-small input[pseudo="-webkit-media-controls-timeline" i], -video::-webkit-media-controls.sizing-small input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-before, -video::-webkit-media-controls.sizing-small input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after, -video::-webkit-media-controls.sizing-small input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-background { - height: 4px; -} - -video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-timeline" i], -video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-before, -video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after, -video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-background { - height: 4px; + padding: 0 32px 20px 32px; } -video::-webkit-media-controls.sizing-large input[pseudo="-webkit-media-controls-timeline" i], -video::-webkit-media-controls.sizing-large input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-before, -video::-webkit-media-controls.sizing-large input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after, -video::-webkit-media-controls.sizing-large input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-background { +input[pseudo="-webkit-media-controls-timeline" i], +input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-before, +input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after, +input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-background, +input[pseudo="-webkit-media-controls-volume-slider" i], +input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-track-segment-highlight-before, +input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-track-segment-highlight-after, +input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-track-segment-background { height: 4px; } -/* TODO(https://crbug.com/857120): All these are the same, so these are unnecessary. */ -video::-webkit-media-controls.sizing-small input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb { - width: 12px; - height: 12px; - margin-top: -4px; -} - -video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb { +input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb, +input[pseudo="-webkit-media-controls-volume-slider" i]::-webkit-slider-thumb { width: 12px; height: 12px; margin-top: -4px; } -video::-webkit-media-controls.sizing-large input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb { - width: 12px; - height: 12px; - margin-top: -4px; -} - -/* TODO(https://crbug.com/857120): All these are the same, so these are unnecessary. */ -video::-webkit-media-controls.sizing-small input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after, -video::-webkit-media-controls.sizing-small input[pseudo="-webkit-media-controls-timeline" i]::-internal-media-controls-segmented-track { - border-radius: 2px; -} - -video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after, -video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-timeline" i]::-internal-media-controls-segmented-track { - border-radius: 2px; -} - -video::-webkit-media-controls.sizing-large input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after, -video::-webkit-media-controls.sizing-large input[pseudo="-webkit-media-controls-timeline" i]::-internal-media-controls-segmented-track { +input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after, +input[pseudo="-webkit-media-controls-timeline" i]::-internal-media-controls-segmented-track, +input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-track-segment-highlight-after, +input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-media-controls-segmented-track { border-radius: 2px; } -video::-webkit-media-controls.sizing-small div[pseudo="-internal-media-controls-loading-panel" i]::-internal-media-controls-loading-panel-spinner-frame { - margin-top: calc( - (var(--overlay-play-button-width, 48px) - + 16px /* timeline height + padding-bottom */) - / -2); -} - -video::-webkit-media-controls.sizing-medium div[pseudo="-internal-media-controls-loading-panel" i]::-internal-media-controls-loading-panel-spinner-frame { - margin-top: calc( - (var(--overlay-play-button-width, 48px) - + 40px /* timeline height + padding-bottom */) - / -2); -} +video::-webkit-media-controls div[pseudo="-internal-media-controls-loading-panel" i]::-internal-media-controls-loading-panel-spinner-frame { + position: absolute; + top: 50%; + left: 50%; + overflow: hidden; -/* TODO(https://crbug.com/857120): remove these rules and the sizing-large CSS class. */ -video::-webkit-media-controls.sizing-large div[pseudo="-internal-media-controls-loading-panel" i]::-internal-media-controls-loading-panel-spinner-frame { - margin-top: calc( - (var(--overlay-play-button-width, 48px) - + 40px /* timeline height + padding-bottom */) - / -2); + height: 72px /* overlay play button height */; + width: 72px /* overlay play button width */; + margin-left: -36px /* (72px overlay play button width / -2) */; + margin-top: -48px /* (72px overlay play button height + 24px timeline height + padding-bottom) / -2) */; } div[pseudo="-internal-media-controls-loading-panel" i]::-internal-media-controls-loading-panel-spinner-mask-1-background { @@ -583,7 +521,8 @@ div[pseudo="-internal-media-controls-loading-panel" i]::-internal-media-controls background-position: center right; } -input[pseudo="-webkit-media-controls-timeline" i]::-internal-media-controls-segmented-track { +input[pseudo="-webkit-media-controls-timeline" i]::-internal-media-controls-segmented-track, +input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-media-controls-segmented-track { -webkit-appearance: -internal-media-control; flex: 1; @@ -591,12 +530,14 @@ input[pseudo="-webkit-media-controls-timeline" i]::-internal-media-controls-segm border-radius: 2px; position: relative; } -video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-timeline" i]::-internal-media-controls-segmented-track { +video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-timeline" i]::-internal-media-controls-segmented-track, +video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-media-controls-segmented-track { background: rgba(255, 255, 255, .3); box-shadow: 0 2px 10px 0 rgba(0,0,0,0.5); } -input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb { +input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb, +input[pseudo="-webkit-media-controls-volume-slider" i]::-webkit-slider-thumb { -webkit-appearance: -internal-media-control; background: rgba(0, 0, 0, .87); box-shadow: 0 0 10px 0 #fff; @@ -608,7 +549,8 @@ input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb { flex: 0 0 0; } -video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb { +video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb, +video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-volume-slider" i]::-webkit-slider-thumb { background: #FFFFFF; box-shadow: unset; } @@ -617,7 +559,8 @@ video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-contr display: none; } -input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-background { +input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-background, +input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-track-segment-background { position: absolute; width: 100%; top: 0; @@ -626,30 +569,58 @@ input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-backg } input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-before, -input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after { +input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after, +input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-track-segment-highlight-before, +input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-track-segment-highlight-after { position: absolute; height: 4px; } -input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-before { +input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-before, +input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-track-segment-highlight-before { background: rgba(0, 0, 0, .87); border-radius: 100px; } -video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-before { +video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-before, +video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-track-segment-highlight-before { background: rgba(255, 255, 255, 1); } -input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after { +input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after, +input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-track-segment-highlight-after { background: rgba(0, 0, 0, .54); border-radius: 2px; } -video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after { +video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after, +video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-volume-slider" i]::-internal-track-segment-highlight-after { background: rgba(255, 255, 255, .54); } audio::-webkit-media-controls-volume-slider, video::-webkit-media-controls-volume-slider { - display: none; + -webkit-appearance: -internal-media-control; + + height: 4px; + width: 52px; + transition: width 0.3s; + margin: 0; + padding: 22px 0; /* (48px button panel height - 4px slider height) / 2 */ + background: transparent; + /* This prevents layout issues in quirks mode. */ + box-sizing: unset !important; +} + +audio::-webkit-media-controls-volume-slider.closed, +video::-webkit-media-controls-volume-slider.closed { + width: 0; + opacity: 0; + pointer-events: none; + transition: width 0.3s ease, opacity 0.28s step-end; +} + +video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-volume-slider" i], +video::-webkit-media-controls.sizing-large input[pseudo="-webkit-media-controls-volume-slider" i] { + padding: 30px 0; /* (64px button panel height - 4px slider height) / 2 */ } /** @@ -852,12 +823,6 @@ audio { height: 54px; } -audio::-webkit-media-controls, -video::-webkit-media-controls.audio-only { - min-width: 240px; - min-height: 54px; -} - audio::-webkit-media-controls-overlay-enclosure, video::-webkit-media-controls.audio-only [pseudo="-webkit-media-controls-overlay-enclosure"] { display: none; @@ -865,7 +830,6 @@ video::-webkit-media-controls.audio-only [pseudo="-webkit-media-controls-overlay audio::-webkit-media-controls-enclosure, video::-webkit-media-controls.audio-only [pseudo="-webkit-media-controls-enclosure"] { - min-height: 54px; max-height: 54px; flex-direction: row; background: #F1F3F4; @@ -951,6 +915,28 @@ video::-webkit-media-controls.audio-only [pseudo="-internal-media-controls-loadi } /** + * Animated Arrow Container + */ + +video::-internal-media-controls-animated-arrow-container { + position: absolute; + display: flex; + align-items: center; + left: 0; + top: 0; + right: 0; + bottom: 0; + overflow: hidden; + z-index: 1; + pointer-events: none; +} + +audio::-internal-media-controls-animated-arrow-container, +video::-webkit-media-controls.audio-only [pseudo="-internal-media-controls-animated-arrow-container"] { + display: none; +} + +/** * Text Tracks */ video::-webkit-media-text-track-container { @@ -1120,6 +1106,11 @@ video::-webkit-media-controls.immersive-mode input[pseudo="-webkit-media-control margin-top: -5px; } +video::-webkit-media-controls.immersive-mode input[pseudo="-webkit-media-controls-overlay-play-button" i] { + margin-left: -52px /* (play button width / 2) + 20px Padding */; + margin-top: -64px /* (play button width + timeline height + padding-bottom) / 2 + padding */ +} + video::-webkit-media-controls.immersive-mode input[pseudo="-webkit-media-controls-overlay-play-button" i]::-internal-media-controls-overlay-play-button-internal { width: 64px; height: 64px; @@ -1127,6 +1118,14 @@ video::-webkit-media-controls.immersive-mode input[pseudo="-webkit-media-control background-size: 36px; } +video::-webkit-media-controls.immersive-mode div[pseudo="-internal-media-controls-loading-panel" i]::-internal-media-controls-loading-panel-spinner-frame { + width: 64px; /* play button width */ + height: 64px; /* play button width */ + margin-top: -44px; /* (play button width + timeline height + padding-bottom) / -2 */ + margin-left: -32px; /* play button width / -2 */ +} + + video::-webkit-media-controls.immersive-mode input[pseudo="-webkit-media-controls-mute-button" i], video::-webkit-media-controls.immersive-mode input[pseudo="-webkit-media-controls-fullscreen-button" i], video::-webkit-media-controls.immersive-mode input[pseudo="-internal-media-controls-overflow-button" i] { diff --git a/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls_overlay_play.css b/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls_animated_arrow.css index b5dfd5231f6..ef090b912e9 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls_overlay_play.css +++ b/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls_animated_arrow.css @@ -5,6 +5,7 @@ #left-arrow, #right-arrow { flex: 1; + text-align: center; } #left-arrow svg, diff --git a/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls_loading.css b/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls_loading.css index 932651f1f63..d70707c79f8 100644 --- a/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls_loading.css +++ b/chromium/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls_loading.css @@ -2,16 +2,6 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.*/ -#spinner-frame { - position: absolute; - height: var(--overlay-play-button-width, 48px); - width: var(--overlay-play-button-width, 48px); - top: 50%; - left: 50%; - margin-left: calc(var(--overlay-play-button-width) / -2); - overflow: hidden; -} - #spinner { animation: container-rotate 1568ms linear infinite; height: 100%; diff --git a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc index fa721b21655..c396e06ea9b 100644 --- a/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc +++ b/chromium/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc @@ -84,11 +84,11 @@ void MediaElementEventListener::handleEvent(ExecutionContext* context, : MediaStreamRegistry::Registry().LookupMediaStreamDescriptor( media_element_->currentSrc().GetString()); DCHECK(descriptor); - for (size_t i = 0; i < descriptor->NumberOfAudioComponents(); i++) { + for (unsigned i = 0; i < descriptor->NumberOfAudioComponents(); i++) { media_stream_->AddTrackByComponentAndFireEvents( descriptor->AudioComponent(i)); } - for (size_t i = 0; i < descriptor->NumberOfVideoComponents(); i++) { + for (unsigned i = 0; i < descriptor->NumberOfVideoComponents(); i++) { media_stream_->AddTrackByComponentAndFireEvents( descriptor->VideoComponent(i)); } diff --git a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc index 7aaa74951db..6b80cf3a665 100644 --- a/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc +++ b/chromium/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc @@ -174,8 +174,13 @@ MediaRecorder::MediaRecorder(ExecutionContext* context, this, &MediaRecorder::DispatchScheduledEvent, context->GetTaskRunner(TaskType::kDOMManipulation))) { - DCHECK(stream_->getTracks().size()); + if (context->IsContextDestroyed()) { + exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError, + "Execution context is detached."); + return; + } + DCHECK(stream_->getTracks().size()); recorder_handler_ = Platform::Current()->CreateMediaRecorderHandler( context->GetTaskRunner(TaskType::kInternalMediaRealTime)); DCHECK(recorder_handler_); diff --git a/chromium/third_party/blink/renderer/modules/mediasession/media_metadata.cc b/chromium/third_party/blink/renderer/modules/mediasession/media_metadata.cc index 831942c83cb..caaa6a4dc92 100644 --- a/chromium/third_party/blink/renderer/modules/mediasession/media_metadata.cc +++ b/chromium/third_party/blink/renderer/modules/mediasession/media_metadata.cc @@ -55,7 +55,7 @@ Vector<v8::Local<v8::Value>> MediaMetadata::artwork( ScriptState* script_state) const { Vector<v8::Local<v8::Value>> result(artwork_.size()); - for (size_t i = 0; i < artwork_.size(); ++i) { + for (wtf_size_t i = 0; i < artwork_.size(); ++i) { result[i] = FreezeV8Object(ToV8(artwork_[i], script_state), script_state->GetIsolate()); } diff --git a/chromium/third_party/blink/renderer/modules/mediasession/media_session.cc b/chromium/third_party/blink/renderer/modules/mediasession/media_session.cc index 1ba96056294..697e0f48ffc 100644 --- a/chromium/third_party/blink/renderer/modules/mediasession/media_session.cc +++ b/chromium/third_party/blink/renderer/modules/mediasession/media_session.cc @@ -194,9 +194,7 @@ mojom::blink::MediaSessionService* MediaSession::GetService() { if (!GetExecutionContext()) return nullptr; - DCHECK(GetExecutionContext()->IsDocument()) - << "MediaSession::getService() is only available from a frame"; - Document* document = ToDocument(GetExecutionContext()); + Document* document = To<Document>(GetExecutionContext()); LocalFrame* frame = document->GetFrame(); if (!frame) return nullptr; @@ -216,10 +214,10 @@ mojom::blink::MediaSessionService* MediaSession::GetService() { void MediaSession::DidReceiveAction( blink::mojom::blink::MediaSessionAction action) { - DCHECK(GetExecutionContext()->IsDocument()); - Document* document = ToDocument(GetExecutionContext()); + Document* document = To<Document>(GetExecutionContext()); std::unique_ptr<UserGestureIndicator> gesture_indicator = - Frame::NotifyUserActivation(document ? document->GetFrame() : nullptr); + LocalFrame::NotifyUserActivation(document ? document->GetFrame() + : nullptr); auto iter = action_handlers_.find(MojomActionToActionName(action)); if (iter == action_handlers_.end()) diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc b/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc index 1fba87ab4b0..2591f3459fe 100644 --- a/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc +++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source.cc @@ -269,7 +269,7 @@ void MediaSource::OnReadyStateChange(const AtomicString& old_state, active_source_buffers_->Clear(); // Clear SourceBuffer references to this object. - for (unsigned long i = 0; i < source_buffers_->length(); ++i) + for (unsigned i = 0; i < source_buffers_->length(); ++i) source_buffers_->item(i)->RemovedFromMediaSource(); source_buffers_->Clear(); @@ -280,7 +280,7 @@ void MediaSource::OnReadyStateChange(const AtomicString& old_state, bool MediaSource::IsUpdating() const { // Return true if any member of |m_sourceBuffers| is updating. - for (unsigned long i = 0; i < source_buffers_->length(); ++i) { + for (unsigned i = 0; i < source_buffers_->length(); ++i) { if (source_buffers_->item(i)->updating()) return true; } @@ -379,7 +379,7 @@ TimeRanges* MediaSource::Buffered() const { // Implements MediaSource algorithm for HTMLMediaElement.buffered. // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#htmlmediaelement-extensions HeapVector<Member<TimeRanges>> ranges(active_source_buffers_->length()); - for (size_t i = 0; i < active_source_buffers_->length(); ++i) + for (unsigned i = 0; i < active_source_buffers_->length(); ++i) ranges[i] = active_source_buffers_->item(i)->buffered(ASSERT_NO_EXCEPTION); // 1. If activeSourceBuffers.length equals 0 then return an empty TimeRanges @@ -391,7 +391,7 @@ TimeRanges* MediaSource::Buffered() const { // SourceBuffer object in activeSourceBuffers. // 3. Let highest end time be the largest range end time in the active ranges. double highest_end_time = -1; - for (size_t i = 0; i < ranges.size(); ++i) { + for (wtf_size_t i = 0; i < ranges.size(); ++i) { unsigned length = ranges[i]->length(); if (length) highest_end_time = std::max( @@ -409,7 +409,7 @@ TimeRanges* MediaSource::Buffered() const { // 5. For each SourceBuffer object in activeSourceBuffers run the following // steps: bool ended = readyState() == EndedKeyword(); - for (size_t i = 0; i < ranges.size(); ++i) { + for (wtf_size_t i = 0; i < ranges.size(); ++i) { // 5.1 Let source ranges equal the ranges returned by the buffered attribute // on the current SourceBuffer. TimeRanges* source_ranges = ranges[i].Get(); @@ -545,7 +545,7 @@ void MediaSource::DurationChangeAlgorithm(double new_duration, // media are disallowed. When truncation is necessary, use remove() to // reduce the buffered range before updating duration. double highest_buffered_presentation_timestamp = 0; - for (size_t i = 0; i < source_buffers_->length(); ++i) { + for (unsigned i = 0; i < source_buffers_->length(); ++i) { highest_buffered_presentation_timestamp = std::max(highest_buffered_presentation_timestamp, source_buffers_->item(i)->HighestPresentationTimestamp()); @@ -582,7 +582,7 @@ void MediaSource::DurationChangeAlgorithm(double new_duration, // Deprecated behavior: if the new duration is less than old duration, // then call remove(new duration, old duration) on all all objects in // sourceBuffers. - for (size_t i = 0; i < source_buffers_->length(); ++i) + for (unsigned i = 0; i < source_buffers_->length(); ++i) source_buffers_->item(i)->remove(new_duration, old_duration, ASSERT_NO_EXCEPTION); } @@ -716,10 +716,10 @@ void MediaSource::SetSourceBufferActive(SourceBuffer* source_buffer, // SourceBuffer transitions to active are not guaranteed to occur in the // same order as buffers in |m_sourceBuffers|, so this method needs to // insert |sourceBuffer| into |m_activeSourceBuffers|. - size_t index_in_source_buffers = source_buffers_->Find(source_buffer); + wtf_size_t index_in_source_buffers = source_buffers_->Find(source_buffer); DCHECK(index_in_source_buffers != kNotFound); - size_t insert_position = 0; + wtf_size_t insert_position = 0; while (insert_position < active_source_buffers_->length() && source_buffers_->Find(active_source_buffers_->item(insert_position)) < index_in_source_buffers) { diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry.cc b/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry.cc index 950e216464c..84c35851400 100644 --- a/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry.cc +++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry.cc @@ -49,27 +49,28 @@ void MediaSourceRegistry::RegisterURL(SecurityOrigin*, MediaSource* source = static_cast<MediaSource*>(registrable); source->AddedToRegistry(); - media_sources_.Set(url.GetString(), source); + media_sources_->Set(url.GetString(), source); } void MediaSourceRegistry::UnregisterURL(const KURL& url) { DCHECK(IsMainThread()); - PersistentHeapHashMap<String, Member<MediaSource>>::iterator iter = - media_sources_.find(url.GetString()); - if (iter == media_sources_.end()) + HeapHashMap<String, Member<MediaSource>>::iterator iter = + media_sources_->find(url.GetString()); + if (iter == media_sources_->end()) return; MediaSource* source = iter->value; - media_sources_.erase(iter); + media_sources_->erase(iter); source->RemovedFromRegistry(); } URLRegistrable* MediaSourceRegistry::Lookup(const String& url) { DCHECK(IsMainThread()); - return url.IsNull() ? nullptr : media_sources_.at(url); + return url.IsNull() ? nullptr : media_sources_->at(url); } -MediaSourceRegistry::MediaSourceRegistry() { +MediaSourceRegistry::MediaSourceRegistry() + : media_sources_(new HeapHashMap<String, Member<MediaSource>>) { HTMLMediaSource::SetRegistry(this); } diff --git a/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry.h b/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry.h index b9a7fed0f2d..84b1ec57e34 100644 --- a/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry.h +++ b/chromium/third_party/blink/renderer/modules/mediasource/media_source_registry.h @@ -34,6 +34,7 @@ #include "base/memory/scoped_refptr.h" #include "third_party/blink/renderer/core/fileapi/url_registry.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/text/string_hash.h" @@ -54,7 +55,7 @@ class MediaSourceRegistry final : public URLRegistry { private: MediaSourceRegistry(); - PersistentHeapHashMap<String, Member<MediaSource>> media_sources_; + Persistent<HeapHashMap<String, Member<MediaSource>>> media_sources_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc index 8007d2c1f32..a495b2e2be6 100644 --- a/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc +++ b/chromium/third_party/blink/renderer/modules/mediasource/source_buffer.cc @@ -939,7 +939,7 @@ bool SourceBuffer::InitializationSegmentReceived( // tracks), then the Track IDs match the ones in the first initialization // segment. if (tracks_match_first_init_segment && new_audio_tracks.size() > 1) { - for (size_t i = 0; i < new_audio_tracks.size(); ++i) { + for (wtf_size_t i = 0; i < new_audio_tracks.size(); ++i) { const String& new_track_id = new_video_tracks[i].id; if (new_track_id != String(audioTracks().AnonymousIndexedGetter(i)->id())) { @@ -950,7 +950,7 @@ bool SourceBuffer::InitializationSegmentReceived( } if (tracks_match_first_init_segment && new_video_tracks.size() > 1) { - for (size_t i = 0; i < new_video_tracks.size(); ++i) { + for (wtf_size_t i = 0; i < new_video_tracks.size(); ++i) { const String& new_track_id = new_video_tracks[i].id; if (new_track_id != String(videoTracks().AnonymousIndexedGetter(i)->id())) { @@ -1312,7 +1312,7 @@ void SourceBuffer::AppendBufferAsyncPart() { // 1. Run the segment parser loop algorithm. // Step 2 doesn't apply since we run Step 1 synchronously here. DCHECK_GE(pending_append_data_.size(), pending_append_data_offset_); - size_t append_size = + wtf_size_t append_size = pending_append_data_.size() - pending_append_data_offset_; // Impose an arbitrary max size for a single append() call so that an append @@ -1320,13 +1320,12 @@ void SourceBuffer::AppendBufferAsyncPart() { // by looking at YouTube SourceBuffer usage across a variety of bitrates. // This value allows relatively large appends while keeping append() call // duration in the ~5-15ms range. - const size_t kMaxAppendSize = 128 * 1024; + const wtf_size_t kMaxAppendSize = 128 * 1024; if (append_size > kMaxAppendSize) append_size = kMaxAppendSize; TRACE_EVENT_ASYNC_STEP_INTO1("media", "SourceBuffer::appendBuffer", this, - "appending", "appendSize", - static_cast<unsigned>(append_size)); + "appending", "appendSize", append_size); // |zero| is used for 0 byte appends so we always have a valid pointer. // We need to convey all appends, even 0 byte ones to |m_webSourceBuffer| diff --git a/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn b/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn index 0503186677f..e77eb497dd3 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/mediastream/BUILD.gn @@ -38,8 +38,6 @@ blink_modules_sources("mediastream") { "navigator_user_media.h", "overconstrained_error.cc", "overconstrained_error.h", - "url_media_stream.cc", - "url_media_stream.h", "user_media_client.cc", "user_media_client.h", "user_media_controller.cc", diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc index 068058a8acb..e34bb663e14 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc +++ b/chromium/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc @@ -64,12 +64,7 @@ struct NameValueStringConstraint { }; // Legal constraint names. -// Temporary Note: Comments about source are where they are copied from. -// Once the chrome parts use the new-style constraint values, they will -// be deleted from the files mentioned. -// TODO(hta): remove comments before https://crbug.com/543997 is closed. -// From content/renderer/media/stream/media_stream_video_source.cc const char kMinAspectRatio[] = "minAspectRatio"; const char kMaxAspectRatio[] = "maxAspectRatio"; const char kMaxWidth[] = "maxWidth"; @@ -78,17 +73,15 @@ const char kMaxHeight[] = "maxHeight"; const char kMinHeight[] = "minHeight"; const char kMaxFrameRate[] = "maxFrameRate"; const char kMinFrameRate[] = "minFrameRate"; -// From content/common/media/media_stream_options.cc const char kMediaStreamSource[] = "chromeMediaSource"; const char kMediaStreamSourceId[] = "chromeMediaSourceId"; // mapped to deviceId const char kMediaStreamSourceInfoId[] = "sourceId"; // mapped to deviceId const char kMediaStreamRenderToAssociatedSink[] = "chromeRenderToAssociatedSink"; -// RenderToAssociatedSink will be going away in M50-M60 some time. +// RenderToAssociatedSink will be going away some time. const char kMediaStreamAudioHotword[] = "googHotword"; // TODO(hta): googHotword should go away. https://crbug.com/577627 -// From content/renderer/media/stream/media_stream_audio_processor_options.cc const char kEchoCancellation[] = "echoCancellation"; const char kDisableLocalEcho[] = "disableLocalEcho"; const char kGoogEchoCancellation[] = "googEchoCancellation"; @@ -102,13 +95,8 @@ const char kGoogArrayGeometry[] = "googArrayGeometry"; const char kGoogHighpassFilter[] = "googHighpassFilter"; const char kGoogTypingNoiseDetection[] = "googTypingNoiseDetection"; const char kGoogAudioMirroring[] = "googAudioMirroring"; - -// From -// third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.cc - // Audio constraints. const char kDAEchoCancellation[] = "googDAEchoCancellation"; - // Google-specific constraint keys for a local video source (getUserMedia). const char kNoiseReduction[] = "googNoiseReduction"; @@ -139,11 +127,8 @@ const char kCpuOveruseEncodeRsdThreshold[] = "googCpuOveruseEncodeRsdThreshold"; const char kCpuOveruseEncodeUsage[] = "googCpuOveruseEncodeUsage"; const char kHighStartBitrate[] = "googHighStartBitrate"; const char kPayloadPadding[] = "googPayloadPadding"; -// From webrtc_audio_capturer const char kAudioLatency[] = "latencyMs"; -// From media_stream_video_capturer_source -// End of names from libjingle // Names that have been used in the past, but should now be ignored. // Kept around for backwards compatibility. // https://crbug.com/579729 @@ -428,12 +413,10 @@ static void ParseOldStyleNames( result.goog_payload_padding.SetExact(ToBoolean(constraint.value_)); } else if (constraint.name_.Equals(kAudioLatency)) { result.goog_latency_ms.SetExact(atoi(constraint.value_.Utf8().c_str())); - } else if (constraint.name_.Equals(kPowerLineFrequency)) { - result.goog_power_line_frequency.SetExact( - atoi(constraint.value_.Utf8().c_str())); } else if (constraint.name_.Equals(kGoogLeakyBucket) || constraint.name_.Equals(kGoogBeamforming) || - constraint.name_.Equals(kGoogArrayGeometry)) { + constraint.name_.Equals(kGoogArrayGeometry) || + constraint.name_.Equals(kPowerLineFrequency)) { // TODO(crbug.com/856176): Remove the kGoogBeamforming and // kGoogArrayGeometry special cases. context->AddConsoleMessage(ConsoleMessage::Create( @@ -793,7 +776,7 @@ bool UseNakedNumeric(T input, NakedValueDisposition which) { } NOTREACHED(); return false; -}; +} template <class T> bool UseNakedNonNumeric(T input, NakedValueDisposition which) { @@ -807,7 +790,7 @@ bool UseNakedNonNumeric(T input, NakedValueDisposition which) { } NOTREACHED(); return false; -}; +} template <typename U, class T> U GetNakedValue(T input, NakedValueDisposition which) { @@ -821,7 +804,7 @@ U GetNakedValue(T input, NakedValueDisposition which) { } NOTREACHED(); return input.Exact(); -}; +} LongOrConstrainLongRange ConvertLong(const LongConstraint& input, NakedValueDisposition naked_treatment) { diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc index 03a93fb8a5c..19ccd3104c1 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc +++ b/chromium/third_party/blink/renderer/modules/mediastream/media_devices.cc @@ -82,7 +82,7 @@ MediaDevices::~MediaDevices() = default; ScriptPromise MediaDevices::enumerateDevices(ScriptState* script_state) { Platform::Current()->UpdateWebRTCAPICount(WebRTCAPIName::kEnumerateDevices); LocalFrame* frame = - ToDocument(ExecutionContext::From(script_state))->GetFrame(); + To<Document>(ExecutionContext::From(script_state))->GetFrame(); if (!frame) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError, @@ -118,7 +118,7 @@ ScriptPromise MediaDevices::SendUserMediaRequest( PromiseResolverCallbacks* callbacks = PromiseResolverCallbacks::Create(resolver); - Document* document = ToDocument(ExecutionContext::From(script_state)); + Document* document = To<Document>(ExecutionContext::From(script_state)); UserMediaController* user_media = UserMediaController::From(document->GetFrame()); if (!user_media) @@ -212,7 +212,7 @@ void MediaDevices::Unpause() { void MediaDevices::OnDevicesChanged( MediaDeviceType type, Vector<mojom::blink::MediaDeviceInfoPtr> device_infos) { - Document* document = ToDocument(GetExecutionContext()); + Document* document = To<Document>(GetExecutionContext()); DCHECK(document); if (RuntimeEnabledFeatures::OnDeviceChangeEnabled()) @@ -240,7 +240,7 @@ void MediaDevices::StartObserving() { if (binding_.is_bound() || stopped_) return; - Document* document = ToDocument(GetExecutionContext()); + Document* document = To<Document>(GetExecutionContext()); if (!document || !document->GetFrame()) return; diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_devices_test.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_devices_test.cc index 8752d092203..daf9d684dd3 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/media_devices_test.cc +++ b/chromium/third_party/blink/renderer/modules/mediastream/media_devices_test.cc @@ -198,9 +198,9 @@ class PromiseObserver { class MediaDevicesTest : public testing::Test { public: - using MediaDeviceInfos = PersistentHeapVector<Member<MediaDeviceInfo>>; + using MediaDeviceInfos = HeapVector<Member<MediaDeviceInfo>>; - MediaDevicesTest() { + MediaDevicesTest() : device_infos_(new MediaDeviceInfos) { dispatcher_host_ = std::make_unique<MockMediaDevicesDispatcherHost>(); } @@ -224,7 +224,7 @@ class MediaDevicesTest : public testing::Test { void DevicesEnumerated(const MediaDeviceInfoVector& device_infos) { devices_enumerated_ = true; for (size_t i = 0; i < device_infos.size(); i++) { - device_infos_.push_back(MediaDeviceInfo::Create( + device_infos_->push_back(MediaDeviceInfo::Create( device_infos[i]->deviceId(), device_infos[i]->label(), device_infos[i]->groupId(), device_infos[i]->DeviceType())); } @@ -247,7 +247,7 @@ class MediaDevicesTest : public testing::Test { bool listener_connection_error() const { return listener_connection_error_; } - const MediaDeviceInfos& device_infos() const { return device_infos_; } + const MediaDeviceInfos& device_infos() const { return *device_infos_; } bool devices_enumerated() const { return devices_enumerated_; } @@ -264,7 +264,7 @@ class MediaDevicesTest : public testing::Test { private: ScopedTestingPlatformSupport<TestingPlatformSupport> platform_; std::unique_ptr<MockMediaDevicesDispatcherHost> dispatcher_host_; - MediaDeviceInfos device_infos_; + Persistent<MediaDeviceInfos> device_infos_; bool devices_enumerated_ = false; bool dispatcher_host_connection_error_ = false; bool device_changed_ = false; diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream.cc index d48dfc7daa1..feef966d923 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream.cc +++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream.cc @@ -48,9 +48,6 @@ static bool ContainsSource(MediaStreamTrackVector& track_vector, static void ProcessTrack(MediaStreamTrack* track, MediaStreamTrackVector& track_vector) { - if (track->Ended()) - return; - MediaStreamSource* source = track->Component()->Source(); if (!ContainsSource(track_vector, source)) track_vector.push_back(track); diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_registry.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_registry.cc index 7a6715dd1d4..db5b71d3df5 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_registry.cc +++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_registry.cc @@ -43,27 +43,29 @@ void MediaStreamRegistry::RegisterURL(SecurityOrigin*, URLRegistrable* stream) { DCHECK(&stream->Registry() == this); DCHECK(IsMainThread()); - stream_descriptors_.Set(url.GetString(), - static_cast<MediaStream*>(stream)->Descriptor()); + stream_descriptors_->Set(url.GetString(), + static_cast<MediaStream*>(stream)->Descriptor()); } void MediaStreamRegistry::UnregisterURL(const KURL& url) { DCHECK(IsMainThread()); - stream_descriptors_.erase(url.GetString()); + stream_descriptors_->erase(url.GetString()); } bool MediaStreamRegistry::Contains(const String& url) { DCHECK(IsMainThread()); - return stream_descriptors_.Contains(url); + return stream_descriptors_->Contains(url); } MediaStreamDescriptor* MediaStreamRegistry::LookupMediaStreamDescriptor( const String& url) { DCHECK(IsMainThread()); - return stream_descriptors_.at(url); + return stream_descriptors_->at(url); } -MediaStreamRegistry::MediaStreamRegistry() { +MediaStreamRegistry::MediaStreamRegistry() + : stream_descriptors_( + new HeapHashMap<String, Member<MediaStreamDescriptor>>) { HTMLMediaElement::SetMediaStreamRegistry(this); } diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_registry.h b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_registry.h index 014d7e9fa36..8f34641d7bc 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_registry.h +++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_registry.h @@ -28,6 +28,7 @@ #include "third_party/blink/renderer/core/fileapi/url_registry.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/text/string_hash.h" @@ -50,7 +51,7 @@ class MODULES_EXPORT MediaStreamRegistry final : public URLRegistry { private: MediaStreamRegistry(); - PersistentHeapHashMap<String, Member<MediaStreamDescriptor>> + Persistent<HeapHashMap<String, Member<MediaStreamDescriptor>>> stream_descriptors_; }; diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.cc b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.cc index 666ef98d3a4..062a7c5a0a7 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.cc +++ b/chromium/third_party/blink/renderer/modules/mediastream/media_stream_track.cc @@ -71,10 +71,12 @@ bool ConstraintSetHasImageCapture( constraint_set.hasExposureMode() || constraint_set.hasFocusMode() || constraint_set.hasPointsOfInterest() || constraint_set.hasExposureCompensation() || + constraint_set.hasExposureTime() || constraint_set.hasColorTemperature() || constraint_set.hasIso() || constraint_set.hasBrightness() || constraint_set.hasContrast() || constraint_set.hasSaturation() || constraint_set.hasSharpness() || - constraint_set.hasZoom() || constraint_set.hasTorch(); + constraint_set.hasFocusDistance() || constraint_set.hasZoom() || + constraint_set.hasTorch(); } bool ConstraintSetHasNonImageCapture( @@ -294,7 +296,7 @@ void MediaStreamTrack::stopTrack(ExecutionContext* execution_context) { return; ready_state_ = MediaStreamSource::kReadyStateEnded; - Document* document = ToDocument(execution_context); + Document* document = To<Document>(execution_context); UserMediaController* user_media = UserMediaController::From(document->GetFrame()); if (user_media) @@ -320,8 +322,8 @@ void MediaStreamTrack::SetConstraints(const WebMediaConstraints& constraints) { void MediaStreamTrack::getCapabilities(MediaTrackCapabilities& capabilities) { if (image_capture_) capabilities = image_capture_->GetMediaTrackCapabilities(); - auto platform_capabilities = component_->Source()->GetCapabilities(); + capabilities.setDeviceId(platform_capabilities.device_id); if (!platform_capabilities.group_id.IsNull()) capabilities.setGroupId(platform_capabilities.group_id); @@ -405,12 +407,14 @@ void MediaStreamTrack::getConstraints(MediaTrackConstraints& constraints) { image_capture_constraints.hasExposureMode() || image_capture_constraints.hasFocusMode() || image_capture_constraints.hasExposureCompensation() || + image_capture_constraints.hasExposureTime() || image_capture_constraints.hasColorTemperature() || image_capture_constraints.hasIso() || image_capture_constraints.hasBrightness() || image_capture_constraints.hasContrast() || image_capture_constraints.hasSaturation() || image_capture_constraints.hasSharpness() || + image_capture_constraints.hasFocusDistance() || image_capture_constraints.hasZoom()) { // Add image capture constraints, if any, as another entry to advanced(). vector.emplace_back(image_capture_constraints); @@ -493,6 +497,42 @@ void MediaStreamTrack::getSettings(MediaTrackSettings& settings) { if (image_capture_) image_capture_->GetMediaTrackSettings(settings); + + if (platform_settings.display_surface) { + WTF::String value; + switch (platform_settings.display_surface.value()) { + case WebMediaStreamTrack::DisplayCaptureSurfaceType::kMonitor: + value = "monitor"; + break; + case WebMediaStreamTrack::DisplayCaptureSurfaceType::kWindow: + value = "window"; + break; + case WebMediaStreamTrack::DisplayCaptureSurfaceType::kApplication: + value = "application"; + break; + case WebMediaStreamTrack::DisplayCaptureSurfaceType::kBrowser: + value = "browser"; + break; + } + settings.setDisplaySurface(value); + } + if (platform_settings.logical_surface) + settings.setLogicalSurface(platform_settings.logical_surface.value()); + if (platform_settings.cursor) { + WTF::String value; + switch (platform_settings.cursor.value()) { + case WebMediaStreamTrack::CursorCaptureType::kNever: + value = "never"; + break; + case WebMediaStreamTrack::CursorCaptureType::kAlways: + value = "always"; + break; + case WebMediaStreamTrack::CursorCaptureType::kMotion: + value = "motion"; + break; + } + settings.setCursor(value); + } } ScriptPromise MediaStreamTrack::applyConstraints( @@ -543,7 +583,7 @@ ScriptPromise MediaStreamTrack::applyConstraints( return promise; } - Document* document = ToDocument(execution_context); + Document* document = To<Document>(execution_context); UserMediaController* user_media = UserMediaController::From(document->GetFrame()); if (!user_media) { diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl index 3a56aa445ee..b6f68f95aec 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl +++ b/chromium/third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl @@ -23,12 +23,14 @@ dictionary MediaTrackCapabilities { sequence<DOMString> exposureMode; sequence<DOMString> focusMode; MediaSettingsRange exposureCompensation; + MediaSettingsRange exposureTime; MediaSettingsRange colorTemperature; MediaSettingsRange iso; MediaSettingsRange brightness; MediaSettingsRange contrast; MediaSettingsRange saturation; MediaSettingsRange sharpness; + MediaSettingsRange focusDistance; MediaSettingsRange zoom; boolean torch; }; diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl index d4f9b77c330..08ce2d9c22e 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl +++ b/chromium/third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl @@ -47,12 +47,14 @@ dictionary MediaTrackConstraintSet { ConstrainDOMString focusMode; ConstrainPoint2D pointsOfInterest; ConstrainDouble exposureCompensation; + ConstrainDouble exposureTime; ConstrainDouble colorTemperature; ConstrainDouble iso; ConstrainDouble brightness; ConstrainDouble contrast; ConstrainDouble saturation; ConstrainDouble sharpness; + ConstrainDouble focusDistance; ConstrainDouble zoom; ConstrainBoolean torch; // The "mandatory" and "_optional" members are retained for conformance diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_track_settings.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_track_settings.idl index 20d06f4e29c..8daf0e93368 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/media_track_settings.idl +++ b/chromium/third_party/blink/renderer/modules/mediastream/media_track_settings.idl @@ -40,12 +40,20 @@ dictionary MediaTrackSettings { DOMString focusMode; sequence<Point2D> pointsOfInterest; double exposureCompensation; + double exposureTime; double colorTemperature; double iso; double brightness; double contrast; double saturation; double sharpness; + double focusDistance; double zoom; boolean torch; + + // Screen Capture API + // https://w3c.github.io/mediacapture-screen-share + [RuntimeEnabled=GetDisplayMedia] DOMString displaySurface; + [RuntimeEnabled=GetDisplayMedia] boolean logicalSurface; + [RuntimeEnabled=GetDisplayMedia] DOMString cursor; }; diff --git a/chromium/third_party/blink/renderer/modules/mediastream/media_track_supported_constraints.idl b/chromium/third_party/blink/renderer/modules/mediastream/media_track_supported_constraints.idl index 0e67999ce01..8d288b623ef 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/media_track_supported_constraints.idl +++ b/chromium/third_party/blink/renderer/modules/mediastream/media_track_supported_constraints.idl @@ -46,12 +46,14 @@ dictionary MediaTrackSupportedConstraints { boolean focusMode = true; boolean pointsOfInterest = true; boolean exposureCompensation = true; + boolean exposureTime = true; boolean colorTemperature = true; boolean iso = true; boolean brightness = true; boolean contrast = true; boolean saturation = true; boolean sharpness = true; + boolean focusDistance = true; boolean zoom = true; boolean torch = true; }; diff --git a/chromium/third_party/blink/renderer/modules/mediastream/url_media_stream.cc b/chromium/third_party/blink/renderer/modules/mediastream/url_media_stream.cc deleted file mode 100644 index 047ff7b3d3b..00000000000 --- a/chromium/third_party/blink/renderer/modules/mediastream/url_media_stream.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "third_party/blink/renderer/modules/mediastream/url_media_stream.h" - -#include "third_party/blink/renderer/core/execution_context/execution_context.h" -#include "third_party/blink/renderer/core/frame/deprecation.h" -#include "third_party/blink/renderer/core/url/dom_url.h" -#include "third_party/blink/renderer/modules/mediastream/media_stream.h" -#include "third_party/blink/renderer/platform/bindings/script_state.h" - -namespace blink { - -String URLMediaStream::createObjectURL(ScriptState* script_state, - MediaStream* stream) { - // Since WebWorkers cannot obtain Stream objects, we should be on the main - // thread. - DCHECK(IsMainThread()); - ExecutionContext* execution_context = ExecutionContext::From(script_state); - DCHECK(execution_context); - DCHECK(stream); - - Deprecation::CountDeprecation(execution_context, - WebFeature::kCreateObjectURLMediaStream); - return DOMURL::CreatePublicURL(execution_context, stream); -} - -} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/mediastream/url_media_stream.h b/chromium/third_party/blink/renderer/modules/mediastream/url_media_stream.h deleted file mode 100644 index 1cf630e7878..00000000000 --- a/chromium/third_party/blink/renderer/modules/mediastream/url_media_stream.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_URL_MEDIA_STREAM_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_URL_MEDIA_STREAM_H_ - -#include "third_party/blink/renderer/platform/wtf/allocator.h" -#include "third_party/blink/renderer/platform/wtf/forward.h" - -namespace blink { - -class MediaStream; -class ScriptState; - -class URLMediaStream { - STATIC_ONLY(URLMediaStream); - - public: - static String createObjectURL(ScriptState*, MediaStream*); -}; - -} // namespace blink - -#endif diff --git a/chromium/third_party/blink/renderer/modules/mediastream/url_media_stream.idl b/chromium/third_party/blink/renderer/modules/mediastream/url_media_stream.idl deleted file mode 100644 index c7f8d34effe..00000000000 --- a/chromium/third_party/blink/renderer/modules/mediastream/url_media_stream.idl +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// An old version of Media Capture and Streams defines URL.createObjectURL: -// https://w3c.github.io/mediacapture-main/archives/20131017/getusermedia.html - -// TODO(foolip): Update link if it's revived in the spec: -// https://github.com/w3c/mediacapture-main/issues/404 - -[ - ImplementedAs=URLMediaStream -] partial interface URL { - [Exposed=(Window,DedicatedWorker,SharedWorker), CallWith=ScriptState] static DOMString createObjectURL(MediaStream stream); -}; diff --git a/chromium/third_party/blink/renderer/modules/mediastream/user_media_client.cc b/chromium/third_party/blink/renderer/modules/mediastream/user_media_client.cc index 68eb294ad3c..6096ec23ea6 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/user_media_client.cc +++ b/chromium/third_party/blink/renderer/modules/mediastream/user_media_client.cc @@ -69,4 +69,11 @@ void UserMediaClient::StopTrack(MediaStreamComponent* track) { } } +bool UserMediaClient::IsCapturing() { + if (!client_) + return false; + + return client_->IsCapturing(); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/mediastream/user_media_client.h b/chromium/third_party/blink/renderer/modules/mediastream/user_media_client.h index 2eb60d43cec..9e9e943b5a0 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/user_media_client.h +++ b/chromium/third_party/blink/renderer/modules/mediastream/user_media_client.h @@ -56,6 +56,7 @@ class MODULES_EXPORT UserMediaClient { void CancelUserMediaRequest(UserMediaRequest*); void ApplyConstraints(ApplyConstraintsRequest*); void StopTrack(MediaStreamComponent*); + bool IsCapturing(); private: explicit UserMediaClient(WebUserMediaClient*); diff --git a/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.cc b/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.cc index 03c2b2a3c38..06e0ae7b328 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.cc +++ b/chromium/third_party/blink/renderer/modules/mediastream/user_media_request.cc @@ -282,11 +282,6 @@ void CountVideoConstraintUses(ExecutionContext* context, constraints, &WebMediaTrackConstraintSet::goog_noise_reduction)) { counter.Count(WebFeature::kMediaStreamConstraintsGoogNoiseReduction); } - if (RequestUsesNumericConstraint( - constraints, - &WebMediaTrackConstraintSet::goog_power_line_frequency)) { - counter.Count(WebFeature::kMediaStreamConstraintsGoogPowerLineFrequency); - } UseCounter::Count(context, WebFeature::kMediaStreamConstraintsVideo); if (counter.IsUnconstrained()) { @@ -497,17 +492,15 @@ bool UserMediaRequest::IsSecureContextUse(String& error_message) { // Feature policy deprecation messages. if (Audio()) { - if (!document->GetFrame()->IsFeatureEnabled( - mojom::FeaturePolicyFeature::kMicrophone, - ReportOptions::kReportOnFailure)) { + if (!document->IsFeatureEnabled(mojom::FeaturePolicyFeature::kMicrophone, + ReportOptions::kReportOnFailure)) { UseCounter::Count( document, WebFeature::kMicrophoneDisabledByFeaturePolicyEstimate); } } if (Video()) { - if (!document->GetFrame()->IsFeatureEnabled( - mojom::FeaturePolicyFeature::kCamera, - ReportOptions::kReportOnFailure)) { + if (!document->IsFeatureEnabled(mojom::FeaturePolicyFeature::kCamera, + ReportOptions::kReportOnFailure)) { UseCounter::Count(document, WebFeature::kCameraDisabledByFeaturePolicyEstimate); } @@ -530,11 +523,7 @@ bool UserMediaRequest::IsSecureContextUse(String& error_message) { } Document* UserMediaRequest::OwnerDocument() { - if (ExecutionContext* context = GetExecutionContext()) { - return ToDocument(context); - } - - return nullptr; + return To<Document>(GetExecutionContext()); } void UserMediaRequest::Start() { diff --git a/chromium/third_party/blink/renderer/modules/mediastream/window_media_stream.idl b/chromium/third_party/blink/renderer/modules/mediastream/window_media_stream.idl index 63c2c5937ef..ecb82580e6f 100644 --- a/chromium/third_party/blink/renderer/modules/mediastream/window_media_stream.idl +++ b/chromium/third_party/blink/renderer/modules/mediastream/window_media_stream.idl @@ -5,7 +5,7 @@ [ ImplementedAs=DOMWindowMediaStream ] partial interface Window { - attribute MediaStreamConstructor webkitMediaStream; + [Measure] attribute MediaStreamConstructor webkitMediaStream; - attribute RTCPeerConnectionConstructor webkitRTCPeerConnection; + [Measure] attribute RTCPeerConnectionConstructor webkitRTCPeerConnection; }; diff --git a/chromium/third_party/blink/renderer/modules/modules_idl_files.gni b/chromium/third_party/blink/renderer/modules/modules_idl_files.gni index 1b46d11ac4f..c97681e4079 100644 --- a/chromium/third_party/blink/renderer/modules/modules_idl_files.gni +++ b/chromium/third_party/blink/renderer/modules/modules_idl_files.gni @@ -73,10 +73,11 @@ modules_idl_files = "background_fetch/background_fetch_update_ui_event.idl", "background_sync/sync_event.idl", "background_sync/sync_manager.idl", + "badging/badge.idl", "battery/battery_manager.idl", "bluetooth/bluetooth.idl", - "bluetooth/bluetooth_device.idl", "bluetooth/bluetooth_characteristic_properties.idl", + "bluetooth/bluetooth_device.idl", "bluetooth/bluetooth_remote_gatt_characteristic.idl", "bluetooth/bluetooth_remote_gatt_descriptor.idl", "bluetooth/bluetooth_remote_gatt_server.idl", @@ -89,6 +90,8 @@ modules_idl_files = "canvas/canvas2d/canvas_pattern.idl", "canvas/canvas2d/canvas_rendering_context_2d.idl", "canvas/canvas2d/path_2d.idl", + "canvas/imagebitmap/image_bitmap_rendering_context.idl", + "canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl", "clipboard/clipboard.idl", "cookie_store/cookie_change_event.idl", "cookie_store/cookie_store.idl", @@ -112,7 +115,9 @@ modules_idl_files = "device_orientation/device_orientation_event.idl", "device_orientation/device_rotation_rate.idl", "encoding/text_decoder.idl", + "encoding/text_decoder_stream.idl", "encoding/text_encoder.idl", + "encoding/text_encoder_stream.idl", "encryptedmedia/media_encrypted_event.idl", "encryptedmedia/media_key_message_event.idl", "encryptedmedia/media_key_session.idl", @@ -120,12 +125,12 @@ modules_idl_files = "encryptedmedia/media_key_system_access.idl", "encryptedmedia/media_keys.idl", "eventsource/event_source.idl", - "filesystem/dom_file_system.idl", - "filesystem/dom_file_system_sync.idl", "filesystem/directory_entry.idl", "filesystem/directory_entry_sync.idl", "filesystem/directory_reader.idl", "filesystem/directory_reader_sync.idl", + "filesystem/dom_file_system.idl", + "filesystem/dom_file_system_sync.idl", "filesystem/entries_callback.idl", "filesystem/entry.idl", "filesystem/entry_callback.idl", @@ -135,9 +140,10 @@ modules_idl_files = "filesystem/file_entry.idl", "filesystem/file_entry_sync.idl", "filesystem/file_system_base_handle.idl", + "filesystem/file_system_callback.idl", "filesystem/file_system_directory_handle.idl", + "filesystem/file_system_directory_iterator.idl", "filesystem/file_system_file_handle.idl", - "filesystem/file_system_callback.idl", "filesystem/file_system_writer.idl", "filesystem/file_writer.idl", "filesystem/file_writer_callback.idl", @@ -154,7 +160,6 @@ modules_idl_files = "geolocation/geolocation.idl", "geolocation/position.idl", "geolocation/position_error.idl", - "canvas/imagebitmap/image_bitmap_rendering_context.idl", "imagecapture/image_capture.idl", "imagecapture/media_settings_range.idl", "imagecapture/photo_capabilities.idl", @@ -165,9 +170,9 @@ modules_idl_files = "indexeddb/idb_index.idl", "indexeddb/idb_key_range.idl", "indexeddb/idb_object_store.idl", + "indexeddb/idb_observation.idl", "indexeddb/idb_observer.idl", "indexeddb/idb_observer_changes.idl", - "indexeddb/idb_observation.idl", "indexeddb/idb_open_db_request.idl", "indexeddb/idb_request.idl", "indexeddb/idb_transaction.idl", @@ -202,27 +207,28 @@ modules_idl_files = "nfc/nfc.idl", "notifications/notification.idl", "notifications/notification_event.idl", - "canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl", "payments/abort_payment_event.idl", "payments/can_make_payment_event.idl", "payments/payment_address.idl", "payments/payment_instruments.idl", "payments/payment_manager.idl", + "payments/payment_method_change_event.idl", + "payments/payment_request.idl", "payments/payment_request_event.idl", "payments/payment_request_update_event.idl", - "payments/payment_request.idl", "payments/payment_response.idl", "peerconnection/rtc_certificate.idl", - "peerconnection/rtc_dtmf_sender.idl", - "peerconnection/rtc_dtmf_tone_change_event.idl", "peerconnection/rtc_data_channel.idl", "peerconnection/rtc_data_channel_event.idl", + "peerconnection/rtc_dtmf_sender.idl", + "peerconnection/rtc_dtmf_tone_change_event.idl", "peerconnection/rtc_ice_candidate.idl", "peerconnection/rtc_ice_transport.idl", "peerconnection/rtc_legacy_stats_report.idl", "peerconnection/rtc_peer_connection.idl", "peerconnection/rtc_peer_connection_ice_event.idl", "peerconnection/rtc_quic_stream.idl", + "peerconnection/rtc_quic_stream_event.idl", "peerconnection/rtc_quic_transport.idl", "peerconnection/rtc_rtp_contributing_source.idl", "peerconnection/rtc_rtp_receiver.idl", @@ -232,8 +238,8 @@ modules_idl_files = "peerconnection/rtc_stats_report.idl", "peerconnection/rtc_stats_response.idl", "peerconnection/rtc_track_event.idl", - "permissions/permissions.idl", "permissions/permission_status.idl", + "permissions/permissions.idl", "picture_in_picture/enter_picture_in_picture_event.idl", "picture_in_picture/picture_in_picture_window.idl", "plugins/mime_type.idl", @@ -253,9 +259,9 @@ modules_idl_files = "push_messaging/push_message_data.idl", "push_messaging/push_subscription.idl", "push_messaging/push_subscription_options.idl", - "quota/dom_error.idl", "quota/deprecated_storage_info.idl", "quota/deprecated_storage_quota.idl", + "quota/dom_error.idl", "quota/storage_manager.idl", "remoteplayback/remote_playback.idl", "screen_orientation/screen_orientation.idl", @@ -269,6 +275,8 @@ modules_idl_files = "sensor/relative_orientation_sensor.idl", "sensor/sensor.idl", "sensor/sensor_error_event.idl", + "serial/serial.idl", + "serial/serial_port.idl", "service_worker/client.idl", "service_worker/clients.idl", "service_worker/extendable_event.idl", @@ -296,14 +304,15 @@ modules_idl_files = "speech/speech_recognition_result.idl", "speech/speech_recognition_result_list.idl", "speech/speech_synthesis.idl", + "speech/speech_synthesis_error_event.idl", "speech/speech_synthesis_event.idl", "speech/speech_synthesis_utterance.idl", "speech/speech_synthesis_voice.idl", "storage/storage.idl", "storage/storage_event.idl", "vr/vr_display.idl", - "vr/vr_display_event.idl", "vr/vr_display_capabilities.idl", + "vr/vr_display_event.idl", "vr/vr_eye_parameters.idl", "vr/vr_frame_data.idl", "vr/vr_pose.idl", @@ -323,8 +332,8 @@ modules_idl_files = "webaudio/audio_scheduled_source_node.idl", "webaudio/audio_worklet.idl", "webaudio/audio_worklet_global_scope.idl", - "webaudio/audio_worklet_processor.idl", "webaudio/audio_worklet_node.idl", + "webaudio/audio_worklet_processor.idl", "webaudio/base_audio_context.idl", "webaudio/biquad_filter_node.idl", "webaudio/channel_merger_node.idl", @@ -363,8 +372,9 @@ modules_idl_files = "webgl/ext_disjoint_timer_query_webgl2.idl", "webgl/ext_frag_depth.idl", "webgl/ext_shader_texture_lod.idl", - "webgl/ext_texture_filter_anisotropic.idl", "webgl/ext_srgb.idl", + "webgl/ext_texture_filter_anisotropic.idl", + "webgl/khr_parallel_shader_compile.idl", "webgl/oes_element_index_uint.idl", "webgl/oes_standard_derivatives.idl", "webgl/oes_texture_float.idl", @@ -419,10 +429,10 @@ modules_idl_files = "websockets/websocket.idl", "webusb/usb.idl", "webusb/usb_alternate_interface.idl", - "webusb/usb_endpoint.idl", "webusb/usb_configuration.idl", "webusb/usb_connection_event.idl", "webusb/usb_device.idl", + "webusb/usb_endpoint.idl", "webusb/usb_in_transfer_result.idl", "webusb/usb_interface.idl", "webusb/usb_isochronous_in_transfer_packet.idl", @@ -459,8 +469,8 @@ if (support_webgl2_compute_context) { modules_callback_function_idl_files = get_path_info([ - "xr/xr_frame_request_callback.idl", "quota/deprecated_storage_callbacks.idl", + "xr/xr_frame_request_callback.idl", ], "abspath") @@ -483,8 +493,8 @@ modules_dictionary_idl_files = "cookie_store/cookie_list_item.idl", "cookie_store/cookie_store_delete_options.idl", "cookie_store/cookie_store_get_options.idl", - "cookie_store/cookie_store_set_options.idl", "cookie_store/cookie_store_set_extra_options.idl", + "cookie_store/cookie_store_set_options.idl", "cookie_store/extendable_cookie_change_event_init.idl", "credentialmanager/authentication_extensions_client_inputs.idl", "credentialmanager/authentication_extensions_client_outputs.idl", @@ -513,18 +523,24 @@ modules_dictionary_idl_files = "encoding/text_decode_options.idl", "encoding/text_decoder_options.idl", "encryptedmedia/media_encrypted_event_init.idl", - "encryptedmedia/media_keys_policy.idl", "encryptedmedia/media_key_message_event_init.idl", "encryptedmedia/media_key_system_configuration.idl", "encryptedmedia/media_key_system_media_capability.idl", + "encryptedmedia/media_keys_policy.idl", "eventsource/event_source_init.idl", + "filesystem/choose_file_system_entries_options.idl", + "filesystem/choose_file_system_entries_options_accepts.idl", + "filesystem/file_system_directory_iterator_entry.idl", "filesystem/file_system_flags.idl", + "filesystem/file_system_get_directory_options.idl", + "filesystem/file_system_get_file_options.idl", + "filesystem/get_system_directory_options.idl", "gamepad/gamepad_effect_parameters.idl", "gamepad/gamepad_event_init.idl", "geolocation/position_options.idl", "imagecapture/constrain_point_2d_parameters.idl", - "imagecapture/point_2d.idl", "imagecapture/photo_settings.idl", + "imagecapture/point_2d.idl", "indexeddb/idb_index_parameters.idl", "indexeddb/idb_object_store_parameters.idl", "indexeddb/idb_observer_init.idl", @@ -570,27 +586,28 @@ modules_dictionary_idl_files = "payments/basic_card_request.idl", "payments/can_make_payment_event_init.idl", "payments/image_object.idl", - "payments/payer_error_fields.idl", - "payments/payment_handler_response.idl", - "payments/payment_request_event_init.idl", + "payments/payer_errors.idl", "payments/payment_currency_amount.idl", "payments/payment_details_base.idl", "payments/payment_details_init.idl", "payments/payment_details_modifier.idl", "payments/payment_details_update.idl", + "payments/payment_handler_response.idl", + "payments/payment_instrument.idl", "payments/payment_item.idl", + "payments/payment_method_change_event_init.idl", "payments/payment_method_data.idl", "payments/payment_options.idl", - "payments/payment_instrument.idl", + "payments/payment_request_event_init.idl", "payments/payment_request_update_event_init.idl", "payments/payment_shipping_option.idl", "payments/payment_validation_errors.idl", "peerconnection/rtc_answer_options.idl", "peerconnection/rtc_configuration.idl", "peerconnection/rtc_data_channel_event_init.idl", + "peerconnection/rtc_data_channel_init.idl", "peerconnection/rtc_dtls_fingerprint.idl", "peerconnection/rtc_dtmf_tone_change_event_init.idl", - "peerconnection/rtc_data_channel_init.idl", "peerconnection/rtc_ice_candidate_init.idl", "peerconnection/rtc_ice_candidate_pair.idl", "peerconnection/rtc_ice_gather_options.idl", @@ -600,6 +617,7 @@ modules_dictionary_idl_files = "peerconnection/rtc_offer_options.idl", "peerconnection/rtc_peer_connection_ice_event_init.idl", "peerconnection/rtc_quic_parameters.idl", + "peerconnection/rtc_quic_stream_event_init.idl", "peerconnection/rtc_rtcp_parameters.idl", "peerconnection/rtc_rtp_capabilities.idl", "peerconnection/rtc_rtp_codec_capability.idl", @@ -609,8 +627,8 @@ modules_dictionary_idl_files = "peerconnection/rtc_rtp_header_extension_capability.idl", "peerconnection/rtc_rtp_header_extension_parameters.idl", "peerconnection/rtc_rtp_parameters.idl", - "peerconnection/rtc_rtp_transceiver_init.idl", "peerconnection/rtc_rtp_send_parameters.idl", + "peerconnection/rtc_rtp_transceiver_init.idl", "peerconnection/rtc_session_description_init.idl", "peerconnection/rtc_track_event_init.idl", "permissions/clipboard_permission_descriptor.idl", @@ -627,6 +645,8 @@ modules_dictionary_idl_files = "sensor/sensor_error_event_init.idl", "sensor/sensor_options.idl", "sensor/spatial_sensor_options.idl", + "serial/serial_options.idl", + "serial/serial_port_request_options.idl", "service_worker/client_query_options.idl", "service_worker/extendable_event_init.idl", "service_worker/extendable_message_event_init.idl", @@ -637,6 +657,8 @@ modules_dictionary_idl_files = "shapedetection/landmark.idl", "speech/speech_recognition_error_init.idl", "speech/speech_recognition_event_init.idl", + "speech/speech_synthesis_error_event_init.idl", + "speech/speech_synthesis_event_init.idl", "storage/storage_event_init.idl", "vr/vr_display_event_init.idl", "vr/vr_layer_init.idl", @@ -645,10 +667,10 @@ modules_dictionary_idl_files = "webaudio/audio_buffer_source_options.idl", "webaudio/audio_context_options.idl", "webaudio/audio_node_options.idl", - "webaudio/audio_worklet_node_options.idl", "webaudio/audio_param_descriptor.idl", "webaudio/audio_processing_event_init.idl", "webaudio/audio_timestamp.idl", + "webaudio/audio_worklet_node_options.idl", "webaudio/biquad_filter_options.idl", "webaudio/channel_merger_options.idl", "webaudio/channel_splitter_options.idl", @@ -660,12 +682,12 @@ modules_dictionary_idl_files = "webaudio/iir_filter_options.idl", "webaudio/media_element_audio_source_options.idl", "webaudio/media_stream_audio_source_options.idl", + "webaudio/offline_audio_completion_event_init.idl", + "webaudio/offline_audio_context_options.idl", + "webaudio/oscillator_options.idl", "webaudio/panner_options.idl", "webaudio/periodic_wave_constraints.idl", "webaudio/periodic_wave_options.idl", - "webaudio/oscillator_options.idl", - "webaudio/offline_audio_completion_event_init.idl", - "webaudio/offline_audio_context_options.idl", "webaudio/stereo_panner_options.idl", "webaudio/wave_shaper_options.idl", "webgl/webgl_context_attributes.idl", @@ -738,19 +760,18 @@ modules_dependency_idl_files = "mediacapturefromelement/html_media_element_capture.idl", "mediasession/navigator_media_session.idl", "mediasource/audio_track_source_buffer.idl", - "mediasource/video_track_source_buffer.idl", "mediasource/html_video_element_media_source.idl", "mediasource/url_media_source.idl", + "mediasource/video_track_source_buffer.idl", "mediastream/media_stream_track_content_hint.idl", "mediastream/navigator_display_media.idl", "mediastream/navigator_media_stream.idl", "mediastream/navigator_user_media.idl", - "mediastream/url_media_stream.idl", "mediastream/window_media_stream.idl", "navigatorcontentutils/navigator_content_utils.idl", - "nfc/navigator_nfc.idl", "netinfo/navigator_network_information.idl", "netinfo/worker_navigator_network_information.idl", + "nfc/navigator_nfc.idl", "notifications/service_worker_global_scope_notifications.idl", "notifications/service_worker_registration_notifications.idl", "payments/html_iframe_element_payments.idl", @@ -770,6 +791,8 @@ modules_dependency_idl_files = "quota/worker_navigator_storage_quota.idl", "remoteplayback/html_media_element_remote_playback.idl", "screen_orientation/screen_screen_orientation.idl", + "serial/navigator_serial.idl", + "serial/worker_navigator_serial.idl", "service_worker/navigator_service_worker.idl", "speech/window_speech.idl", "speech/window_speech_synthesis.idl", diff --git a/chromium/third_party/blink/renderer/modules/modules_initializer.cc b/chromium/third_party/blink/renderer/modules/modules_initializer.cc index b62523ddaf3..82b006bfe0f 100644 --- a/chromium/third_party/blink/renderer/modules/modules_initializer.cc +++ b/chromium/third_party/blink/renderer/modules/modules_initializer.cc @@ -75,7 +75,7 @@ #include "third_party/blink/renderer/modules/speech/speech_recognition_controller.h" #include "third_party/blink/renderer/modules/storage/dom_window_storage_controller.h" #include "third_party/blink/renderer/modules/storage/inspector_dom_storage_agent.h" -#include "third_party/blink/renderer/modules/storage/storage_namespace_controller.h" +#include "third_party/blink/renderer/modules/storage/storage_namespace.h" #include "third_party/blink/renderer/modules/time_zone_monitor/time_zone_monitor_client.h" #include "third_party/blink/renderer/modules/vr/navigator_vr.h" #include "third_party/blink/renderer/modules/vr/vr_controller.h" @@ -225,7 +225,7 @@ void ModulesInitializer::InitInspectorAgentSession( session->Append(new InspectorDOMStorageAgent(inspected_frames)); if (allow_view_agents) { session->Append(InspectorDatabaseAgent::Create(page)); - session->Append(new InspectorAccessibilityAgent(page, dom_agent)); + session->Append(new InspectorAccessibilityAgent(inspected_frames, dom_agent)); session->Append(InspectorCacheStorageAgent::Create(inspected_frames)); } } @@ -274,7 +274,7 @@ void ModulesInitializer::ProvideModulesToPage(Page& page, MediaKeysController::ProvideMediaKeysTo(page); ::blink::ProvideContextFeaturesTo(page, ContextFeaturesClientImpl::Create()); ::blink::ProvideDatabaseClientTo(page, new DatabaseClient); - StorageNamespaceController::ProvideStorageNamespaceTo(page, client); + StorageNamespace::ProvideSessionStorageNamespaceTo(page, client); } void ModulesInitializer::ForceNextWebGLContextCreationToFail() const { diff --git a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.cc b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.cc index 587fae6bbbc..e62eb4a998d 100644 --- a/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.cc +++ b/chromium/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.cc @@ -30,6 +30,7 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/use_counter.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/modules/netinfo/network_information.cc b/chromium/third_party/blink/renderer/modules/netinfo/network_information.cc index 127db758e76..7597be853ed 100644 --- a/chromium/third_party/blink/renderer/modules/netinfo/network_information.cc +++ b/chromium/third_party/blink/renderer/modules/netinfo/network_information.cc @@ -11,6 +11,8 @@ #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/frame/settings.h" +#include "third_party/blink/renderer/core/inspector/console_message.h" +#include "third_party/blink/renderer/core/inspector/console_types.h" #include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" @@ -23,10 +25,10 @@ Settings* GetSettings(ExecutionContext* execution_context) { if (!execution_context) return nullptr; - if (!execution_context->IsDocument()) + auto* document = DynamicTo<Document>(execution_context); + if (!document) return nullptr; - Document* document = ToDocument(execution_context); // |document| is guaranteed to be non-null since |execution_context| is // non-null. return document->GetSettings(); @@ -64,6 +66,11 @@ String ConnectionTypeToString(WebConnectionType type) { return "none"; } +String GetConsoleLogStringForWebHoldback() { + return "Network quality values are overridden using a holdback experiment, " + "and so may be inaccurate"; +} + } // namespace NetworkInformation* NetworkInformation::Create(ExecutionContext* context) { @@ -95,7 +102,15 @@ double NetworkInformation::downlinkMax() const { return downlink_max_mbps_; } -String NetworkInformation::effectiveType() const { +String NetworkInformation::effectiveType() { + MaybeShowWebHoldbackConsoleMsg(); + base::Optional<WebEffectiveConnectionType> override_ect = + GetNetworkStateNotifier().GetWebHoldbackEffectiveType(); + if (override_ect) { + return NetworkStateNotifier::EffectiveConnectionTypeToString( + override_ect.value()); + } + // effective_type_ is only updated when listening for events, so ask // networkStateNotifier if not listening (crbug.com/379841). if (!IsObserving()) { @@ -107,7 +122,14 @@ String NetworkInformation::effectiveType() const { return NetworkStateNotifier::EffectiveConnectionTypeToString(effective_type_); } -unsigned long NetworkInformation::rtt() const { +unsigned long NetworkInformation::rtt() { + MaybeShowWebHoldbackConsoleMsg(); + base::Optional<TimeDelta> override_rtt = + GetNetworkStateNotifier().GetWebHoldbackHttpRtt(); + if (override_rtt) { + return GetNetworkStateNotifier().RoundRtt(Host(), override_rtt.value()); + } + if (!IsObserving()) { return GetNetworkStateNotifier().RoundRtt( Host(), GetNetworkStateNotifier().HttpRtt()); @@ -116,7 +138,15 @@ unsigned long NetworkInformation::rtt() const { return http_rtt_msec_; } -double NetworkInformation::downlink() const { +double NetworkInformation::downlink() { + MaybeShowWebHoldbackConsoleMsg(); + base::Optional<double> override_downlink_mbps = + GetNetworkStateNotifier().GetWebHoldbackDownlinkThroughputMbps(); + if (override_downlink_mbps) { + return GetNetworkStateNotifier().RoundMbps(Host(), + override_downlink_mbps.value()); + } + if (!IsObserving()) { return GetNetworkStateNotifier().RoundMbps( Host(), GetNetworkStateNotifier().DownlinkThroughputMbps()); @@ -148,20 +178,27 @@ void NetworkInformation::ConnectionChange( double new_downlink_mbps = GetNetworkStateNotifier().RoundMbps(host, downlink_mbps); + bool network_quality_estimate_changed = false; + // Allow setting |network_quality_estimate_changed| to true only if the + // network quality holdback experiment is not enabled. + if (!GetNetworkStateNotifier().GetWebHoldbackEffectiveType()) { + network_quality_estimate_changed = effective_type_ != effective_type || + http_rtt_msec_ != new_http_rtt_msec || + downlink_mbps_ != new_downlink_mbps; + } + // This can happen if the observer removes and then adds itself again // during notification, or if |transport_rtt| was the only metric that // changed. if (type_ == type && downlink_max_mbps_ == downlink_max_mbps && - effective_type_ == effective_type && - http_rtt_msec_ == new_http_rtt_msec && - downlink_mbps_ == new_downlink_mbps && save_data_ == save_data) { + !network_quality_estimate_changed && save_data_ == save_data) { return; } + // If the NetInfoDownlinkMaxEnabled is not enabled, then |type| and + // |downlink_max_mbps| should not be checked for change. if (!RuntimeEnabledFeatures::NetInfoDownlinkMaxEnabled() && - effective_type_ == effective_type && - http_rtt_msec_ == new_http_rtt_msec && - downlink_mbps_ == new_downlink_mbps && save_data_ == save_data) { + !network_quality_estimate_changed && save_data_ == save_data) { return; } @@ -171,9 +208,11 @@ void NetworkInformation::ConnectionChange( type_ = type; downlink_max_mbps_ = downlink_max_mbps; - effective_type_ = effective_type; - http_rtt_msec_ = new_http_rtt_msec; - downlink_mbps_ = new_downlink_mbps; + if (network_quality_estimate_changed) { + effective_type_ = effective_type; + http_rtt_msec_ = new_http_rtt_msec; + downlink_mbps_ = new_downlink_mbps; + } save_data_ = save_data; if (type_changed) @@ -194,6 +233,7 @@ void NetworkInformation::AddedEventListener( RegisteredEventListener& registered_listener) { EventTargetWithInlineData::AddedEventListener(event_type, registered_listener); + MaybeShowWebHoldbackConsoleMsg(); StartObserving(); } @@ -243,18 +283,20 @@ void NetworkInformation::StopObserving() { NetworkInformation::NetworkInformation(ExecutionContext* context) : ContextLifecycleObserver(context), - type_(GetNetworkStateNotifier().ConnectionType()), - downlink_max_mbps_(GetNetworkStateNotifier().MaxBandwidth()), - effective_type_(GetNetworkStateNotifier().EffectiveType()), - http_rtt_msec_(GetNetworkStateNotifier().RoundRtt( - Host(), - GetNetworkStateNotifier().HttpRtt())), - downlink_mbps_(GetNetworkStateNotifier().RoundMbps( - Host(), - GetNetworkStateNotifier().DownlinkThroughputMbps())), - save_data_(GetNetworkStateNotifier().SaveDataEnabled() && - !IsInDataSaverHoldbackWebApi(GetExecutionContext())), + web_holdback_console_message_shown_(false), context_stopped_(false) { + base::Optional<TimeDelta> http_rtt; + base::Optional<double> downlink_mbps; + + GetNetworkStateNotifier().GetMetricsWithWebHoldback( + &type_, &downlink_max_mbps_, &effective_type_, &http_rtt, &downlink_mbps, + &save_data_); + + http_rtt_msec_ = GetNetworkStateNotifier().RoundRtt(Host(), http_rtt); + downlink_mbps_ = GetNetworkStateNotifier().RoundMbps(Host(), downlink_mbps); + save_data_ = + save_data_ && !IsInDataSaverHoldbackWebApi(GetExecutionContext()); + DCHECK_LE(1u, GetNetworkStateNotifier().RandomizationSalt()); DCHECK_GE(20u, GetNetworkStateNotifier().RandomizationSalt()); } @@ -268,4 +310,15 @@ const String NetworkInformation::Host() const { return GetExecutionContext() ? GetExecutionContext()->Url().Host() : String(); } +void NetworkInformation::MaybeShowWebHoldbackConsoleMsg() { + if (web_holdback_console_message_shown_) + return; + web_holdback_console_message_shown_ = true; + if (!GetNetworkStateNotifier().GetWebHoldbackEffectiveType()) + return; + GetExecutionContext()->AddConsoleMessage( + ConsoleMessage::Create(kOtherMessageSource, kWarningMessageLevel, + GetConsoleLogStringForWebHoldback())); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/netinfo/network_information.h b/chromium/third_party/blink/renderer/modules/netinfo/network_information.h index 5af8102fbe6..b8170e43fcd 100644 --- a/chromium/third_party/blink/renderer/modules/netinfo/network_information.h +++ b/chromium/third_party/blink/renderer/modules/netinfo/network_information.h @@ -32,9 +32,9 @@ class NetworkInformation final String type() const; double downlinkMax() const; - String effectiveType() const; - unsigned long rtt() const; - double downlink() const; + String effectiveType(); + unsigned long rtt(); + double downlink(); bool saveData() const; // NetworkStateObserver overrides. @@ -79,6 +79,8 @@ class NetworkInformation final const String Host() const; + void MaybeShowWebHoldbackConsoleMsg(); + // Touched only on context thread. WebConnectionType type_; @@ -101,6 +103,11 @@ class NetworkInformation final // Whether the data saving mode is enabled. bool save_data_; + // True if the console message indicating that network quality is overridden + // using a holdback experiment has been shown. Set to true if the console + // message has been shown, or if the holdback experiment is not enabled. + bool web_holdback_console_message_shown_; + // Whether ContextLifecycleObserver::contextDestroyed has been called. bool context_stopped_; diff --git a/chromium/third_party/blink/renderer/modules/nfc/OWNERS b/chromium/third_party/blink/renderer/modules/nfc/OWNERS index 24ac3f7fea7..0243a40c25d 100644 --- a/chromium/third_party/blink/renderer/modules/nfc/OWNERS +++ b/chromium/third_party/blink/renderer/modules/nfc/OWNERS @@ -1,3 +1,2 @@ -alexander.shalamov@intel.com kenneth.r.christiansen@intel.com -rijubrata.bhaumik@intel.com
\ No newline at end of file +rijubrata.bhaumik@intel.com diff --git a/chromium/third_party/blink/renderer/modules/nfc/nfc.cc b/chromium/third_party/blink/renderer/modules/nfc/nfc.cc index e86dbe865b6..282d7b54c03 100644 --- a/chromium/third_party/blink/renderer/modules/nfc/nfc.cc +++ b/chromium/third_party/blink/renderer/modules/nfc/nfc.cc @@ -20,6 +20,7 @@ #include "third_party/blink/renderer/modules/nfc/nfc_push_options.h" #include "third_party/blink/renderer/modules/nfc/nfc_watch_options.h" #include "third_party/blink/renderer/platform/mojo/mojo_helper.h" +#include "third_party/blink/renderer/platform/weborigin/security_origin.h" namespace { const char kJsonMimePostfix[] = "+json"; @@ -269,7 +270,7 @@ struct TypeConverter<NFCMessagePtr, blink::NFCMessage> { NFCMessagePtr messagePtr = NFCMessage::New(); messagePtr->url = message.url(); messagePtr->data.resize(message.records().size()); - for (size_t i = 0; i < message.records().size(); ++i) { + for (wtf_size_t i = 0; i < message.records().size(); ++i) { NFCRecordPtr record = NFCRecord::From(message.records()[i]); if (record.is_null()) return nullptr; @@ -618,7 +619,7 @@ NFCMessage ToNFCMessage(ScriptState* script_state, NFCMessage nfc_message; nfc_message.setURL(message->url); blink::HeapVector<NFCRecord> records; - for (size_t i = 0; i < message->data.size(); ++i) + for (wtf_size_t i = 0; i < message->data.size(); ++i) records.push_back(ToNFCRecord(script_state, message->data[i])); nfc_message.setRecords(records); return nfc_message; @@ -626,7 +627,7 @@ NFCMessage ToNFCMessage(ScriptState* script_state, size_t GetNFCMessageSize(const device::mojom::blink::NFCMessagePtr& message) { size_t message_size = message->url.CharactersSizeInBytes(); - for (size_t i = 0; i < message->data.size(); ++i) { + for (wtf_size_t i = 0; i < message->data.size(); ++i) { message_size += message->data[i]->media_type.CharactersSizeInBytes(); message_size += message->data[i]->data.size(); } @@ -774,7 +775,7 @@ ScriptPromise NFC::watch(ScriptState* script_state, } // https://w3c.github.io/web-nfc/#dom-nfc-cancelwatch -ScriptPromise NFC::cancelWatch(ScriptState* script_state, long id) { +ScriptPromise NFC::cancelWatch(ScriptState* script_state, int32_t id) { ScriptPromise promise = RejectIfNotSupported(script_state); if (!promise.IsEmpty()) return promise; @@ -871,8 +872,8 @@ bool NFC::IsSupportedInContext(ExecutionContext* context, String& error_message) { // https://w3c.github.io/web-nfc/#security-policies // WebNFC API must be only accessible from top level browsing context. - if (!ToDocument(context)->domWindow()->GetFrame() || - !ToDocument(context)->GetFrame()->IsMainFrame()) { + if (!To<Document>(context)->domWindow()->GetFrame() || + !To<Document>(context)->GetFrame()->IsMainFrame()) { error_message = "Must be in a top-level browsing context"; return false; } diff --git a/chromium/third_party/blink/renderer/modules/nfc/nfc.h b/chromium/third_party/blink/renderer/modules/nfc/nfc.h index 393638048eb..554581deb53 100644 --- a/chromium/third_party/blink/renderer/modules/nfc/nfc.h +++ b/chromium/third_party/blink/renderer/modules/nfc/nfc.h @@ -52,7 +52,7 @@ class NFC final : public ScriptWrappable, ScriptPromise watch(ScriptState*, V8MessageCallback*, const NFCWatchOptions&); // Cancels watch operation with id. - ScriptPromise cancelWatch(ScriptState*, long id); + ScriptPromise cancelWatch(ScriptState*, int32_t id); // Cancels all watch operations. ScriptPromise cancelWatch(ScriptState*); diff --git a/chromium/third_party/blink/renderer/modules/notifications/notification.cc b/chromium/third_party/blink/renderer/modules/notifications/notification.cc index 6e277ad9cba..ce2d4eb96d1 100644 --- a/chromium/third_party/blink/renderer/modules/notifications/notification.cc +++ b/chromium/third_party/blink/renderer/modules/notifications/notification.cc @@ -57,6 +57,7 @@ #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" #include "third_party/blink/renderer/platform/wtf/functional.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" namespace blink { @@ -86,19 +87,19 @@ Notification* Notification::Create(ExecutionContext* context, return nullptr; } + auto* document = DynamicTo<Document>(context); if (context->IsSecureContext()) { UseCounter::Count(context, WebFeature::kNotificationSecureOrigin); - if (context->IsDocument()) { + if (document) { UseCounter::CountCrossOriginIframe( - *ToDocument(context), WebFeature::kNotificationAPISecureOriginIframe); + *document, WebFeature::kNotificationAPISecureOriginIframe); } } else { Deprecation::CountDeprecation(context, WebFeature::kNotificationInsecureOrigin); - if (context->IsDocument()) { + if (document) { Deprecation::CountDeprecationCrossOriginIframe( - *ToDocument(context), - WebFeature::kNotificationAPIInsecureOriginIframe); + *document, WebFeature::kNotificationAPIInsecureOriginIframe); } } @@ -126,7 +127,6 @@ Notification* Notification::Create(ExecutionContext* context, notification->SchedulePrepareShow(); - Document* document = context->IsDocument() ? ToDocument(context) : nullptr; if (document && document->GetFrame()) { if (auto* frame_resource_coordinator = document->GetFrame()->GetFrameResourceCoordinator()) { @@ -229,10 +229,11 @@ void Notification::OnShow() { void Notification::OnClick(OnClickCallback completed_closure) { ExecutionContext* context = GetExecutionContext(); - Document* document = context->IsDocument() ? ToDocument(context) : nullptr; + Document* document = DynamicTo<Document>(context); std::unique_ptr<UserGestureIndicator> gesture_indicator = - Frame::NotifyUserActivation(document ? document->GetFrame() : nullptr, - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation( + document ? document->GetFrame() : nullptr, + UserGestureToken::kNewGesture); ScopedWindowFocusAllowedIndicator window_focus_allowed(GetExecutionContext()); DispatchEvent(*Event::Create(EventTypeNames::click)); @@ -345,7 +346,7 @@ Vector<v8::Local<v8::Value>> Notification::actions( const Vector<mojom::blink::NotificationActionPtr>& actions = data_->actions.value(); result.Grow(actions.size()); - for (size_t i = 0; i < actions.size(); ++i) { + for (wtf_size_t i = 0; i < actions.size(); ++i) { NotificationAction action; switch (actions[i]->type) { @@ -402,8 +403,9 @@ String Notification::permission(ExecutionContext* context) { // // TODO(crbug.com/758603): Move this check to the browser process when the // NotificationService connection becomes frame-bound. - if (status == mojom::blink::PermissionStatus::ASK && context->IsDocument()) { - LocalFrame* frame = ToDocument(context)->GetFrame(); + if (status == mojom::blink::PermissionStatus::ASK) { + auto* document = DynamicTo<Document>(context); + LocalFrame* frame = document ? document->GetFrame() : nullptr; if (!frame || frame->IsCrossOriginSubframe()) status = mojom::blink::PermissionStatus::DENIED; } @@ -415,10 +417,11 @@ ScriptPromise Notification::requestPermission( ScriptState* script_state, V8NotificationPermissionCallback* deprecated_callback) { ExecutionContext* context = ExecutionContext::From(script_state); - Document* doc = ToDocumentOrNull(context); + Document* doc = DynamicTo<Document>(context); probe::breakableLocation(context, "Notification.requestPermission"); - if (!Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr)) { + if (!LocalFrame::HasTransientUserActivation(doc ? doc->GetFrame() + : nullptr)) { PerformanceMonitor::ReportGenericViolation( context, PerformanceMonitor::kDiscouragedAPIUse, "Only request notification permission in response to a user gesture.", @@ -433,8 +436,8 @@ ScriptPromise Notification::requestPermission( // Sites cannot request notification permission from cross-origin iframes, // but they can use notifications if permission had already been granted. - if (context->IsDocument()) { - LocalFrame* frame = ToDocument(context)->GetFrame(); + if (auto* document = DynamicTo<Document>(context)) { + LocalFrame* frame = document->GetFrame(); if (!frame || frame->IsCrossOriginSubframe()) { Deprecation::CountDeprecation( context, WebFeature::kNotificationPermissionRequestedIframe); diff --git a/chromium/third_party/blink/renderer/modules/notifications/notification_data.cc b/chromium/third_party/blink/renderer/modules/notifications/notification_data.cc index 76675044019..4e22ec98d17 100644 --- a/chromium/third_party/blink/renderer/modules/notifications/notification_data.cc +++ b/chromium/third_party/blink/renderer/modules/notifications/notification_data.cc @@ -11,6 +11,7 @@ #include "third_party/blink/renderer/modules/notifications/notification_options.h" #include "third_party/blink/renderer/modules/vibration/vibration_controller.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/blink/renderer/platform/wtf/text/string_view.h" #include "third_party/blink/renderer/platform/wtf/time.h" @@ -100,7 +101,7 @@ mojom::blink::NotificationDataPtr CreateNotificationData( notification_data->data = Vector<uint8_t>(); notification_data->data->Append( serialized_script_value->Data(), - serialized_script_value->DataLengthInBytes()); + SafeCast<wtf_size_t>(serialized_script_value->DataLengthInBytes())); } Vector<mojom::blink::NotificationActionPtr> actions; diff --git a/chromium/third_party/blink/renderer/modules/notifications/notification_data.h b/chromium/third_party/blink/renderer/modules/notifications/notification_data.h index 0dcb0f0228b..2e21e5b5fbe 100644 --- a/chromium/third_party/blink/renderer/modules/notifications/notification_data.h +++ b/chromium/third_party/blink/renderer/modules/notifications/notification_data.h @@ -5,7 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NOTIFICATIONS_NOTIFICATION_DATA_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_NOTIFICATIONS_NOTIFICATION_DATA_H_ -#include "third_party/blink/public/platform/modules/notifications/notification.mojom-blink.h" +#include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h" #include "third_party/blink/renderer/modules/modules_export.h" namespace WTF { diff --git a/chromium/third_party/blink/renderer/modules/notifications/notification_data_test.cc b/chromium/third_party/blink/renderer/modules/notifications/notification_data_test.cc index edd59252eee..24296339e3d 100644 --- a/chromium/third_party/blink/renderer/modules/notifications/notification_data_test.cc +++ b/chromium/third_party/blink/renderer/modules/notifications/notification_data_test.cc @@ -134,7 +134,7 @@ TEST_F(NotificationDataTest, ReflectProperties) { ASSERT_EQ(vibration_pattern.size(), notification_data->vibration_pattern->size()); - for (size_t i = 0; i < vibration_pattern.size(); ++i) { + for (wtf_size_t i = 0; i < vibration_pattern.size(); ++i) { EXPECT_EQ( vibration_pattern[i], static_cast<unsigned>(notification_data->vibration_pattern.value()[i])); @@ -259,7 +259,7 @@ TEST_F(NotificationDataTest, VibrationNormalization) { ASSERT_EQ(normalized_pattern.size(), notification_data->vibration_pattern->size()); - for (size_t i = 0; i < normalized_pattern.size(); ++i) { + for (wtf_size_t i = 0; i < normalized_pattern.size(); ++i) { EXPECT_EQ(normalized_pattern[i], notification_data->vibration_pattern.value()[i]); } @@ -323,7 +323,7 @@ TEST_F(NotificationDataTest, MaximumActionCount) { // The stored actions will be capped to |maxActions| entries. ASSERT_EQ(Notification::maxActions(), notification_data->actions->size()); - for (size_t i = 0; i < Notification::maxActions(); ++i) { + for (wtf_size_t i = 0; i < Notification::maxActions(); ++i) { String expected_action = String::Number(i); EXPECT_EQ(expected_action, notification_data->actions.value()[i]->action); } diff --git a/chromium/third_party/blink/renderer/modules/notifications/notification_image_loader.cc b/chromium/third_party/blink/renderer/modules/notifications/notification_image_loader.cc index fffba5f48a7..efe063638b4 100644 --- a/chromium/third_party/blink/renderer/modules/notifications/notification_image_loader.cc +++ b/chromium/third_party/blink/renderer/modules/notifications/notification_image_loader.cc @@ -113,9 +113,8 @@ void NotificationImageLoader::Start(ExecutionContext* context, resource_loader_options.request_initiator_context = kWorkerContext; ResourceRequest resource_request(url); - resource_request.SetRequestContext(WebURLRequest::kRequestContextImage); + resource_request.SetRequestContext(mojom::RequestContextType::IMAGE); resource_request.SetPriority(ResourceLoadPriority::kMedium); - resource_request.SetRequestorOrigin(context->GetSecurityOrigin()); threadable_loader_ = new ThreadableLoader( *context, this, resource_loader_options); diff --git a/chromium/third_party/blink/renderer/modules/notifications/notification_manager.cc b/chromium/third_party/blink/renderer/modules/notifications/notification_manager.cc index 21d3be41d51..36bc76a3af6 100644 --- a/chromium/third_party/blink/renderer/modules/notifications/notification_manager.cc +++ b/chromium/third_party/blink/renderer/modules/notifications/notification_manager.cc @@ -5,8 +5,8 @@ #include "third_party/blink/renderer/modules/notifications/notification_manager.h" #include "services/service_manager/public/cpp/interface_provider.h" +#include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h" #include "third_party/blink/public/platform/interface_provider.h" -#include "third_party/blink/public/platform/modules/notifications/notification.mojom-blink.h" #include "third_party/blink/public/platform/modules/permissions/permission.mojom-blink.h" #include "third_party/blink/public/platform/modules/permissions/permission_status.mojom-blink.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_registration.h" @@ -79,10 +79,10 @@ ScriptPromise NotificationManager::RequestPermission( ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); - Document* doc = ToDocumentOrNull(context); + Document* doc = DynamicTo<Document>(context); permission_service_->RequestPermission( CreatePermissionDescriptor(mojom::blink::PermissionName::NOTIFICATIONS), - Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr), + LocalFrame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr), WTF::Bind( &NotificationManager::OnPermissionRequestComplete, WrapPersistent(this), WrapPersistent(resolver), diff --git a/chromium/third_party/blink/renderer/modules/notifications/notification_resources_loader.cc b/chromium/third_party/blink/renderer/modules/notifications/notification_resources_loader.cc index 9e861a7858d..8bc1348277f 100644 --- a/chromium/third_party/blink/renderer/modules/notifications/notification_resources_loader.cc +++ b/chromium/third_party/blink/renderer/modules/notifications/notification_resources_loader.cc @@ -5,6 +5,7 @@ #include "third_party/blink/renderer/modules/notifications/notification_resources_loader.h" #include <cmath> +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/histogram.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/threading.h" diff --git a/chromium/third_party/blink/renderer/modules/notifications/notification_resources_loader.h b/chromium/third_party/blink/renderer/modules/notifications/notification_resources_loader.h index f9b3e5fa784..1e8eb32074b 100644 --- a/chromium/third_party/blink/renderer/modules/notifications/notification_resources_loader.h +++ b/chromium/third_party/blink/renderer/modules/notifications/notification_resources_loader.h @@ -6,7 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_NOTIFICATIONS_NOTIFICATION_RESOURCES_LOADER_H_ #include <memory> -#include "third_party/blink/public/platform/modules/notifications/notification.mojom-blink.h" +#include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/notifications/notification_image_loader.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" diff --git a/chromium/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h b/chromium/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h index 4af07fde36b..38c1ad06f17 100644 --- a/chromium/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h +++ b/chromium/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h @@ -7,7 +7,7 @@ #include <memory> #include "base/memory/scoped_refptr.h" -#include "third_party/blink/public/platform/modules/notifications/notification.mojom-blink.h" +#include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" diff --git a/chromium/third_party/blink/renderer/modules/payments/BUILD.gn b/chromium/third_party/blink/renderer/modules/payments/BUILD.gn index 50bd846f9e7..ec0f2d75820 100644 --- a/chromium/third_party/blink/renderer/modules/payments/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/payments/BUILD.gn @@ -31,6 +31,8 @@ blink_modules_sources("payments") { "payment_instruments.h", "payment_manager.cc", "payment_manager.h", + "payment_method_change_event.cc", + "payment_method_change_event.h", "payment_request.cc", "payment_request.h", "payment_request_event.cc", diff --git a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.cc b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.cc index 7d563b26b3c..106793d6bd2 100644 --- a/chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.cc +++ b/chromium/third_party/blink/renderer/modules/payments/can_make_payment_event.cc @@ -10,7 +10,6 @@ #include "third_party/blink/renderer/core/workers/worker_location.h" #include "third_party/blink/renderer/modules/service_worker/respond_with_observer.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h" -#include "third_party/blink/renderer/modules/service_worker/service_worker_window_client_callback.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" diff --git a/chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc b/chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc index 28d762d6593..dc139e1e201 100644 --- a/chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc +++ b/chromium/third_party/blink/renderer/modules/payments/on_payment_response_test.cc @@ -78,7 +78,7 @@ TEST(OnPaymentResponseTest, RejectMissingName) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); + BuildPaymentResponseForTest(); request->show(scope.GetScriptState()) .Then(funcs.ExpectNoCall(), funcs.ExpectCall()); @@ -100,7 +100,7 @@ TEST(OnPaymentResponseTest, RejectMissingEmail) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); + BuildPaymentResponseForTest(); request->show(scope.GetScriptState()) .Then(funcs.ExpectNoCall(), funcs.ExpectCall()); @@ -122,7 +122,7 @@ TEST(OnPaymentResponseTest, RejectMissingPhone) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); + BuildPaymentResponseForTest(); request->show(scope.GetScriptState()) .Then(funcs.ExpectNoCall(), funcs.ExpectCall()); @@ -195,8 +195,8 @@ TEST(OnPaymentResponseTest, RejectEmptyName) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); - response->payer_name = ""; + BuildPaymentResponseForTest(); + response->payer->name = ""; request->show(scope.GetScriptState()) .Then(funcs.ExpectNoCall(), funcs.ExpectCall()); @@ -218,8 +218,8 @@ TEST(OnPaymentResponseTest, RejectEmptyEmail) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); - response->payer_email = ""; + BuildPaymentResponseForTest(); + response->payer->email = ""; request->show(scope.GetScriptState()) .Then(funcs.ExpectNoCall(), funcs.ExpectCall()); @@ -241,8 +241,8 @@ TEST(OnPaymentResponseTest, RejectEmptyPhone) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); - response->payer_phone = ""; + BuildPaymentResponseForTest(); + response->payer->phone = ""; request->show(scope.GetScriptState()) .Then(funcs.ExpectNoCall(), funcs.ExpectCall()); @@ -264,7 +264,7 @@ TEST(OnPaymentResponseTest, RejectNotRequestedAddress) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); ASSERT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); + BuildPaymentResponseForTest(); response->shipping_address = payments::mojom::blink::PaymentAddress::New(); response->shipping_address->country = "US"; response->shipping_address->language_code = "en"; @@ -290,7 +290,7 @@ TEST(OnPaymentResponseTest, RejectNotRequestedShippingOption) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); ASSERT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); + BuildPaymentResponseForTest(); response->shipping_option = ""; request->show(scope.GetScriptState()) @@ -313,8 +313,8 @@ TEST(OnPaymentResponseTest, RejectNotRequestedName) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); - response->payer_name = ""; + BuildPaymentResponseForTest(); + response->payer->name = ""; request->show(scope.GetScriptState()) .Then(funcs.ExpectNoCall(), funcs.ExpectCall()); @@ -336,8 +336,8 @@ TEST(OnPaymentResponseTest, RejectNotRequestedEmail) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); - response->payer_email = ""; + BuildPaymentResponseForTest(); + response->payer->email = ""; request->show(scope.GetScriptState()) .Then(funcs.ExpectNoCall(), funcs.ExpectCall()); @@ -359,8 +359,8 @@ TEST(OnPaymentResponseTest, RejectNotRequestedPhone) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); - response->payer_phone = ""; + BuildPaymentResponseForTest(); + response->payer->phone = ""; request->show(scope.GetScriptState()) .Then(funcs.ExpectNoCall(), funcs.ExpectCall()); @@ -466,8 +466,9 @@ TEST(OnPaymentResponseTest, CanRequestName) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); - response->payer_name = "Jon Doe"; + BuildPaymentResponseForTest(); + response->payer = payments::mojom::blink::PayerDetail::New(); + response->payer->name = "Jon Doe"; ScriptValue out_value; request->show(scope.GetScriptState()) .Then(PaymentResponseFunction::Create(scope.GetScriptState(), &out_value), @@ -495,8 +496,8 @@ TEST(OnPaymentResponseTest, CanRequestEmail) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); - response->payer_email = "abc@gmail.com"; + BuildPaymentResponseForTest(); + response->payer->email = "abc@gmail.com"; ScriptValue out_value; request->show(scope.GetScriptState()) .Then(PaymentResponseFunction::Create(scope.GetScriptState(), &out_value), @@ -524,8 +525,8 @@ TEST(OnPaymentResponseTest, CanRequestPhone) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); - response->payer_phone = "0123"; + BuildPaymentResponseForTest(); + response->payer->phone = "0123"; ScriptValue out_value; request->show(scope.GetScriptState()) @@ -581,8 +582,8 @@ TEST(OnPaymentResponseTest, PhoneNotRequred) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); - response->payer_phone = String(); + BuildPaymentResponseForTest(); + response->payer->phone = String(); ScriptValue out_value; request->show(scope.GetScriptState()) .Then(PaymentResponseFunction::Create(scope.GetScriptState(), &out_value), @@ -610,8 +611,8 @@ TEST(OnPaymentResponseTest, NameNotRequired) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); - response->payer_name = String(); + BuildPaymentResponseForTest(); + response->payer->name = String(); ScriptValue out_value; request->show(scope.GetScriptState()) .Then(PaymentResponseFunction::Create(scope.GetScriptState(), &out_value), @@ -639,8 +640,8 @@ TEST(OnPaymentResponseTest, EmailNotRequired) { BuildPaymentDetailsInitForTest(), options, scope.GetExceptionState()); EXPECT_FALSE(scope.GetExceptionState().HadException()); payments::mojom::blink::PaymentResponsePtr response = - payments::mojom::blink::PaymentResponse::New(); - response->payer_email = String(); + BuildPaymentResponseForTest(); + response->payer->email = String(); ScriptValue out_value; request->show(scope.GetScriptState()) .Then(PaymentResponseFunction::Create(scope.GetScriptState(), &out_value), diff --git a/chromium/third_party/blink/renderer/modules/payments/payer_error_fields.idl b/chromium/third_party/blink/renderer/modules/payments/payer_errors.idl index a56a8892749..5598afa6d68 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payer_error_fields.idl +++ b/chromium/third_party/blink/renderer/modules/payments/payer_errors.idl @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://w3c.github.io/payment-request/#payererrorfields-dictionary +// https://w3c.github.io/payment-request/#payererrors-dictionary -dictionary PayerErrorFields { +dictionary PayerErrors { DOMString email; DOMString name; DOMString phone; diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_address.idl b/chromium/third_party/blink/renderer/modules/payments/payment_address.idl index 74bda4207e3..58901857b34 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_address.idl +++ b/chromium/third_party/blink/renderer/modules/payments/payment_address.idl @@ -13,7 +13,7 @@ readonly attribute DOMString city; readonly attribute DOMString country; readonly attribute DOMString dependentLocality; - readonly attribute DOMString languageCode; + [MeasureAs=PaymentAddressLanguageCode] readonly attribute DOMString languageCode; readonly attribute DOMString organization; readonly attribute DOMString phone; readonly attribute DOMString postalCode; diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_details_update.idl b/chromium/third_party/blink/renderer/modules/payments/payment_details_update.idl index 73d0fcd66f4..7d798eb5d07 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_details_update.idl +++ b/chromium/third_party/blink/renderer/modules/payments/payment_details_update.idl @@ -7,4 +7,5 @@ dictionary PaymentDetailsUpdate : PaymentDetailsBase { DOMString error; PaymentItem total; + AddressErrors shippingAddressErrors; }; diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_instruments.cc b/chromium/third_party/blink/renderer/modules/payments/payment_instruments.cc index 3c0e57ec11f..c452409fdbf 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_instruments.cc +++ b/chromium/third_party/blink/renderer/modules/payments/payment_instruments.cc @@ -242,7 +242,7 @@ ScriptPromise PaymentInstruments::set(ScriptState* script_state, ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ExecutionContext* context = ExecutionContext::From(script_state); - Document* doc = ToDocumentOrNull(context); + Document* doc = DynamicTo<Document>(context); // Should move this permission check to browser process. // Please see http://crbug.com/795929 @@ -250,7 +250,8 @@ ScriptPromise PaymentInstruments::set(ScriptState* script_state, ->RequestPermission( CreatePermissionDescriptor( mojom::blink::PermissionName::PAYMENT_HANDLER), - Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr), + LocalFrame::HasTransientUserActivation(doc ? doc->GetFrame() + : nullptr), WTF::Bind(&PaymentInstruments::OnRequestPermission, WrapPersistent(this), WrapPersistent(resolver), instrument_key, diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.cc b/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.cc new file mode 100644 index 00000000000..7d47a1040c7 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.cc @@ -0,0 +1,43 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/payments/payment_method_change_event.h" + +#include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/platform/bindings/script_state.h" + +namespace blink { + +PaymentMethodChangeEvent::~PaymentMethodChangeEvent() = default; + +// static +PaymentMethodChangeEvent* PaymentMethodChangeEvent::Create( + ScriptState* script_state, + const AtomicString& type, + const PaymentMethodChangeEventInit& init) { + return new PaymentMethodChangeEvent(script_state, type, init); +} + +const String& PaymentMethodChangeEvent::methodName() const { + return method_name_; +} + +const ScriptValue PaymentMethodChangeEvent::methodDetails( + ScriptState* script_state) const { + return ScriptValue(script_state, method_details_.V8ValueFor(script_state)); +} + +PaymentMethodChangeEvent::PaymentMethodChangeEvent( + ScriptState* script_state, + const AtomicString& type, + const PaymentMethodChangeEventInit& init) + : PaymentRequestUpdateEvent(ExecutionContext::From(script_state), + type, + init), + method_name_(init.methodName()), + method_details_(init.hasMethodDetails() + ? init.methodDetails() + : ScriptValue::CreateNull(script_state)) {} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.h b/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.h new file mode 100644 index 00000000000..f557cbcd21f --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.h @@ -0,0 +1,47 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_METHOD_CHANGE_EVENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_METHOD_CHANGE_EVENT_H_ + +#include "third_party/blink/renderer/bindings/core/v8/script_value.h" +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/modules/payments/payment_method_change_event_init.h" +#include "third_party/blink/renderer/modules/payments/payment_request_update_event.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace blink { + +class ScriptState; + +class MODULES_EXPORT PaymentMethodChangeEvent final + : public PaymentRequestUpdateEvent { + DEFINE_WRAPPERTYPEINFO(); + + public: + ~PaymentMethodChangeEvent() override; + + static PaymentMethodChangeEvent* Create( + ScriptState*, + const AtomicString& type, + const PaymentMethodChangeEventInit& = PaymentMethodChangeEventInit()); + + const String& methodName() const; + const ScriptValue methodDetails(ScriptState*) const; + + private: + PaymentMethodChangeEvent(ScriptState*, + const AtomicString& type, + const PaymentMethodChangeEventInit&); + + String method_name_; + ScriptValue method_details_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_METHOD_CHANGE_EVENT_H_ diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.idl b/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.idl new file mode 100644 index 00000000000..98e6d845206 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event.idl @@ -0,0 +1,16 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://w3c.github.io/payment-request/#paymentmethodchangeevent-interface + +[ + RuntimeEnabled=PaymentMethodChangeEvent, + ConstructorCallWith=ScriptState, + Constructor(DOMString type, optional PaymentMethodChangeEventInit eventInitDict), + SecureContext, + Exposed=Window +] interface PaymentMethodChangeEvent : PaymentRequestUpdateEvent { + readonly attribute DOMString methodName; + [CallWith=ScriptState] readonly attribute object? methodDetails; +}; diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event_init.idl b/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event_init.idl new file mode 100644 index 00000000000..71e71402f30 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/payments/payment_method_change_event_init.idl @@ -0,0 +1,10 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://w3c.github.io/payment-request/#paymentmethodchangeeventinit-dictionary + +dictionary PaymentMethodChangeEventInit : PaymentRequestUpdateEventInit { + DOMString methodName = ""; + object? methodDetails = null; +}; diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request.cc b/chromium/third_party/blink/renderer/modules/payments/payment_request.cc index 18edea360e1..e16c732ce23 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_request.cc +++ b/chromium/third_party/blink/renderer/modules/payments/payment_request.cc @@ -9,6 +9,7 @@ #include "base/location.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "services/service_manager/public/cpp/interface_provider.h" +#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/public/platform/web_feature.mojom-blink.h" @@ -40,7 +41,7 @@ #include "third_party/blink/renderer/modules/payments/basic_card_helper.h" #include "third_party/blink/renderer/modules/payments/basic_card_request.h" #include "third_party/blink/renderer/modules/payments/html_iframe_element_payments.h" -#include "third_party/blink/renderer/modules/payments/payer_error_fields.h" +#include "third_party/blink/renderer/modules/payments/payer_errors.h" #include "third_party/blink/renderer/modules/payments/payment_address.h" #include "third_party/blink/renderer/modules/payments/payment_details_init.h" #include "third_party/blink/renderer/modules/payments/payment_details_update.h" @@ -52,10 +53,10 @@ #include "third_party/blink/renderer/modules/payments/payments_validators.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" -#include "third_party/blink/renderer/platform/feature_policy/feature_policy.h" #include "third_party/blink/renderer/platform/mojo/mojo_helper.h" #include "third_party/blink/renderer/platform/uuid.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" +#include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" @@ -64,8 +65,8 @@ namespace { using ::payments::mojom::blink::AddressErrors; using ::payments::mojom::blink::AddressErrorsPtr; using ::payments::mojom::blink::CanMakePaymentQueryResult; -using ::payments::mojom::blink::PayerErrorFields; -using ::payments::mojom::blink::PayerErrorFieldsPtr; +using ::payments::mojom::blink::PayerErrors; +using ::payments::mojom::blink::PayerErrorsPtr; using ::payments::mojom::blink::PaymentAddress; using ::payments::mojom::blink::PaymentAddressPtr; using ::payments::mojom::blink::PaymentCurrencyAmount; @@ -149,9 +150,8 @@ struct TypeConverter<PaymentValidationErrorsPtr, const blink::PaymentValidationErrors& input) { PaymentValidationErrorsPtr output = payments::mojom::blink::PaymentValidationErrors::New(); - output->payer = input.hasPayer() - ? PayerErrorFields::From(input.payer()) - : PayerErrorFields::From(blink::PayerErrorFields()); + output->payer = input.hasPayer() ? PayerErrors::From(input.payer()) + : PayerErrors::From(blink::PayerErrors()); output->shipping_address = input.hasShippingAddress() ? AddressErrors::From(input.shippingAddress()) @@ -161,10 +161,9 @@ struct TypeConverter<PaymentValidationErrorsPtr, }; template <> -struct TypeConverter<PayerErrorFieldsPtr, blink::PayerErrorFields> { - static PayerErrorFieldsPtr Convert(const blink::PayerErrorFields& input) { - PayerErrorFieldsPtr output = - payments::mojom::blink::PayerErrorFields::New(); +struct TypeConverter<PayerErrorsPtr, blink::PayerErrors> { + static PayerErrorsPtr Convert(const blink::PayerErrors& input) { + PayerErrorsPtr output = payments::mojom::blink::PayerErrors::New(); output->email = input.hasEmail() ? input.email() : g_empty_string; output->name = input.hasName() ? input.name() : g_empty_string; output->phone = input.hasPhone() ? input.phone() : g_empty_string; @@ -541,6 +540,10 @@ void CountPaymentRequestNetworkNameInSupportedMethod( bool IsValidMethodFormat(const String& identifier) { KURL url(NullURL(), identifier); if (url.IsValid()) { + // Allow localhost payment method for test. + if (SecurityOrigin::Create(url)->IsLocalhost()) + return true; + // URL PMI validation rules: // https://www.w3.org/TR/payment-method-id/#dfn-validate-a-url-based-payment-method-identifier return url.Protocol() == "https" && url.User().IsEmpty() && @@ -675,7 +678,7 @@ void ValidateAndConvertPaymentDetailsUpdate(const PaymentDetailsUpdate& input, return; } - if (input.hasError() && !input.error().IsNull()) { + if (input.hasError()) { String error_message; if (!PaymentsValidators::IsValidErrorMsgFormat(input.error(), &error_message)) { @@ -683,8 +686,18 @@ void ValidateAndConvertPaymentDetailsUpdate(const PaymentDetailsUpdate& input, return; } output->error = input.error(); - } else { - output->error = ""; + } + + if (input.hasShippingAddressErrors()) { + String error_message; + if (!PaymentsValidators::IsValidAddressErrorsFormat( + input.shippingAddressErrors(), &error_message)) { + exception_state.ThrowTypeError(error_message); + return; + } + output->shipping_address_errors = + payments::mojom::blink::AddressErrors::From( + input.shippingAddressErrors()); } } @@ -731,17 +744,19 @@ void ValidateAndConvertPaymentMethodData( } } -bool AllowedToUsePaymentRequest(const Frame* frame) { +bool AllowedToUsePaymentRequest(const ExecutionContext* execution_context) { // To determine whether a Document object |document| is allowed to use the // feature indicated by attribute name |allowpaymentrequest|, run these steps: + // Note: PaymentRequest is only exposed to Window and not workers. // 1. If |document| has no browsing context, then return false. - if (!frame) + const Document* document = To<Document>(execution_context); + if (!document->GetFrame()) return false; // 2. If Feature Policy is enabled, return the policy for "payment" feature. - return frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kPayment, - ReportOptions::kReportOnFailure); + return document->IsFeatureEnabled(mojom::FeaturePolicyFeature::kPayment, + ReportOptions::kReportOnFailure); } void WarnIgnoringQueryQuotaForCanMakePayment( @@ -792,7 +807,7 @@ ScriptPromise PaymentRequest::show(ScriptState* script_state) { // TODO(crbug.com/825270): Reject with SecurityError DOMException if triggered // without user activation. - bool is_user_gesture = Frame::HasTransientUserActivation(GetFrame()); + bool is_user_gesture = LocalFrame::HasTransientUserActivation(GetFrame()); if (!is_user_gesture) { UseCounter::Count(GetExecutionContext(), WebFeature::kPaymentRequestShowWithoutGesture); @@ -1048,7 +1063,7 @@ PaymentRequest::PaymentRequest(ExecutionContext* execution_context, &PaymentRequest::OnCompleteTimeout) { DCHECK(GetExecutionContext()->IsSecureContext()); - if (!AllowedToUsePaymentRequest(GetFrame())) { + if (!AllowedToUsePaymentRequest(execution_context)) { exception_state.ThrowSecurityError( "Must be in a top-level browsing context or an iframe needs to specify " "'allowpaymentrequest' explicitly"); @@ -1152,6 +1167,20 @@ void PaymentRequest::OnShippingOptionChange(const String& shipping_option_id) { } } +void PaymentRequest::OnPayerDetailChange( + payments::mojom::blink::PayerDetailPtr detail) { + DCHECK(payment_response_); + DCHECK(GetPendingAcceptPromiseResolver()); + DCHECK(!complete_resolver_); + + PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::Create( + GetExecutionContext(), EventTypeNames::payerdetailchange); + event->SetTarget(payment_response_); + event->SetPaymentDetailsUpdater(this); + payment_response_->UpdatePayerDetail(std::move(detail)); + payment_response_->DispatchEvent(*event); +} + void PaymentRequest::OnPaymentResponse(PaymentResponsePtr response) { DCHECK(GetPendingAcceptPromiseResolver()); DCHECK(!complete_resolver_); @@ -1184,12 +1213,13 @@ void PaymentRequest::OnPaymentResponse(PaymentResponsePtr response) { } } - if ((options_.requestPayerName() && response->payer_name.IsEmpty()) || - (options_.requestPayerEmail() && response->payer_email.IsEmpty()) || - (options_.requestPayerPhone() && response->payer_phone.IsEmpty()) || - (!options_.requestPayerName() && !response->payer_name.IsNull()) || - (!options_.requestPayerEmail() && !response->payer_email.IsNull()) || - (!options_.requestPayerPhone() && !response->payer_phone.IsNull())) { + DCHECK(response->payer); + if ((options_.requestPayerName() && response->payer->name.IsEmpty()) || + (options_.requestPayerEmail() && response->payer->email.IsEmpty()) || + (options_.requestPayerPhone() && response->payer->phone.IsEmpty()) || + (!options_.requestPayerName() && !response->payer->name.IsNull()) || + (!options_.requestPayerEmail() && !response->payer->email.IsNull()) || + (!options_.requestPayerPhone() && !response->payer->phone.IsNull())) { resolver->Reject(DOMException::Create(DOMExceptionCode::kSyntaxError)); ClearResolversAndCloseMojoConnection(); return; @@ -1199,7 +1229,8 @@ void PaymentRequest::OnPaymentResponse(PaymentResponsePtr response) { if (retry_resolver_) { DCHECK(payment_response_); - payment_response_->Update(std::move(response), shipping_address_.Get()); + payment_response_->Update(retry_resolver_->GetScriptState(), + std::move(response), shipping_address_.Get()); retry_resolver_->Resolve(); // Do not close the mojo connection here. The merchant website should call @@ -1207,7 +1238,8 @@ void PaymentRequest::OnPaymentResponse(PaymentResponsePtr response) { // connection to display a success or failure message to the user. retry_resolver_.Clear(); } else if (accept_resolver_) { - payment_response_ = new PaymentResponse(std::move(response), + payment_response_ = new PaymentResponse(accept_resolver_->GetScriptState(), + std::move(response), shipping_address_.Get(), this, id_); accept_resolver_->Resolve(payment_response_); diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request.h b/chromium/third_party/blink/renderer/modules/payments/payment_request.h index 4a722414604..0b264dc9458 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_request.h +++ b/chromium/third_party/blink/renderer/modules/payments/payment_request.h @@ -71,6 +71,7 @@ class MODULES_EXPORT PaymentRequest final DEFINE_ATTRIBUTE_EVENT_LISTENER(shippingaddresschange); DEFINE_ATTRIBUTE_EVENT_LISTENER(shippingoptionchange); + DEFINE_ATTRIBUTE_EVENT_LISTENER(paymentmethodchange); ScriptPromise canMakePayment(ScriptState*); @@ -116,6 +117,7 @@ class MODULES_EXPORT PaymentRequest final void OnShippingAddressChange( payments::mojom::blink::PaymentAddressPtr) override; void OnShippingOptionChange(const String& shipping_option_id) override; + void OnPayerDetailChange(payments::mojom::blink::PayerDetailPtr) override; void OnPaymentResponse(payments::mojom::blink::PaymentResponsePtr) override; void OnError(payments::mojom::blink::PaymentErrorReason) override; void OnComplete() override; diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request.idl b/chromium/third_party/blink/renderer/modules/payments/payment_request.idl index 41e01295d93..f7837401510 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_request.idl +++ b/chromium/third_party/blink/renderer/modules/payments/payment_request.idl @@ -25,4 +25,5 @@ attribute EventHandler onshippingaddresschange; attribute EventHandler onshippingoptionchange; + [RuntimeEnabled=PaymentMethodChangeEvent] attribute EventHandler onpaymentmethodchange; }; diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request_event.cc b/chromium/third_party/blink/renderer/modules/payments/payment_request_event.cc index a411eb90f26..2b422f7b0ed 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_request_event.cc +++ b/chromium/third_party/blink/renderer/modules/payments/payment_request_event.cc @@ -13,7 +13,6 @@ #include "third_party/blink/renderer/core/workers/worker_location.h" #include "third_party/blink/renderer/modules/service_worker/respond_with_observer.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h" -#include "third_party/blink/renderer/modules/service_worker/service_worker_window_client_callback.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" @@ -104,7 +103,7 @@ ScriptPromise PaymentRequestEvent::openWindow(ScriptState* script_state, context->ConsumeWindowInteraction(); ServiceWorkerGlobalScopeClient::From(context)->OpenWindowForPaymentHandler( - parsed_url_to_open, std::make_unique<NavigateClientCallback>(resolver)); + parsed_url_to_open, resolver); return promise; } diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event.h b/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event.h index 62401d47f3e..27380478aad 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event.h +++ b/chromium/third_party/blink/renderer/modules/payments/payment_request_update_event.h @@ -20,8 +20,8 @@ class ExceptionState; class ExecutionContext; class ScriptState; -class MODULES_EXPORT PaymentRequestUpdateEvent final : public Event, - public PaymentUpdater { +class MODULES_EXPORT PaymentRequestUpdateEvent : public Event, + public PaymentUpdater { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(PaymentRequestUpdateEvent) @@ -47,11 +47,12 @@ class MODULES_EXPORT PaymentRequestUpdateEvent final : public Event, void OnUpdateEventTimeoutForTesting(); - private: + protected: PaymentRequestUpdateEvent(ExecutionContext*, const AtomicString& type, const PaymentRequestUpdateEventInit&); + private: void OnUpdateEventTimeout(TimerBase*); // True after event.updateWith() was called. diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_response.cc b/chromium/third_party/blink/renderer/modules/payments/payment_response.cc index eb6539bba9b..68f5ae9f221 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_response.cc +++ b/chromium/third_party/blink/renderer/modules/payments/payment_response.cc @@ -10,47 +10,82 @@ #include "third_party/blink/renderer/modules/payments/payment_state_resolver.h" #include "third_party/blink/renderer/modules/payments/payment_validation_errors.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" namespace blink { PaymentResponse::PaymentResponse( + ScriptState* script_state, payments::mojom::blink::PaymentResponsePtr response, PaymentAddress* shipping_address, PaymentStateResolver* payment_state_resolver, - const String& requestId) - : requestId_(requestId), + const String& request_id) + : ContextLifecycleObserver(ExecutionContext::From(script_state)), + request_id_(request_id), method_name_(response->method_name), - stringified_details_(response->stringified_details), shipping_address_(shipping_address), shipping_option_(response->shipping_option), - payer_name_(response->payer_name), - payer_email_(response->payer_email), - payer_phone_(response->payer_phone), + payer_name_(response->payer->name), + payer_email_(response->payer->email), + payer_phone_(response->payer->phone), payment_state_resolver_(payment_state_resolver) { DCHECK(payment_state_resolver_); + UpdateDetailsFromJSON(script_state, response->stringified_details); } PaymentResponse::~PaymentResponse() = default; void PaymentResponse::Update( + ScriptState* script_state, payments::mojom::blink::PaymentResponsePtr response, PaymentAddress* shipping_address) { DCHECK(response); + DCHECK(response->payer); method_name_ = response->method_name; - stringified_details_ = response->stringified_details; shipping_address_ = shipping_address; shipping_option_ = response->shipping_option; - payer_name_ = response->payer_name; - payer_email_ = response->payer_email; - payer_phone_ = response->payer_phone; + payer_name_ = response->payer->name; + payer_email_ = response->payer->email; + payer_phone_ = response->payer->phone; + UpdateDetailsFromJSON(script_state, response->stringified_details); +} + +void PaymentResponse::UpdatePayerDetail( + payments::mojom::blink::PayerDetailPtr detail) { + DCHECK(detail); + payer_name_ = detail->name; + payer_email_ = detail->email; + payer_phone_ = detail->phone; +} + +void PaymentResponse::UpdateDetailsFromJSON(ScriptState* script_state, + const String& json) { + ScriptState::Scope scope(script_state); + if (json.IsEmpty()) { + details_ = V8ObjectBuilder(script_state).GetScriptValue(); + return; + } + + ExceptionState exception_state(script_state->GetIsolate(), + ExceptionState::kConstructionContext, + "PaymentResponse"); + v8::Local<v8::Value> parsed_value = + FromJSONString(script_state->GetIsolate(), script_state->GetContext(), + json, exception_state); + if (exception_state.HadException()) { + exception_state.ClearException(); + details_ = V8ObjectBuilder(script_state).GetScriptValue(); + return; + } + details_ = ScriptValue(script_state, parsed_value); } ScriptValue PaymentResponse::toJSONForBinding(ScriptState* script_state) const { V8ObjectBuilder result(script_state); result.AddString("requestId", requestId()); result.AddString("methodName", methodName()); - result.Add("details", details(script_state, ASSERT_NO_EXCEPTION)); + result.Add("details", details(script_state)); if (shippingAddress()) result.Add("shippingAddress", @@ -66,12 +101,8 @@ ScriptValue PaymentResponse::toJSONForBinding(ScriptState* script_state) const { return result.GetScriptValue(); } -ScriptValue PaymentResponse::details(ScriptState* script_state, - ExceptionState& exception_state) const { - return ScriptValue( - script_state, - FromJSONString(script_state->GetIsolate(), script_state->GetContext(), - stringified_details_, exception_state)); +ScriptValue PaymentResponse::details(ScriptState* script_state) const { + return ScriptValue(script_state, details_.V8ValueFor(script_state)); } ScriptPromise PaymentResponse::complete(ScriptState* script_state, @@ -91,10 +122,23 @@ ScriptPromise PaymentResponse::retry( return payment_state_resolver_->Retry(script_state, error_fields); } +bool PaymentResponse::HasPendingActivity() const { + return !!payment_state_resolver_; +} + +const AtomicString& PaymentResponse::InterfaceName() const { + return EventTypeNames::payerdetailchange; +} + +ExecutionContext* PaymentResponse::GetExecutionContext() const { + return ContextLifecycleObserver::GetExecutionContext(); +} + void PaymentResponse::Trace(blink::Visitor* visitor) { visitor->Trace(shipping_address_); visitor->Trace(payment_state_resolver_); - ScriptWrappable::Trace(visitor); + EventTargetWithInlineData::Trace(visitor); + ContextLifecycleObserver::Trace(visitor); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_response.h b/chromium/third_party/blink/renderer/modules/payments/payment_response.h index 7bbef17b997..f20071dc9f7 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_response.h +++ b/chromium/third_party/blink/renderer/modules/payments/payment_response.h @@ -6,8 +6,11 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_RESPONSE_H_ #include "third_party/blink/public/mojom/payments/payment_request.mojom-blink.h" +#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_value.h" +#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" +#include "third_party/blink/renderer/core/dom/events/event_target.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/payments/payment_currency_amount.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" @@ -17,30 +20,38 @@ namespace blink { -class ExceptionState; class PaymentAddress; class PaymentStateResolver; class PaymentValidationErrors; class ScriptState; -class MODULES_EXPORT PaymentResponse final : public ScriptWrappable { +class MODULES_EXPORT PaymentResponse final + : public EventTargetWithInlineData, + public ContextLifecycleObserver, + public ActiveScriptWrappable<PaymentResponse> { DEFINE_WRAPPERTYPEINFO(); + USING_GARBAGE_COLLECTED_MIXIN(PaymentResponse); WTF_MAKE_NONCOPYABLE(PaymentResponse); public: - PaymentResponse(payments::mojom::blink::PaymentResponsePtr, - PaymentAddress* shipping_address_, - PaymentStateResolver*, - const String& requestId); + PaymentResponse(ScriptState* script_state, + payments::mojom::blink::PaymentResponsePtr response, + PaymentAddress* shipping_address, + PaymentStateResolver* payment_state_resolver, + const String& request_id); ~PaymentResponse() override; - void Update(payments::mojom::blink::PaymentResponsePtr, PaymentAddress*); + void Update(ScriptState* script_state, + payments::mojom::blink::PaymentResponsePtr response, + PaymentAddress* shipping_address); + void UpdatePayerDetail(payments::mojom::blink::PayerDetailPtr); + void UpdateDetailsFromJSON(ScriptState* script_state, const String& json); ScriptValue toJSONForBinding(ScriptState*) const; - const String& requestId() const { return requestId_; } + const String& requestId() const { return request_id_; } const String& methodName() const { return method_name_; } - ScriptValue details(ScriptState*, ExceptionState&) const; + ScriptValue details(ScriptState* script_state) const; PaymentAddress* shippingAddress() const { return shipping_address_.Get(); } const String& shippingOption() const { return shipping_option_; } const String& payerName() const { return payer_name_; } @@ -50,12 +61,19 @@ class MODULES_EXPORT PaymentResponse final : public ScriptWrappable { ScriptPromise complete(ScriptState*, const String& result = ""); ScriptPromise retry(ScriptState*, const PaymentValidationErrors&); + bool HasPendingActivity() const override; + + DEFINE_ATTRIBUTE_EVENT_LISTENER(payerdetailchange); + + const AtomicString& InterfaceName() const override; + ExecutionContext* GetExecutionContext() const override; + void Trace(blink::Visitor*) override; private: - String requestId_; + String request_id_; String method_name_; - String stringified_details_; + ScriptValue details_; Member<PaymentAddress> shipping_address_; String shipping_option_; String payer_name_; diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_response.idl b/chromium/third_party/blink/renderer/modules/payments/payment_response.idl index 545ede68953..31096ecec5d 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_response.idl +++ b/chromium/third_party/blink/renderer/modules/payments/payment_response.idl @@ -15,13 +15,14 @@ enum PaymentComplete { [ RuntimeEnabled=PaymentRequest, SecureContext, - Exposed=Window -] interface PaymentResponse { + Exposed=Window, + ActiveScriptWrappable +] interface PaymentResponse : EventTarget { serializer = {attribute}; readonly attribute DOMString requestId; readonly attribute DOMString methodName; - [CallWith=ScriptState, RaisesException] readonly attribute object details; + [CallWith=ScriptState] readonly attribute object details; readonly attribute PaymentAddress? shippingAddress; readonly attribute DOMString? shippingOption; readonly attribute DOMString? payerName; @@ -30,4 +31,6 @@ enum PaymentComplete { [CallWith=ScriptState, NewObject] Promise<void> complete(optional PaymentComplete paymentResult = "unknown"); [CallWith=ScriptState, NewObject, RuntimeEnabled=PaymentRetry] Promise<void> retry(PaymentValidationErrors errorFields); + + [RuntimeEnabled=PaymentRetry] attribute EventHandler onpayerdetailchange; }; diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_response_test.cc b/chromium/third_party/blink/renderer/modules/payments/payment_response_test.cc index 53c12f8a740..5f1b4d99506 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_response_test.cc +++ b/chromium/third_party/blink/renderer/modules/payments/payment_response_test.cc @@ -11,6 +11,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h" #include "third_party/blink/renderer/modules/payments/payment_address.h" #include "third_party/blink/renderer/modules/payments/payment_state_resolver.h" #include "third_party/blink/renderer/modules/payments/payment_test_helper.h" @@ -53,13 +54,14 @@ TEST(PaymentResponseTest, DataCopiedOver) { input->method_name = "foo"; input->stringified_details = "{\"transactionId\": 123}"; input->shipping_option = "standardShippingOption"; - input->payer_name = "Jon Doe"; - input->payer_email = "abc@gmail.com"; - input->payer_phone = "0123"; + input->payer->name = "Jon Doe"; + input->payer->email = "abc@gmail.com"; + input->payer->phone = "0123"; MockPaymentStateResolver* complete_callback = new MockPaymentStateResolver; PaymentResponse* output = - new PaymentResponse(std::move(input), nullptr, complete_callback, "id"); + new PaymentResponse(scope.GetScriptState(), std::move(input), nullptr, + complete_callback, "id"); EXPECT_EQ("foo", output->methodName()); EXPECT_EQ("standardShippingOption", output->shippingOption()); @@ -68,8 +70,7 @@ TEST(PaymentResponseTest, DataCopiedOver) { EXPECT_EQ("0123", output->payerPhone()); EXPECT_EQ("id", output->requestId()); - ScriptValue details = - output->details(scope.GetScriptState(), scope.GetExceptionState()); + ScriptValue details = output->details(scope.GetScriptState()); ASSERT_FALSE(scope.GetExceptionState().HadException()); ASSERT_TRUE(details.V8Value()->IsObject()); @@ -83,19 +84,41 @@ TEST(PaymentResponseTest, DataCopiedOver) { EXPECT_EQ(123, transaction_id.V8Value().As<v8::Number>()->Value()); } -TEST(PaymentResponseTest, PaymentResponseDetailsJSONObject) { +TEST(PaymentResponseTest, + PaymentResponseDetailsWithUnexpectedJSONFormatString) { V8TestingScope scope; payments::mojom::blink::PaymentResponsePtr input = BuildPaymentResponseForTest(); input->stringified_details = "transactionId"; MockPaymentStateResolver* complete_callback = new MockPaymentStateResolver; PaymentResponse* output = - new PaymentResponse(std::move(input), nullptr, complete_callback, "id"); + new PaymentResponse(scope.GetScriptState(), std::move(input), nullptr, + complete_callback, "id"); - ScriptValue details = - output->details(scope.GetScriptState(), scope.GetExceptionState()); + ScriptValue details = output->details(scope.GetScriptState()); + ASSERT_TRUE(details.V8Value()->IsObject()); + + String stringified_details = ToBlinkString<String>( + v8::JSON::Stringify(scope.GetContext(), + details.V8Value().As<v8::Object>()) + .ToLocalChecked(), + kDoNotExternalize); + + EXPECT_EQ("{}", stringified_details); +} - ASSERT_TRUE(scope.GetExceptionState().HadException()); +TEST(PaymentResponseTest, PaymentResponseDetailsRetrunsTheSameObject) { + V8TestingScope scope; + payments::mojom::blink::PaymentResponsePtr input = + BuildPaymentResponseForTest(); + input->method_name = "foo"; + input->stringified_details = "{\"transactionId\": 123}"; + MockPaymentStateResolver* complete_callback = new MockPaymentStateResolver; + PaymentResponse* output = + new PaymentResponse(scope.GetScriptState(), std::move(input), nullptr, + complete_callback, "id"); + EXPECT_EQ(output->details(scope.GetScriptState()), + output->details(scope.GetScriptState())); } TEST(PaymentResponseTest, CompleteCalledWithSuccess) { @@ -106,7 +129,8 @@ TEST(PaymentResponseTest, CompleteCalledWithSuccess) { input->stringified_details = "{\"transactionId\": 123}"; MockPaymentStateResolver* complete_callback = new MockPaymentStateResolver; PaymentResponse* output = - new PaymentResponse(std::move(input), nullptr, complete_callback, "id"); + new PaymentResponse(scope.GetScriptState(), std::move(input), nullptr, + complete_callback, "id"); EXPECT_CALL(*complete_callback, Complete(scope.GetScriptState(), PaymentStateResolver::kSuccess)); @@ -122,7 +146,8 @@ TEST(PaymentResponseTest, CompleteCalledWithFailure) { input->stringified_details = "{\"transactionId\": 123}"; MockPaymentStateResolver* complete_callback = new MockPaymentStateResolver; PaymentResponse* output = - new PaymentResponse(std::move(input), nullptr, complete_callback, "id"); + new PaymentResponse(scope.GetScriptState(), std::move(input), nullptr, + complete_callback, "id"); EXPECT_CALL(*complete_callback, Complete(scope.GetScriptState(), PaymentStateResolver::kFail)); @@ -133,13 +158,13 @@ TEST(PaymentResponseTest, CompleteCalledWithFailure) { TEST(PaymentResponseTest, JSONSerializerTest) { V8TestingScope scope; payments::mojom::blink::PaymentResponsePtr input = - payments::mojom::blink::PaymentResponse::New(); + BuildPaymentResponseForTest(); input->method_name = "foo"; input->stringified_details = "{\"transactionId\": 123}"; input->shipping_option = "standardShippingOption"; - input->payer_email = "abc@gmail.com"; - input->payer_phone = "0123"; - input->payer_name = "Jon Doe"; + input->payer->email = "abc@gmail.com"; + input->payer->phone = "0123"; + input->payer->name = "Jon Doe"; input->shipping_address = payments::mojom::blink::PaymentAddress::New(); input->shipping_address->country = "US"; input->shipping_address->language_code = "en"; @@ -150,8 +175,9 @@ TEST(PaymentResponseTest, JSONSerializerTest) { PaymentAddress* address = new PaymentAddress(std::move(input->shipping_address)); - PaymentResponse* output = new PaymentResponse( - std::move(input), address, new MockPaymentStateResolver, "id"); + PaymentResponse* output = + new PaymentResponse(scope.GetScriptState(), std::move(input), address, + new MockPaymentStateResolver, "id"); ScriptValue json_object = output->toJSONForBinding(scope.GetScriptState()); EXPECT_TRUE(json_object.IsObject()); diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_test_helper.cc b/chromium/third_party/blink/renderer/modules/payments/payment_test_helper.cc index 01b16898ce4..b532619a039 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_test_helper.cc +++ b/chromium/third_party/blink/renderer/modules/payments/payment_test_helper.cc @@ -191,6 +191,7 @@ HeapVector<PaymentMethodData> BuildPaymentMethodDataForTest() { payments::mojom::blink::PaymentResponsePtr BuildPaymentResponseForTest() { payments::mojom::blink::PaymentResponsePtr result = payments::mojom::blink::PaymentResponse::New(); + result->payer = payments::mojom::blink::PayerDetail::New(); return result; } diff --git a/chromium/third_party/blink/renderer/modules/payments/payment_validation_errors.idl b/chromium/third_party/blink/renderer/modules/payments/payment_validation_errors.idl index d25f288226b..518ea1d2dae 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payment_validation_errors.idl +++ b/chromium/third_party/blink/renderer/modules/payments/payment_validation_errors.idl @@ -5,6 +5,6 @@ // https://w3c.github.io/payment-request/#dom-paymentvalidationerrors dictionary PaymentValidationErrors { - PayerErrorFields payer; + PayerErrors payer; AddressErrors shippingAddress; }; diff --git a/chromium/third_party/blink/renderer/modules/payments/payments_validators.cc b/chromium/third_party/blink/renderer/modules/payments/payments_validators.cc index 3b2bdeccca4..467d970f0c1 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payments_validators.cc +++ b/chromium/third_party/blink/renderer/modules/payments/payments_validators.cc @@ -5,6 +5,8 @@ #include "third_party/blink/renderer/modules/payments/payments_validators.h" #include "third_party/blink/renderer/bindings/core/v8/script_regexp.h" +#include "third_party/blink/renderer/modules/payments/address_errors.h" +#include "third_party/blink/renderer/modules/payments/payer_errors.h" #include "third_party/blink/renderer/modules/payments/payment_validation_errors.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/text/string_impl.h" @@ -126,65 +128,60 @@ bool PaymentsValidators::IsValidErrorMsgFormat(const String& error, } // static -bool PaymentsValidators::IsValidPaymentValidationErrorsFormat( - const PaymentValidationErrors& errors, +bool PaymentsValidators::IsValidAddressErrorsFormat( + const AddressErrors& errors, String* optional_error_message) { - if (errors.hasPayer()) { - if ((errors.payer().hasEmail() && - !IsValidErrorMsgFormat(errors.payer().email(), - optional_error_message)) || - (errors.payer().hasName() && - !IsValidErrorMsgFormat(errors.payer().name(), - optional_error_message)) || - (errors.payer().hasPhone() && - !IsValidErrorMsgFormat(errors.payer().phone(), - optional_error_message))) { - return false; - } - } + return (!errors.hasAddressLine() || + IsValidErrorMsgFormat(errors.addressLine(), + optional_error_message)) && + (!errors.hasCity() || + IsValidErrorMsgFormat(errors.city(), optional_error_message)) && + (!errors.hasCountry() || + IsValidErrorMsgFormat(errors.country(), optional_error_message)) && + (!errors.hasDependentLocality() || + IsValidErrorMsgFormat(errors.dependentLocality(), + optional_error_message)) && + (!errors.hasLanguageCode() || + IsValidErrorMsgFormat(errors.languageCode(), + optional_error_message)) && + (!errors.hasOrganization() || + IsValidErrorMsgFormat(errors.organization(), + optional_error_message)) && + (!errors.hasPhone() || + IsValidErrorMsgFormat(errors.phone(), optional_error_message)) && + (!errors.hasPostalCode() || + IsValidErrorMsgFormat(errors.postalCode(), optional_error_message)) && + (!errors.hasRecipient() || + IsValidErrorMsgFormat(errors.recipient(), optional_error_message)) && + (!errors.hasRegion() || + IsValidErrorMsgFormat(errors.region(), optional_error_message)) && + (!errors.hasRegionCode() || + IsValidErrorMsgFormat(errors.regionCode(), optional_error_message)) && + (!errors.hasSortingCode() || + IsValidErrorMsgFormat(errors.sortingCode(), optional_error_message)); +} - if (errors.hasShippingAddress()) { - if ((errors.shippingAddress().hasAddressLine() && - !IsValidErrorMsgFormat(errors.shippingAddress().addressLine(), - optional_error_message)) || - (errors.shippingAddress().hasCity() && - !IsValidErrorMsgFormat(errors.shippingAddress().city(), - optional_error_message)) || - (errors.shippingAddress().hasCountry() && - !IsValidErrorMsgFormat(errors.shippingAddress().country(), - optional_error_message)) || - (errors.shippingAddress().hasDependentLocality() && - !IsValidErrorMsgFormat(errors.shippingAddress().dependentLocality(), - optional_error_message)) || - (errors.shippingAddress().hasLanguageCode() && - !IsValidErrorMsgFormat(errors.shippingAddress().languageCode(), - optional_error_message)) || - (errors.shippingAddress().hasOrganization() && - !IsValidErrorMsgFormat(errors.shippingAddress().organization(), - optional_error_message)) || - (errors.shippingAddress().hasPhone() && - !IsValidErrorMsgFormat(errors.shippingAddress().phone(), - optional_error_message)) || - (errors.shippingAddress().hasPostalCode() && - !IsValidErrorMsgFormat(errors.shippingAddress().postalCode(), - optional_error_message)) || - (errors.shippingAddress().hasRecipient() && - !IsValidErrorMsgFormat(errors.shippingAddress().recipient(), - optional_error_message)) || - (errors.shippingAddress().hasRegion() && - !IsValidErrorMsgFormat(errors.shippingAddress().region(), - optional_error_message)) || - (errors.shippingAddress().hasRegionCode() && - !IsValidErrorMsgFormat(errors.shippingAddress().regionCode(), - optional_error_message)) || - (errors.shippingAddress().hasSortingCode() && - !IsValidErrorMsgFormat(errors.shippingAddress().sortingCode(), - optional_error_message))) { - return false; - } - } +// static +bool PaymentsValidators::IsValidPayerErrorsFormat( + const PayerErrors& errors, + String* optional_error_message) { + return (!errors.hasEmail() || + IsValidErrorMsgFormat(errors.email(), optional_error_message)) && + (!errors.hasName() || + IsValidErrorMsgFormat(errors.name(), optional_error_message)) && + (!errors.hasPhone() || + IsValidErrorMsgFormat(errors.phone(), optional_error_message)); +} - return true; +// static +bool PaymentsValidators::IsValidPaymentValidationErrorsFormat( + const PaymentValidationErrors& errors, + String* optional_error_message) { + return (!errors.hasPayer() || + IsValidPayerErrorsFormat(errors.payer(), optional_error_message)) && + (!errors.hasShippingAddress() || + IsValidAddressErrorsFormat(errors.shippingAddress(), + optional_error_message)); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/payments/payments_validators.h b/chromium/third_party/blink/renderer/modules/payments/payments_validators.h index c9c2f86f38e..1a7d384165b 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payments_validators.h +++ b/chromium/third_party/blink/renderer/modules/payments/payments_validators.h @@ -12,6 +12,8 @@ namespace blink { +class AddressErrors; +class PayerErrors; class PaymentValidationErrors; class MODULES_EXPORT PaymentsValidators final { @@ -54,8 +56,15 @@ class MODULES_EXPORT PaymentsValidators final { static bool IsValidErrorMsgFormat(const String& code, String* optional_error_message); - // Returns false if |payment_validation_errors| has too long string (greater - // than 2048). + // Returns false if |errors| has too long string (greater than 2048). + static bool IsValidAddressErrorsFormat(const AddressErrors& errors, + String* optional_error_message); + + // Returns false if |errors| has too long string (greater than 2048). + static bool IsValidPayerErrorsFormat(const PayerErrors& errors, + String* optional_error_message); + + // Returns false if |errors| has too long string (greater than 2048). static bool IsValidPaymentValidationErrorsFormat( const PaymentValidationErrors& errors, String* optional_error_message); diff --git a/chromium/third_party/blink/renderer/modules/payments/payments_validators_test.cc b/chromium/third_party/blink/renderer/modules/payments/payments_validators_test.cc index 3f2928c34da..431c7751226 100644 --- a/chromium/third_party/blink/renderer/modules/payments/payments_validators_test.cc +++ b/chromium/third_party/blink/renderer/modules/payments/payments_validators_test.cc @@ -296,7 +296,7 @@ PaymentValidationErrors toPaymentValidationErrors( ValidationErrorsTestCase test_case) { PaymentValidationErrors errors; - PayerErrorFields payer; + PayerErrors payer; payer.setEmail(test_case.m_payer_email); payer.setName(test_case.m_payer_name); payer.setPhone(test_case.m_payer_phone); diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn b/chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn index 70eb3421216..0592dce010e 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/peerconnection/BUILD.gn @@ -6,10 +6,32 @@ import("//third_party/blink/renderer/modules/modules.gni") blink_modules_sources("peerconnection") { sources = [ + "adapters/ice_transport_adapter.h", + "adapters/ice_transport_adapter_cross_thread_factory.h", + "adapters/ice_transport_adapter_impl.cc", + "adapters/ice_transport_adapter_impl.h", "adapters/ice_transport_host.cc", "adapters/ice_transport_host.h", "adapters/ice_transport_proxy.cc", "adapters/ice_transport_proxy.h", + "adapters/p2p_quic_packet_transport.h", + "adapters/p2p_quic_stream.h", + "adapters/p2p_quic_stream_impl.cc", + "adapters/p2p_quic_stream_impl.h", + "adapters/p2p_quic_transport.h", + "adapters/p2p_quic_transport_factory.h", + "adapters/p2p_quic_transport_factory_impl.cc", + "adapters/p2p_quic_transport_factory_impl.h", + "adapters/p2p_quic_transport_impl.cc", + "adapters/p2p_quic_transport_impl.h", + "adapters/quic_stream_host.cc", + "adapters/quic_stream_host.h", + "adapters/quic_stream_proxy.cc", + "adapters/quic_stream_proxy.h", + "adapters/quic_transport_host.cc", + "adapters/quic_transport_host.h", + "adapters/quic_transport_proxy.cc", + "adapters/quic_transport_proxy.h", "adapters/web_rtc_cross_thread_copier.cc", "adapters/web_rtc_cross_thread_copier.h", "rtc_certificate.cc", @@ -36,6 +58,8 @@ blink_modules_sources("peerconnection") { "rtc_peer_connection_ice_event.h", "rtc_quic_stream.cc", "rtc_quic_stream.h", + "rtc_quic_stream_event.cc", + "rtc_quic_stream_event.h", "rtc_quic_transport.cc", "rtc_quic_transport.h", "rtc_rtp_contributing_source.cc", diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/DEPS b/chromium/third_party/blink/renderer/modules/peerconnection/DEPS index 1e08706b174..8fe2aa371f2 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/DEPS +++ b/chromium/third_party/blink/renderer/modules/peerconnection/DEPS @@ -7,4 +7,8 @@ include_rules = [ "+third_party/blink/renderer/modules/mediastream", "+third_party/blink/renderer/modules/modules_export.h", "+third_party/blink/renderer/modules/peerconnection", + "+net/third_party/quic", + "+net/quic/chromium", + "+net/quic", + "+net/test", ] diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h new file mode 100644 index 00000000000..77354113979 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h @@ -0,0 +1,89 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_ADAPTER_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_ADAPTER_H_ + +#include "third_party/webrtc/p2p/base/p2ptransportchannel.h" + +namespace blink { + +class P2PQuicPacketTransport; + +// Defines the ICE candidate policy the browser uses to surface the permitted +// candidates to the application. +// https://w3c.github.io/webrtc-pc/#dom-rtcicetransportpolicy +enum class IceTransportPolicy { + // The ICE Agent uses only media relay candidates. + kRelay, + // The ICE Agent can use any type of candidate. + kAll +}; + +// The IceTransportAdapter is the API used by the RTCIceTransport Blink binding +// to interact with the ICE implementation. It exactly mirrors the requirements +// of the RTCIceTransport: each JavaScript method that must interact with the +// ICE implementation should map to exactly one method call on this interface. +// This interface is designed to be fully asynchronous; all methods are void and +// callbacks occur via the Delegate (implemented by the client). +// +// The ICE Agent is immediately active once this object has been constructed. It +// can be stopped by deleting the IceTransportAdapter. +class IceTransportAdapter { + public: + // Delegate to receive callbacks from the IceTransportAdapter. The Delegate + // must outlive the IceTransportAdapter. + class Delegate { + public: + virtual ~Delegate() = default; + + // Called asynchronously when the ICE gathering state changes. + virtual void OnGatheringStateChanged(cricket::IceGatheringState new_state) { + } + + // Called asynchronously when a new ICE candidate has been gathered. + virtual void OnCandidateGathered(const cricket::Candidate& candidate) {} + + // Called asynchronously when the ICE connection state has changed. + virtual void OnStateChanged(cricket::IceTransportState new_state) {} + + // Called asynchronously when the ICE agent selects a different candidate + // pair for the active connection. + virtual void OnSelectedCandidatePairChanged( + const std::pair<cricket::Candidate, cricket::Candidate>& + selected_candidate_pair) {} + }; + + virtual ~IceTransportAdapter() = default; + + // Start ICE candidate gathering. + virtual void StartGathering( + const cricket::IceParameters& local_parameters, + const cricket::ServerAddresses& stun_servers, + const std::vector<cricket::RelayServerConfig>& turn_servers, + IceTransportPolicy policy) = 0; + + // Start ICE connectivity checks with the given initial remote candidates. + virtual void Start( + const cricket::IceParameters& remote_parameters, + cricket::IceRole role, + const std::vector<cricket::Candidate>& initial_remote_candidates) = 0; + + // Handle a remote ICE restart. This changes the remote parameters and clears + // all remote candidates. + virtual void HandleRemoteRestart( + const cricket::IceParameters& new_remote_parameters) = 0; + + // Adds a remote candidate to potentially start connectivity checks with. + // The caller must ensure Start() has already bene called. + virtual void AddRemoteCandidate(const cricket::Candidate& candidate) = 0; + + // Gets a P2PQuicPacketTransport that is backed by this ICE connection. The + // returned instance lives the same lifetime as the IceTransportAdapter. + virtual P2PQuicPacketTransport* packet_transport() const = 0; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_ADAPTER_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_cross_thread_factory.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_cross_thread_factory.h new file mode 100644 index 00000000000..8d5f51e72cf --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_cross_thread_factory.h @@ -0,0 +1,32 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_ADAPTER_CROSS_THREAD_FACTORY_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_ADAPTER_CROSS_THREAD_FACTORY_H_ + +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h" + +namespace blink { + +// This class creates a single concrete instance of an IceTransportAdapter with +// a hook to allow creating dependencies on the main thread (the +// IceTransportAdapter is created on the worker thread). +// +// Callers must call InitializeOnMainThread() before ConstructOnWorkerThread(). +class IceTransportAdapterCrossThreadFactory { + public: + virtual ~IceTransportAdapterCrossThreadFactory() = default; + + // Construct any dependencies on the main thread. Can only be called once. + virtual void InitializeOnMainThread() = 0; + + // Construct the IceTransportAdapter instance with the given delegate. Can + // only be called once. + virtual std::unique_ptr<IceTransportAdapter> ConstructOnWorkerThread( + IceTransportAdapter::Delegate* delegate) = 0; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_ADAPTER_CROSS_THREAD_FACTORY_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc new file mode 100644 index 00000000000..9b0eb52ca30 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc @@ -0,0 +1,218 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h" + +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h" + +namespace blink { +namespace { + +// Implementation of P2PQuicPacketTransport backed by a P2PTransportChannel. +class QuicPacketTransportAdapter : public P2PQuicPacketTransport, + public sigslot::has_slots<> { + public: + QuicPacketTransportAdapter( + cricket::P2PTransportChannel* p2p_transport_channel) + : p2p_transport_channel_(p2p_transport_channel) { + DCHECK(p2p_transport_channel_); + p2p_transport_channel_->SignalReadPacket.connect( + this, &QuicPacketTransportAdapter::OnReadPacket); + p2p_transport_channel_->SignalWritableState.connect( + this, &QuicPacketTransportAdapter::OnWritableState); + } + + ~QuicPacketTransportAdapter() override { + // Caller is responsible for unsetting the write observer and receive + // delegate before destroying this. + DCHECK(!write_observer_); + DCHECK(!receive_delegate_); + } + + int WritePacket(const QuicPacket& packet) override { + rtc::PacketOptions options; + options.packet_id = packet.packet_number; + int flags = 0; + return p2p_transport_channel_->SendPacket(packet.buffer, packet.buf_len, + options, flags); + } + + void SetReceiveDelegate(ReceiveDelegate* receive_delegate) override { + receive_delegate_ = receive_delegate; + } + + void SetWriteObserver(WriteObserver* write_observer) override { + write_observer_ = write_observer; + } + + bool Writable() override { return p2p_transport_channel_->writable(); } + + private: + // P2PTransportChannel callbacks. + void OnReadPacket(rtc::PacketTransportInternal* packet_transport, + const char* buffer, + size_t buffer_length, + const rtc::PacketTime& packet_time, + int flags) { + DCHECK_EQ(packet_transport, p2p_transport_channel_); + if (!receive_delegate_) { + // TODO(crbug.com/874296): Consider providing a small buffer. + return; + } + receive_delegate_->OnPacketDataReceived(buffer, buffer_length); + } + void OnWritableState(rtc::PacketTransportInternal* packet_transport) { + DCHECK_EQ(packet_transport, p2p_transport_channel_); + if (!write_observer_) { + return; + } + if (p2p_transport_channel_->writable()) { + write_observer_->OnCanWrite(); + } + } + + cricket::P2PTransportChannel* p2p_transport_channel_; + ReceiveDelegate* receive_delegate_ = nullptr; + WriteObserver* write_observer_ = nullptr; +}; + +} // namespace + +IceTransportAdapterImpl::IceTransportAdapterImpl( + Delegate* delegate, + std::unique_ptr<cricket::PortAllocator> port_allocator, + rtc::Thread* thread) + : delegate_(delegate), port_allocator_(std::move(port_allocator)) { + // TODO(bugs.webrtc.org/9419): Remove once WebRTC can be built as a component. + if (!rtc::ThreadManager::Instance()->CurrentThread()) { + rtc::ThreadManager::Instance()->SetCurrentThread(thread); + } + + // These settings are copied from PeerConnection: + // https://codesearch.chromium.org/chromium/src/third_party/webrtc/pc/peerconnection.cc?l=4708&rcl=820ebd0f661696043959b5105b2814e0edd8b694 + port_allocator_->set_step_delay(cricket::kMinimumStepDelay); + port_allocator_->set_flags(port_allocator_->flags() | + cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET | + cricket::PORTALLOCATOR_ENABLE_IPV6 | + cricket::PORTALLOCATOR_ENABLE_IPV6_ON_WIFI); + port_allocator_->Initialize(); + + p2p_transport_channel_ = std::make_unique<cricket::P2PTransportChannel>( + "", 0, port_allocator_.get()); + p2p_transport_channel_->SignalGatheringState.connect( + this, &IceTransportAdapterImpl::OnGatheringStateChanged); + p2p_transport_channel_->SignalCandidateGathered.connect( + this, &IceTransportAdapterImpl::OnCandidateGathered); + p2p_transport_channel_->SignalStateChanged.connect( + this, &IceTransportAdapterImpl::OnStateChanged); + p2p_transport_channel_->SignalNetworkRouteChanged.connect( + this, &IceTransportAdapterImpl::OnNetworkRouteChanged); + // We need to set the ICE role even before Start is called since the Port + // assumes that the role has been set before receiving incoming connectivity + // checks. These checks can race with the information signaled for Start. + p2p_transport_channel_->SetIceRole(cricket::ICEROLE_CONTROLLING); + // The ICE tiebreaker is used to determine which side is controlling/ + // controlled when both sides start in the same role. The number is randomly + // generated so that each peer can calculate a.tiebreaker <= b.tiebreaker + // consistently. + p2p_transport_channel_->SetIceTiebreaker(rtc::CreateRandomId64()); + quic_packet_transport_adapter_ = std::make_unique<QuicPacketTransportAdapter>( + p2p_transport_channel_.get()); +} + +IceTransportAdapterImpl::~IceTransportAdapterImpl() = default; + +static uint32_t GetCandidateFilterForPolicy(IceTransportPolicy policy) { + switch (policy) { + case IceTransportPolicy::kRelay: + return cricket::CF_RELAY; + case IceTransportPolicy::kAll: + return cricket::CF_ALL; + } + NOTREACHED(); + return 0; +} + +void IceTransportAdapterImpl::StartGathering( + const cricket::IceParameters& local_parameters, + const cricket::ServerAddresses& stun_servers, + const std::vector<cricket::RelayServerConfig>& turn_servers, + IceTransportPolicy policy) { + port_allocator_->set_candidate_filter(GetCandidateFilterForPolicy(policy)); + port_allocator_->SetConfiguration(stun_servers, turn_servers, + port_allocator_->candidate_pool_size(), + port_allocator_->prune_turn_ports()); + + p2p_transport_channel_->SetIceParameters(local_parameters); + p2p_transport_channel_->MaybeStartGathering(); + DCHECK_EQ(p2p_transport_channel_->gathering_state(), + cricket::kIceGatheringGathering); +} + +void IceTransportAdapterImpl::Start( + const cricket::IceParameters& remote_parameters, + cricket::IceRole role, + const std::vector<cricket::Candidate>& initial_remote_candidates) { + p2p_transport_channel_->SetRemoteIceParameters(remote_parameters); + p2p_transport_channel_->SetIceRole(role); + for (const auto& candidate : initial_remote_candidates) { + p2p_transport_channel_->AddRemoteCandidate(candidate); + } +} + +void IceTransportAdapterImpl::HandleRemoteRestart( + const cricket::IceParameters& new_remote_parameters) { + auto remote_candidates = p2p_transport_channel_->remote_candidates(); + for (const auto& remote_candidate : remote_candidates) { + p2p_transport_channel_->RemoveRemoteCandidate(remote_candidate); + } + p2p_transport_channel_->SetRemoteIceParameters(new_remote_parameters); +} + +void IceTransportAdapterImpl::AddRemoteCandidate( + const cricket::Candidate& candidate) { + p2p_transport_channel_->AddRemoteCandidate(candidate); +} + +P2PQuicPacketTransport* IceTransportAdapterImpl::packet_transport() const { + return quic_packet_transport_adapter_.get(); +} + +void IceTransportAdapterImpl::OnGatheringStateChanged( + cricket::IceTransportInternal* transport) { + DCHECK_EQ(transport, p2p_transport_channel_.get()); + delegate_->OnGatheringStateChanged(p2p_transport_channel_->gathering_state()); +} + +void IceTransportAdapterImpl::OnCandidateGathered( + cricket::IceTransportInternal* transport, + const cricket::Candidate& candidate) { + DCHECK_EQ(transport, p2p_transport_channel_.get()); + delegate_->OnCandidateGathered(candidate); +} + +void IceTransportAdapterImpl::OnStateChanged( + cricket::IceTransportInternal* transport) { + DCHECK_EQ(transport, p2p_transport_channel_.get()); + delegate_->OnStateChanged(p2p_transport_channel_->GetState()); +} + +void IceTransportAdapterImpl::OnNetworkRouteChanged( + absl::optional<rtc::NetworkRoute> new_network_route) { + const cricket::CandidatePairInterface* selected_connection = + p2p_transport_channel_->selected_connection(); + if (!selected_connection) { + // The selected connection will only be null if the ICE connection has + // totally failed, at which point we'll get a StateChanged signal. The + // client will implicitly clear the selected candidate pair when it receives + // the failed state change, so we don't need to give an explicit callback + // here. + return; + } + delegate_->OnSelectedCandidatePairChanged( + std::make_pair(selected_connection->local_candidate(), + selected_connection->remote_candidate())); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h new file mode 100644 index 00000000000..0b92df88e9a --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h @@ -0,0 +1,59 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_ADAPTER_IMPL_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_ADAPTER_IMPL_H_ + +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h" + +namespace blink { + +// IceTransportAdapter implementation backed by the WebRTC PortAllocator / +// P2PTransportChannel. +class IceTransportAdapterImpl final : public IceTransportAdapter, + public sigslot::has_slots<> { + public: + // Must be constructed on the WebRTC worker thread. + // |delegate| must outlive the IceTransportAdapter. + // |thread| should be the rtc::Thread instance associated with the WebRTC + // worker thread. + IceTransportAdapterImpl( + Delegate* delegate, + std::unique_ptr<cricket::PortAllocator> port_allocator, + rtc::Thread* thread); + ~IceTransportAdapterImpl() override; + + // IceTransportAdapter overrides. + void StartGathering( + const cricket::IceParameters& local_parameters, + const cricket::ServerAddresses& stun_servers, + const std::vector<cricket::RelayServerConfig>& turn_servers, + IceTransportPolicy policy) override; + void Start(const cricket::IceParameters& remote_parameters, + cricket::IceRole role, + const std::vector<cricket::Candidate>& initial_remote_candidates) + override; + void HandleRemoteRestart( + const cricket::IceParameters& new_remote_parameters) override; + void AddRemoteCandidate(const cricket::Candidate& candidate) override; + P2PQuicPacketTransport* packet_transport() const override; + + private: + // Callbacks from P2PTransportChannel. + void OnGatheringStateChanged(cricket::IceTransportInternal* transport); + void OnCandidateGathered(cricket::IceTransportInternal* transport, + const cricket::Candidate& candidate); + void OnStateChanged(cricket::IceTransportInternal* transport); + void OnNetworkRouteChanged( + absl::optional<rtc::NetworkRoute> new_network_route); + + Delegate* const delegate_; + std::unique_ptr<cricket::PortAllocator> port_allocator_; + std::unique_ptr<cricket::P2PTransportChannel> p2p_transport_channel_; + std::unique_ptr<P2PQuicPacketTransport> quic_packet_transport_adapter_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_ADAPTER_IMPL_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.cc index 34ce669362c..5860ed120ed 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.cc +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.cc @@ -4,6 +4,7 @@ #include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h" #include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h" #include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h" #include "third_party/blink/renderer/platform/cross_thread_functional.h" @@ -13,117 +14,124 @@ namespace blink { IceTransportHost::IceTransportHost( scoped_refptr<base::SingleThreadTaskRunner> proxy_thread, - base::WeakPtr<IceTransportProxy> proxy, - std::unique_ptr<cricket::PortAllocator> port_allocator) + scoped_refptr<base::SingleThreadTaskRunner> host_thread, + base::WeakPtr<IceTransportProxy> proxy) : proxy_thread_(std::move(proxy_thread)), - port_allocator_(std::move(port_allocator)), + host_thread_(std::move(host_thread)), proxy_(std::move(proxy)) { DETACH_FROM_THREAD(thread_checker_); DCHECK(proxy_thread_); + DCHECK(host_thread_); DCHECK(proxy_); - DCHECK(port_allocator_); } IceTransportHost::~IceTransportHost() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!HasConsumer()); } -void IceTransportHost::Initialize(rtc::Thread* host_thread_rtc_thread) { +void IceTransportHost::Initialize( + std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - // TODO(bugs.webrtc.org/9419): Remove once WebRTC can be built as a component. - if (!rtc::ThreadManager::Instance()->CurrentThread()) { - rtc::ThreadManager::Instance()->SetCurrentThread(host_thread_rtc_thread); - } - // These settings are copied from PeerConnection: - // https://codesearch.chromium.org/chromium/src/third_party/webrtc/pc/peerconnection.cc?l=4708&rcl=820ebd0f661696043959b5105b2814e0edd8b694 - port_allocator_->set_step_delay(cricket::kMinimumStepDelay); - port_allocator_->set_flags(port_allocator_->flags() | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET | - cricket::PORTALLOCATOR_ENABLE_IPV6 | - cricket::PORTALLOCATOR_ENABLE_IPV6_ON_WIFI); - port_allocator_->Initialize(); - transport_ = std::make_unique<cricket::P2PTransportChannel>( - "", 0, port_allocator_.get()); - transport_->SignalGatheringState.connect( - this, &IceTransportHost::OnGatheringStateChanged); - transport_->SignalCandidateGathered.connect( - this, &IceTransportHost::OnCandidateGathered); - transport_->SignalStateChanged.connect(this, - &IceTransportHost::OnStateChanged); - // The ICE tiebreaker is used to determine which side is controlling/ - // controlled when both sides start in the same role. The number is randomly - // generated so that each peer can calculate a.tiebreaker <= b.tiebreaker - // consistently. - transport_->SetIceTiebreaker(rtc::CreateRandomId64()); + DCHECK(adapter_factory); + transport_ = adapter_factory->ConstructOnWorkerThread(this); +} + +scoped_refptr<base::SingleThreadTaskRunner> IceTransportHost::proxy_thread() + const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return proxy_thread_; +} + +scoped_refptr<base::SingleThreadTaskRunner> IceTransportHost::host_thread() + const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return host_thread_; } void IceTransportHost::StartGathering( const cricket::IceParameters& local_parameters, const cricket::ServerAddresses& stun_servers, const std::vector<cricket::RelayServerConfig>& turn_servers, - int32_t candidate_filter) { + IceTransportPolicy policy) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - port_allocator_->set_candidate_filter(candidate_filter); - port_allocator_->SetConfiguration(stun_servers, turn_servers, - port_allocator_->candidate_pool_size(), - port_allocator_->prune_turn_ports()); - - transport_->SetIceParameters(local_parameters); - transport_->MaybeStartGathering(); - DCHECK_EQ(transport_->gathering_state(), cricket::kIceGatheringGathering); + transport_->StartGathering(local_parameters, stun_servers, turn_servers, + policy); } -void IceTransportHost::SetRole(cricket::IceRole role) { +void IceTransportHost::Start( + const cricket::IceParameters& remote_parameters, + cricket::IceRole role, + const std::vector<cricket::Candidate>& initial_remote_candidates) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - transport_->SetIceRole(role); + transport_->Start(remote_parameters, role, initial_remote_candidates); } -void IceTransportHost::SetRemoteParameters( - const cricket::IceParameters& remote_parameters) { +void IceTransportHost::HandleRemoteRestart( + const cricket::IceParameters& new_remote_parameters) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - transport_->SetRemoteIceParameters(remote_parameters); + transport_->HandleRemoteRestart(new_remote_parameters); } void IceTransportHost::AddRemoteCandidate(const cricket::Candidate& candidate) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); transport_->AddRemoteCandidate(candidate); + +} + +bool IceTransportHost::HasConsumer() const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return consumer_host_; } -void IceTransportHost::ClearRemoteCandidates() { +IceTransportAdapter* IceTransportHost::ConnectConsumer( + QuicTransportHost* consumer_host) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - auto remote_candidates = transport_->remote_candidates(); - for (const auto& remote_candidate : remote_candidates) { - transport_->RemoveRemoteCandidate(remote_candidate); - } + DCHECK(consumer_host); + DCHECK(!consumer_host_); + consumer_host_ = consumer_host; + return transport_.get(); +} + +void IceTransportHost::DisconnectConsumer(QuicTransportHost* consumer_host) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(consumer_host); + DCHECK_EQ(consumer_host, consumer_host_); + consumer_host_ = nullptr; } void IceTransportHost::OnGatheringStateChanged( - cricket::IceTransportInternal* transport) { + cricket::IceGatheringState new_state) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK_EQ(transport, transport_.get()); PostCrossThreadTask( *proxy_thread_, FROM_HERE, CrossThreadBind(&IceTransportProxy::OnGatheringStateChanged, proxy_, - transport_->gathering_state())); + new_state)); } void IceTransportHost::OnCandidateGathered( - cricket::IceTransportInternal* transport, const cricket::Candidate& candidate) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK_EQ(transport, transport_.get()); PostCrossThreadTask(*proxy_thread_, FROM_HERE, CrossThreadBind(&IceTransportProxy::OnCandidateGathered, proxy_, candidate)); } -void IceTransportHost::OnStateChanged( - cricket::IceTransportInternal* transport) { +void IceTransportHost::OnStateChanged(cricket::IceTransportState new_state) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK_EQ(transport, transport_.get()); - PostCrossThreadTask(*proxy_thread_, FROM_HERE, - CrossThreadBind(&IceTransportProxy::OnStateChanged, - proxy_, transport_->GetState())); + PostCrossThreadTask( + *proxy_thread_, FROM_HERE, + CrossThreadBind(&IceTransportProxy::OnStateChanged, proxy_, new_state)); +} + +void IceTransportHost::OnSelectedCandidatePairChanged( + const std::pair<cricket::Candidate, cricket::Candidate>& + selected_candidate_pair) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + PostCrossThreadTask( + *proxy_thread_, FROM_HERE, + CrossThreadBind(&IceTransportProxy::OnSelectedCandidatePairChanged, + proxy_, selected_candidate_pair)); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.h index 094130d2e91..9f78111ace8 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.h +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.h @@ -9,15 +9,13 @@ #include "base/memory/weak_ptr.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_checker.h" -#include "third_party/webrtc/p2p/base/p2ptransportchannel.h" - -namespace rtc { -class Thread; -} +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_cross_thread_factory.h" namespace blink { class IceTransportProxy; +class QuicTransportHost; // This class is the host side correspondent to the IceTransportProxy. See the // IceTransportProxy documentation for background. This class lives on the host @@ -41,38 +39,53 @@ class IceTransportProxy; // // The Host can be constructed on any thread but after that point all methods // must be called on the host thread. -class IceTransportHost final : public sigslot::has_slots<> { +class IceTransportHost final : public IceTransportAdapter::Delegate { public: IceTransportHost(scoped_refptr<base::SingleThreadTaskRunner> proxy_thread, - base::WeakPtr<IceTransportProxy> proxy, - std::unique_ptr<cricket::PortAllocator> port_allocator); + scoped_refptr<base::SingleThreadTaskRunner> host_thread, + base::WeakPtr<IceTransportProxy> proxy); ~IceTransportHost() override; - void Initialize(rtc::Thread* host_thread_rtc_thread); + void Initialize( + std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory); + + scoped_refptr<base::SingleThreadTaskRunner> proxy_thread() const; + scoped_refptr<base::SingleThreadTaskRunner> host_thread() const; void StartGathering( const cricket::IceParameters& local_parameters, const cricket::ServerAddresses& stun_servers, const std::vector<cricket::RelayServerConfig>& turn_servers, - int32_t candidate_filter); - - void SetRole(cricket::IceRole role); - void SetRemoteParameters(const cricket::IceParameters& remote_parameters); - + IceTransportPolicy policy); + void Start(const cricket::IceParameters& remote_parameters, + cricket::IceRole role, + const std::vector<cricket::Candidate>& initial_remote_candidates); + void HandleRemoteRestart(const cricket::IceParameters& new_remote_parameters); void AddRemoteCandidate(const cricket::Candidate& candidate); - void ClearRemoteCandidates(); + + // A QuicTransportHost can be connected to this IceTransportHost. Only one can + // be connected at a time, and the caller must ensure that the consumer is + // disconnected before destroying the IceTransportHost. + // ConnectConsumer returns an implementation of IceTransportAdapter that + // should only be used on the host thread. + bool HasConsumer() const; + IceTransportAdapter* ConnectConsumer(QuicTransportHost* consumer_host); + void DisconnectConsumer(QuicTransportHost* consumer_host); private: - // Callbacks from P2PTransportChannel. - void OnGatheringStateChanged(cricket::IceTransportInternal* transport); - void OnCandidateGathered(cricket::IceTransportInternal* transport, - const cricket::Candidate& candidate); - void OnStateChanged(cricket::IceTransportInternal* transport); + // IceTransportAdapter::Delegate overrides. + void OnGatheringStateChanged(cricket::IceGatheringState new_state) override; + void OnCandidateGathered(const cricket::Candidate& candidate) override; + void OnStateChanged(cricket::IceTransportState new_state) override; + void OnSelectedCandidatePairChanged( + const std::pair<cricket::Candidate, cricket::Candidate>& + selected_candidate_pair) override; const scoped_refptr<base::SingleThreadTaskRunner> proxy_thread_; - std::unique_ptr<cricket::PortAllocator> port_allocator_; - std::unique_ptr<cricket::P2PTransportChannel> transport_; + const scoped_refptr<base::SingleThreadTaskRunner> host_thread_; + std::unique_ptr<IceTransportAdapter> transport_; base::WeakPtr<IceTransportProxy> proxy_; + QuicTransportHost* consumer_host_ = nullptr; THREAD_CHECKER(thread_checker_); }; diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc index a8ab2c4e151..b1463372d2e 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc @@ -13,11 +13,12 @@ namespace blink { IceTransportProxy::IceTransportProxy( FrameScheduler* frame_scheduler, + scoped_refptr<base::SingleThreadTaskRunner> proxy_thread, scoped_refptr<base::SingleThreadTaskRunner> host_thread, - rtc::Thread* host_thread_rtc_thread, Delegate* delegate, - std::unique_ptr<cricket::PortAllocator> port_allocator) - : host_thread_(std::move(host_thread)), + std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory) + : proxy_thread_(std::move(proxy_thread)), + host_thread_(std::move(host_thread)), host_(nullptr, base::OnTaskRunnerDeleter(host_thread_)), delegate_(delegate), connection_handle_for_scheduler_( @@ -25,55 +26,71 @@ IceTransportProxy::IceTransportProxy( weak_ptr_factory_(this) { DCHECK(host_thread_); DCHECK(delegate_); - scoped_refptr<base::SingleThreadTaskRunner> proxy_thread = - frame_scheduler->GetTaskRunner(TaskType::kNetworking); - DCHECK(proxy_thread->BelongsToCurrentThread()); + DCHECK(adapter_factory); + DCHECK(proxy_thread_->BelongsToCurrentThread()); + adapter_factory->InitializeOnMainThread(); // Wait to initialize the host until the weak_ptr_factory_ is initialized. // The IceTransportHost is constructed on the proxy thread but should only be // interacted with via PostTask to the host thread. The OnTaskRunnerDeleter // (configured above) will ensure it gets deleted on the host thread. - host_.reset(new IceTransportHost(proxy_thread, weak_ptr_factory_.GetWeakPtr(), - std::move(port_allocator))); - PostCrossThreadTask( - *host_thread_, FROM_HERE, - CrossThreadBind(&IceTransportHost::Initialize, - CrossThreadUnretained(host_.get()), - CrossThreadUnretained(host_thread_rtc_thread))); + host_.reset(new IceTransportHost(proxy_thread_, host_thread_, + weak_ptr_factory_.GetWeakPtr())); + PostCrossThreadTask(*host_thread_, FROM_HERE, + CrossThreadBind(&IceTransportHost::Initialize, + CrossThreadUnretained(host_.get()), + WTF::Passed(std::move(adapter_factory)))); } IceTransportProxy::~IceTransportProxy() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!HasConsumer()); // Note: The IceTransportHost will be deleted on the host thread. } +scoped_refptr<base::SingleThreadTaskRunner> IceTransportProxy::proxy_thread() + const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return proxy_thread_; +} + +scoped_refptr<base::SingleThreadTaskRunner> IceTransportProxy::host_thread() + const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return host_thread_; +} + void IceTransportProxy::StartGathering( const cricket::IceParameters& local_parameters, const cricket::ServerAddresses& stun_servers, const std::vector<cricket::RelayServerConfig>& turn_servers, - int32_t candidate_filter) { + IceTransportPolicy policy) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); PostCrossThreadTask( *host_thread_, FROM_HERE, CrossThreadBind(&IceTransportHost::StartGathering, CrossThreadUnretained(host_.get()), local_parameters, - stun_servers, turn_servers, candidate_filter)); + stun_servers, turn_servers, policy)); } -void IceTransportProxy::SetRole(cricket::IceRole role) { +void IceTransportProxy::Start( + const cricket::IceParameters& remote_parameters, + cricket::IceRole role, + const std::vector<cricket::Candidate>& initial_remote_candidates) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); PostCrossThreadTask( *host_thread_, FROM_HERE, - CrossThreadBind(&IceTransportHost::SetRole, - CrossThreadUnretained(host_.get()), role)); + CrossThreadBind(&IceTransportHost::Start, + CrossThreadUnretained(host_.get()), remote_parameters, + role, initial_remote_candidates)); } -void IceTransportProxy::SetRemoteParameters( - const cricket::IceParameters& remote_parameters) { +void IceTransportProxy::HandleRemoteRestart( + const cricket::IceParameters& new_remote_parameters) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - PostCrossThreadTask( - *host_thread_, FROM_HERE, - CrossThreadBind(&IceTransportHost::SetRemoteParameters, - CrossThreadUnretained(host_.get()), remote_parameters)); + PostCrossThreadTask(*host_thread_, FROM_HERE, + CrossThreadBind(&IceTransportHost::HandleRemoteRestart, + CrossThreadUnretained(host_.get()), + new_remote_parameters)); } void IceTransportProxy::AddRemoteCandidate( @@ -85,11 +102,25 @@ void IceTransportProxy::AddRemoteCandidate( CrossThreadUnretained(host_.get()), candidate)); } -void IceTransportProxy::ClearRemoteCandidates() { +bool IceTransportProxy::HasConsumer() const { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - PostCrossThreadTask(*host_thread_, FROM_HERE, - CrossThreadBind(&IceTransportHost::ClearRemoteCandidates, - CrossThreadUnretained(host_.get()))); + return consumer_proxy_; +} + +IceTransportHost* IceTransportProxy::ConnectConsumer( + QuicTransportProxy* consumer_proxy) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(consumer_proxy); + DCHECK(!consumer_proxy_); + consumer_proxy_ = consumer_proxy; + return host_.get(); +} + +void IceTransportProxy::DisconnectConsumer(QuicTransportProxy* consumer_proxy) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(consumer_proxy); + DCHECK_EQ(consumer_proxy, consumer_proxy_); + consumer_proxy_ = nullptr; } void IceTransportProxy::OnGatheringStateChanged( @@ -109,4 +140,11 @@ void IceTransportProxy::OnStateChanged(cricket::IceTransportState new_state) { delegate_->OnStateChanged(new_state); } +void IceTransportProxy::OnSelectedCandidatePairChanged( + const std::pair<cricket::Candidate, cricket::Candidate>& + selected_candidate_pair) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + delegate_->OnSelectedCandidatePairChanged(selected_candidate_pair); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h index 10b3f33c286..d10b8666da0 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h @@ -9,6 +9,8 @@ #include "base/memory/weak_ptr.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_checker.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_cross_thread_factory.h" #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" #include "third_party/webrtc/p2p/base/p2ptransportchannel.h" @@ -19,6 +21,7 @@ class Thread; namespace blink { class IceTransportHost; +class QuicTransportProxy; // This class allows the ICE implementation (P2PTransportChannel) to run on a // thread different from the thread from which it is controlled. All @@ -47,30 +50,46 @@ class IceTransportProxy final { } virtual void OnCandidateGathered(const cricket::Candidate& candidate) {} virtual void OnStateChanged(cricket::IceTransportState new_state) {} + virtual void OnSelectedCandidatePairChanged( + const std::pair<cricket::Candidate, cricket::Candidate>& + selected_candidate_pair) {} }; // Construct a Proxy with the underlying ICE implementation running on the // given host thread and callbacks serviced by the given delegate. // The P2PTransportChannel will be created with the given PortAllocator. // The delegate must outlive the IceTransportProxy. - IceTransportProxy(FrameScheduler* frame_scheduler, - scoped_refptr<base::SingleThreadTaskRunner> host_thread, - rtc::Thread* host_thread_rtc_thread, - Delegate* delegate, - std::unique_ptr<cricket::PortAllocator> port_allocator); + IceTransportProxy( + FrameScheduler* frame_scheduler, + scoped_refptr<base::SingleThreadTaskRunner> proxy_thread, + scoped_refptr<base::SingleThreadTaskRunner> host_thread, + Delegate* delegate, + std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory); ~IceTransportProxy(); + scoped_refptr<base::SingleThreadTaskRunner> proxy_thread() const; + scoped_refptr<base::SingleThreadTaskRunner> host_thread() const; + + // These methods are proxied to an IceTransportAdapter instance. void StartGathering( const cricket::IceParameters& local_parameters, const cricket::ServerAddresses& stun_servers, const std::vector<cricket::RelayServerConfig>& turn_servers, - int32_t candidate_filter); - - void SetRole(cricket::IceRole role); - void SetRemoteParameters(const cricket::IceParameters& remote_parameters); - + IceTransportPolicy policy); + void Start(const cricket::IceParameters& remote_parameters, + cricket::IceRole role, + const std::vector<cricket::Candidate>& initial_remote_candidates); + void HandleRemoteRestart(const cricket::IceParameters& new_remote_parameters); void AddRemoteCandidate(const cricket::Candidate& candidate); - void ClearRemoteCandidates(); + + // A QuicTransportProxy can be connected to this IceTransportProxy. Only one + // can be connected at a time, and the caller must ensure that the consumer + // is disconnected before destroying the IceTransportProxy. + // ConnectConsumer returns an IceTransportHost that can be used to connect + // a QuicTransportHost. + bool HasConsumer() const; + IceTransportHost* ConnectConsumer(QuicTransportProxy* consumer_proxy); + void DisconnectConsumer(QuicTransportProxy* consumer_proxy); private: // Callbacks from RTCIceTransportHost. @@ -78,12 +97,17 @@ class IceTransportProxy final { void OnGatheringStateChanged(cricket::IceGatheringState new_state); void OnCandidateGathered(const cricket::Candidate& candidate); void OnStateChanged(cricket::IceTransportState new_state); + void OnSelectedCandidatePairChanged( + const std::pair<cricket::Candidate, cricket::Candidate>& + selected_candidate_pair); + const scoped_refptr<base::SingleThreadTaskRunner> proxy_thread_; const scoped_refptr<base::SingleThreadTaskRunner> host_thread_; // Since the Host is deleted on the host thread (via OnTaskRunnerDeleter), as // long as this is alive it is safe to post tasks to it (using unretained). std::unique_ptr<IceTransportHost, base::OnTaskRunnerDeleter> host_; Delegate* const delegate_; + QuicTransportProxy* consumer_proxy_ = nullptr; // This handle notifies scheduler about an active connection associated // with a frame. Handle should be destroyed when connection is closed. diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h new file mode 100644 index 00000000000..b9b76fe5f72 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h @@ -0,0 +1,69 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_PACKET_TRANSPORT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_PACKET_TRANSPORT_H_ + +#include "net/third_party/quic/core/quic_packet_writer.h" +#include "net/third_party/quic/core/quic_types.h" +#include "net/third_party/quic/platform/api/quic_export.h" + +namespace blink { + +// This is the interface for the underlying packet transport used by the +// P2PQuicTransport for receiving and writing data. The standard +// implementation of this interface uses an ICE transport. +// +// This object should be run entirely on the webrtc worker thread. +class P2PQuicPacketTransport { + public: + // This is subclassed by the P2PQuicTransport so that it can receive incoming + // data. The standard case is for this to be the P2PQuicTransport. + // The P2PQuicPacketTransport will outlive the ReceiveDelegate. + class ReceiveDelegate { + public: + virtual ~ReceiveDelegate() = default; + virtual void OnPacketDataReceived(const char* data, size_t data_len) = 0; + }; + + // This is subclassed by the Writer, so that it is aware when the + // P2PQuicPacketTransport is ready to write data. The + // P2PQuicPacketTransport will outlive the WriteObserver. + class WriteObserver { + public: + virtual ~WriteObserver() = default; + virtual void OnCanWrite() = 0; + }; + + struct QuicPacket { + // This is taken from the quic::QuicConnection, and 0 means that it is not + // set. Packet numbers are used to provide metadata to the implementation of + // the P2PQuicPacketTransport, but this number is not used by the QUIC + // library itself. + quic::QuicPacketNumber packet_number; + const char* buffer; + size_t buf_len; + }; + + virtual ~P2PQuicPacketTransport() = default; + + // Called by the P2PQuicPacketWriter (in quic_transport_factory_impl.cc) when + // writing QUIC packets to the network. Return the number of written bytes. + // Return 0 if the write is blocked. + virtual int WritePacket(const QuicPacket& packet) = 0; + // Sets the ReceiveDelegate for receiving packets. + // Since the ReceiveDelegate has a shorter lifetime than the + // P2PQuicPacketTransport, it must unset itself upon destruction. + virtual void SetReceiveDelegate(ReceiveDelegate* receive_delegate) = 0; + // Sets the WriteObserver for obsererving when it can write to the + // P2PQuicPacketTransport. Since the WriteObserver has a shorter lifetime than + // the P2PQuicPacketTransport, it must unset itself upon destruction. + virtual void SetWriteObserver(WriteObserver* write_observer) = 0; + // Returns true if the P2PQuicPacketTransport can write. + virtual bool Writable() = 0; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_PACKET_TRANSPORT_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h new file mode 100644 index 00000000000..a7ae56f2261 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h @@ -0,0 +1,65 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_STREAM_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_STREAM_H_ + +namespace blink { + +// The bidirectional QUIC stream object to be used by the RTCQuicStream Web +// API. See: https://w3c.github.io/webrtc-quic/#quicstream* +// +// Lifetime: The P2PQuicStream is owned by the P2PQuicTransport, and can be +// deleted after the stream is closed for reading and writing. This can happen +// in 3 ways: 1) OnRemoteReset has been fired. 2) Calling Reset(). 3) Both +// Finish() has been called and OnRemoteFinish has been fired. +class P2PQuicStream { + public: + // Receives callbacks for receiving RST_STREAM frames or a STREAM_FRAME with + // the FIN bit set. The Delegate should be subclassed by an object that can + // post the task to the main JS thread. The delegate's lifetime should outlive + // this P2PQuicStream. + class Delegate { + public: + virtual ~Delegate() {} + + // Called when the stream receives a RST_STREAM frame from the remote side. + // This means the stream is closed and can no longer read or write, and is + // deleted by the quic::QuicSession. + virtual void OnRemoteReset() {} + + // Called when the P2PQuicStream has consumed all incoming data from the + // remote side up to the FIN bit. Consuming means that the data is marked + // as consumed by quic::QuicStreamSequencer, but the data has not + // necessarily been read by the application. If the stream has already + // finished writing, then upon consuming the FIN bit the stream can no + // longer read or write and is deleted by the quic::QuicSession. + virtual void OnRemoteFinish() {} + }; + + // Sends a RST_STREAM frame to the remote side. This closes the P2PQuicStream + // for reading & writing and it will be deleted by the quic::QuicSession. When + // the remote side receives the RST_STREAM frame it will close the stream for + // reading and writing and send a RST_STREAM frame back. Calling Reset() will + // not trigger OnRemoteReset to be called locally when the RST_STREAM frame is + // received from the remote side, because the local stream is already closed. + virtual void Reset() = 0; + + // Sends a stream frame with the FIN bit set, which notifies the remote side + // that this stream is done writing. The stream can no longer write after + // calling this function. If the stream has already received a FIN bit, this + // will close the stream for reading & writing and it will be deleted by the + // quic::QuicSession. + virtual void Finish() = 0; + + // Sets the delegate object, which must outlive the P2PQuicStream. + virtual void SetDelegate(Delegate* delegate) = 0; + + // TODO:(https://crbug.com/874296): Create functions for reading and writing, + // specifically for waitForReadable/waitForWriteable. +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_STREAM_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.cc new file mode 100644 index 00000000000..ce6c4f4fda4 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.cc @@ -0,0 +1,66 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h" + +#include "net/third_party/quic/core/quic_error_codes.h" + +namespace blink { + +P2PQuicStreamImpl::P2PQuicStreamImpl(quic::QuicStreamId id, + quic::QuicSession* session) + : quic::QuicStream(id, session, /*is_static=*/false, quic::BIDIRECTIONAL) {} + +P2PQuicStreamImpl::~P2PQuicStreamImpl() {} + +void P2PQuicStreamImpl::OnDataAvailable() { + // We just drop the data by marking all data as immediately consumed. + sequencer()->MarkConsumed(sequencer()->ReadableBytes()); + if (sequencer()->IsClosed()) { + // This means all data has been consumed up to the FIN bit. + OnFinRead(); + } +} + +void P2PQuicStreamImpl::Reset() { + if (rst_sent()) { + // No need to reset twice. This could have already been sent as consequence + // of receiving a RST_STREAM frame. + return; + } + quic::QuicStream::Reset(quic::QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED); +} + +void P2PQuicStreamImpl::Finish() { + // Should never call Finish twice. + DCHECK(!fin_sent()); + quic::QuicStream::WriteOrBufferData("", /*fin=*/true, nullptr); +} + +void P2PQuicStreamImpl::SetDelegate(P2PQuicStream::Delegate* delegate) { + delegate_ = delegate; +} + +void P2PQuicStreamImpl::OnStreamReset(const quic::QuicRstStreamFrame& frame) { + // TODO(https://crbug.com/874296): If we get an incoming stream we need to + // make sure that the delegate is set before we have incoming data. + DCHECK(delegate_); + // Calling this on the QuicStream will ensure that the stream is closed + // for reading and writing and we send a RST frame to the remote side if + // we have not already. + quic::QuicStream::OnStreamReset(frame); + delegate_->OnRemoteReset(); +} + +void P2PQuicStreamImpl::OnFinRead() { + // TODO(https://crbug.com/874296): If we get an incoming stream we need to + // make sure that the delegate is set before we have incoming data. + DCHECK(delegate_); + // Calling this on the QuicStream ensures that the stream is closed + // for reading. + quic::QuicStream::OnFinRead(); + delegate_->OnRemoteFinish(); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h new file mode 100644 index 00000000000..81cb68d02d0 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h @@ -0,0 +1,57 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_STREAM_IMPL_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_STREAM_IMPL_H_ + +#include "net/third_party/quic/core/quic_session.h" +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h" + +namespace blink { + +class MODULES_EXPORT P2PQuicStreamImpl final : public P2PQuicStream, + public quic::QuicStream { + public: + P2PQuicStreamImpl(quic::QuicStreamId id, quic::QuicSession* session); + ~P2PQuicStreamImpl() override; + + // QuicStream overrides. + // + // Right now this marks the data as consumed and drops it. + // TODO(https://crbug.com/874296): We need to update this function for + // reading and consuming data properly while the main JavaScript thread is + // busy. See: + // https://w3c.github.io/webrtc-quic/#dom-rtcquicstream-waitforreadable + void OnDataAvailable() override; + + // P2PQuicStream overrides + void SetDelegate(P2PQuicStream::Delegate* delegate) override; + + void Reset() override; + + void Finish() override; + + // quic::QuicStream overrides + // + // Called by the quic::QuicSession when receiving a RST_STREAM frame from the + // remote side. This closes the stream for reading & writing (if not already + // closed), and sends a RST_STREAM frame if one has not been sent yet. + void OnStreamReset(const quic::QuicRstStreamFrame& frame) override; + + // Called when the stream has finished consumed data up to the FIN bit from + // the quic::QuicStreamSequencer. This will close the underlying QuicStream + // for reading. This can be called either by the P2PQuicStreamImpl when + // reading data, or by the quic::QuicStreamSequencer if we're done reading & + // receive a stream frame with the FIN bit. + void OnFinRead() override; + + private: + using quic::QuicStream::Reset; + Delegate* delegate_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_STREAM_IMPL_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h new file mode 100644 index 00000000000..ace4820ebcf --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h @@ -0,0 +1,77 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_H_ + +#include "third_party/webrtc/rtc_base/sslfingerprint.h" + +namespace blink { + +class P2PQuicStream; + +// Used by the RTCQuicTransport Web API. This transport creates and manages +// streams, handles negotiation, state changes and errors. Every +// P2PQuicTransport function maps directly to a method in the RTCQuicTransport +// Web API, i.e. RTCQuicTransport::stop() --> +// P2PQuicTransport::Stop(). This allows posting just one task across +// thread boundaries to execute a function. +// +// This object should be run entirely on the webrtc worker thread. +class P2PQuicTransport { + public: + // Used for receiving callbacks from the P2PQuicTransport regarding QUIC + // connection changes, handshake success/failures and new QuicStreams being + // added from the remote side. + class Delegate { + public: + virtual ~Delegate() = default; + // Called when receiving a close frame from the remote side, due to + // calling P2PQuicTransport::Stop(). + virtual void OnRemoteStopped() {} + // Called when the connection is closed due to a QUIC error. This can happen + // locally by the framer, or remotely by the peer. + virtual void OnConnectionFailed(const std::string& error_details, + bool from_remote) {} + // Called when the crypto handshake has completed and fingerprints have been + // verified. + virtual void OnConnected() {} + + // Called when an incoming stream is received from the remote side. This + // stream is owned by the P2PQuicTransport. Its lifetime is managed by the + // P2PQuicTransport, and can be deleted when: + // - The P2PQuicStream becomes closed for reading and writing. + // - Stop() is called. + // - The P2PQuicTransport is deleted. + virtual void OnStream(P2PQuicStream* stream) {} + }; + + virtual ~P2PQuicTransport() = default; + + // Closes the QuicConnection and sends a close frame to the remote side. + // This will trigger P2PQuicTransport::Delegate::OnRemoteClosed() on the + // remote side. + virtual void Stop() = 0; + + // Starts the QUIC handshake negotiation and sets the remote fingerprints + // that were signaled through a secure channel. These fingerprints are used to + // verify the self signed remote certificate used in the QUIC handshake. See: + // https://w3c.github.io/webrtc-quic/#quic-transport* + virtual void Start(std::vector<std::unique_ptr<rtc::SSLFingerprint>> + remote_fingerprints) = 0; + + // Creates a new outgoing stream. This stream is owned by the + // P2PQuicTransport. Its lifetime is managed by the P2PQuicTransport, + // and can be deleted when: + // - The P2PQuicStream becomes closed for reading and writing. + // - Stop() is called. + // - The P2PQuicTransport is deleted. + virtual P2PQuicStream* CreateStream() = 0; + + // TODO(https://crbug.com/874296): Consider adding a getter for the + // local fingerprints of the certificate(s) set in the constructor. +}; +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h new file mode 100644 index 00000000000..a6c67feb4d8 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h @@ -0,0 +1,73 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_FACTORY_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_FACTORY_H_ + +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h" +#include "third_party/webrtc/rtc_base/rtccertificate.h" +#include "third_party/webrtc/rtc_base/scoped_ref_ptr.h" + +namespace blink { + +// A simple config object for creating a P2PQuicTransport. It's constructor +// guarantees that the required objects for creating a P2PQuicTransport are part +// of the P2PQuicTransportConfig. +struct P2PQuicTransportConfig final { + // This object is only moveable. + explicit P2PQuicTransportConfig( + P2PQuicTransport::Delegate* const delegate_in, + P2PQuicPacketTransport* const packet_transport_in, + const std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> + certificates_in) + : packet_transport(packet_transport_in), + certificates(certificates_in), + delegate(delegate_in) { + DCHECK_GT(certificates.size(), 0u); + DCHECK(packet_transport); + DCHECK(delegate); + } + P2PQuicTransportConfig(const P2PQuicTransportConfig&) = delete; + P2PQuicTransportConfig& operator=(const P2PQuicTransportConfig&) = delete; + P2PQuicTransportConfig(P2PQuicTransportConfig&&) = default; + P2PQuicTransportConfig& operator=(P2PQuicTransportConfig&&) = delete; + ~P2PQuicTransportConfig() = default; + + // The standard case is an ICE transport. It's lifetime will be managed by + // the ICE transport objects and outlive the P2PQuicTransport. + P2PQuicPacketTransport* const packet_transport; + bool is_server = true; + // The certificates are owned by the P2PQuicTransport. These come from + // blink::RTCCertificates: https://www.w3.org/TR/webrtc/#dom-rtccertificate + const std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> certificates; + // Mandatory for creating a P2PQuicTransport and must outlive + // the P2PQuicTransport. In the standard case the |delegate_| will be + // the object that owns the P2PQuicTransport. + P2PQuicTransport::Delegate* const delegate; + // When set to true the P2PQuicTransport will immediately be able + // to listen and respond to a crypto handshake upon construction. + // This will NOT start a handshake. + bool can_respond_to_crypto_handshake = true; +}; + +// For creating a P2PQuicTransport. This factory should be injected into +// whichever object plans to own and use a P2PQuicTransport. The +// P2PQuicTransportFactory needs to outlive the P2PQuicTransport it creates. +// +// This object should be run entirely on the webrtc worker thread. +class P2PQuicTransportFactory { + public: + virtual ~P2PQuicTransportFactory() = default; + + // Creates the P2PQuicTransport. This should be called on the same + // thread that the P2PQuicTransport will be used on. + virtual std::unique_ptr<P2PQuicTransport> CreateQuicTransport( + P2PQuicTransportConfig config) = 0; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_FACTORY_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc new file mode 100644 index 00000000000..73e4c3a649a --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc @@ -0,0 +1,194 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h" +#include "net/third_party/quic/core/quic_packet_writer.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h" +#include "third_party/webrtc/rtc_base/rtccertificate.h" + +namespace blink { + +namespace { + +// The P2PQuicPacketWriter is a private helper class that implements the +// QuicPacketWriter using a P2PQuicPacketTransport. This allows us to +// connect our own packet transport for writing into the QuicConnection. +// The normal case is using an ICE transport (packet_transport) for writing. +class P2PQuicPacketWriter : public quic::QuicPacketWriter, + public P2PQuicPacketTransport::WriteObserver { + public: + P2PQuicPacketWriter(P2PQuicPacketTransport* packet_transport) + : packet_transport_(packet_transport) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(packet_transport_); + packet_transport_->SetWriteObserver(this); + } + + // This way the packet transport knows it no longer has a write observer and + // can DCHECK this on destruction. + ~P2PQuicPacketWriter() override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + packet_transport_->SetWriteObserver(nullptr); + } + + // Sets the QuicConnection (which owns this packet writer). This allows us + // to get the packet numbers of QUIC packets we write. The QuicConnection + // is created with a quic::QuicPacketWriter, so we can't set the connection + // in the constructor. + void InitializeWithQuicConnection(quic::QuicConnection* connection) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(connection); + if (packet_transport_->Writable()) { + SetWritable(); + } + connection_ = connection; + } + + // quic::QuicPacketWriter overrides. + + // Writes a QUIC packet to the network with the packet number as additional + // packet info. + quic::WriteResult WritePacket(const char* buffer, + size_t buf_len, + const quic::QuicIpAddress& self_address, + const quic::QuicSocketAddress& peer_address, + quic::PerPacketOptions* options) override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(connection_); + if (IsWriteBlocked()) { + return quic::WriteResult(quic::WRITE_STATUS_BLOCKED, EWOULDBLOCK); + } + + P2PQuicPacketTransport::QuicPacket packet; + packet.packet_number = connection_->packet_generator().packet_number(); + packet.buffer = buffer; + packet.buf_len = buf_len; + int bytes_written = packet_transport_->WritePacket(packet); + if (bytes_written <= 0) { + writable_ = false; + return quic::WriteResult(quic::WRITE_STATUS_BLOCKED, EWOULDBLOCK); + } + return quic::WriteResult(quic::WRITE_STATUS_OK, bytes_written); + } + + bool IsWriteBlockedDataBuffered() const override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return false; + } + + bool IsWriteBlocked() const override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return !writable_; + } + + quic::QuicByteCount GetMaxPacketSize( + const quic::QuicSocketAddress& peer_address) const override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + // This can be configured later. + return 1200; + } + + void SetWritable() override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + writable_ = true; + } + + bool SupportsReleaseTime() const override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return false; + } + + bool IsBatchMode() const override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return false; + } + + char* GetNextWriteLocation( + const quic::QuicIpAddress& self_address, + const quic::QuicSocketAddress& peer_address) override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return nullptr; + } + + quic::WriteResult Flush() override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return quic::WriteResult(quic::WRITE_STATUS_OK, 0); + } + + // P2PQuicPacketTransport::WriteDelegate override. + void OnCanWrite() override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + SetWritable(); + connection_->OnCanWrite(); + } + + private: + // The packet transport is owned by the P2PQuicSession, not the + // BlinkPacketWriter. + P2PQuicPacketTransport* packet_transport_; + // The QuicConnection owns this packet writer and will outlive it. + quic::QuicConnection* connection_; + + bool writable_ = false; + THREAD_CHECKER(thread_checker_); +}; + +// Creates the QuicConnection for the QuicSession. Currently this connection +// uses a dummy address and ID. The |packet_writer| is a basic implementation +// using the QuicTransportConfig::packet_transport for writing. The |helper| +// and |alarm_factory| should be chromium specific implementations. +std::unique_ptr<quic::QuicConnection> CreateQuicConnection( + bool is_server, + quic::QuicConnectionHelperInterface* helper, + quic::QuicPacketWriter* packet_writer, + quic::QuicAlarmFactory* alarm_factory) { + quic::QuicIpAddress ip; + ip.FromString("0.0.0.0"); + quic::QuicSocketAddress dummy_address(ip, 0 /* Port */); + quic::Perspective perspective = + is_server ? quic::Perspective::IS_SERVER : quic::Perspective::IS_CLIENT; + return std::make_unique<quic::QuicConnection>( + 0 /* dummy ID */, dummy_address, helper, alarm_factory, packet_writer, + /* owns_writer */ true, perspective, quic::CurrentSupportedVersions()); +} +} // namespace + +P2PQuicTransportFactoryImpl::P2PQuicTransportFactoryImpl( + quic::QuicClock* clock, + std::unique_ptr<quic::QuicAlarmFactory> alarm_factory) + : clock_(clock), alarm_factory_(std::move(alarm_factory)) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +} + +// The P2PQuicTransportImpl is created with Chromium specific QUIC objects: +// QuicClock, QuicRandom, QuicConnectionHelper and QuicAlarmFactory. +std::unique_ptr<P2PQuicTransport> +P2PQuicTransportFactoryImpl::CreateQuicTransport( + P2PQuicTransportConfig config) { + DCHECK(config.packet_transport); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + quic::QuicRandom* quic_random = quic::QuicRandom::GetInstance(); + // The P2PQuicSession owns these chromium specific objects required + // by the QuicConnection. These outlive the QuicConnection itself. + std::unique_ptr<net::QuicChromiumConnectionHelper> helper = + std::make_unique<net::QuicChromiumConnectionHelper>(clock_, quic_random); + + P2PQuicPacketWriter* packet_writer = + new P2PQuicPacketWriter(config.packet_transport); + std::unique_ptr<quic::QuicConnection> quic_connection = CreateQuicConnection( + config.is_server, helper.get(), packet_writer, alarm_factory_.get()); + // It's okay for the quic::QuicConnection to have a P2PQuicPacketWriter before + // the P2PQuicPacketWriter is initialized, because the P2QuicPacketWriter + // won't be writable until this occurs. + packet_writer->InitializeWithQuicConnection(quic_connection.get()); + + // QUIC configurations for the session are specified here. + quic::QuicConfig quic_config; + return std::make_unique<P2PQuicTransportImpl>( + std::move(config), std::move(helper), std::move(quic_connection), + quic_config, clock_); +} +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h new file mode 100644 index 00000000000..6bc83546ab8 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h @@ -0,0 +1,43 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_FACTORY_IMPL_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_FACTORY_IMPL_H_ + +#include "net/third_party/quic/core/quic_connection.h" +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h" + +namespace blink { + +// For creating a P2PQuicTransportImpl to be used for the blink Web API - +// RTCQuicTransport. +// +// This object should be run entirely on the webrtc worker thread. +class MODULES_EXPORT P2PQuicTransportFactoryImpl final + : public P2PQuicTransportFactory { + public: + P2PQuicTransportFactoryImpl( + quic::QuicClock* clock, + std::unique_ptr<quic::QuicAlarmFactory> alarm_factory); + ~P2PQuicTransportFactoryImpl() override {} + + // QuicTransportFactoryInterface override. + std::unique_ptr<P2PQuicTransport> CreateQuicTransport( + P2PQuicTransportConfig config) override; + + private: + // This is used to create a QuicChromiumConnectionHelper for the session. + // Should outlive the P2PQuicTransportFactoryImpl. + quic::QuicClock* clock_; + // Used for alarms that drive the underlying QUIC library. Should use the same + // clock as |clock_|. + std::unique_ptr<quic::QuicAlarmFactory> alarm_factory_; + THREAD_CHECKER(thread_checker_); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_FACTORY_IMPL_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc new file mode 100644 index 00000000000..fe216c251e0 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc @@ -0,0 +1,355 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h" + +#include "net/quic/quic_chromium_connection_helper.h" +#include "net/third_party/quic/core/crypto/proof_source.h" +#include "net/third_party/quic/core/crypto/quic_random.h" +#include "net/third_party/quic/core/quic_config.h" +#include "net/third_party/quic/core/tls_client_handshaker.h" +#include "net/third_party/quic/core/tls_server_handshaker.h" +#include "net/third_party/quic/tools/quic_simple_crypto_server_stream_helper.h" + +namespace blink { + +namespace { + +static const char kClosingDetails[] = "Application closed connection."; +static const size_t kHostnameLength = 32; + +// TODO(https://crbug.com/874300): Create a secure connection by implementing a +// P2PProofSource and P2PProofVerifier and remove these once the TLS 1.3 +// handshake is implemented for QUIC. This will allow us to verify for both the +// server and client: +// - The self signed certificate fingerprint matches the remote +// fingerprint that was signaled. +// - The peer owns the certificate, by verifying the signature of the hash of +// the handshake context. +// +// Used by QuicCryptoServerConfig to provide dummy proof credentials +// (taken from quic/quartc). +class DummyProofSource : public quic::ProofSource { + public: + DummyProofSource() {} + ~DummyProofSource() override {} + + // ProofSource override. + void GetProof(const quic::QuicSocketAddress& server_addr, + const quic::QuicString& hostname, + const quic::QuicString& server_config, + quic::QuicTransportVersion transport_version, + quic::QuicStringPiece chlo_hash, + std::unique_ptr<Callback> callback) override { + quic::QuicReferenceCountedPointer<ProofSource::Chain> chain; + quic::QuicCryptoProof proof; + std::vector<quic::QuicString> certs; + certs.push_back("Dummy cert"); + chain = new ProofSource::Chain(certs); + proof.signature = "Dummy signature"; + proof.leaf_cert_scts = "Dummy timestamp"; + callback->Run(true, chain, proof, nullptr /* details */); + } + + quic::QuicReferenceCountedPointer<Chain> GetCertChain( + const quic::QuicSocketAddress& server_address, + const quic::QuicString& hostname) override { + return quic::QuicReferenceCountedPointer<Chain>(); + } + + void ComputeTlsSignature( + const quic::QuicSocketAddress& server_address, + const quic::QuicString& hostname, + uint16_t signature_algorithm, + quic::QuicStringPiece in, + std::unique_ptr<SignatureCallback> callback) override { + callback->Run(true, "Dummy signature"); + } +}; + +// Used by QuicCryptoClientConfig to ignore the peer's credentials +// and establish an insecure QUIC connection (taken from quic/quartc). +class InsecureProofVerifier : public quic::ProofVerifier { + public: + InsecureProofVerifier() {} + ~InsecureProofVerifier() override {} + + // ProofVerifier override. + quic::QuicAsyncStatus VerifyProof( + const quic::QuicString& hostname, + const uint16_t port, + const quic::QuicString& server_config, + quic::QuicTransportVersion transport_version, + quic::QuicStringPiece chlo_hash, + const std::vector<quic::QuicString>& certs, + const quic::QuicString& cert_sct, + const quic::QuicString& signature, + const quic::ProofVerifyContext* context, + quic::QuicString* error_details, + std::unique_ptr<quic::ProofVerifyDetails>* verify_details, + std::unique_ptr<quic::ProofVerifierCallback> callback) override { + return quic::QUIC_SUCCESS; + } + + quic::QuicAsyncStatus VerifyCertChain( + const quic::QuicString& hostname, + const std::vector<quic::QuicString>& certs, + const quic::ProofVerifyContext* context, + quic::QuicString* error_details, + std::unique_ptr<quic::ProofVerifyDetails>* details, + std::unique_ptr<quic::ProofVerifierCallback> callback) override { + return quic::QUIC_SUCCESS; + } + + std::unique_ptr<quic::ProofVerifyContext> CreateDefaultContext() override { + return nullptr; + } +}; + +// A dummy helper for a server crypto stream that accepts all client hellos +// and generates a random connection ID. +class DummyCryptoServerStreamHelper + : public quic::QuicCryptoServerStream::Helper { + public: + explicit DummyCryptoServerStreamHelper(quic::QuicRandom* random) + : random_(random) {} + ~DummyCryptoServerStreamHelper() override {} + + quic::QuicConnectionId GenerateConnectionIdForReject( + quic::QuicConnectionId connection_id) const override { + return random_->RandUint64(); + } + + bool CanAcceptClientHello(const quic::CryptoHandshakeMessage& message, + const quic::QuicSocketAddress& client_address, + const quic::QuicSocketAddress& peer_address, + const quic::QuicSocketAddress& self_address, + quic::QuicString* error_details) const override { + return true; + } + + private: + // Used to generate random connection IDs. Needs to outlive this. + quic::QuicRandom* random_; +}; +} // namespace + +P2PQuicTransportImpl::P2PQuicTransportImpl( + P2PQuicTransportConfig p2p_transport_config, + std::unique_ptr<net::QuicChromiumConnectionHelper> helper, + std::unique_ptr<quic::QuicConnection> connection, + const quic::QuicConfig& quic_config, + quic::QuicClock* clock) + : quic::QuicSession(connection.get(), nullptr /* visitor */, quic_config), + helper_(std::move(helper)), + connection_(std::move(connection)), + perspective_(p2p_transport_config.is_server + ? quic::Perspective::IS_SERVER + : quic::Perspective::IS_CLIENT), + packet_transport_(p2p_transport_config.packet_transport), + delegate_(p2p_transport_config.delegate), + clock_(clock) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(delegate_); + DCHECK(clock_); + DCHECK(packet_transport_); + DCHECK_GT(p2p_transport_config.certificates.size(), 0u); + if (p2p_transport_config.can_respond_to_crypto_handshake) { + InitializeCryptoStream(); + } + // TODO(https://crbug.com/874296): The web API accepts multiple certificates, + // and we might want to pass these down to let QUIC decide on what to use. + certificate_ = p2p_transport_config.certificates[0]; + packet_transport_->SetReceiveDelegate(this); +} + +P2PQuicTransportImpl::~P2PQuicTransportImpl() { + packet_transport_->SetReceiveDelegate(nullptr); +} + +void P2PQuicTransportImpl::Stop() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (IsClosed()) { + return; + } + // The error code used for the connection closing is + // quic::QUIC_CONNECTION_CANCELLED. This allows us to distinguish that the + // application closed the connection, as opposed to it closing from a + // failure/error. + connection_->CloseConnection( + quic::QuicErrorCode::QUIC_CONNECTION_CANCELLED, kClosingDetails, + quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); +} + +void P2PQuicTransportImpl::Start( + std::vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK_EQ(remote_fingerprints_.size(), 0u); + DCHECK_GT(remote_fingerprints.size(), 0u); + if (IsClosed()) { + // We could have received a close from the remote side before calling this. + return; + } + // These will be used to verify the remote certificate during the handshake. + remote_fingerprints_ = std::move(remote_fingerprints); + + if (perspective_ == quic::Perspective::IS_CLIENT) { + quic::QuicCryptoClientStream* client_crypto_stream = + static_cast<quic::QuicCryptoClientStream*>(crypto_stream_.get()); + client_crypto_stream->CryptoConnect(); + } +} + +void P2PQuicTransportImpl::OnPacketDataReceived(const char* data, + size_t data_len) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + // Received data from the |packet_transport_|. Create a QUIC packet and send + // it to be processed by the QuicSession/Connection. + quic::QuicReceivedPacket packet(data, data_len, clock_->Now()); + ProcessUdpPacket(connection()->self_address(), connection()->peer_address(), + packet); +} + +quic::QuicCryptoStream* P2PQuicTransportImpl::GetMutableCryptoStream() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return crypto_stream_.get(); +} + +const quic::QuicCryptoStream* P2PQuicTransportImpl::GetCryptoStream() const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return crypto_stream_.get(); +} + +P2PQuicStreamImpl* P2PQuicTransportImpl::CreateStream() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return CreateOutgoingBidirectionalStream(); +} + +P2PQuicStreamImpl* P2PQuicTransportImpl::CreateOutgoingBidirectionalStream() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + P2PQuicStreamImpl* stream = CreateStreamInternal(GetNextOutgoingStreamId()); + ActivateStream(std::unique_ptr<P2PQuicStreamImpl>(stream)); + return stream; +} + +P2PQuicStreamImpl* P2PQuicTransportImpl::CreateOutgoingUnidirectionalStream() { + DCHECK(false); + return nullptr; +} + +P2PQuicStreamImpl* P2PQuicTransportImpl::CreateIncomingDynamicStream( + quic::QuicStreamId id) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + P2PQuicStreamImpl* stream = CreateStreamInternal(id); + ActivateStream(std::unique_ptr<P2PQuicStreamImpl>(stream)); + delegate_->OnStream(stream); + return stream; +} + +P2PQuicStreamImpl* P2PQuicTransportImpl::CreateStreamInternal( + quic::QuicStreamId id) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(crypto_stream_); + DCHECK(IsEncryptionEstablished()); + DCHECK(!IsClosed()); + return new P2PQuicStreamImpl(id, this); +} + +void P2PQuicTransportImpl::InitializeCryptoStream() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!crypto_stream_); + switch (perspective_) { + case quic::Perspective::IS_CLIENT: { + if (!crypto_client_config_) { + // The |crypto_client_config_| has not already been set (by the test). + std::unique_ptr<quic::ProofVerifier> proof_verifier( + new InsecureProofVerifier); + crypto_client_config_ = std::make_unique<quic::QuicCryptoClientConfig>( + std::move(proof_verifier), + quic::TlsClientHandshaker::CreateSslCtx()); + } + // The host must be unique for every endpoint the client communicates + // with. + char random_hostname[kHostnameLength]; + helper_->GetRandomGenerator()->RandBytes(random_hostname, + kHostnameLength); + quic::QuicServerId server_id( + /*host=*/quic::QuicString(random_hostname, kHostnameLength), + /*port=*/0, + /*privacy_mode_enabled=*/false); + crypto_stream_ = std::make_unique<quic::QuicCryptoClientStream>( + server_id, /*QuicSession=*/this, + crypto_client_config_->proof_verifier()->CreateDefaultContext(), + crypto_client_config_.get(), /*ProofHandler=*/this); + QuicSession::Initialize(); + break; + } + case quic::Perspective::IS_SERVER: { + std::unique_ptr<quic::ProofSource> proof_source(new DummyProofSource); + crypto_server_config_ = std::make_unique<quic::QuicCryptoServerConfig>( + quic::QuicCryptoServerConfig::TESTING, helper_->GetRandomGenerator(), + std::move(proof_source), quic::KeyExchangeSource::Default(), + quic::TlsServerHandshaker::CreateSslCtx()); + // Provide server with serialized config string to prove ownership. + quic::QuicCryptoServerConfig::ConfigOptions options; + // The |message| is used to handle the return value of AddDefaultConfig + // which is raw pointer of the CryptoHandshakeMessage. + std::unique_ptr<quic::CryptoHandshakeMessage> message( + crypto_server_config_->AddDefaultConfig( + helper_->GetRandomGenerator(), helper_->GetClock(), options)); + compressed_certs_cache_.reset(new quic::QuicCompressedCertsCache( + quic::QuicCompressedCertsCache::kQuicCompressedCertsCacheSize)); + bool use_stateless_rejects_if_peer_supported = false; + server_stream_helper_ = std::make_unique<DummyCryptoServerStreamHelper>( + helper_->GetRandomGenerator()); + + crypto_stream_ = std::make_unique<quic::QuicCryptoServerStream>( + crypto_server_config_.get(), compressed_certs_cache_.get(), + use_stateless_rejects_if_peer_supported, this, + server_stream_helper_.get()); + QuicSession::Initialize(); + break; + } + default: + NOTREACHED(); + break; + } +} + +void P2PQuicTransportImpl::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + QuicSession::OnCryptoHandshakeEvent(event); + if (event == HANDSHAKE_CONFIRMED) { + DCHECK(IsEncryptionEstablished()); + DCHECK(IsCryptoHandshakeConfirmed()); + delegate_->OnConnected(); + } +} + +void P2PQuicTransportImpl::OnConnectionClosed( + quic::QuicErrorCode error, + const std::string& error_details, + quic::ConnectionCloseSource source) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + quic::QuicSession::OnConnectionClosed(error, error_details, source); + if (error != quic::QuicErrorCode::QUIC_CONNECTION_CANCELLED) { + delegate_->OnConnectionFailed( + error_details, source == quic::ConnectionCloseSource::FROM_PEER); + } else if (source == quic::ConnectionCloseSource::FROM_PEER) { + // This connection was closed by the application of the remote side. + delegate_->OnRemoteStopped(); + } +} + +bool P2PQuicTransportImpl::IsClosed() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return !connection_->connected(); +} + +void P2PQuicTransportImpl::set_crypto_client_config( + std::unique_ptr<quic::QuicCryptoClientConfig> crypto_client_config) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + crypto_client_config_ = std::move(crypto_client_config); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h new file mode 100644 index 00000000000..609f223cc98 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h @@ -0,0 +1,180 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_IMPL_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_IMPL_H_ + +#include "base/threading/thread_checker.h" +#include "net/quic/quic_chromium_connection_helper.h" +#include "net/third_party/quic/core/crypto/quic_crypto_client_config.h" +#include "net/third_party/quic/core/crypto/quic_crypto_server_config.h" +#include "net/third_party/quic/core/quic_crypto_client_stream.h" +#include "net/third_party/quic/core/quic_crypto_server_stream.h" +#include "net/third_party/quic/core/quic_packet_writer.h" +#include "net/third_party/quic/core/quic_session.h" +#include "net/third_party/quic/tools/quic_simple_crypto_server_stream_helper.h" +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h" +#include "third_party/webrtc/rtc_base/rtccertificate.h" + +namespace blink { + +// The P2PQuicTransportImpl subclasses the quic::QuicSession in order to expose +// QUIC as a P2P transport. This specific subclass implements the crypto +// handshake for a peer to peer connection, which requires verifying the remote +// certificate's fingerprint, but otherwise exposes a raw quic::QuicSession. +// +// At a high level, the quic::QuicConnection manages the actual connection +// between two endpoints, while the quic::QuicSession owns and manages the +// quic::QuicStreams. The quic::QuicSession also handles the negotiation between +// endpoints, session control (reset, window updates, control frames, etc.), and +// callbacks from either the connection (quic::QuicConnectionVisitorInterface), +// frames being acked or lost (quic::SessionNotifierInterface), or handshake +// state changes. +// +// This object should be run entirely on the webrtc worker thread. +class MODULES_EXPORT P2PQuicTransportImpl final + : public quic::QuicSession, + public P2PQuicTransport, + public P2PQuicPacketTransport::ReceiveDelegate, + public quic::QuicCryptoClientStream::ProofHandler { + public: + P2PQuicTransportImpl( + P2PQuicTransportConfig p2p_transport_config, + std::unique_ptr<net::QuicChromiumConnectionHelper> helper, + std::unique_ptr<quic::QuicConnection> connection, + const quic::QuicConfig& quic_config, + quic::QuicClock* clock); + + ~P2PQuicTransportImpl() override; + + // P2PQuicTransport overrides. + + void Stop() override; + + // Sets the remote fingerprints, and if the the P2PQuicTransportImpl is a + // client starts the QUIC handshake . This handshake is currently insecure, + // meaning that the certificates used are fake and are not verified. It also + // assumes a handshake for a server/client case. This must be called before + // creating any streams. + // + // TODO(https://crbug.com/874300): Verify both the client and server + // certificates with the signaled remote fingerprints. Until the TLS 1.3 + // handshake is supported in the QUIC core library we can only verify the + // server's certificate, but not the client's. Note that this means + // implementing the handshake for a P2P case, in which case verification + // completes after both receiving the signaled remote fingerprint and getting + // a client hello. Because either can come first, a synchronous call to verify + // the remote fingerprint is not possible. + void Start(std::vector<std::unique_ptr<rtc::SSLFingerprint>> + remote_fingerprints) override; + + // Creates an outgoing stream that is owned by the quic::QuicSession. + P2PQuicStreamImpl* CreateStream() override; + + // P2PQuicPacketTransport::Delegate override. + void OnPacketDataReceived(const char* data, size_t data_len) override; + + // quic::QuicCryptoClientStream::ProofHandler overrides used in a client + // connection to get certificate verification details. + + // Called when the proof verification completes. This information is used + // for 0 RTT handshakes, which isn't relevant for our P2P handshake. + void OnProofValid( + const quic::QuicCryptoClientConfig::CachedState& cached) override{}; + + // Called when proof verification become available. + void OnProofVerifyDetailsAvailable( + const quic::ProofVerifyDetails& verify_details) override{}; + + // quic::QuicConnectionVisitorInterface override. + void OnConnectionClosed(quic::QuicErrorCode error, + const std::string& error_details, + quic::ConnectionCloseSource source) override; + + protected: + // quic::QuicSession overrides. + // TODO(https://crbug.com/874296): Subclass QuicStream and implement these + // functions. + + // Creates a new stream initiated from the remote side. The caller does not + // own the stream, so the stream is activated and ownership is moved to the + // quic::QuicSession. + P2PQuicStreamImpl* CreateIncomingDynamicStream( + quic::QuicStreamId id) override; + + // Creates a new outgoing stream. The caller does not own the + // stream, so the stream is activated and ownership is moved to the + // quic::QuicSession. + P2PQuicStreamImpl* CreateOutgoingBidirectionalStream() override; + P2PQuicStreamImpl* CreateOutgoingUnidirectionalStream() override; + + void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override; + + private: + // This is for testing connection failures and handshake failures. + friend class P2PQuicTransportTest; + + // These functions are used for testing. + // + // Returns true if the quic::QuicConnection has been closed remotely or + // locally. + bool IsClosed(); + quic::QuicConnection* connection() { return connection_.get(); } + // Allows the test to set its own proof verification. + void set_crypto_client_config( + std::unique_ptr<quic::QuicCryptoClientConfig> crypto_client_config); + + // quic::QuicSession overrides. + const quic::QuicCryptoStream* GetCryptoStream() const override; + quic::QuicCryptoStream* GetMutableCryptoStream() override; + + // Creates the crypto stream necessary for handshake negotiation, and + // initializes the parent class (quic::QuicSession). This must be called on + // both sides before communicating between endpoints (Start, Close, etc.). + void InitializeCryptoStream(); + + // Creates a new stream. This helper function is used when we need to create + // a new incoming stream or outgoing stream. + P2PQuicStreamImpl* CreateStreamInternal(quic::QuicStreamId id); + + // The server_config and client_config are used for setting up the crypto + // connection. The ownership of these objects or the objects they own + // (quic::ProofSource, quic::ProofVerifier, etc.), are not passed on to the + // QUIC library for the handshake, so we must own them here. A client + // |perspective_| will not have a crypto_server_config and vice versa. + std::unique_ptr<quic::QuicCryptoServerConfig> crypto_server_config_; + std::unique_ptr<quic::QuicCryptoClientConfig> crypto_client_config_; + // Used by server |crypto_stream_| to track most recently compressed certs. + std::unique_ptr<quic::QuicCompressedCertsCache> compressed_certs_cache_; + std::unique_ptr<quic::QuicCryptoServerStream::Helper> server_stream_helper_; + // Owned by the P2PQuicTransportImpl. |helper_| is placed before + // |connection_|Â to ensure it outlives it. + std::unique_ptr<net::QuicChromiumConnectionHelper> helper_; + + std::unique_ptr<quic::QuicConnection> connection_; + + std::unique_ptr<quic::QuicCryptoStream> crypto_stream_; + // Crypto information. Note that currently the handshake is insecure and these + // are not used... + rtc::scoped_refptr<rtc::RTCCertificate> certificate_; + std::vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints_; + + quic::Perspective perspective_; + // Outlives the P2PQuicTransport. + P2PQuicPacketTransport* packet_transport_; + P2PQuicTransport::Delegate* delegate_ = nullptr; + // Owned by whatever creates the P2PQuicTransportImpl. The |clock_| needs to + // outlive the P2PQuicTransportImpl. + quic::QuicClock* clock_ = nullptr; + + THREAD_CHECKER(thread_checker_); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_IMPL_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_test.cc new file mode 100644 index 00000000000..c889ea9d2a2 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_test.cc @@ -0,0 +1,1177 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/quic_chromium_alarm_factory.h" +#include "net/quic/test_task_runner.h" +#include "net/test/gtest_util.h" +#include "net/third_party/quic/core/tls_client_handshaker.h" +#include "net/third_party/quic/test_tools/mock_clock.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h" +#include "third_party/webrtc/rtc_base/rtccertificate.h" +#include "third_party/webrtc/rtc_base/sslfingerprint.h" +#include "third_party/webrtc/rtc_base/sslidentity.h" + +namespace blink { + +namespace { + +// The types of callbacks that can be fired on a P2PQuicTransport::Delegate. +enum class TransportCallbackType { + kNone, + kOnRemoteStopped, + kOnConnectionFailed, + kOnConnected, + kOnStream +}; + +// The types of callbacks that can be fired on a P2PQuicStream::Delegate. +enum class StreamCallbackType { kNone, kOnRemoteReset, kOnRemoteFinish }; + +// The QuicStreamDelegate implements counters for callbacks. It can also set +// expectations for a specific callback. When an expectation is set the +// quic::TestTaskRunner drives the test until the callbacks have been fired, and +// we are no longer expecting the callback. +class QuicStreamDelegateForTesting final : public P2PQuicStream::Delegate { + public: + ~QuicStreamDelegateForTesting() override {} + + void OnRemoteReset() override { + if (callback_type_expected_ == StreamCallbackType::kOnRemoteReset) { + callback_type_expected_ = StreamCallbackType::kNone; + } + remote_reset_count_++; + }; + + void OnRemoteFinish() override { + if (callback_type_expected_ == StreamCallbackType::kOnRemoteFinish) { + callback_type_expected_ = StreamCallbackType::kNone; + } + remote_finish_count_++; + }; + + int remote_reset_count() { return remote_reset_count_; } + + int remote_finish_count() { return remote_finish_count_; } + + // Sets the type of callback expected to be called. + void ExpectCallback(StreamCallbackType callback_type) { + callback_type_expected_ = callback_type; + } + + // Returns if we are expecting a callback that hasn't been fired yet. + bool IsExpectingCallback() const { + return callback_type_expected_ != StreamCallbackType::kNone; + } + + private: + int remote_reset_count_ = 0; + int remote_finish_count_ = 0; + StreamCallbackType callback_type_expected_ = StreamCallbackType::kNone; +}; + +// Implements counters for callbacks. It can also set expectations for a +// specific callback. When an expectation is set the quic::TestTaskRunner +// drives the test until the callbacks have been fired, and we are no longer +// expecting the callback. +// +// TODO(https://crbug.com/874296): If these files get moved to the platform +// directory we will run the tests in a different test environment. In that case +// it will make more sense to use the TestCompletionCallback and the RunLoop for +// driving the test. +class QuicTransportDelegateForTest final : public P2PQuicTransport::Delegate { + public: + ~QuicTransportDelegateForTest() override {} + void OnRemoteStopped() override { + if (callback_type_expected_ == TransportCallbackType::kOnRemoteStopped) { + callback_type_expected_ = TransportCallbackType::kNone; + } + stopped_count_++; + } + + void OnConnectionFailed(const std::string& error_details, + bool from_remote) override { + if (callback_type_expected_ == TransportCallbackType::kOnConnectionFailed) { + callback_type_expected_ = TransportCallbackType::kNone; + } + connection_failed_count_++; + } + + void OnConnected() override { + if (callback_type_expected_ == TransportCallbackType::kOnConnected) { + callback_type_expected_ = TransportCallbackType::kNone; + } + connected_count_++; + } + + // We store the remotely created stream. + void OnStream(P2PQuicStream* stream) override { + if (callback_type_expected_ == TransportCallbackType::kOnStream) { + callback_type_expected_ = TransportCallbackType::kNone; + } + streams_.push_back(static_cast<P2PQuicStreamImpl*>(stream)); + on_stream_count_++; + } + + int stopped_count() const { return stopped_count_; } + + int connection_failed_count() const { return connection_failed_count_; } + + int connected_count() const { return connected_count_; } + + int on_stream_count() const { return on_stream_count_; } + + // Sets the type of callback expected to be called. + void ExpectCallback(TransportCallbackType callback_type) { + callback_type_expected_ = callback_type; + } + + // Returns if we are expecting a callback that hasn't been fired yet. + bool IsExpectingCallback() const { + return callback_type_expected_ != TransportCallbackType::kNone; + } + + std::vector<P2PQuicStreamImpl*> streams() const { return streams_; } + + private: + TransportCallbackType callback_type_expected_ = TransportCallbackType::kNone; + int stopped_count_ = 0; + int connection_failed_count_ = 0; + int connected_count_ = 0; + int on_stream_count_ = 0; + // The delegates created for each stream as a result of the remote side + // creating streams and sending data (triggering OnStream). P2PQuicStreamsImpl + // are owned by the P2PQuicTransport. + std::vector<P2PQuicStreamImpl*> streams_; +}; + +// This is a fake packet transport to be used by the P2PQuicTransportImpl. It +// allows to easily connect two packet transports together. We send packets +// asynchronously, by using the same alarm factory that is being used for the +// underlying QUIC library. +class FakePacketTransport : public P2PQuicPacketTransport, + public quic::QuicAlarm::Delegate { + public: + FakePacketTransport(quic::QuicAlarmFactory* alarm_factory, + quic::MockClock* clock) + : alarm_(alarm_factory->CreateAlarm(new AlarmDelegate(this))), + clock_(clock) {} + ~FakePacketTransport() override { + // The write observer should be unset when it is destroyed. + DCHECK(!write_observer_); + }; + + // Called by QUIC for writing data to the other side. The flow for writing a + // packet is P2PQuicTransportImpl --> quic::QuicConnection --> + // quic::QuicPacketWriter --> FakePacketTransport. In this case the + // FakePacketTransport just writes directly to the FakePacketTransport on the + // other side. + int WritePacket(const QuicPacket& packet) override { + // For the test there should always be a peer_packet_transport_ connected at + // this point. + if (!peer_packet_transport_) { + return 0; + } + last_packet_num_ = packet.packet_number; + packet_queue_.emplace_back(packet.buffer, packet.buf_len); + alarm_->Cancel(); + // We don't want get 0 RTT. + alarm_->Set(clock_->Now() + quic::QuicTime::Delta::FromMicroseconds(10)); + + return packet.buf_len; + } + + // Sets the P2PQuicTransportImpl as the delegate. + void SetReceiveDelegate( + P2PQuicPacketTransport::ReceiveDelegate* delegate) override { + // We can't set two ReceiveDelegates for one packet transport. + DCHECK(!delegate_ || !delegate); + delegate_ = delegate; + } + + void SetWriteObserver( + P2PQuicPacketTransport::WriteObserver* write_observer) override { + // We can't set two WriteObservers for one packet transport. + DCHECK(!write_observer_ || !write_observer); + write_observer_ = write_observer; + } + + bool Writable() override { return true; } + + // Connects the other FakePacketTransport, so we can write to the peer. + void ConnectPeerTransport(FakePacketTransport* peer_packet_transport) { + DCHECK(!peer_packet_transport_); + peer_packet_transport_ = peer_packet_transport; + } + + // Disconnects the delegate, so we no longer write to it. The test must call + // this before destructing either of the packet transports! + void DisconnectPeerTransport(FakePacketTransport* peer_packet_transport) { + DCHECK(peer_packet_transport_ == peer_packet_transport); + peer_packet_transport_ = nullptr; + } + + // The callback used in order for us to communicate between + // FakePacketTransports. + void OnDataReceivedFromPeer(const char* data, size_t data_len) { + DCHECK(delegate_); + delegate_->OnPacketDataReceived(data, data_len); + } + + int last_packet_num() { return last_packet_num_; } + + private: + // Wraps the FakePacketTransport so that we can pass in a raw pointer that can + // be reference counted when calling CreateAlarm(). + class AlarmDelegate : public quic::QuicAlarm::Delegate { + public: + explicit AlarmDelegate(FakePacketTransport* packet_transport) + : packet_transport_(packet_transport) {} + + void OnAlarm() override { packet_transport_->OnAlarm(); } + + private: + FakePacketTransport* packet_transport_; + }; + + // Called when we should write any buffered data. + void OnAlarm() override { + // Send the data to the peer at this point. + peer_packet_transport_->OnDataReceivedFromPeer( + packet_queue_.front().c_str(), packet_queue_.front().length()); + packet_queue_.pop_front(); + + // If there's more packets to be sent out, reset the alarm to send it as the + // next task. + if (!packet_queue_.empty()) { + alarm_->Cancel(); + alarm_->Set(clock_->Now()); + } + } + // If async, packets are queued here to send. + quic::QuicDeque<quic::QuicString> packet_queue_; + // Alarm used to send data asynchronously. + quic::QuicArenaScopedPtr<quic::QuicAlarm> alarm_; + // The P2PQuicTransportImpl, which sets itself as the delegate in its + // constructor. After receiving data it forwards it along to QUIC. + P2PQuicPacketTransport::ReceiveDelegate* delegate_ = nullptr; + + // The P2PQuicPacketWriter, which sets itself as a write observer + // during the P2PQuicTransportFactoryImpl::CreateQuicTransport. It is + // owned by the QuicConnection and will + P2PQuicPacketTransport::WriteObserver* write_observer_ = nullptr; + + // The other FakePacketTransport that we are writing to. It's the + // responsibility of the test to disconnect this delegate + // (set_delegate(nullptr);) before it is destructed. + FakePacketTransport* peer_packet_transport_ = nullptr; + quic::QuicPacketNumber last_packet_num_; + quic::MockClock* clock_; +}; + +// A helper class to bundle test objects together. +class QuicPeerForTest { + public: + QuicPeerForTest( + std::unique_ptr<FakePacketTransport> packet_transport, + std::unique_ptr<QuicTransportDelegateForTest> quic_transport_delegate, + std::unique_ptr<P2PQuicTransportImpl> quic_transport, + rtc::scoped_refptr<rtc::RTCCertificate> certificate) + : packet_transport_(std::move(packet_transport)), + quic_transport_delegate_(std::move(quic_transport_delegate)), + quic_transport_(std::move(quic_transport)), + certificate_(certificate) {} + + FakePacketTransport* packet_transport() { return packet_transport_.get(); } + + QuicTransportDelegateForTest* quic_transport_delegate() { + return quic_transport_delegate_.get(); + } + + P2PQuicTransportImpl* quic_transport() { return quic_transport_.get(); } + + rtc::scoped_refptr<rtc::RTCCertificate> certificate() { return certificate_; } + + private: + std::unique_ptr<FakePacketTransport> packet_transport_; + std::unique_ptr<QuicTransportDelegateForTest> quic_transport_delegate_; + std::unique_ptr<P2PQuicTransportImpl> quic_transport_; + rtc::scoped_refptr<rtc::RTCCertificate> certificate_; +}; + +rtc::scoped_refptr<rtc::RTCCertificate> CreateTestCertificate() { + rtc::KeyParams params; + rtc::SSLIdentity* ssl_identity = + rtc::SSLIdentity::Generate("dummy_certificate", params); + return rtc::RTCCertificate::Create( + std::unique_ptr<rtc::SSLIdentity>(ssl_identity)); +} + +// Allows faking a failing handshake. +class FailingProofVerifier : public quic::ProofVerifier { + public: + FailingProofVerifier() {} + ~FailingProofVerifier() override {} + + // ProofVerifier override. + quic::QuicAsyncStatus VerifyProof( + const quic::QuicString& hostname, + const uint16_t port, + const quic::QuicString& server_config, + quic::QuicTransportVersion transport_version, + quic::QuicStringPiece chlo_hash, + const std::vector<quic::QuicString>& certs, + const quic::QuicString& cert_sct, + const quic::QuicString& signature, + const quic::ProofVerifyContext* context, + quic::QuicString* error_details, + std::unique_ptr<quic::ProofVerifyDetails>* verify_details, + std::unique_ptr<quic::ProofVerifierCallback> callback) override { + return quic::QUIC_FAILURE; + } + + quic::QuicAsyncStatus VerifyCertChain( + const quic::QuicString& hostname, + const std::vector<quic::QuicString>& certs, + const quic::ProofVerifyContext* context, + quic::QuicString* error_details, + std::unique_ptr<quic::ProofVerifyDetails>* details, + std::unique_ptr<quic::ProofVerifierCallback> callback) override { + return quic::QUIC_FAILURE; + } + + std::unique_ptr<quic::ProofVerifyContext> CreateDefaultContext() override { + return nullptr; + } +}; +} // namespace + +// Unit tests for the P2PQuicTransport, using an underlying fake packet +// transport that sends packets directly between endpoints. This also tests +// P2PQuicStreams for test cases that involve two streams connected between +// separate endpoints. This is because the P2PQuicStream is highly coupled to +// the P2PQuicSession for communicating between endpoints, so we would like to +// test it with the real session object. +// +// The test is driven using the quic::TestTaskRunner to run posted tasks until +// callbacks have been fired. +class P2PQuicTransportTest : public testing::Test { + public: + P2PQuicTransportTest() {} + + ~P2PQuicTransportTest() override { + // This must be done before desctructing the transports so that we don't + // have any dangling pointers. + client_peer_->packet_transport()->DisconnectPeerTransport( + server_peer_->packet_transport()); + server_peer_->packet_transport()->DisconnectPeerTransport( + client_peer_->packet_transport()); + } + + // Connects both peer's underlying transports and creates both + // P2PQuicTransportImpls. + void Initialize(bool can_respond_to_crypto_handshake = true) { + // Quic crashes if packets are sent at time 0, and the clock defaults to 0. + clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(1000)); + runner_ = new net::test::TestTaskRunner(&clock_); + net::QuicChromiumAlarmFactory* alarm_factory = + new net::QuicChromiumAlarmFactory(runner_.get(), &clock_); + quic_transport_factory_ = std::make_unique<P2PQuicTransportFactoryImpl>( + &clock_, std::unique_ptr<net::QuicChromiumAlarmFactory>(alarm_factory)); + + std::unique_ptr<FakePacketTransport> client_packet_transport = + std::make_unique<FakePacketTransport>(alarm_factory, &clock_); + std::unique_ptr<FakePacketTransport> server_packet_transport = + std::make_unique<FakePacketTransport>(alarm_factory, &clock_); + // Connect the transports so that they can speak to each other. + client_packet_transport->ConnectPeerTransport( + server_packet_transport.get()); + server_packet_transport->ConnectPeerTransport( + client_packet_transport.get()); + rtc::scoped_refptr<rtc::RTCCertificate> client_cert = + CreateTestCertificate(); + + std::unique_ptr<QuicTransportDelegateForTest> + client_quic_transport_delegate = + std::make_unique<QuicTransportDelegateForTest>(); + std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> client_certificates; + client_certificates.push_back(client_cert); + P2PQuicTransportConfig client_config(client_quic_transport_delegate.get(), + client_packet_transport.get(), + client_certificates); + client_config.is_server = false; + client_config.can_respond_to_crypto_handshake = + can_respond_to_crypto_handshake; + // We can't downcast a unique_ptr to an object, so we have to release, cast + // it, then create a unique_ptr of the downcasted pointer. + P2PQuicTransportImpl* client_quic_transport_ptr = + static_cast<P2PQuicTransportImpl*>( + quic_transport_factory_ + ->CreateQuicTransport(std::move(client_config)) + .release()); + std::unique_ptr<P2PQuicTransportImpl> client_quic_transport = + std::unique_ptr<P2PQuicTransportImpl>(client_quic_transport_ptr); + client_peer_ = std::make_unique<QuicPeerForTest>( + std::move(client_packet_transport), + std::move(client_quic_transport_delegate), + std::move(client_quic_transport), client_cert); + + std::unique_ptr<QuicTransportDelegateForTest> + server_quic_transport_delegate = + std::make_unique<QuicTransportDelegateForTest>(); + + rtc::scoped_refptr<rtc::RTCCertificate> server_cert = + CreateTestCertificate(); + std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> server_certificates; + server_certificates.push_back(server_cert); + P2PQuicTransportConfig server_config(server_quic_transport_delegate.get(), + server_packet_transport.get(), + server_certificates); + server_config.is_server = true; + server_config.can_respond_to_crypto_handshake = + can_respond_to_crypto_handshake; + P2PQuicTransportImpl* server_quic_transport_ptr = + static_cast<P2PQuicTransportImpl*>( + quic_transport_factory_ + ->CreateQuicTransport(std::move(server_config)) + .release()); + std::unique_ptr<P2PQuicTransportImpl> server_quic_transport = + std::unique_ptr<P2PQuicTransportImpl>(server_quic_transport_ptr); + server_peer_ = std::make_unique<QuicPeerForTest>( + std::move(server_packet_transport), + std::move(server_quic_transport_delegate), + std::move(server_quic_transport), server_cert); + } + + // Sets a FailingProofVerifier to the client transport before initializing + // the its crypto stream. This allows the client to fail the proof + // verification step during the crypto handshake. + void InitializeWithFailingProofVerification() { + // Allows us to initialize the crypto streams after constructing the + // objects. + Initialize(false); + // Create the client crypto config and insert it into the client transport. + std::unique_ptr<quic::ProofVerifier> proof_verifier( + new FailingProofVerifier); + std::unique_ptr<quic::QuicCryptoClientConfig> crypto_client_config = + std::make_unique<quic::QuicCryptoClientConfig>( + std::move(proof_verifier), + quic::TlsClientHandshaker::CreateSslCtx()); + client_peer_->quic_transport()->set_crypto_client_config( + std::move(crypto_client_config)); + // Now initialize the crypto streams. + client_peer_->quic_transport()->InitializeCryptoStream(); + server_peer_->quic_transport()->InitializeCryptoStream(); + } + + // Drives the test until we are't expecting any more callbacks to be fired. + // This is done using the net::test::TestTaskRunner, which runs the tasks + // in the correct order and then advances the quic::MockClock to the time the + // task is run. + void RunUntilCallbacksFired() { + while (server_peer_->quic_transport_delegate()->IsExpectingCallback() || + client_peer_->quic_transport_delegate()->IsExpectingCallback() || + ExpectingStreamCallback()) { + // We shouldn't enter a case where we are expecting a callback + // and we're out of tasks to run. + ASSERT_GT(runner_->GetPostedTasks().size(), 0u); + runner_->RunNextTask(); + } + } + + bool ExpectingStreamCallback() { + return streams_setup_ && (client_stream_delegate_->IsExpectingCallback() || + server_stream_delegate_->IsExpectingCallback()); + } + + // Drives the test by running the current tasks that are posted. + void RunCurrentTasks() { + size_t posted_tasks_size = runner_->GetPostedTasks().size(); + for (size_t i = 0; i < posted_tasks_size; ++i) { + runner_->RunNextTask(); + } + } + + // Starts the handshake, by setting the remote fingerprints and kicking off + // the handshake from the client. + void StartHandshake() { + std::vector<std::unique_ptr<rtc::SSLFingerprint>> server_fingerprints; + server_fingerprints.emplace_back(rtc::SSLFingerprint::Create( + "sha-256", server_peer_->certificate()->identity())); + // The server side doesn't currently need call this to set the remote + // fingerprints, but once P2P certificate verification is supported in the + // TLS 1.3 handshake this will ben necessary. + server_peer_->quic_transport()->Start(std::move(server_fingerprints)); + + std::vector<std::unique_ptr<rtc::SSLFingerprint>> client_fingerprints; + client_fingerprints.emplace_back(rtc::SSLFingerprint::Create( + "sha-256", client_peer_->certificate()->identity())); + client_peer_->quic_transport()->Start(std::move(client_fingerprints)); + } + + // Sets up an initial handshake and connection between peers. + void Connect() { + client_peer_->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnected); + server_peer_->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnected); + StartHandshake(); + RunUntilCallbacksFired(); + ExpectSecureConnection(); + } + + // Creates a P2PQuicStreamImpl on both the client and server side that are + // connected to each other. + void SetupConnectedStreams() { + // We must already have a secure connection before streams are created. + ASSERT_TRUE(client_peer_->quic_transport()->IsEncryptionEstablished()); + ASSERT_TRUE(server_peer_->quic_transport()->IsEncryptionEstablished()); + + client_stream_ = client_peer_->quic_transport()->CreateStream(); + ASSERT_TRUE(client_stream_); + client_stream_id_ = client_stream_->id(); + client_stream_delegate_ = std::make_unique<QuicStreamDelegateForTesting>(); + client_stream_->SetDelegate(client_stream_delegate_.get()); + + // Send some data to trigger the remote side (server side) to get an + // incoming stream. + server_peer_->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnStream); + client_stream_->WriteOrBufferData("hello", false, nullptr); + RunUntilCallbacksFired(); + + ASSERT_EQ(1u, server_peer_->quic_transport()->GetNumActiveStreams()); + ASSERT_EQ(1u, client_peer_->quic_transport()->GetNumActiveStreams()); + ASSERT_EQ(1u, server_peer_->quic_transport_delegate()->streams().size()); + server_stream_ = server_peer_->quic_transport_delegate()->streams()[0]; + ASSERT_TRUE(server_stream_); + server_stream_id_ = server_stream_->id(); + server_stream_delegate_ = std::make_unique<QuicStreamDelegateForTesting>(); + server_stream_->SetDelegate(server_stream_delegate_.get()); + streams_setup_ = true; + } + + void ExpectSecureConnection() { + EXPECT_TRUE(client_peer_->quic_transport()->IsEncryptionEstablished()); + EXPECT_TRUE(client_peer_->quic_transport()->IsCryptoHandshakeConfirmed()); + EXPECT_TRUE(server_peer_->quic_transport()->IsCryptoHandshakeConfirmed()); + EXPECT_TRUE(server_peer_->quic_transport()->IsEncryptionEstablished()); + } + + void ExpectConnectionNotEstablished() { + EXPECT_FALSE(client_peer_->quic_transport()->IsEncryptionEstablished()); + EXPECT_FALSE(client_peer_->quic_transport()->IsCryptoHandshakeConfirmed()); + EXPECT_FALSE(server_peer_->quic_transport()->IsCryptoHandshakeConfirmed()); + EXPECT_FALSE(server_peer_->quic_transport()->IsEncryptionEstablished()); + } + + // Test that the callbacks were called appropriately after a successful + // crypto handshake. + void ExpectSuccessfulHandshake() { + EXPECT_EQ(1, client_peer_->quic_transport_delegate()->connected_count()); + EXPECT_EQ(0, client_peer_->quic_transport_delegate()->stopped_count()); + EXPECT_EQ( + 0, client_peer_->quic_transport_delegate()->connection_failed_count()); + + EXPECT_EQ(1, server_peer_->quic_transport_delegate()->connected_count()); + EXPECT_EQ(0, server_peer_->quic_transport_delegate()->stopped_count()); + EXPECT_EQ( + 0, server_peer_->quic_transport_delegate()->connection_failed_count()); + } + + void ExpectTransportsClosed() { + EXPECT_TRUE(client_peer_->quic_transport()->IsClosed()); + EXPECT_TRUE(server_peer_->quic_transport()->IsClosed()); + } + + void ExpectStreamsClosed() { + ASSERT_TRUE(streams_setup_); + EXPECT_EQ(0u, client_peer_->quic_transport()->GetNumActiveStreams()); + EXPECT_TRUE( + client_peer_->quic_transport()->IsClosedStream(client_stream_id_)); + EXPECT_EQ(0u, server_peer_->quic_transport()->GetNumActiveStreams()); + EXPECT_TRUE( + server_peer()->quic_transport()->IsClosedStream(server_stream_id_)); + } + + // Exposes these private functions to the test. + bool IsClientClosed() { return client_peer_->quic_transport()->IsClosed(); } + bool IsServerClosed() { return server_peer_->quic_transport()->IsClosed(); } + + // Tests that the callbacks were appropriately called after the client + // stops the connection. Only the server should receive the OnRemoteStopped() + // callback. + void ExpectClientStopped() { + ExpectTransportsClosed(); + EXPECT_EQ(0, client_peer_->quic_transport_delegate()->stopped_count()); + EXPECT_EQ( + 0, client_peer_->quic_transport_delegate()->connection_failed_count()); + EXPECT_EQ(1, server_peer_->quic_transport_delegate()->stopped_count()); + EXPECT_EQ( + 0, server_peer_->quic_transport_delegate()->connection_failed_count()); + } + + // Tests that the callbacks were appropriately called after the server + // stops the connection. Only the client should receive the OnRemoteStopped() + // callback. + void ExpectServerStopped() { + ExpectTransportsClosed(); + EXPECT_EQ(1, client_peer_->quic_transport_delegate()->stopped_count()); + EXPECT_EQ( + 0, client_peer_->quic_transport_delegate()->connection_failed_count()); + EXPECT_EQ(0, server_peer_->quic_transport_delegate()->stopped_count()); + EXPECT_EQ( + 0, server_peer_->quic_transport_delegate()->connection_failed_count()); + } + + QuicPeerForTest* client_peer() { return client_peer_.get(); } + + quic::QuicConnection* client_connection() { + return client_peer_->quic_transport()->connection(); + } + + QuicPeerForTest* server_peer() { return server_peer_.get(); } + + quic::QuicConnection* server_connection() { + return server_peer_->quic_transport()->connection(); + } + + P2PQuicStreamImpl* server_stream() { return server_stream_; } + + P2PQuicStreamImpl* client_stream() { return client_stream_; } + + quic::QuicStreamId server_stream_id() { return server_stream_id_; } + + quic::QuicStreamId client_stream_id() { return client_stream_id_; } + + QuicStreamDelegateForTesting* server_stream_delegate() { + return server_stream_delegate_.get(); + } + + QuicStreamDelegateForTesting* client_stream_delegate() { + return client_stream_delegate_.get(); + } + + private: + quic::MockClock clock_; + // The TestTaskRunner is used by the QUIC library for setting/firing alarms. + // We are able to explicitly run these tasks ourselves with the + // TestTaskRunner. + scoped_refptr<net::test::TestTaskRunner> runner_; + + std::unique_ptr<P2PQuicTransportFactoryImpl> quic_transport_factory_; + std::unique_ptr<QuicPeerForTest> client_peer_; + std::unique_ptr<QuicPeerForTest> server_peer_; + + // Stream objects, which are created with SetupConnectedStream(). + bool streams_setup_ = false; + std::unique_ptr<QuicStreamDelegateForTesting> client_stream_delegate_; + std::unique_ptr<QuicStreamDelegateForTesting> server_stream_delegate_; + // The P2PQuicStreamImpls are owned by the P2PQuicTransport. + P2PQuicStreamImpl* client_stream_ = nullptr; + P2PQuicStreamImpl* server_stream_ = nullptr; + // We cache the values before the streams are potentially closed and deleted. + quic::QuicStreamId server_stream_id_; + quic::QuicStreamId client_stream_id_; +}; + +// Tests that we can connect two quic transports. +TEST_F(P2PQuicTransportTest, HandshakeConnectsPeers) { + Initialize(); + Connect(); + + ExpectSuccessfulHandshake(); +} + +// Tests the standard case for the server side closing the connection. +TEST_F(P2PQuicTransportTest, ServerStops) { + Initialize(); + Connect(); + client_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnRemoteStopped); + server_peer()->quic_transport()->Stop(); + RunUntilCallbacksFired(); + + ExpectServerStopped(); +} + +// Tests the standard case for the client side closing the connection. +TEST_F(P2PQuicTransportTest, ClientStops) { + Initialize(); + Connect(); + server_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnRemoteStopped); + client_peer()->quic_transport()->Stop(); + RunUntilCallbacksFired(); + + ExpectClientStopped(); +} + +// Tests that if either side tries to close the connection a second time, it +// will be ignored because the connection has already been closed. +TEST_F(P2PQuicTransportTest, StopAfterStopped) { + Initialize(); + Connect(); + server_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnRemoteStopped); + client_peer()->quic_transport()->Stop(); + RunUntilCallbacksFired(); + client_peer()->quic_transport()->Stop(); + server_peer()->quic_transport()->Stop(); + RunCurrentTasks(); + + ExpectClientStopped(); +} + +// Tests that when the client closes the connection the subsequent call to +// Start() will be ignored. +TEST_F(P2PQuicTransportTest, ClientStopsBeforeClientStarts) { + Initialize(); + server_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnRemoteStopped); + client_peer()->quic_transport()->Stop(); + StartHandshake(); + RunUntilCallbacksFired(); + + ExpectConnectionNotEstablished(); + ExpectClientStopped(); +} + +// Tests that if the server closes the connection before the client starts the +// handshake, the client side will already be closed and Start() will be +// ignored. +TEST_F(P2PQuicTransportTest, ServerStopsBeforeClientStarts) { + Initialize(); + client_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnRemoteStopped); + server_peer()->quic_transport()->Stop(); + StartHandshake(); + RunUntilCallbacksFired(); + + ExpectConnectionNotEstablished(); + ExpectServerStopped(); +} + +// Tests that when the server's connection fails and then a handshake is +// attempted the transports will not become connected. +TEST_F(P2PQuicTransportTest, ClientConnectionClosesBeforeHandshake) { + Initialize(); + client_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnectionFailed); + server_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnectionFailed); + client_connection()->CloseConnection( + quic::QuicErrorCode::QUIC_INTERNAL_ERROR, "internal error", + quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + StartHandshake(); + RunUntilCallbacksFired(); + + ExpectConnectionNotEstablished(); +} + +// Tests that when the server's connection fails and then a handshake is +// attempted the transports will not become connected. +TEST_F(P2PQuicTransportTest, ServerConnectionClosesBeforeHandshake) { + Initialize(); + client_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnectionFailed); + server_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnectionFailed); + server_connection()->CloseConnection( + quic::QuicErrorCode::QUIC_INTERNAL_ERROR, "internal error", + quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + StartHandshake(); + RunUntilCallbacksFired(); + + ExpectConnectionNotEstablished(); +} + +// Tests that the appropriate callbacks are fired when the handshake fails. +TEST_F(P2PQuicTransportTest, HandshakeFailure) { + InitializeWithFailingProofVerification(); + client_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnectionFailed); + server_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnectionFailed); + StartHandshake(); + RunUntilCallbacksFired(); + + EXPECT_EQ( + 1, client_peer()->quic_transport_delegate()->connection_failed_count()); + EXPECT_EQ( + 1, server_peer()->quic_transport_delegate()->connection_failed_count()); + ExpectConnectionNotEstablished(); + ExpectTransportsClosed(); +} + +// Tests that the appropriate callbacks are fired when the client's connection +// fails after the transports have connected. +TEST_F(P2PQuicTransportTest, ClientConnectionFailureAfterConnected) { + Initialize(); + Connect(); + // Close the connection with an internal QUIC error. + client_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnectionFailed); + server_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnectionFailed); + client_connection()->CloseConnection( + quic::QuicErrorCode::QUIC_INTERNAL_ERROR, "internal error", + quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + RunUntilCallbacksFired(); + + ExpectTransportsClosed(); + EXPECT_EQ( + 1, client_peer()->quic_transport_delegate()->connection_failed_count()); + EXPECT_EQ( + 1, server_peer()->quic_transport_delegate()->connection_failed_count()); +} + +// Tests that the appropriate callbacks are fired when the server's connection +// fails after the transports have connected. +TEST_F(P2PQuicTransportTest, ServerConnectionFailureAfterConnected) { + Initialize(); + Connect(); + // Close the connection with an internal QUIC error. + client_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnectionFailed); + server_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnectionFailed); + server_connection()->CloseConnection( + quic::QuicErrorCode::QUIC_INTERNAL_ERROR, "internal error", + quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + RunUntilCallbacksFired(); + + ExpectTransportsClosed(); + EXPECT_EQ( + 1, client_peer()->quic_transport_delegate()->connection_failed_count()); + EXPECT_EQ( + 1, server_peer()->quic_transport_delegate()->connection_failed_count()); +} + +// Tests that closing the connection with no ACK frame does not make any +// difference in the closing procedure. +TEST_F(P2PQuicTransportTest, ConnectionFailureNoAckFrame) { + Initialize(); + Connect(); + client_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnectionFailed); + server_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnectionFailed); + client_connection()->CloseConnection( + quic::QuicErrorCode::QUIC_INTERNAL_ERROR, "internal error", + quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET_WITH_NO_ACK); + RunUntilCallbacksFired(); + + ExpectTransportsClosed(); + EXPECT_EQ( + 1, client_peer()->quic_transport_delegate()->connection_failed_count()); + EXPECT_EQ( + 1, server_peer()->quic_transport_delegate()->connection_failed_count()); +} + +// Tests that a silent failure will only close on one side. +TEST_F(P2PQuicTransportTest, ConnectionSilentFailure) { + Initialize(); + Connect(); + client_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnConnectionFailed); + client_connection()->CloseConnection( + quic::QuicErrorCode::QUIC_INTERNAL_ERROR, "internal error", + quic::ConnectionCloseBehavior::SILENT_CLOSE); + RunUntilCallbacksFired(); + + EXPECT_TRUE(IsClientClosed()); + EXPECT_EQ( + 1, client_peer()->quic_transport_delegate()->connection_failed_count()); + EXPECT_FALSE(IsServerClosed()); + EXPECT_EQ( + 0, server_peer()->quic_transport_delegate()->connection_failed_count()); +} + +// Tests that the client transport can create a stream and an incoming stream +// will be created on the remote server. +TEST_F(P2PQuicTransportTest, ClientCreatesStream) { + Initialize(); + Connect(); + P2PQuicStreamImpl* client_stream = + client_peer()->quic_transport()->CreateStream(); + RunCurrentTasks(); + + ASSERT_TRUE(client_stream); + EXPECT_TRUE(client_peer()->quic_transport()->HasOpenDynamicStreams()); + EXPECT_EQ(0, server_peer()->quic_transport_delegate()->on_stream_count()); + EXPECT_FALSE(server_peer()->quic_transport()->HasOpenDynamicStreams()); + + // After sending data across it will trigger a stream to be created on the + // server side. + server_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnStream); + client_stream->WriteOrBufferData("hello", false, nullptr); + RunUntilCallbacksFired(); + + EXPECT_EQ(1, server_peer()->quic_transport_delegate()->on_stream_count()); + EXPECT_TRUE(server_peer()->quic_transport()->HasOpenDynamicStreams()); +} + +// Tests that the server transport can create a stream and an incoming stream +// will be created on the remote client. +TEST_F(P2PQuicTransportTest, ServerCreatesStream) { + Initialize(); + Connect(); + P2PQuicStreamImpl* server_stream = + server_peer()->quic_transport()->CreateStream(); + RunCurrentTasks(); + + ASSERT_TRUE(server_stream); + EXPECT_TRUE(server_peer()->quic_transport()->HasOpenDynamicStreams()); + EXPECT_EQ(0, client_peer()->quic_transport_delegate()->on_stream_count()); + EXPECT_FALSE(client_peer()->quic_transport()->HasOpenDynamicStreams()); + + // After sending data across it will trigger a stream to be created on the + // client side. + client_peer()->quic_transport_delegate()->ExpectCallback( + TransportCallbackType::kOnStream); + server_stream->WriteOrBufferData("hello", false, nullptr); + RunUntilCallbacksFired(); + + EXPECT_EQ(1, client_peer()->quic_transport_delegate()->on_stream_count()); + EXPECT_TRUE(client_peer()->quic_transport()->HasOpenDynamicStreams()); +} + +// Tests that when the client transport calls Stop() it closes its outgoing +// stream, which, in turn closes the incoming stream on the server quic +// transport. +TEST_F(P2PQuicTransportTest, ClientClosingConnectionClosesStreams) { + Initialize(); + Connect(); + SetupConnectedStreams(); + + client_peer()->quic_transport()->Stop(); + RunCurrentTasks(); + + ExpectTransportsClosed(); + ExpectStreamsClosed(); +} + +// Tests that when the server transport calls Stop() it closes its incoming +// stream, which, in turn closes the outgoing stream on the client quic +// transport. +TEST_F(P2PQuicTransportTest, ServerClosingConnectionClosesStreams) { + Initialize(); + Connect(); + SetupConnectedStreams(); + + server_peer()->quic_transport()->Stop(); + RunCurrentTasks(); + + ExpectTransportsClosed(); + ExpectStreamsClosed(); +} + +// Tests that calling Reset() will close both side's streams for reading and +// writing. +TEST_F(P2PQuicTransportTest, ClientStreamReset) { + Initialize(); + Connect(); + SetupConnectedStreams(); + + server_stream_delegate()->ExpectCallback(StreamCallbackType::kOnRemoteReset); + client_stream()->Reset(); + RunUntilCallbacksFired(); + + ExpectStreamsClosed(); +} + +// Tests that calling Reset() will close both side's streams for reading and +// writing. +TEST_F(P2PQuicTransportTest, ServerStreamReset) { + Initialize(); + Connect(); + SetupConnectedStreams(); + + client_stream_delegate()->ExpectCallback(StreamCallbackType::kOnRemoteReset); + server_stream()->Reset(); + RunUntilCallbacksFired(); + + ExpectStreamsClosed(); +} + +// Tests the basic case for calling Finish() on both sides. +TEST_F(P2PQuicTransportTest, StreamFinishHandshake) { + Initialize(); + Connect(); + SetupConnectedStreams(); + + server_stream_delegate()->ExpectCallback(StreamCallbackType::kOnRemoteFinish); + client_stream()->Finish(); + RunUntilCallbacksFired(); + + ASSERT_EQ(1u, server_peer()->quic_transport()->GetNumActiveStreams()); + ASSERT_EQ(1u, client_peer()->quic_transport()->GetNumActiveStreams()); + EXPECT_EQ(0, client_stream_delegate()->remote_finish_count()); + EXPECT_TRUE(client_stream()->write_side_closed()); + EXPECT_FALSE(client_stream()->reading_stopped()); + EXPECT_FALSE(server_stream()->write_side_closed()); + EXPECT_TRUE(server_stream()->reading_stopped()); + EXPECT_FALSE( + server_peer()->quic_transport()->IsClosedStream(server_stream_id())); + EXPECT_FALSE( + client_peer()->quic_transport()->IsClosedStream(client_stream_id())); + + client_stream_delegate()->ExpectCallback(StreamCallbackType::kOnRemoteFinish); + server_stream()->Finish(); + RunUntilCallbacksFired(); + // This is required so that the client acks the FIN back to the server side + // and the server side removes its zombie streams. + RunCurrentTasks(); + + ASSERT_EQ(0u, server_peer()->quic_transport()->GetNumActiveStreams()); + ASSERT_EQ(0u, client_peer()->quic_transport()->GetNumActiveStreams()); + EXPECT_EQ(1, server_stream_delegate()->remote_finish_count()); + EXPECT_EQ(1, client_stream_delegate()->remote_finish_count()); + EXPECT_TRUE( + server_peer()->quic_transport()->IsClosedStream(server_stream_id())); + EXPECT_TRUE( + client_peer()->quic_transport()->IsClosedStream(client_stream_id())); +} + +// Tests that if a Reset() is called after Finish(), both sides close down +// properly. +TEST_F(P2PQuicTransportTest, StreamResetAfterFinish) { + Initialize(); + Connect(); + SetupConnectedStreams(); + + server_stream_delegate()->ExpectCallback(StreamCallbackType::kOnRemoteFinish); + client_stream()->Finish(); + RunUntilCallbacksFired(); + + server_stream_delegate()->ExpectCallback(StreamCallbackType::kOnRemoteReset); + client_stream()->Reset(); + RunUntilCallbacksFired(); + + ExpectStreamsClosed(); + EXPECT_EQ(0, client_stream_delegate()->remote_reset_count()); +} + +// Tests that if a Reset() is called after receiving a stream frame with the FIN +// bit set from the remote side, both sides close down properly. +TEST_F(P2PQuicTransportTest, StreamResetAfterRemoteFinish) { + Initialize(); + Connect(); + SetupConnectedStreams(); + + server_stream_delegate()->ExpectCallback(StreamCallbackType::kOnRemoteFinish); + client_stream()->Finish(); + RunUntilCallbacksFired(); + + client_stream_delegate()->ExpectCallback(StreamCallbackType::kOnRemoteReset); + // The server stream has received its FIN bit from the remote side, and + // responds with a Reset() to close everything down. + server_stream()->Reset(); + RunUntilCallbacksFired(); + + ExpectStreamsClosed(); + EXPECT_EQ(0, server_stream_delegate()->remote_reset_count()); +} + +// The following unit tests are more isolated to the P2PQuicStreamImpl +// implementation. They only test a stream's behavior on one side (not any +// interactions between two connected streams). + +TEST_F(P2PQuicTransportTest, StreamFinishSendsFinAndCanNoLongerWrite) { + Initialize(); + Connect(); + P2PQuicStreamImpl* stream = client_peer()->quic_transport()->CreateStream(); + + stream->Finish(); + EXPECT_TRUE(stream->fin_sent()); + EXPECT_TRUE(stream->write_side_closed()); + EXPECT_FALSE(stream->reading_stopped()); +} + +TEST_F(P2PQuicTransportTest, StreamResetSendsRstAndBecomesClosed) { + Initialize(); + Connect(); + + P2PQuicStreamImpl* stream = client_peer()->quic_transport()->CreateStream(); + quic::QuicStreamId stream_id = stream->id(); + + stream->Reset(); + + EXPECT_TRUE(client_peer()->quic_transport()->IsClosedStream(stream_id)); +} + +// Tests that when a stream receives a stream frame with the FIN bit set it +// will fire the appropriate callback and close the stream for reading. +TEST_F(P2PQuicTransportTest, StreamOnStreamFrameWithFin) { + Initialize(); + Connect(); + P2PQuicStreamImpl* stream = client_peer()->quic_transport()->CreateStream(); + QuicStreamDelegateForTesting stream_delegate; + stream->SetDelegate(&stream_delegate); + + quic::QuicStreamFrame fin_frame(stream->id(), /*fin=*/true, 0, 0); + stream->OnStreamFrame(fin_frame); + EXPECT_EQ(1, stream_delegate.remote_finish_count()); + EXPECT_TRUE(stream->reading_stopped()); + EXPECT_FALSE(stream->write_side_closed()); +} + +// Tests that when a stream receives a stream frame with the FIN bit set after +// it has called Finish(), then the stream will close. +TEST_F(P2PQuicTransportTest, StreamClosedAfterReceivesFin) { + Initialize(); + Connect(); + P2PQuicStreamImpl* stream = client_peer()->quic_transport()->CreateStream(); + quic::QuicStreamId stream_id = stream->id(); + QuicStreamDelegateForTesting stream_delegate; + stream->SetDelegate(&stream_delegate); + + stream->Finish(); + EXPECT_FALSE(client_peer()->quic_transport()->IsClosedStream(stream_id)); + quic::QuicStreamFrame fin_frame(stream->id(), /*fin=*/true, 0, 0); + stream->OnStreamFrame(fin_frame); + + EXPECT_TRUE(client_peer()->quic_transport()->IsClosedStream(stream_id)); +} + +// Tests that when a stream calls Finish() after receiving a stream frame with +// the FIN bit then the stream will close. +TEST_F(P2PQuicTransportTest, StreamClosedAfterFinish) { + Initialize(); + Connect(); + P2PQuicStreamImpl* stream = client_peer()->quic_transport()->CreateStream(); + quic::QuicStreamId stream_id = stream->id(); + QuicStreamDelegateForTesting stream_delegate; + stream->SetDelegate(&stream_delegate); + + quic::QuicStreamFrame fin_frame(stream->id(), /*fin=*/true, 0, 0); + stream->OnStreamFrame(fin_frame); + EXPECT_FALSE(client_peer()->quic_transport()->IsClosedStream(stream_id)); + stream->Finish(); + + EXPECT_TRUE(client_peer()->quic_transport()->IsClosedStream(stream_id)); +} + +// Tests that when a stream receives a RST_STREAM frame it will fire the +// appropriate callback and the stream will become closed. +TEST_F(P2PQuicTransportTest, StreamClosedAfterReceivingReset) { + Initialize(); + Connect(); + P2PQuicStreamImpl* stream = client_peer()->quic_transport()->CreateStream(); + quic::QuicStreamId stream_id = stream->id(); + QuicStreamDelegateForTesting stream_delegate; + stream->SetDelegate(&stream_delegate); + + quic::QuicRstStreamFrame rst_frame(quic::kInvalidControlFrameId, stream_id, + quic::QUIC_STREAM_CANCELLED, 0); + stream->OnStreamReset(rst_frame); + + EXPECT_EQ(1, stream_delegate.remote_reset_count()); + EXPECT_TRUE(client_peer()->quic_transport()->IsClosedStream(stream_id)); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.cc new file mode 100644 index 00000000000..71545c64e99 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.cc @@ -0,0 +1,88 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.h" + +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h" +#include "third_party/blink/renderer/platform/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/web_task_runner.h" + +namespace blink { + +QuicStreamHost::QuicStreamHost() { + DETACH_FROM_THREAD(thread_checker_); +} + +QuicStreamHost::~QuicStreamHost() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +} + +void QuicStreamHost::set_proxy(base::WeakPtr<QuicStreamProxy> stream_proxy) { + DETACH_FROM_THREAD(thread_checker_); + stream_proxy_ = stream_proxy; +} + +void QuicStreamHost::Initialize(QuicTransportHost* transport_host, + P2PQuicStream* p2p_stream) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(transport_host); + DCHECK(p2p_stream); + transport_host_ = transport_host; + p2p_stream_ = p2p_stream; + p2p_stream_->SetDelegate(this); +} + +scoped_refptr<base::SingleThreadTaskRunner> QuicStreamHost::proxy_thread() + const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(transport_host_); + return transport_host_->proxy_thread(); +} + +void QuicStreamHost::Reset() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(p2p_stream_); + p2p_stream_->Reset(); + Delete(); +} + +void QuicStreamHost::Finish() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(p2p_stream_); + p2p_stream_->Finish(); + writeable_ = false; + if (!readable_ && !writeable_) { + Delete(); + } +} + +void QuicStreamHost::OnRemoteReset() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + PostCrossThreadTask( + *proxy_thread(), FROM_HERE, + CrossThreadBind(&QuicStreamProxy::OnRemoteReset, stream_proxy_)); + Delete(); +} + +void QuicStreamHost::OnRemoteFinish() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + PostCrossThreadTask( + *proxy_thread(), FROM_HERE, + CrossThreadBind(&QuicStreamProxy::OnRemoteFinish, stream_proxy_)); + readable_ = false; + if (!readable_ && !writeable_) { + Delete(); + } +} + +void QuicStreamHost::Delete() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(transport_host_); + // OnRemoveStream will delete |this|. + transport_host_->OnRemoveStream(this); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.h new file mode 100644 index 00000000000..baab847dff6 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.h @@ -0,0 +1,86 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_STREAM_HOST_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_STREAM_HOST_H_ + +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "base/threading/thread_checker.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h" + +namespace blink { + +class QuicStreamProxy; +class QuicTransportHost; + +// This class is the host side correspondent to the QuicStreamProxy. See the +// QuicStreamProxy documentation for background. This class lives on the host +// thread and proxies calls between the QuicStreamProxy and the P2PQuicStream +// (which is single-threaded). +// +// The QuicStreamHost is owned by the QuicTransportHost and constructed when +// either a new local QUIC stream is created or when a remote QUIC stream has +// been created. The stream host will be deleted in the following circumstances: +// 1) Reset() is called. +// 2) OnRemoteReset() is indicated. +// 3) Finish() and OnRemoteFinish() have been called. +// The QuicStreamHost will instruct the QuicTransportHost to delete it when any +// condition has been met. +// +// Since the QuicStreamHost can be constructed from either the proxy or host +// thread, initialization happens in three steps: +// 1) QuicStreamHost is constructed. +// 2) set_proxy is called when a WeakPtr to the corresponding proxy-thread +// object. +// 3) Initialize is called on the host thread. +class QuicStreamHost final : public base::SupportsWeakPtr<QuicStreamHost>, + public P2PQuicStream::Delegate { + public: + QuicStreamHost(); + ~QuicStreamHost() override; + + // Sets a WeakPtr to the corresponding QuicStreamProxy. This is valid on + // either the proxy or host thread. Should happen right after construction. + void set_proxy(base::WeakPtr<QuicStreamProxy> stream_proxy); + + // Initializes the QuicStreamHost. Must be called on the host thread. + // |transport_host| must outlive this object. + void Initialize(QuicTransportHost* transport_host, P2PQuicStream* p2p_stream); + + // The remaining methods can only be called from the host thread and must be + // preceded by Initialize(). + + scoped_refptr<base::SingleThreadTaskRunner> proxy_thread() const; + + void Reset(); + void Finish(); + + private: + // Instruct the QuicTransportHost to remove and delete this stream host. + void Delete(); + + // P2PQuicStream::Delegate overrides. + void OnRemoteReset() override; + void OnRemoteFinish() override; + + // Up reference. Owned by QuicTransportProxy. + QuicTransportHost* transport_host_ = nullptr; + // Forward reference. Owned by P2PQuicTransport. + P2PQuicStream* p2p_stream_ = nullptr; + // Back reference. Owned by QuicTransportProxy. + base::WeakPtr<QuicStreamProxy> stream_proxy_; + + // |readable_| transitions to false when OnRemoteFinish() is called. + bool readable_ = true; + // |writeable_| transitions to false when Finish() is called. + bool writeable_ = true; + + THREAD_CHECKER(thread_checker_); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_STREAM_HOST_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.cc new file mode 100644 index 00000000000..e50ebf0925d --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.cc @@ -0,0 +1,91 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h" + +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h" +#include "third_party/blink/renderer/platform/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/web_task_runner.h" + +namespace blink { + +QuicStreamProxy::QuicStreamProxy() { + DETACH_FROM_THREAD(thread_checker_); +} + +QuicStreamProxy::~QuicStreamProxy() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +} + +void QuicStreamProxy::set_host(base::WeakPtr<QuicStreamHost> stream_host) { + DETACH_FROM_THREAD(thread_checker_); + stream_host_ = stream_host; +} + +void QuicStreamProxy::Initialize(QuicTransportProxy* transport_proxy) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(transport_proxy); + transport_proxy_ = transport_proxy; +} + +void QuicStreamProxy::set_delegate(Delegate* delegate) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(delegate); + delegate_ = delegate; +} + +scoped_refptr<base::SingleThreadTaskRunner> QuicStreamProxy::host_thread() + const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(transport_proxy_); + return transport_proxy_->host_thread(); +} + +void QuicStreamProxy::Reset() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + PostCrossThreadTask(*host_thread(), FROM_HERE, + CrossThreadBind(&QuicStreamHost::Reset, stream_host_)); + Delete(); +} + +void QuicStreamProxy::Finish() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + PostCrossThreadTask(*host_thread(), FROM_HERE, + CrossThreadBind(&QuicStreamHost::Finish, stream_host_)); + writeable_ = false; + if (!readable_ && !writeable_) { + Delete(); + } +} + +void QuicStreamProxy::OnRemoteReset() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(delegate_); + // Need to copy the |delegate_| member since Delete() will destroy |this|. + Delegate* delegate_copy = delegate_; + Delete(); + delegate_copy->OnRemoteReset(); +} + +void QuicStreamProxy::OnRemoteFinish() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(delegate_); + // Need to copy the |delegate_| member since Delete() will destroy |this|. + Delegate* delegate_copy = delegate_; + readable_ = false; + if (!readable_ && !writeable_) { + Delete(); + } + delegate_copy->OnRemoteFinish(); +} + +void QuicStreamProxy::Delete() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + // OnRemoveStream will delete |this|. + transport_proxy_->OnRemoveStream(this); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h new file mode 100644 index 00000000000..0d059f635f6 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h @@ -0,0 +1,98 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_STREAM_PROXY_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_STREAM_PROXY_H_ + +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "base/threading/thread_checker.h" + +namespace blink { + +class QuicStreamHost; +class QuicTransportProxy; + +// This class allows interactions with a QUIC stream that runs on a thread +// different from which it is controlled. All interactions with the QUIC +// implementation happen asynchronously. +// +// The QuicStreamProxy is owned by the QuicTransportProxy and constructed when +// either a new local QUIC stream is created or when a remote QUIC stream has +// been created. The stream proxy will be deleted in the following +// circumstances: +// 1) Reset() is called. +// 2) OnRemoteReset() is indicated. +// 3) Finish() and OnRemoteFinish() have been called. +// The client is responsible for knowing when any of these conditions have been +// met and clearing its reference accordingly. +// +// Since the QuicStreamProxy can be constructed from either the proxy or host +// thread, initialization happens in four steps: +// 1) QuicStreamProxy is constructed. +// 2) set_host is called with a WeakPtr to the corresponding host-thread object. +// 3) Initialize is called on the proxy thread. +// 4) set_delegate is called on the proxy thread. +class QuicStreamProxy final : public base::SupportsWeakPtr<QuicStreamProxy> { + public: + class Delegate { + public: + virtual ~Delegate() = default; + + // Called when the remote side resets the stream. + virtual void OnRemoteReset() {} + // Called when the remote side finishes the stream. + virtual void OnRemoteFinish() {} + }; + + QuicStreamProxy(); + ~QuicStreamProxy(); + + // Sets a WeakPtr to the corresponding QuicStreamHost. This is valid on either + // the proxy or host thread. Should happen right after construction. + void set_host(base::WeakPtr<QuicStreamHost> stream_host); + + // Initializes the QuicStreamProxy. Must be called on the proxy thread. + // |transport_proxy| must outlive this object. + void Initialize(QuicTransportProxy* transport_proxy); + + // Sets the delegate for receiving remote callbacks. + void set_delegate(Delegate* delegate); + + // The remaining methods can only be called from the proxy thread and must + // be preceded by Initialize(). + + scoped_refptr<base::SingleThreadTaskRunner> host_thread() const; + + void Reset(); + void Finish(); + + private: + // Instruct the QuicTransportProxy to remove and delete this stream proxy. + void Delete(); + + // Callbacks from QuicStreamHost. + friend class QuicStreamHost; + void OnRemoteReset(); + void OnRemoteFinish(); + + // Up reference. Owned by the QuicTransportProxy client. + QuicTransportProxy* transport_proxy_ = nullptr; + // Forward reference. Owned by the QuicTransportHost. + base::WeakPtr<QuicStreamHost> stream_host_; + // Back reference. Owned by the RTCQuicTransport. + Delegate* delegate_ = nullptr; + + // |readable_| transitions to false when OnRemoteFinish() is called. + bool readable_ = true; + // |writeable_| transitions to false when Finish() is called. + bool writeable_ = true; + + THREAD_CHECKER(thread_checker_); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_STREAM_PROXY_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc new file mode 100644 index 00000000000..cc99a068d8e --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc @@ -0,0 +1,139 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h" + +#include <utility> + +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h" +#include "third_party/blink/renderer/platform/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/web_task_runner.h" + +namespace blink { + +QuicTransportHost::QuicTransportHost( + base::WeakPtr<QuicTransportProxy> proxy, + std::unique_ptr<P2PQuicTransportFactory> quic_transport_factory) + : quic_transport_factory_(std::move(quic_transport_factory)), + proxy_(std::move(proxy)) { + DETACH_FROM_THREAD(thread_checker_); + DCHECK(quic_transport_factory_); + DCHECK(proxy_); +} + +QuicTransportHost::~QuicTransportHost() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + // If the TaskRunner this is getting initialized on is destroyed before + // Initialize is called then |ice_transport_host_| may still be null. + if (ice_transport_host_) { + ice_transport_host_->DisconnectConsumer(this); + } +} + +void QuicTransportHost::Initialize( + IceTransportHost* ice_transport_host, + quic::Perspective perspective, + const std::vector<rtc::scoped_refptr<rtc::RTCCertificate>>& certificates) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(ice_transport_host); + DCHECK(!ice_transport_host_); + ice_transport_host_ = ice_transport_host; + P2PQuicTransportConfig config( + this, ice_transport_host->ConnectConsumer(this)->packet_transport(), + certificates); + config.is_server = (perspective == quic::Perspective::IS_SERVER); + quic_transport_ = + quic_transport_factory_->CreateQuicTransport(std::move(config)); +} + +scoped_refptr<base::SingleThreadTaskRunner> QuicTransportHost::proxy_thread() + const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return ice_transport_host_->proxy_thread(); +} + +scoped_refptr<base::SingleThreadTaskRunner> QuicTransportHost::host_thread() + const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return ice_transport_host_->host_thread(); +} + +void QuicTransportHost::Start( + std::vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + quic_transport_->Start(std::move(remote_fingerprints)); +} + +void QuicTransportHost::Stop() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + quic_transport_->Stop(); +} + +void QuicTransportHost::CreateStream( + std::unique_ptr<QuicStreamHost> stream_host) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + P2PQuicStream* p2p_stream = quic_transport_->CreateStream(); + stream_host->Initialize(this, p2p_stream); + stream_hosts_.insert( + std::make_pair(stream_host.get(), std::move(stream_host))); +} + +void QuicTransportHost::OnRemoveStream(QuicStreamHost* stream_host_to_remove) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + auto it = stream_hosts_.find(stream_host_to_remove); + DCHECK(it != stream_hosts_.end()); + stream_hosts_.erase(it); +} + +void QuicTransportHost::OnRemoteStopped() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + stream_hosts_.clear(); + PostCrossThreadTask( + *proxy_thread(), FROM_HERE, + CrossThreadBind(&QuicTransportProxy::OnRemoteStopped, proxy_)); +} + +void QuicTransportHost::OnConnectionFailed(const std::string& error_details, + bool from_remote) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + stream_hosts_.clear(); + PostCrossThreadTask(*proxy_thread(), FROM_HERE, + CrossThreadBind(&QuicTransportProxy::OnConnectionFailed, + proxy_, error_details, from_remote)); +} + +void QuicTransportHost::OnConnected() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + PostCrossThreadTask( + *proxy_thread(), FROM_HERE, + CrossThreadBind(&QuicTransportProxy::OnConnected, proxy_)); +} + +void QuicTransportHost::OnStream(P2PQuicStream* p2p_stream) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(p2p_stream); + + auto stream_proxy = std::make_unique<QuicStreamProxy>(); + auto stream_host = std::make_unique<QuicStreamHost>(); + stream_proxy->set_host(stream_host->AsWeakPtr()); + stream_host->set_proxy(stream_proxy->AsWeakPtr()); + + stream_host->Initialize(this, p2p_stream); + + stream_hosts_.insert( + std::make_pair(stream_host.get(), std::move(stream_host))); + + PostCrossThreadTask(*proxy_thread(), FROM_HERE, + CrossThreadBind(&QuicTransportProxy::OnStream, proxy_, + WTF::Passed(std::move(stream_proxy)))); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h new file mode 100644 index 00000000000..82b52eeb929 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h @@ -0,0 +1,90 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_TRANSPORT_HOST_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_TRANSPORT_HOST_H_ + +#include <unordered_map> + +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "base/threading/thread_checker.h" +#include "net/third_party/quic/core/quic_types.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h" + +namespace blink { + +class IceTransportHost; +class P2PQuicTransportFactory; +class QuicStreamHost; +class QuicTransportProxy; + +// The host class is the host side correspondent to the QuicTransportProxy. See +// the QuicTransportProxy documentation for background. This class lives on the +// host thread and proxies calls between the QuicTransportProxy and the +// P2PQuicTransport (which is single-threaded). +// +// proxy thread host thread +// +-----------------------+ +-----------------------------------+ +// | | | | +// | <-> ICE Proxy | =========> | ICE Host <-> P2PTransportChannel | +// | ^ | <--------- | ^ ^ | +// | client | | | | | | +// | v | | v v | +// | <-> QUIC Proxy | =========> | QUIC Host <-> P2PQuicTransport | +// | | <--------- | | +// +-----------------------+ +-----------------------------------+ +// +// The QuicTransportHost connects to the underlying IceTransportHost in +// Initialize and disconnects in the destructor. The IceTransportHost must +// outlive the QuicTransportHost. +// +// The Host can be constructed on any thread but after that point all methods +// must be called on the host thread. +class QuicTransportHost final : public P2PQuicTransport::Delegate { + public: + QuicTransportHost( + base::WeakPtr<QuicTransportProxy> transport_proxy, + std::unique_ptr<P2PQuicTransportFactory> quic_transport_factory); + ~QuicTransportHost() override; + + void Initialize( + IceTransportHost* ice_transport_host, + quic::Perspective perspective, + const std::vector<rtc::scoped_refptr<rtc::RTCCertificate>>& certificates); + + scoped_refptr<base::SingleThreadTaskRunner> proxy_thread() const; + scoped_refptr<base::SingleThreadTaskRunner> host_thread() const; + + void Start( + std::vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints); + void Stop(); + + void CreateStream(std::unique_ptr<QuicStreamHost> stream_host); + + // QuicStreamHost callbacks. + void OnRemoveStream(QuicStreamHost* stream_host_to_remove); + + private: + // P2PQuicTransport::Delegate overrides. + void OnRemoteStopped() override; + void OnConnectionFailed(const std::string& error_details, + bool from_remote) override; + void OnConnected() override; + void OnStream(P2PQuicStream* stream) override; + + std::unique_ptr<P2PQuicTransportFactory> quic_transport_factory_; + std::unique_ptr<P2PQuicTransport> quic_transport_; + base::WeakPtr<QuicTransportProxy> proxy_; + IceTransportHost* ice_transport_host_ = nullptr; + std::unordered_map<QuicStreamHost*, std::unique_ptr<QuicStreamHost>> + stream_hosts_; + + THREAD_CHECKER(thread_checker_); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_TRANSPORT_HOST_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc new file mode 100644 index 00000000000..af29f9e0546 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc @@ -0,0 +1,151 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h" + +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h" +#include "third_party/blink/renderer/platform/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/web_task_runner.h" + +namespace blink { + +QuicTransportProxy::QuicTransportProxy( + Delegate* delegate, + IceTransportProxy* ice_transport_proxy, + quic::Perspective perspective, + const std::vector<rtc::scoped_refptr<rtc::RTCCertificate>>& certificates, + std::unique_ptr<P2PQuicTransportFactory> quic_transport_factory) + : host_(nullptr, + base::OnTaskRunnerDeleter(ice_transport_proxy->host_thread())), + delegate_(delegate), + ice_transport_proxy_(ice_transport_proxy), + weak_ptr_factory_(this) { + DCHECK(delegate_); + DCHECK(ice_transport_proxy_); + scoped_refptr<base::SingleThreadTaskRunner> proxy_thread = + ice_transport_proxy->proxy_thread(); + DCHECK(proxy_thread->BelongsToCurrentThread()); + // Wait to initialize the host until the weak_ptr_factory_ is initialized. + // The QuicTransportHost is constructed on the proxy thread but should only be + // interacted with via PostTask to the host thread. The OnTaskRunnerDeleter + // (configured above) will ensure it gets deleted on the host thread. + host_.reset(new QuicTransportHost(weak_ptr_factory_.GetWeakPtr(), + std::move(quic_transport_factory))); + // Connect to the IceTransportProxy. This gives us a reference to the + // underlying IceTransportHost that should be connected by the + // QuicTransportHost on the host thread. It is safe to post it unretained + // since the IceTransportHost's ownership is determined by the + // IceTransportProxy, and the IceTransportProxy is required to outlive this + // object. + IceTransportHost* ice_transport_host = + ice_transport_proxy->ConnectConsumer(this); + PostCrossThreadTask(*host_thread(), FROM_HERE, + CrossThreadBind(&QuicTransportHost::Initialize, + CrossThreadUnretained(host_.get()), + CrossThreadUnretained(ice_transport_host), + perspective, certificates)); +} + +QuicTransportProxy::~QuicTransportProxy() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + ice_transport_proxy_->DisconnectConsumer(this); + // Note: The QuicTransportHost will be deleted on the host thread. +} + +scoped_refptr<base::SingleThreadTaskRunner> QuicTransportProxy::proxy_thread() + const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return ice_transport_proxy_->proxy_thread(); +} + +scoped_refptr<base::SingleThreadTaskRunner> QuicTransportProxy::host_thread() + const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return ice_transport_proxy_->host_thread(); +} + +void QuicTransportProxy::Start( + std::vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + PostCrossThreadTask( + *host_thread(), FROM_HERE, + CrossThreadBind(&QuicTransportHost::Start, + CrossThreadUnretained(host_.get()), + WTF::Passed(std::move(remote_fingerprints)))); +} + +void QuicTransportProxy::Stop() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + PostCrossThreadTask(*host_thread(), FROM_HERE, + CrossThreadBind(&QuicTransportHost::Stop, + CrossThreadUnretained(host_.get()))); +} + +QuicStreamProxy* QuicTransportProxy::CreateStream() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + auto stream_proxy = std::make_unique<QuicStreamProxy>(); + auto stream_host = std::make_unique<QuicStreamHost>(); + stream_proxy->set_host(stream_host->AsWeakPtr()); + stream_host->set_proxy(stream_proxy->AsWeakPtr()); + + stream_proxy->Initialize(this); + + PostCrossThreadTask(*host_thread(), FROM_HERE, + CrossThreadBind(&QuicTransportHost::CreateStream, + CrossThreadUnretained(host_.get()), + WTF::Passed(std::move(stream_host)))); + + QuicStreamProxy* stream_proxy_ptr = stream_proxy.get(); + stream_proxies_.insert( + std::make_pair(stream_proxy_ptr, std::move(stream_proxy))); + return stream_proxy_ptr; +} + +void QuicTransportProxy::OnRemoveStream( + QuicStreamProxy* stream_proxy_to_remove) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + auto it = stream_proxies_.find(stream_proxy_to_remove); + DCHECK(it != stream_proxies_.end()); + stream_proxies_.erase(it); +} + +void QuicTransportProxy::OnConnected() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + delegate_->OnConnected(); +} + +void QuicTransportProxy::OnRemoteStopped() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + stream_proxies_.clear(); + delegate_->OnRemoteStopped(); +} + +void QuicTransportProxy::OnConnectionFailed(const std::string& error_details, + bool from_remote) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + delegate_->OnConnectionFailed(error_details, from_remote); + stream_proxies_.clear(); +} + +void QuicTransportProxy::OnStream( + std::unique_ptr<QuicStreamProxy> stream_proxy) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + stream_proxy->Initialize(this); + + QuicStreamProxy* stream_proxy_ptr = stream_proxy.get(); + stream_proxies_.insert( + std::make_pair(stream_proxy_ptr, std::move(stream_proxy))); + delegate_->OnStream(stream_proxy_ptr); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h new file mode 100644 index 00000000000..004aced7f9d --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h @@ -0,0 +1,110 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_TRANSPORT_PROXY_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_TRANSPORT_PROXY_H_ + +#include <unordered_map> +#include <vector> + +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "base/threading/thread_checker.h" +#include "net/third_party/quic/core/quic_types.h" +#include "third_party/webrtc/rtc_base/scoped_ref_ptr.h" + +namespace rtc { +class RTCCertificate; +struct SSLFingerprint; +} // namespace rtc + +namespace blink { + +class IceTransportProxy; +class QuicStreamProxy; +class QuicTransportHost; +class P2PQuicTransportFactory; + +// This class allows the QUIC implementation (P2PQuicTransport) to run on a +// thread different from the thread from which it is controlled. All +// interactions with the QUIC implementation happen asynchronously. +// +// The QuicTransportProxy is intended to be used with an IceTransportProxy -- +// see the IceTransportProxy class documentation for background and terms. The +// proxy and host threads used with the QuicTransportProxy should be the same as +// the ones used with the connected IceTransportProxy. +class QuicTransportProxy final { + public: + // Delegate for receiving callbacks from the QUIC implementation. These all + // run on the proxy thread. + class Delegate { + public: + virtual ~Delegate() = default; + + // Called when the QUIC handshake finishes and fingerprints have been + // verified. + virtual void OnConnected() {} + // Called when the remote side has indicated it is closed. + virtual void OnRemoteStopped() {} + // Called when the connection is closed due to a QUIC error. This can happen + // locally by the framer or remotely by the peer. + virtual void OnConnectionFailed(const std::string& error_details, + bool from_remote) {} + // Called when the remote side has created a new stream. + virtual void OnStream(QuicStreamProxy* stream_proxy) {} + }; + + // Construct a Proxy with the underlying QUIC implementation running on the + // same thread as the IceTransportProxy. Callbacks will be serviced by the + // given delegate. + // The delegate and IceTransportProxy must outlive the QuicTransportProxy. + // The QuicTransportProxy will immediately connect to the given + // IceTransportProxy; it can be disconnected by destroying the + // QuicTransportProxy object. + QuicTransportProxy( + Delegate* delegate, + IceTransportProxy* ice_transport_proxy, + quic::Perspective perspective, + const std::vector<rtc::scoped_refptr<rtc::RTCCertificate>>& certificates, + std::unique_ptr<P2PQuicTransportFactory> quic_transport_factory); + ~QuicTransportProxy(); + + scoped_refptr<base::SingleThreadTaskRunner> proxy_thread() const; + scoped_refptr<base::SingleThreadTaskRunner> host_thread() const; + + void Start( + std::vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints); + void Stop(); + + QuicStreamProxy* CreateStream(); + + // QuicStreamProxy callbacks. + void OnRemoveStream(QuicStreamProxy* stream_proxy); + + private: + // Callbacks from QuicTransportHost. + friend class QuicTransportHost; + void OnConnected(); + void OnRemoteStopped(); + void OnConnectionFailed(const std::string& error_details, bool from_remote); + void OnStream(std::unique_ptr<QuicStreamProxy> stream_proxy); + + // Since the Host is deleted on the host thread (Via OnTaskRunnerDeleter), as + // long as this is alive it is safe to post tasks to it (using unretained). + std::unique_ptr<QuicTransportHost, base::OnTaskRunnerDeleter> host_; + Delegate* const delegate_; + IceTransportProxy* ice_transport_proxy_; + std::unordered_map<QuicStreamProxy*, std::unique_ptr<QuicStreamProxy>> + stream_proxies_; + + THREAD_CHECKER(thread_checker_); + + // Must be the last member. + base::WeakPtrFactory<QuicTransportProxy> weak_ptr_factory_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_TRANSPORT_PROXY_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h index 7f19fb64954..73ab10b27a1 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h +++ b/chromium/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h @@ -8,10 +8,12 @@ // This file defines specializations for the CrossThreadCopier that allow WebRTC // types to be passed across threads using their copy constructors. +#include <memory> #include <set> #include <vector> #include "third_party/blink/renderer/platform/cross_thread_copier.h" +#include "third_party/webrtc/rtc_base/scoped_ref_ptr.h" namespace cricket { class Candidate; @@ -20,12 +22,26 @@ struct RelayServerConfig; } // namespace cricket namespace rtc { +class RTCCertificate; class SocketAddress; } namespace blink { template <> +struct CrossThreadCopier<std::string> + : public CrossThreadCopierPassThrough<std::string> { + STATIC_ONLY(CrossThreadCopier); +}; + +template <typename T, typename Allocator> +struct CrossThreadCopier<std::vector<std::unique_ptr<T>, Allocator>> { + STATIC_ONLY(CrossThreadCopier); + using Type = std::vector<std::unique_ptr<T>, Allocator>; + static Type Copy(Type vector) { return std::move(vector); } +}; + +template <> struct CrossThreadCopier<cricket::IceParameters> : public CrossThreadCopierPassThrough<cricket::IceParameters> { STATIC_ONLY(CrossThreadCopier); @@ -45,11 +61,31 @@ struct CrossThreadCopier<std::vector<cricket::RelayServerConfig>> }; template <> +struct CrossThreadCopier<std::vector<cricket::Candidate>> + : public CrossThreadCopierPassThrough<std::vector<cricket::Candidate>> { + STATIC_ONLY(CrossThreadCopier); +}; + +template <> struct CrossThreadCopier<cricket::Candidate> : public CrossThreadCopierPassThrough<cricket::Candidate> { STATIC_ONLY(CrossThreadCopier); }; +template <> +struct CrossThreadCopier<std::vector<rtc::scoped_refptr<rtc::RTCCertificate>>> + : public CrossThreadCopierPassThrough< + std::vector<rtc::scoped_refptr<rtc::RTCCertificate>>> { + STATIC_ONLY(CrossThreadCopier); +}; + +template <> +struct CrossThreadCopier<std::pair<cricket::Candidate, cricket::Candidate>> + : public CrossThreadCopierPassThrough< + std::pair<cricket::Candidate, cricket::Candidate>> { + STATIC_ONLY(CrossThreadCopier); +}; + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_WEB_RTC_CROSS_THREAD_COPIER_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.idl index e80074f057d..44ced3eb309 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.idl +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_certificate.idl @@ -29,7 +29,7 @@ */ // https://w3c.github.io/webrtc-pc/#rtccertificate-interface -[Exposed=Window] +[Exposed=Window, Serializable] interface RTCCertificate { // The expiration time in ms relative to epoch, 1970-01-01T00:00:00Z. readonly attribute DOMTimeStamp expires; diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.cc index 8f44593af4f..d312c8030e0 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.cc +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.cc @@ -35,15 +35,14 @@ #include "third_party/blink/renderer/modules/mediastream/media_stream_track.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_dtmf_tone_change_event.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/wtf/functional.h" namespace blink { static const int kMinToneDurationMs = 40; static const int kDefaultToneDurationMs = 100; static const int kMaxToneDurationMs = 6000; -// TODO(hta): Adjust kMinInterToneGapMs to 30 once WebRTC code has changed -// CL in progress: https://webrtc-review.googlesource.com/c/src/+/55260 -static const int kMinInterToneGapMs = 50; +static const int kMinInterToneGapMs = 30; static const int kMaxInterToneGapMs = 6000; static const int kDefaultInterToneGapMs = 70; @@ -58,10 +57,7 @@ RTCDTMFSender::RTCDTMFSender(ExecutionContext* context, std::unique_ptr<WebRTCDTMFSenderHandler> handler) : ContextLifecycleObserver(context), handler_(std::move(handler)), - stopped_(false), - scheduled_event_timer_(context->GetTaskRunner(TaskType::kNetworking), - this, - &RTCDTMFSender::ScheduledEventTimerFired) { + stopped_(false) { handler_->SetClient(this); } @@ -79,7 +75,7 @@ bool RTCDTMFSender::canInsertDTMF() const { } String RTCDTMFSender::toneBuffer() const { - return handler_->CurrentToneBuffer(); + return tone_buffer_; } void RTCDTMFSender::insertDTMF(const String& tones, @@ -99,8 +95,6 @@ void RTCDTMFSender::insertDTMF(const String& tones, int inter_tone_gap, ExceptionState& exception_state) { // https://w3c.github.io/webrtc-pc/#dom-rtcdtmfsender-insertdtmf - // TODO(hta): Add check on transceiver's "stopped" and "currentDirection" - // attributes if (!canInsertDTMF()) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, "The 'canInsertDTMF' attribute is false: " @@ -116,23 +110,61 @@ void RTCDTMFSender::insertDTMF(const String& tones, } // Spec: Clamp the duration to between 40 and 6000 ms - duration = std::max(duration, kMinToneDurationMs); - duration = std::min(duration, kMaxToneDurationMs); + duration_ = std::max(duration, kMinToneDurationMs); + duration_ = std::min(duration_, kMaxToneDurationMs); // Spec: Clamp the inter-tone gap to between 30 and 6000 ms - inter_tone_gap = std::max(inter_tone_gap, kMinInterToneGapMs); - inter_tone_gap = std::min(inter_tone_gap, kMaxInterToneGapMs); + inter_tone_gap_ = std::max(inter_tone_gap, kMinInterToneGapMs); + inter_tone_gap_ = std::min(inter_tone_gap_, kMaxInterToneGapMs); // Spec: a-d should be represented in the tone buffer as A-D - if (!handler_->InsertDTMF(tones.UpperASCII(), duration, inter_tone_gap)) { - exception_state.ThrowDOMException( - DOMExceptionCode::kSyntaxError, - "Could not send provided tones, '" + tones + "'."); + tone_buffer_ = tones.UpperASCII(); + + if (tone_buffer_.IsEmpty()) { + return; + } + if (!playout_task_is_scheduled_) { + playout_task_is_scheduled_ = true; + GetExecutionContext() + ->GetTaskRunner(TaskType::kNetworking) + ->PostTask(FROM_HERE, WTF::Bind(&RTCDTMFSender::PlayoutTask, + WrapPersistent(this))); + } +} + +void RTCDTMFSender::PlayoutTask() { + playout_task_is_scheduled_ = false; + // TODO(crbug.com/891638): Add check on transceiver's "stopped" + // and "currentDirection" attributes as per spec. + if (tone_buffer_.IsEmpty()) { + Member<Event> event = RTCDTMFToneChangeEvent::Create(""); + DispatchEvent(*event.Release()); + return; + } + WebString this_tone = tone_buffer_.Substring(0, 1); + tone_buffer_ = tone_buffer_.Substring(1, tone_buffer_.length() - 1); + // InsertDTMF handles both tones and ",", and calls DidPlayTone after + // the specified delay. + if (!handler_->InsertDTMF(this_tone, duration_, inter_tone_gap_)) { + LOG(ERROR) << "DTMF: Could not send provided tone, '" << this_tone.Ascii() + << "'."; return; } + playout_task_is_scheduled_ = true; + Member<Event> event = RTCDTMFToneChangeEvent::Create(this_tone); + DispatchEvent(*event.Release()); } void RTCDTMFSender::DidPlayTone(const WebString& tone) { - ScheduleDispatchEvent(RTCDTMFToneChangeEvent::Create(tone)); + // We're using the DidPlayTone with an empty buffer to signal the + // end of the tone. + if (tone.IsEmpty()) { + GetExecutionContext() + ->GetTaskRunner(TaskType::kNetworking) + ->PostDelayedTask( + FROM_HERE, + WTF::Bind(&RTCDTMFSender::PlayoutTask, WrapPersistent(this)), + base::TimeDelta::FromMilliseconds(inter_tone_gap_)); + } } const AtomicString& RTCDTMFSender::InterfaceName() const { @@ -148,27 +180,7 @@ void RTCDTMFSender::ContextDestroyed(ExecutionContext*) { handler_->SetClient(nullptr); } -void RTCDTMFSender::ScheduleDispatchEvent(Event* event) { - scheduled_events_.push_back(event); - - if (!scheduled_event_timer_.IsActive()) - scheduled_event_timer_.StartOneShot(TimeDelta(), FROM_HERE); -} - -void RTCDTMFSender::ScheduledEventTimerFired(TimerBase*) { - if (stopped_) - return; - - HeapVector<Member<Event>> events; - events.swap(scheduled_events_); - - HeapVector<Member<Event>>::iterator it = events.begin(); - for (; it != events.end(); ++it) - DispatchEvent(*it->Release()); -} - void RTCDTMFSender::Trace(blink::Visitor* visitor) { - visitor->Trace(scheduled_events_); EventTargetWithInlineData::Trace(visitor); ContextLifecycleObserver::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.h index c356c957487..1ee1ead6834 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.h +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.h @@ -75,18 +75,17 @@ class RTCDTMFSender final : public EventTargetWithInlineData, std::unique_ptr<WebRTCDTMFSenderHandler>); void Dispose(); - void ScheduleDispatchEvent(Event*); - void ScheduledEventTimerFired(TimerBase*); - // WebRTCDTMFSenderHandlerClient + void PlayoutTask(); void DidPlayTone(const WebString&) override; std::unique_ptr<WebRTCDTMFSenderHandler> handler_; bool stopped_; - - TaskRunnerTimer<RTCDTMFSender> scheduled_event_timer_; - HeapVector<Member<Event>> scheduled_events_; + String tone_buffer_; + int duration_; + int inter_tone_gap_; + bool playout_task_is_scheduled_ = false; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h index 08aa5b19001..b5715c8dee9 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h @@ -32,6 +32,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ICE_CANDIDATE_H_ #include "third_party/blink/public/platform/web_rtc_ice_candidate.h" +#include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/wtf/forward.h" @@ -43,7 +44,7 @@ class ExecutionContext; class ScriptState; class ScriptValue; -class RTCIceCandidate final : public ScriptWrappable { +class MODULES_EXPORT RTCIceCandidate final : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc index 117eccf66e5..2f4c4d6d152 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc @@ -5,11 +5,13 @@ #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h" #include "third_party/blink/public/platform/platform.h" -#include "third_party/blink/public/platform/web_thread.h" #include "third_party/blink/public/web/web_local_frame.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_cross_thread_factory.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_error_util.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_gather_options.h" @@ -17,6 +19,8 @@ #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_server.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event_init.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/webrtc/api/jsepicecandidate.h" #include "third_party/webrtc/api/peerconnectioninterface.h" #include "third_party/webrtc/p2p/base/portallocator.h" @@ -47,25 +51,71 @@ RTCIceCandidate* ConvertToRtcIceCandidate(const cricket::Candidate& candidate) { WebString::FromUTF8(webrtc::SdpSerializeCandidate(candidate)), "", 0)); } +class DefaultIceTransportAdapterCrossThreadFactory + : public IceTransportAdapterCrossThreadFactory { + public: + void InitializeOnMainThread() override { + DCHECK(!port_allocator_); + DCHECK(!worker_thread_rtc_thread_); + port_allocator_ = Platform::Current()->CreateWebRtcPortAllocator( + WebLocalFrame::FrameForCurrentContext()); + worker_thread_rtc_thread_ = + Platform::Current()->GetWebRtcWorkerThreadRtcThread(); + } + + std::unique_ptr<IceTransportAdapter> ConstructOnWorkerThread( + IceTransportAdapter::Delegate* delegate) override { + DCHECK(port_allocator_); + DCHECK(worker_thread_rtc_thread_); + return std::make_unique<IceTransportAdapterImpl>( + delegate, std::move(port_allocator_), worker_thread_rtc_thread_); + } + + private: + std::unique_ptr<cricket::PortAllocator> port_allocator_; + rtc::Thread* worker_thread_rtc_thread_ = nullptr; +}; + } // namespace RTCIceTransport* RTCIceTransport::Create(ExecutionContext* context) { - return new RTCIceTransport(context); -} - -RTCIceTransport::RTCIceTransport(ExecutionContext* context) + LocalFrame* frame = To<Document>(context)->GetFrame(); + scoped_refptr<base::SingleThreadTaskRunner> proxy_thread = + frame->GetTaskRunner(TaskType::kNetworking); + scoped_refptr<base::SingleThreadTaskRunner> host_thread = + Platform::Current()->GetWebRtcWorkerThread(); + return new RTCIceTransport( + context, std::move(proxy_thread), std::move(host_thread), + std::make_unique<DefaultIceTransportAdapterCrossThreadFactory>()); +} + +RTCIceTransport* RTCIceTransport::Create( + ExecutionContext* context, + scoped_refptr<base::SingleThreadTaskRunner> proxy_thread, + scoped_refptr<base::SingleThreadTaskRunner> host_thread, + std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory) { + return new RTCIceTransport(context, std::move(proxy_thread), + std::move(host_thread), + std::move(adapter_factory)); +} + +RTCIceTransport::RTCIceTransport( + ExecutionContext* context, + scoped_refptr<base::SingleThreadTaskRunner> proxy_thread, + scoped_refptr<base::SingleThreadTaskRunner> host_thread, + std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory) : ContextLifecycleObserver(context) { - Document* document = ToDocument(GetExecutionContext()); - LocalFrame* frame = document->GetFrame(); - DCHECK(frame); + DCHECK(context); + DCHECK(proxy_thread); + DCHECK(host_thread); + DCHECK(adapter_factory); + DCHECK(proxy_thread->BelongsToCurrentThread()); - std::unique_ptr<cricket::PortAllocator> port_allocator = - Platform::Current()->CreateWebRtcPortAllocator( - WebLocalFrame::FrameForCurrentContext()); + LocalFrame* frame = To<Document>(context)->GetFrame(); + DCHECK(frame); proxy_.reset(new IceTransportProxy( - frame->GetFrameScheduler(), Platform::Current()->GetWebRtcWorkerThread(), - Platform::Current()->GetWebRtcWorkerThreadRtcThread(), this, - std::move(port_allocator))); + frame->GetFrameScheduler(), std::move(proxy_thread), + std::move(host_thread), this, std::move(adapter_factory))); GenerateLocalParameters(); } @@ -74,6 +124,29 @@ RTCIceTransport::~RTCIceTransport() { DCHECK(!proxy_); } +bool RTCIceTransport::HasConsumer() const { + return consumer_; +} + +IceTransportProxy* RTCIceTransport::ConnectConsumer( + RTCQuicTransport* consumer) { + DCHECK(consumer); + DCHECK(proxy_); + if (!consumer_) { + consumer_ = consumer; + } else { + DCHECK_EQ(consumer_, consumer); + } + return proxy_.get(); +} + +void RTCIceTransport::DisconnectConsumer(RTCQuicTransport* consumer) { + DCHECK(consumer); + DCHECK(proxy_); + DCHECK_EQ(consumer, consumer_); + consumer_ = nullptr; +} + String RTCIceTransport::role() const { switch (role_) { case cricket::ICEROLE_CONTROLLING: @@ -187,6 +260,17 @@ ConvertIceServers(const HeapVector<RTCIceServer>& ice_servers) { return converted_ice_servers; } +static IceTransportPolicy IceTransportPolicyFromString(const String& str) { + if (str == "relay") { + return IceTransportPolicy::kRelay; + } + if (str == "all") { + return IceTransportPolicy::kAll; + } + NOTREACHED(); + return IceTransportPolicy::kAll; +} + void RTCIceTransport::gather(const RTCIceGatherOptions& options, ExceptionState& exception_state) { if (RaiseExceptionIfClosed(exception_state)) { @@ -214,14 +298,9 @@ void RTCIceTransport::gather(const RTCIceGatherOptions& options, return; } gathering_state_ = cricket::kIceGatheringGathering; - uint32_t candidate_filter = cricket::CF_ALL; - if (options.gatherPolicy() == "relay") { - candidate_filter = cricket::CF_RELAY; - } else { - DCHECK_EQ(options.gatherPolicy(), "all"); - } proxy_->StartGathering(ConvertIceParameters(local_parameters_), stun_servers, - turn_servers, candidate_filter); + turn_servers, + IceTransportPolicyFromString(options.gatherPolicy())); } static cricket::IceRole IceRoleFromString(const String& role_string) { @@ -267,21 +346,26 @@ void RTCIceTransport::start(const RTCIceParameters& remote_parameters, } if (!remote_parameters_) { // Calling start() for the first time. - proxy_->SetRole(role); role_ = role; if (remote_candidates_.size() > 0) { - for (RTCIceCandidate* remote_candidate : remote_candidates_) { - // This conversion is safe since we throw an exception in - // addRemoteCandidate on malformed ICE candidates. - proxy_->AddRemoteCandidate( - *ConvertToCricketIceCandidate(*remote_candidate)); - } state_ = RTCIceTransportState::kChecking; } + std::vector<cricket::Candidate> initial_remote_candidates; + for (RTCIceCandidate* remote_candidate : remote_candidates_) { + // This conversion is safe since we throw an exception in + // addRemoteCandidate on malformed ICE candidates. + initial_remote_candidates.push_back( + *ConvertToCricketIceCandidate(*remote_candidate)); + } + proxy_->Start(ConvertIceParameters(remote_parameters), role, + initial_remote_candidates); + if (consumer_) { + consumer_->OnTransportStarted(); + } } else { - proxy_->ClearRemoteCandidates(); remote_candidates_.clear(); state_ = RTCIceTransportState::kNew; + proxy_->HandleRemoteRestart(ConvertIceParameters(remote_parameters)); } remote_parameters_ = remote_parameters; } @@ -290,7 +374,13 @@ void RTCIceTransport::stop() { if (IsClosed()) { return; } + if (HasConsumer()) { + consumer_->stop(); + } + // Stopping the consumer should cause it to disconnect. + DCHECK(!HasConsumer()); state_ = RTCIceTransportState::kClosed; + selected_candidate_pair_ = base::nullopt; proxy_.reset(); } @@ -366,9 +456,25 @@ void RTCIceTransport::OnStateChanged(cricket::IceTransportState new_state) { return; } state_ = local_new_state; + if (state_ == RTCIceTransportState::kFailed) { + selected_candidate_pair_ = base::nullopt; + } DispatchEvent(*Event::Create(EventTypeNames::statechange)); } +void RTCIceTransport::OnSelectedCandidatePairChanged( + const std::pair<cricket::Candidate, cricket::Candidate>& + selected_candidate_pair) { + RTCIceCandidate* local = + ConvertToRtcIceCandidate(selected_candidate_pair.first); + RTCIceCandidate* remote = + ConvertToRtcIceCandidate(selected_candidate_pair.second); + selected_candidate_pair_ = RTCIceCandidatePair(); + selected_candidate_pair_->setLocal(local); + selected_candidate_pair_->setRemote(remote); + DispatchEvent(*Event::Create(EventTypeNames::selectedcandidatepairchange)); +} + bool RTCIceTransport::RaiseExceptionIfClosed( ExceptionState& exception_state) const { if (IsClosed()) { @@ -402,6 +508,7 @@ void RTCIceTransport::Trace(blink::Visitor* visitor) { visitor->Trace(local_candidates_); visitor->Trace(remote_candidates_); visitor->Trace(selected_candidate_pair_); + visitor->Trace(consumer_); EventTargetWithInlineData::Trace(visitor); ContextLifecycleObserver::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h index fa8e307d1f9..2a39f0c5dbc 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h @@ -19,6 +19,8 @@ namespace blink { class ExceptionState; class RTCIceCandidate; class RTCIceGatherOptions; +class IceTransportAdapterCrossThreadFactory; +class RTCQuicTransport; enum class RTCIceTransportState { kNew, @@ -43,17 +45,40 @@ class MODULES_EXPORT RTCIceTransport final : public EventTargetWithInlineData, public ActiveScriptWrappable<RTCIceTransport>, public ContextLifecycleObserver, - private IceTransportProxy::Delegate { + public IceTransportProxy::Delegate { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(RTCIceTransport); public: static RTCIceTransport* Create(ExecutionContext* context); + static RTCIceTransport* Create( + ExecutionContext* context, + scoped_refptr<base::SingleThreadTaskRunner> proxy_thread, + scoped_refptr<base::SingleThreadTaskRunner> host_thread, + std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory); ~RTCIceTransport() override; + // Returns true if start() has been called. + bool IsStarted() const { return role_ != cricket::ICEROLE_UNKNOWN; } + + // Returns the role specified in start(). + cricket::IceRole GetRole() const { return role_; } + + // Returns true if the RTCIceTransport is in a terminal state. bool IsClosed() const { return state_ == RTCIceTransportState::kClosed; } + // An RTCQuicTransport can be connected to this RTCIceTransport. Only one can + // be connected at a time. The consumer will be automatically disconnected + // if stop() is called on this object. Otherwise, the RTCQuicTransport is + // responsible for disconnecting itself when it is done. + // ConnectConsumer returns an IceTransportProxy that can be used to connect + // a QuicTransportProxy. It may be called repeatedly with the same + // RTCQuicTransport. + bool HasConsumer() const; + IceTransportProxy* ConnectConsumer(RTCQuicTransport* consumer); + void DisconnectConsumer(RTCQuicTransport* consumer); + // rtc_ice_transport.idl String role() const; String state() const; @@ -74,6 +99,7 @@ class MODULES_EXPORT RTCIceTransport final ExceptionState& exception_state); DEFINE_ATTRIBUTE_EVENT_LISTENER(statechange); DEFINE_ATTRIBUTE_EVENT_LISTENER(gatheringstatechange); + DEFINE_ATTRIBUTE_EVENT_LISTENER(selectedcandidatepairchange); DEFINE_ATTRIBUTE_EVENT_LISTENER(icecandidate); // EventTarget overrides. @@ -90,12 +116,19 @@ class MODULES_EXPORT RTCIceTransport final void Trace(blink::Visitor* visitor) override; private: - explicit RTCIceTransport(ExecutionContext* context); + explicit RTCIceTransport( + ExecutionContext* context, + scoped_refptr<base::SingleThreadTaskRunner> proxy_thread, + scoped_refptr<base::SingleThreadTaskRunner> host_thread, + std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory); // IceTransportProxy::Delegate overrides. void OnGatheringStateChanged(cricket::IceGatheringState new_state) override; void OnCandidateGathered(const cricket::Candidate& candidate) override; void OnStateChanged(cricket::IceTransportState new_state) override; + void OnSelectedCandidatePairChanged( + const std::pair<cricket::Candidate, cricket::Candidate>& + selected_candidate_pair) override; // Fills in |local_parameters_| with a random usernameFragment and a random // password. @@ -115,6 +148,8 @@ class MODULES_EXPORT RTCIceTransport final base::Optional<RTCIceCandidatePair> selected_candidate_pair_; + Member<RTCQuicTransport> consumer_; + // Handle to the WebRTC ICE transport. Created when this binding is // constructed and deleted once network traffic should be stopped. std::unique_ptr<IceTransportProxy> proxy_; diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl index a2aca1fe626..76656b1b2cf 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl @@ -47,7 +47,7 @@ enum RTCIceGatheringState { RTCIceParameters? getRemoteParameters(); attribute EventHandler onstatechange; attribute EventHandler ongatheringstatechange; - // TODO(crbug.com/864871): Implement onselectedcandidatepairchange. + attribute EventHandler onselectedcandidatepairchange; // The following is defined in the WebRTC-ICE extension specification. // https://w3c.github.io/webrtc-ice/#rtcicetransport* diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.cc new file mode 100644 index 00000000000..1dcb46312f3 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.cc @@ -0,0 +1,573 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file tests the RTCIceTransport Blink bindings, IceTransportProxy and +// IceTransportHost by mocking out the underlying IceTransportAdapter. +// Everything is run on a single thread but with separate TestSimpleTaskRunners +// for the main thread / worker thread. + +#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h" + +#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_ice_transport_adapter_cross_thread_factory.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_packet_transport.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate_init.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_gather_options.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.h" +#include "third_party/webrtc/pc/webrtcsdp.h" + +namespace blink { +namespace { + +using testing::_; +using testing::Assign; +using testing::AllOf; +using testing::DoDefault; +using testing::ElementsAre; +using testing::Field; +using testing::InSequence; +using testing::Invoke; +using testing::InvokeWithoutArgs; +using testing::Mock; +using testing::StrEq; +using testing::StrNe; + +constexpr char kRemoteUsernameFragment1[] = "usernameFragment"; +constexpr char kRemotePassword1[] = "password"; + +constexpr char kRemoteUsernameFragment2[] = "secondUsernameFragment"; +constexpr char kRemotePassword2[] = "secondPassword"; + +RTCIceParameters CreateRemoteRTCIceParameters2() { + RTCIceParameters ice_parameters; + ice_parameters.setUsernameFragment(kRemoteUsernameFragment2); + ice_parameters.setPassword(kRemotePassword2); + return ice_parameters; +} + +constexpr char kLocalIceCandidateStr1[] = + "candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host generation 2"; +constexpr char kRemoteIceCandidateStr1[] = + "candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host generation 2"; +constexpr char kRemoteIceCandidateStr2[] = + "candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx raddr " + "192.168.1.5 rport 2346 generation 2"; + +RTCIceCandidate* RTCIceCandidateFromString(V8TestingScope& scope, + const String& candidate_str) { + RTCIceCandidateInit init; + init.setCandidate(candidate_str); + return RTCIceCandidate::Create(scope.GetExecutionContext(), init, + ASSERT_NO_EXCEPTION); +} + +cricket::Candidate CricketCandidateFromString( + const std::string& candidate_str) { + cricket::Candidate candidate; + bool success = + webrtc::SdpDeserializeCandidate("", candidate_str, &candidate, nullptr); + DCHECK(success); + return candidate; +} + +} // namespace + +// static +RTCIceParameters RTCIceTransportTest::CreateRemoteRTCIceParameters1() { + RTCIceParameters ice_parameters; + ice_parameters.setUsernameFragment(kRemoteUsernameFragment1); + ice_parameters.setPassword(kRemotePassword1); + return ice_parameters; +} + +RTCIceTransportTest::RTCIceTransportTest() + : main_thread_(new base::TestSimpleTaskRunner()), + worker_thread_(new base::TestSimpleTaskRunner()) {} + +RTCIceTransportTest::~RTCIceTransportTest() { + // When the V8TestingScope is destroyed at the end of a test, it will call + // ContextDestroyed on the RTCIceTransport which will queue a task to delete + // the IceTransportAdapter. RunUntilIdle() here ensures that the task will + // be executed and the IceTransportAdapter deleted before finishing the + // test. + RunUntilIdle(); + + // Explicitly verify expectations of garbage collected mock objects. + for (auto mock : mock_event_listeners_) { + Mock::VerifyAndClear(mock); + } +} + +void RTCIceTransportTest::RunUntilIdle() { + while (worker_thread_->HasPendingTask() || main_thread_->HasPendingTask()) { + worker_thread_->RunPendingTasks(); + main_thread_->RunPendingTasks(); + } +} + +RTCIceTransport* RTCIceTransportTest::CreateIceTransport( + V8TestingScope& scope) { + return CreateIceTransport( + scope, std::make_unique<MockIceTransportAdapter>( + std::make_unique<MockP2PQuicPacketTransport>())); +} + +RTCIceTransport* RTCIceTransportTest::CreateIceTransport( + V8TestingScope& scope, + IceTransportAdapter::Delegate** delegate_out) { + return CreateIceTransport(scope, std::make_unique<MockIceTransportAdapter>(), + delegate_out); +} + +RTCIceTransport* RTCIceTransportTest::CreateIceTransport( + V8TestingScope& scope, + std::unique_ptr<MockIceTransportAdapter> mock, + IceTransportAdapter::Delegate** delegate_out) { + if (delegate_out) { + // Ensure the caller has not left the delegate_out value floating. + DCHECK_EQ(nullptr, *delegate_out); + } + return RTCIceTransport::Create( + scope.GetExecutionContext(), main_thread_, worker_thread_, + std::make_unique<MockIceTransportAdapterCrossThreadFactory>( + std::move(mock), delegate_out)); +} + +MockEventListener* RTCIceTransportTest::CreateMockEventListener() { + MockEventListener* event_listener = new MockEventListener(); + mock_event_listeners_.push_back(event_listener); + return event_listener; +} + +// Test that calling gather({}) calls StartGathering with non-empty local +// parameters. +TEST_F(RTCIceTransportTest, GatherStartsGatheringWithNonEmptyLocalParameters) { + V8TestingScope scope; + + auto mock = std::make_unique<MockIceTransportAdapter>(); + auto ice_parameters_not_empty = + AllOf(Field(&cricket::IceParameters::ufrag, StrNe("")), + Field(&cricket::IceParameters::pwd, StrNe(""))); + EXPECT_CALL(*mock, StartGathering(ice_parameters_not_empty, _, _, _)) + .Times(1); + + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, std::move(mock)); + RTCIceGatherOptions options; + options.setGatherPolicy("all"); + ice_transport->gather(options, ASSERT_NO_EXCEPTION); +} + +// Test that calling gather({ gatherPolicy: 'all' }) calls StartGathering with +// IceTransportPolicy::kAll. +TEST_F(RTCIceTransportTest, GatherIceTransportPolicyAll) { + V8TestingScope scope; + + auto mock = std::make_unique<MockIceTransportAdapter>(); + EXPECT_CALL(*mock, StartGathering(_, _, _, IceTransportPolicy::kAll)) + .Times(1); + + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, std::move(mock)); + RTCIceGatherOptions options; + options.setGatherPolicy("all"); + ice_transport->gather(options, ASSERT_NO_EXCEPTION); +} + +// Test that calling gather({ gatherPolicy: 'relay' }) calls StartGathering with +// IceTransportPolicy::kRelay. +TEST_F(RTCIceTransportTest, GatherIceTransportPolicyRelay) { + V8TestingScope scope; + + auto mock = std::make_unique<MockIceTransportAdapter>(); + EXPECT_CALL(*mock, StartGathering(_, _, _, IceTransportPolicy::kRelay)) + .Times(1); + + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, std::move(mock)); + RTCIceGatherOptions options; + options.setGatherPolicy("relay"); + ice_transport->gather(options, ASSERT_NO_EXCEPTION); +} + +// Test that calling stop() deletes the underlying IceTransportAdapter. +TEST_F(RTCIceTransportTest, StopDeletesIceTransportAdapter) { + V8TestingScope scope; + + bool mock_deleted = false; + auto mock = std::make_unique<MockIceTransportAdapter>(); + EXPECT_CALL(*mock, Die()).WillOnce(Assign(&mock_deleted, true)); + + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, std::move(mock)); + RTCIceGatherOptions options; + options.setGatherPolicy("all"); + ice_transport->gather(options, ASSERT_NO_EXCEPTION); + + ice_transport->stop(); + RunUntilIdle(); + + EXPECT_TRUE(mock_deleted); +} + +// Test that the IceTransportAdapter is deleted on ContextDestroyed. +TEST_F(RTCIceTransportTest, ContextDestroyedDeletesIceTransportAdapter) { + V8TestingScope scope; + + bool mock_deleted = false; + auto mock = std::make_unique<MockIceTransportAdapter>(); + EXPECT_CALL(*mock, Die()).WillOnce(Assign(&mock_deleted, true)); + + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, std::move(mock)); + RTCIceGatherOptions options; + options.setGatherPolicy("all"); + ice_transport->gather(options, ASSERT_NO_EXCEPTION); + + ice_transport->ContextDestroyed(scope.GetExecutionContext()); + RunUntilIdle(); + + EXPECT_TRUE(mock_deleted); +} + +// Test that calling OnGatheringStateChanged(complete) on the delegate fires a +// null icecandidate event and a gatheringstatechange event. +TEST_F(RTCIceTransportTest, OnGatheringStateChangedCompleteFiresEvents) { + V8TestingScope scope; + + IceTransportAdapter::Delegate* delegate = nullptr; + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, &delegate); + RTCIceGatherOptions options; + options.setGatherPolicy("all"); + ice_transport->gather(options, ASSERT_NO_EXCEPTION); + RunUntilIdle(); + ASSERT_TRUE(delegate); + + Persistent<MockEventListener> ice_candidate_listener = + CreateMockEventListener(); + Persistent<MockEventListener> gathering_state_change_listener = + CreateMockEventListener(); + { + InSequence dummy; + EXPECT_CALL(*ice_candidate_listener, handleEvent(_, _)) + .WillOnce(Invoke([ice_transport](ExecutionContext*, Event* event) { + auto* ice_event = static_cast<RTCPeerConnectionIceEvent*>(event); + EXPECT_EQ(nullptr, ice_event->candidate()); + })); + EXPECT_CALL(*gathering_state_change_listener, handleEvent(_, _)) + .WillOnce(InvokeWithoutArgs([ice_transport] { + EXPECT_EQ("complete", ice_transport->gatheringState()); + })); + } + ice_transport->addEventListener(EventTypeNames::icecandidate, + ice_candidate_listener); + ice_transport->addEventListener(EventTypeNames::gatheringstatechange, + gathering_state_change_listener); + delegate->OnGatheringStateChanged(cricket::kIceGatheringComplete); + + RunUntilIdle(); +} + +// Test that calling start() calls Start on the IceTransportAdapter with the +// correct arguments when no remote candidates had previously been added. +TEST_F(RTCIceTransportTest, + StartPassesRemoteParametersAndRoleAndInitialRemoteCandidates) { + V8TestingScope scope; + + auto mock = std::make_unique<MockIceTransportAdapter>(); + auto ice_parameters_equal = AllOf( + Field(&cricket::IceParameters::ufrag, StrEq(kRemoteUsernameFragment1)), + Field(&cricket::IceParameters::pwd, StrEq(kRemotePassword1))); + EXPECT_CALL(*mock, Start(ice_parameters_equal, cricket::ICEROLE_CONTROLLING, + ElementsAre())) + .Times(1); + + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, std::move(mock)); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling", + ASSERT_NO_EXCEPTION); +} + +MATCHER_P(SerializedIceCandidateEq, candidate_str, "") { + std::string arg_str = webrtc::SdpSerializeCandidate(arg); + *result_listener << "Expected ICE candidate that serializes to: " + << candidate_str << "; got: " << arg_str; + return arg_str == candidate_str; +} + +// Test that remote candidates are not passed to the IceTransportAdapter until +// start() is called. +TEST_F(RTCIceTransportTest, RemoteCandidatesNotPassedUntilStartCalled) { + V8TestingScope scope; + + auto mock = std::make_unique<MockIceTransportAdapter>(); + EXPECT_CALL( + *mock, + Start(_, _, + ElementsAre(SerializedIceCandidateEq(kRemoteIceCandidateStr1)))) + .Times(1); + EXPECT_CALL(*mock, AddRemoteCandidate(_)).Times(0); + + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, std::move(mock)); + ice_transport->addRemoteCandidate( + RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1), + ASSERT_NO_EXCEPTION); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling", + ASSERT_NO_EXCEPTION); +} + +// Test that receiving an OnStateChanged callback with the completed state +// updates the RTCIceTransport state to 'connected' and fires a statechange +// event. +TEST_F(RTCIceTransportTest, OnStateChangedCompletedUpdatesStateAndFiresEvent) { + V8TestingScope scope; + + IceTransportAdapter::Delegate* delegate = nullptr; + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, &delegate); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling", + ASSERT_NO_EXCEPTION); + RunUntilIdle(); + ASSERT_TRUE(delegate); + + Persistent<MockEventListener> event_listener = CreateMockEventListener(); + EXPECT_CALL(*event_listener, handleEvent(_, _)) + .WillOnce(InvokeWithoutArgs( + [ice_transport] { EXPECT_EQ("connected", ice_transport->state()); })); + ice_transport->addEventListener(EventTypeNames::statechange, event_listener); + + ice_transport->addRemoteCandidate( + RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1), + ASSERT_NO_EXCEPTION); + delegate->OnCandidateGathered( + CricketCandidateFromString(kLocalIceCandidateStr1)); + + delegate->OnStateChanged(cricket::IceTransportState::STATE_COMPLETED); + + RunUntilIdle(); +} + +// Test that receiving an OnStateChanged callback with the failed state updates +// the RTCIceTransport state to 'failed' and fires a statechange event. +TEST_F(RTCIceTransportTest, OnStateChangedFailedUpdatesStateAndFiresEvent) { + V8TestingScope scope; + + IceTransportAdapter::Delegate* delegate = nullptr; + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, &delegate); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling", + ASSERT_NO_EXCEPTION); + RunUntilIdle(); + ASSERT_TRUE(delegate); + + Persistent<MockEventListener> event_listener = CreateMockEventListener(); + EXPECT_CALL(*event_listener, handleEvent(_, _)) + .WillOnce(InvokeWithoutArgs( + [ice_transport] { EXPECT_EQ("failed", ice_transport->state()); })); + ice_transport->addEventListener(EventTypeNames::statechange, event_listener); + + ice_transport->addRemoteCandidate( + RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1), + ASSERT_NO_EXCEPTION); + delegate->OnCandidateGathered( + CricketCandidateFromString(kLocalIceCandidateStr1)); + + delegate->OnStateChanged(cricket::IceTransportState::STATE_FAILED); + + RunUntilIdle(); +} + +// Test that calling OnSelectedCandidatePairChanged the first time fires the +// selectedcandidatepairchange event and sets the selected candidate pair. +TEST_F(RTCIceTransportTest, InitialOnSelectedCandidatePairChangedFiresEvent) { + V8TestingScope scope; + + IceTransportAdapter::Delegate* delegate = nullptr; + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, &delegate); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling", + ASSERT_NO_EXCEPTION); + RunUntilIdle(); + ASSERT_TRUE(delegate); + + Persistent<MockEventListener> event_listener = CreateMockEventListener(); + EXPECT_CALL(*event_listener, handleEvent(_, _)) + .WillOnce(InvokeWithoutArgs([ice_transport] { + base::Optional<RTCIceCandidatePair> selected_candidate_pair; + ice_transport->getSelectedCandidatePair(selected_candidate_pair); + ASSERT_TRUE(selected_candidate_pair); + EXPECT_EQ(ice_transport->getLocalCandidates()[0]->candidate(), + selected_candidate_pair->local()->candidate()); + EXPECT_EQ(ice_transport->getRemoteCandidates()[0]->candidate(), + selected_candidate_pair->remote()->candidate()); + })); + ice_transport->addEventListener(EventTypeNames::selectedcandidatepairchange, + event_listener); + + ice_transport->addRemoteCandidate( + RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1), + ASSERT_NO_EXCEPTION); + delegate->OnCandidateGathered( + CricketCandidateFromString(kLocalIceCandidateStr1)); + delegate->OnSelectedCandidatePairChanged( + std::make_pair(CricketCandidateFromString(kLocalIceCandidateStr1), + CricketCandidateFromString(kRemoteIceCandidateStr1))); + + RunUntilIdle(); +} + +// Test that calling OnSelectedCandidatePairChanged with a different remote +// candidate fires the event and updates the selected candidate pair. +TEST_F(RTCIceTransportTest, + OnSelectedCandidatePairChangedWithDifferentRemoteCandidateFiresEvent) { + V8TestingScope scope; + + IceTransportAdapter::Delegate* delegate = nullptr; + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, &delegate); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling", + ASSERT_NO_EXCEPTION); + RunUntilIdle(); + ASSERT_TRUE(delegate); + + Persistent<MockEventListener> event_listener = CreateMockEventListener(); + EXPECT_CALL(*event_listener, handleEvent(_, _)) + .WillOnce(DoDefault()) // First event is already tested above. + .WillOnce(InvokeWithoutArgs([ice_transport] { + base::Optional<RTCIceCandidatePair> selected_candidate_pair; + ice_transport->getSelectedCandidatePair(selected_candidate_pair); + ASSERT_TRUE(selected_candidate_pair); + EXPECT_EQ(ice_transport->getLocalCandidates()[0]->candidate(), + selected_candidate_pair->local()->candidate()); + EXPECT_EQ(ice_transport->getRemoteCandidates()[1]->candidate(), + selected_candidate_pair->remote()->candidate()); + })); + ice_transport->addEventListener(EventTypeNames::selectedcandidatepairchange, + event_listener); + + ice_transport->addRemoteCandidate( + RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1), + ASSERT_NO_EXCEPTION); + delegate->OnCandidateGathered( + CricketCandidateFromString(kLocalIceCandidateStr1)); + + delegate->OnSelectedCandidatePairChanged( + std::make_pair(CricketCandidateFromString(kLocalIceCandidateStr1), + CricketCandidateFromString(kRemoteIceCandidateStr1))); + + ice_transport->addRemoteCandidate( + RTCIceCandidateFromString(scope, kRemoteIceCandidateStr2), + ASSERT_NO_EXCEPTION); + delegate->OnSelectedCandidatePairChanged( + std::make_pair(CricketCandidateFromString(kLocalIceCandidateStr1), + CricketCandidateFromString(kRemoteIceCandidateStr2))); + + RunUntilIdle(); +} + +// Test that receiving an OnStateChange callback to the failed state once a +// connection has been established clears the selected candidate pair without +// firing the selectedcandidatepairchange event. +TEST_F(RTCIceTransportTest, + OnStateChangeFailedAfterConnectedClearsSelectedCandidatePair) { + V8TestingScope scope; + + IceTransportAdapter::Delegate* delegate = nullptr; + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, &delegate); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling", + ASSERT_NO_EXCEPTION); + RunUntilIdle(); + ASSERT_TRUE(delegate); + + Persistent<MockEventListener> state_change_event_listener = + CreateMockEventListener(); + EXPECT_CALL(*state_change_event_listener, handleEvent(_, _)) + .WillOnce(DoDefault()) // First event is for 'connected'. + .WillOnce(InvokeWithoutArgs([ice_transport] { + EXPECT_EQ("failed", ice_transport->state()); + base::Optional<RTCIceCandidatePair> selected_candidate_pair; + ice_transport->getSelectedCandidatePair(selected_candidate_pair); + EXPECT_EQ(base::nullopt, selected_candidate_pair); + })); + ice_transport->addEventListener(EventTypeNames::statechange, + state_change_event_listener); + + Persistent<MockEventListener> selected_candidate_pair_change_event_listener = + CreateMockEventListener(); + EXPECT_CALL(*selected_candidate_pair_change_event_listener, handleEvent(_, _)) + .Times(1); // First event is for the connected pair. + ice_transport->addEventListener( + EventTypeNames::selectedcandidatepairchange, + selected_candidate_pair_change_event_listener); + + // Establish the connection + ice_transport->addRemoteCandidate( + RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1), + ASSERT_NO_EXCEPTION); + delegate->OnCandidateGathered( + CricketCandidateFromString(kLocalIceCandidateStr1)); + delegate->OnStateChanged(cricket::IceTransportState::STATE_COMPLETED); + delegate->OnSelectedCandidatePairChanged( + std::make_pair(CricketCandidateFromString(kLocalIceCandidateStr1), + CricketCandidateFromString(kRemoteIceCandidateStr1))); + + // Transition to failed. + delegate->OnStateChanged(cricket::IceTransportState::STATE_FAILED); + + RunUntilIdle(); +} + +// Test that receiving an OnSelectedCandidatePairChange callback after a remote +// ICE restart still updates the selected candidate pair. +TEST_F(RTCIceTransportTest, + RemoteIceRestartRaceWithSelectedCandidatePairChange) { + V8TestingScope scope; + + IceTransportAdapter::Delegate* delegate = nullptr; + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, &delegate); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling", + ASSERT_NO_EXCEPTION); + RunUntilIdle(); + ASSERT_TRUE(delegate); + + Persistent<MockEventListener> event_listener = CreateMockEventListener(); + EXPECT_CALL(*event_listener, handleEvent(_, _)) + .WillOnce(InvokeWithoutArgs([ice_transport] { + base::Optional<RTCIceCandidatePair> selected_candidate_pair; + ice_transport->getSelectedCandidatePair(selected_candidate_pair); + ASSERT_TRUE(selected_candidate_pair); + EXPECT_EQ(kLocalIceCandidateStr1, + selected_candidate_pair->local()->candidate()); + EXPECT_EQ(kRemoteIceCandidateStr1, + selected_candidate_pair->remote()->candidate()); + })); + ice_transport->addEventListener(EventTypeNames::selectedcandidatepairchange, + event_listener); + + ice_transport->addRemoteCandidate( + RTCIceCandidateFromString(scope, kRemoteIceCandidateStr1), + ASSERT_NO_EXCEPTION); + + // Changing remote ICE parameters indicate a remote ICE restart. This clears + // the stored list of remote candidates. + ice_transport->start(CreateRemoteRTCIceParameters2(), "controlling", + ASSERT_NO_EXCEPTION); + + // These callbacks are part of the previous generation but should still take + // effect. + delegate->OnCandidateGathered( + CricketCandidateFromString(kLocalIceCandidateStr1)); + delegate->OnStateChanged(cricket::IceTransportState::STATE_COMPLETED); + delegate->OnSelectedCandidatePairChanged( + std::make_pair(CricketCandidateFromString(kLocalIceCandidateStr1), + CricketCandidateFromString(kRemoteIceCandidateStr1))); + + RunUntilIdle(); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h new file mode 100644 index 00000000000..9e2d7c1f91f --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h @@ -0,0 +1,68 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ICE_TRANSPORT_TEST_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ICE_TRANSPORT_TEST_H_ + +#include "base/test/test_simple_task_runner.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/core/dom/events/event_listener.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_ice_transport_adapter.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h" + +namespace blink { + +class MockEventListener final : public EventListener { + public: + MockEventListener() : EventListener(ListenerType::kCPPEventListenerType) {} + + bool operator==(const EventListener& other) const final { + return this == &other; + } + + MOCK_METHOD2(handleEvent, void(ExecutionContext*, Event*)); +}; + +class RTCIceTransportTest : public testing::Test { + public: + static RTCIceParameters CreateRemoteRTCIceParameters1(); + + RTCIceTransportTest(); + ~RTCIceTransportTest() override; + + // Run the main thread and worker thread until both are idle. + void RunUntilIdle(); + + // Construct a new RTCIceTrnasport with a default MockIceTransportAdapter. + RTCIceTransport* CreateIceTransport(V8TestingScope& scope); + + // Construct a new RTCIceTransport with a mock IceTransportAdapter. + RTCIceTransport* CreateIceTransport( + V8TestingScope& scope, + IceTransportAdapter::Delegate** delegate_out); + + // Construct a new RTCIceTransport with the given mock IceTransportAdapter. + // |delegate_out|, if non-null, will be populated once the IceTransportAdapter + // is constructed on the worker thread. + RTCIceTransport* CreateIceTransport( + V8TestingScope& scope, + std::unique_ptr<MockIceTransportAdapter> mock, + IceTransportAdapter::Delegate** delegate_out = nullptr); + + // Use this method to construct a MockEventListener so that the expectations + // can be explicitly checked at the end of the test. Normally the expectations + // would be verified in the mock destructor, but since MockEventListener is + // garbage collected this may happen after the test has finished, improperly + // letting it pass. + MockEventListener* CreateMockEventListener(); + + private: + scoped_refptr<base::TestSimpleTaskRunner> main_thread_; + scoped_refptr<base::TestSimpleTaskRunner> worker_thread_; + std::vector<Persistent<MockEventListener>> mock_event_listeners_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ICE_TRANSPORT_TEST_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 f89532a99f3..1072ca64219 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 @@ -39,6 +39,7 @@ #include "base/metrics/histogram_macros.h" #include "base/optional.h" #include "services/metrics/public/cpp/ukm_builders.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/public/platform/web_crypto_algorithm_params.h" @@ -113,7 +114,9 @@ #include "third_party/blink/renderer/platform/peerconnection/rtc_offer_options_platform.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/wtf/time.h" +#include "third_party/webrtc/api/jsep.h" #include "third_party/webrtc/api/peerconnectioninterface.h" +#include "third_party/webrtc/pc/sessiondescription.h" namespace blink { @@ -325,12 +328,14 @@ webrtc::PeerConnectionInterface::RTCConfiguration ParseConfiguration( web_configuration.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; } } else { - if (!RuntimeEnabledFeatures::RTCUnifiedPlanByDefaultEnabled()) { + if (!base::FeatureList::IsEnabled(features::kRTCUnifiedPlanByDefault) && + !RuntimeEnabledFeatures::RTCUnifiedPlanByDefaultEnabled()) { // By default: The default SDP semantics is: "kPlanB". web_configuration.sdp_semantics = webrtc::SdpSemantics::kPlanB; } else { // Override default SDP semantics to "kUnifiedPlan" with - // RuntimeEnabled=RTCUnifiedPlanByDefault. + // --enable-features=RTCUnifiedPlanByDefault or with + // --enable-blink-features=RTCUnifiedPlanByDefault. web_configuration.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; } } @@ -549,7 +554,8 @@ RTCPeerConnection* RTCPeerConnection::Create( } RTCPeerConnection* peer_connection = new RTCPeerConnection( - context, std::move(configuration), constraints, exception_state); + context, std::move(configuration), rtc_configuration.hasSdpSemantics(), + constraints, exception_state); peer_connection->PauseIfNeeded(); if (exception_state.HadException()) return nullptr; @@ -564,6 +570,7 @@ RTCPeerConnection* RTCPeerConnection::Create( RTCPeerConnection::RTCPeerConnection( ExecutionContext* context, webrtc::PeerConnectionInterface::RTCConfiguration configuration, + bool sdp_semantics_specified, WebMediaConstraints constraints, ExceptionState& exception_state) : PausableObject(context), @@ -582,8 +589,9 @@ RTCPeerConnection::RTCPeerConnection( stopped_(false), closed_(false), has_data_channels_(false), - sdp_semantics_(configuration.sdp_semantics) { - Document* document = ToDocument(GetExecutionContext()); + sdp_semantics_(configuration.sdp_semantics), + sdp_semantics_specified_(sdp_semantics_specified) { + Document* document = To<Document>(GetExecutionContext()); InstanceCounters::IncrementCounter( InstanceCounters::kRTCPeerConnectionCounter); @@ -838,9 +846,47 @@ DOMException* RTCPeerConnection::checkSdpForStateErrors( return nullptr; } +bool RTCPeerConnection::ShouldShowComplexPlanBSdpWarning( + const RTCSessionDescriptionInit& session_description_init) const { + if (sdp_semantics_specified_) + return false; + if (!session_description_init.hasType() || !session_description_init.hasSdp()) + return false; + std::unique_ptr<webrtc::SessionDescriptionInterface> session_description( + webrtc::CreateSessionDescription( + session_description_init.type().Utf8().data(), + session_description_init.sdp().Utf8().data(), nullptr)); + if (!session_description) + return false; + size_t num_audio_mlines = 0u; + size_t num_video_mlines = 0u; + size_t num_audio_tracks = 0u; + size_t num_video_tracks = 0u; + for (const cricket::ContentInfo& content : + session_description->description()->contents()) { + cricket::MediaType media_type = content.media_description()->type(); + size_t num_tracks = std::max(static_cast<size_t>(1u), + content.media_description()->streams().size()); + if (media_type == cricket::MEDIA_TYPE_AUDIO) { + ++num_audio_mlines; + num_audio_tracks += num_tracks; + } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { + ++num_video_mlines; + num_video_tracks += num_tracks; + } + } + return (num_audio_mlines == 1u && num_audio_tracks > 1u) || + (num_video_mlines == 1u && num_video_tracks > 1u); +} + ScriptPromise RTCPeerConnection::setLocalDescription( ScriptState* script_state, const RTCSessionDescriptionInit& session_description_init) { + if (ShouldShowComplexPlanBSdpWarning(session_description_init)) { + Deprecation::CountDeprecation( + GetExecutionContext(), + WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics); + } String sdp; DOMException* exception = checkSdpForStateErrors( ExecutionContext::From(script_state), session_description_init, &sdp); @@ -861,6 +907,11 @@ ScriptPromise RTCPeerConnection::setLocalDescription( const RTCSessionDescriptionInit& session_description_init, V8VoidFunction* success_callback, V8RTCPeerConnectionErrorCallback* error_callback) { + if (ShouldShowComplexPlanBSdpWarning(session_description_init)) { + Deprecation::CountDeprecation( + GetExecutionContext(), + WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics); + } ExecutionContext* context = ExecutionContext::From(script_state); if (success_callback && error_callback) { UseCounter::Count( @@ -926,6 +977,11 @@ RTCSessionDescription* RTCPeerConnection::pendingLocalDescription() { ScriptPromise RTCPeerConnection::setRemoteDescription( ScriptState* script_state, const RTCSessionDescriptionInit& session_description_init) { + if (ShouldShowComplexPlanBSdpWarning(session_description_init)) { + Deprecation::CountDeprecation( + GetExecutionContext(), + WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics); + } if (signaling_state_ == webrtc::PeerConnectionInterface::SignalingState::kClosed) { return ScriptPromise::RejectWithDOMException( @@ -948,6 +1004,11 @@ ScriptPromise RTCPeerConnection::setRemoteDescription( const RTCSessionDescriptionInit& session_description_init, V8VoidFunction* success_callback, V8RTCPeerConnectionErrorCallback* error_callback) { + if (ShouldShowComplexPlanBSdpWarning(session_description_init)) { + Deprecation::CountDeprecation( + GetExecutionContext(), + WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics); + } ExecutionContext* context = ExecutionContext::From(script_state); if (success_callback && error_callback) { UseCounter::Count( @@ -1928,6 +1989,13 @@ RTCRtpReceiver* RTCPeerConnection::CreateOrUpdateReceiver( if (receiver_it == rtp_receivers_.end()) { // Create new receiver. receiver = new RTCRtpReceiver(std::move(web_receiver), track, {}); + // Receiving tracks should be muted by default. SetReadyState() propagates + // the related state changes to ensure it is muted on all layers. It also + // fires events - which is not desired - but because they fire synchronously + // there are no listeners to detect this so this is indistinguishable from + // having constructed the track in an already muted state. + receiver->track()->Component()->Source()->SetReadyState( + MediaStreamSource::kReadyStateMuted); rtp_receivers_.push_back(receiver); } else { // Update existing receiver is a no-op. @@ -2193,6 +2261,7 @@ void RTCPeerConnection::DidModifyTransceivers( remove_list; HeapVector<std::pair<Member<MediaStream>, Member<MediaStreamTrack>>> add_list; HeapVector<Member<RTCRtpTransceiver>> track_events; + MediaStreamVector previous_streams = getRemoteStreams(); for (auto& web_transceiver : web_transceivers) { auto* it = FindTransceiver(*web_transceiver); bool previously_had_recv = @@ -2212,11 +2281,23 @@ void RTCPeerConnection::DidModifyTransceivers( ProcessRemovalOfRemoteTrack(transceiver, &remove_list, &mute_tracks); } } + MediaStreamVector current_streams = getRemoteStreams(); for (auto& track : mute_tracks) { + // Mute the track. Fires "track.onmute" synchronously. track->Component()->Source()->SetReadyState( MediaStreamSource::kReadyStateMuted); } + // Remove/add tracks to streams, this fires "stream.onremovetrack" and + // "stream.onaddtrack" asynchronously (delayed with ScheduleDispatchEvent()). + // This means that the streams will be updated immediately, but the + // corresponding events will fire after "pc.ontrack". + // TODO(https://crbug.com/788558): These should probably also fire + // synchronously (before "pc.ontrack"). The webrtc-pc spec references the + // mediacapture-streams spec for adding and removing tracks to streams, which + // adds/removes and fires synchronously, but it says to do this in a queued + // task, which would lead to unexpected behavior: the streams would be empty + // at "pc.ontrack". for (auto& pair : remove_list) { auto& stream = pair.first; auto& track = pair.second; @@ -2232,10 +2313,34 @@ void RTCPeerConnection::DidModifyTransceivers( } } + // Legacy APIs: "pc.onaddstream" and "pc.onremovestream". + for (const auto& current_stream : current_streams) { + if (!previous_streams.Contains(current_stream)) { + ScheduleDispatchEvent( + MediaStreamEvent::Create(EventTypeNames::addstream, current_stream)); + } + } + for (const auto& previous_stream : previous_streams) { + if (!current_streams.Contains(previous_stream)) { + ScheduleDispatchEvent(MediaStreamEvent::Create( + EventTypeNames::removestream, previous_stream)); + } + } + + // Fire "pc.ontrack" synchronously. for (auto& transceiver : track_events) { - ScheduleDispatchEvent(new RTCTrackEvent( + auto* track_event = new RTCTrackEvent( transceiver->receiver(), transceiver->receiver()->track(), - transceiver->receiver()->streams(), transceiver)); + transceiver->receiver()->streams(), transceiver); + DispatchEvent(*track_event); + } + + // Unmute "pc.ontrack" tracks. Fires "track.onunmute" synchronously. + // TODO(https://crbug.com/889487): The correct thing to do is to unmute in + // response to receiving RTP packets. + for (auto& transceiver : track_events) { + transceiver->receiver()->track()->Component()->Source()->SetReadyState( + MediaStreamSource::kReadyStateLive); } } @@ -2321,7 +2426,7 @@ void RTCPeerConnection::DidAddRemoteDataChannel( } void RTCPeerConnection::DidNoteInterestingUsage(int usage_pattern) { - Document* document = ToDocument(GetExecutionContext()); + Document* document = To<Document>(GetExecutionContext()); ukm::SourceId source_id = document->UkmSourceID(); ukm::builders::WebRTC_AddressHarvesting(source_id) .SetUsagePattern(usage_pattern) @@ -2446,7 +2551,7 @@ void RTCPeerConnection::CloseInternal() { transceiver->OnPeerConnectionClosed(); } - Document* document = ToDocument(GetExecutionContext()); + Document* document = To<Document>(GetExecutionContext()); HostsUsingFeatures::CountAnyWorld( *document, HostsUsingFeatures::Feature::kRTCPeerConnectionUsed); @@ -2483,7 +2588,7 @@ void RTCPeerConnection::DispatchScheduledEvent() { } void RTCPeerConnection::RecordRapporMetrics() { - Document* document = ToDocument(GetExecutionContext()); + Document* document = To<Document>(GetExecutionContext()); for (const auto& component : tracks_.Keys()) { switch (component->Source()->GetType()) { case MediaStreamSource::kTypeAudio: diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h index 49450d4fd8d..fc779f36c01 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h @@ -258,6 +258,18 @@ class MODULES_EXPORT RTCPeerConnection final static int PeerConnectionCount(); static int PeerConnectionCountLimit(); + // SLD/SRD helper method, public for testing. + // "Complex" Plan B SDP is SDP that is not compatible with Unified Plan, i.e. + // SDP that has multiple tracks listed under the same m= sections. We should + // show a deprecation warning when setLocalDescription() or + // setRemoteDescription() is called and: + // - The SDP is complex Plan B SDP. + // - sdpSemantics was not specified at RTCPeerConnection construction. + // Such calls would normally succeed, but as soon as the default switches to + // Unified Plan they would fail. This decides whether to show deprecation for + // WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics. + bool ShouldShowComplexPlanBSdpWarning(const RTCSessionDescriptionInit&) const; + void Trace(blink::Visitor*) override; private: @@ -288,6 +300,7 @@ class MODULES_EXPORT RTCPeerConnection final RTCPeerConnection(ExecutionContext*, webrtc::PeerConnectionInterface::RTCConfiguration, + bool sdp_semantics_specified, WebMediaConstraints, ExceptionState&); void Dispose(); @@ -442,6 +455,8 @@ class MODULES_EXPORT RTCPeerConnection final // "kUnifiedPlan", if constructed with "kDefault" it is translated to one or // the other. webrtc::SdpSemantics sdp_semantics_; + // Whether sdpSemantics was specified at construction. + bool sdp_semantics_specified_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.h index d3c5e40b2ca..bdedd7d9cc0 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.h +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.h @@ -32,7 +32,7 @@ namespace blink { class RTCIceCandidate; class RTCPeerConnectionIceEventInit; -class RTCPeerConnectionIceEvent final : public Event { +class MODULES_EXPORT RTCPeerConnectionIceEvent final : public Event { DEFINE_WRAPPERTYPEINFO(); public: diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc index cdef1438738..a20d8fa8d5c 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc @@ -19,16 +19,352 @@ #include "third_party/blink/renderer/modules/mediastream/media_stream_track.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_configuration.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_server.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_session_description_init.h" #include "third_party/blink/renderer/platform/heap/heap_allocator.h" #include "third_party/blink/renderer/platform/testing/testing_platform_support.h" #include "third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h" namespace blink { +static const char* kOfferSdpUnifiedPlanSingleAudioSingleVideo = + "v=0\r\n" + "o=- 6676943034916303038 2 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "a=group:BUNDLE 0 1\r\n" + "a=msid-semantic: WMS\r\n" + "m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 " + "126\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:pKAt\r\n" + "a=ice-pwd:bDmIGcCbVl+VkMymNfwdE/Mv\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "F2:D4:95:C5:FC:98:F2:7E:6F:6C:46:BF:5E:05:00:56:4F:A9:BC:4B:1E:56:98:C1:" + "68:BF:5E:7D:01:A3:EC:93\r\n" + "a=setup:actpass\r\n" + "a=mid:0\r\n" + "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n" + "a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid\r\n" + "a=sendrecv\r\n" + "a=msid:- 36f80301-b634-4c5a-a03b-d1ad79997531\r\n" + "a=rtcp-mux\r\n" + "a=rtpmap:111 opus/48000/2\r\n" + "a=rtcp-fb:111 transport-cc\r\n" + "a=fmtp:111 minptime=10;useinbandfec=1\r\n" + "a=rtpmap:103 ISAC/16000\r\n" + "a=rtpmap:104 ISAC/32000\r\n" + "a=rtpmap:9 G722/8000\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:106 CN/32000\r\n" + "a=rtpmap:105 CN/16000\r\n" + "a=rtpmap:13 CN/8000\r\n" + "a=rtpmap:110 telephone-event/48000\r\n" + "a=rtpmap:112 telephone-event/32000\r\n" + "a=rtpmap:113 telephone-event/16000\r\n" + "a=rtpmap:126 telephone-event/8000\r\n" + "a=ssrc:4264546776 cname:GkUsSfx+DbDplYYT\r\n" + "a=ssrc:4264546776 msid: 36f80301-b634-4c5a-a03b-d1ad79997531\r\n" + "a=ssrc:4264546776 mslabel:\r\n" + "a=ssrc:4264546776 label:36f80301-b634-4c5a-a03b-d1ad79997531\r\n" + "m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:pKAt\r\n" + "a=ice-pwd:bDmIGcCbVl+VkMymNfwdE/Mv\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "F2:D4:95:C5:FC:98:F2:7E:6F:6C:46:BF:5E:05:00:56:4F:A9:BC:4B:1E:56:98:C1:" + "68:BF:5E:7D:01:A3:EC:93\r\n" + "a=setup:actpass\r\n" + "a=mid:1\r\n" + "a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\n" + "a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n" + "a=extmap:4 urn:3gpp:video-orientation\r\n" + "a=extmap:5 " + "http://www.ietf.org/id/" + "draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n" + "a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\n" + "a=extmap:7 " + "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\n" + "a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\n" + "a=extmap:10 " + "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\n" + "a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid\r\n" + "a=sendrecv\r\n" + "a=msid:- 0db71b61-c1ae-4741-bcce-320a254244f3\r\n" + "a=rtcp-mux\r\n" + "a=rtcp-rsize\r\n" + "a=rtpmap:96 VP8/90000\r\n" + "a=rtcp-fb:96 goog-remb\r\n" + "a=rtcp-fb:96 transport-cc\r\n" + "a=rtcp-fb:96 ccm fir\r\n" + "a=rtcp-fb:96 nack\r\n" + "a=rtcp-fb:96 nack pli\r\n" + "a=rtpmap:97 rtx/90000\r\n" + "a=fmtp:97 apt=96\r\n" + "a=rtpmap:98 VP9/90000\r\n" + "a=rtcp-fb:98 goog-remb\r\n" + "a=rtcp-fb:98 transport-cc\r\n" + "a=rtcp-fb:98 ccm fir\r\n" + "a=rtcp-fb:98 nack\r\n" + "a=rtcp-fb:98 nack pli\r\n" + "a=fmtp:98 x-google-profile-id=0\r\n" + "a=rtpmap:99 rtx/90000\r\n" + "a=fmtp:99 apt=98\r\n" + "a=rtpmap:100 red/90000\r\n" + "a=rtpmap:101 rtx/90000\r\n" + "a=fmtp:101 apt=100\r\n" + "a=rtpmap:102 ulpfec/90000\r\n" + "a=ssrc-group:FID 680673332 1566706172\r\n" + "a=ssrc:680673332 cname:GkUsSfx+DbDplYYT\r\n" + "a=ssrc:680673332 msid: 0db71b61-c1ae-4741-bcce-320a254244f3\r\n" + "a=ssrc:680673332 mslabel:\r\n" + "a=ssrc:680673332 label:0db71b61-c1ae-4741-bcce-320a254244f3\r\n" + "a=ssrc:1566706172 cname:GkUsSfx+DbDplYYT\r\n" + "a=ssrc:1566706172 msid: 0db71b61-c1ae-4741-bcce-320a254244f3\r\n" + "a=ssrc:1566706172 mslabel:\r\n" + "a=ssrc:1566706172 label:0db71b61-c1ae-4741-bcce-320a254244f3\r\n"; + +static const char* kOfferSdpUnifiedPlanMultipleAudioTracks = + "v=0\r\n" + "o=- 1821816752660535838 2 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "a=group:BUNDLE 0 1\r\n" + "a=msid-semantic: WMS\r\n" + "m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 " + "126\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:rbEc\r\n" + "a=ice-pwd:vmDec3+MrTigDESzNiDuWBnD\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "05:9B:0A:BC:B3:E1:B9:5C:A6:78:96:23:00:0F:96:71:7B:B0:3E:37:87:1D:3A:62:" + "5E:00:A5:27:22:BB:26:5D\r\n" + "a=setup:actpass\r\n" + "a=mid:0\r\n" + "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n" + "a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid\r\n" + "a=sendrecv\r\n" + "a=msid:- adcd8158-3ad7-4a1f-ac87-8711db959fe8\r\n" + "a=rtcp-mux\r\n" + "a=rtpmap:111 opus/48000/2\r\n" + "a=rtcp-fb:111 transport-cc\r\n" + "a=fmtp:111 minptime=10;useinbandfec=1\r\n" + "a=rtpmap:103 ISAC/16000\r\n" + "a=rtpmap:104 ISAC/32000\r\n" + "a=rtpmap:9 G722/8000\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:106 CN/32000\r\n" + "a=rtpmap:105 CN/16000\r\n" + "a=rtpmap:13 CN/8000\r\n" + "a=rtpmap:110 telephone-event/48000\r\n" + "a=rtpmap:112 telephone-event/32000\r\n" + "a=rtpmap:113 telephone-event/16000\r\n" + "a=rtpmap:126 telephone-event/8000\r\n" + "a=ssrc:2988156579 cname:gr88KGUzymBvrIaJ\r\n" + "a=ssrc:2988156579 msid: adcd8158-3ad7-4a1f-ac87-8711db959fe8\r\n" + "a=ssrc:2988156579 mslabel:\r\n" + "a=ssrc:2988156579 label:adcd8158-3ad7-4a1f-ac87-8711db959fe8\r\n" + "m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 " + "126\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:rbEc\r\n" + "a=ice-pwd:vmDec3+MrTigDESzNiDuWBnD\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "05:9B:0A:BC:B3:E1:B9:5C:A6:78:96:23:00:0F:96:71:7B:B0:3E:37:87:1D:3A:62:" + "5E:00:A5:27:22:BB:26:5D\r\n" + "a=setup:actpass\r\n" + "a=mid:1\r\n" + "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n" + "a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid\r\n" + "a=sendrecv\r\n" + "a=msid:- b5f69d2c-e753-4eb5-a302-d41ee75f9fcb\r\n" + "a=rtcp-mux\r\n" + "a=rtpmap:111 opus/48000/2\r\n" + "a=rtcp-fb:111 transport-cc\r\n" + "a=fmtp:111 minptime=10;useinbandfec=1\r\n" + "a=rtpmap:103 ISAC/16000\r\n" + "a=rtpmap:104 ISAC/32000\r\n" + "a=rtpmap:9 G722/8000\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:106 CN/32000\r\n" + "a=rtpmap:105 CN/16000\r\n" + "a=rtpmap:13 CN/8000\r\n" + "a=rtpmap:110 telephone-event/48000\r\n" + "a=rtpmap:112 telephone-event/32000\r\n" + "a=rtpmap:113 telephone-event/16000\r\n" + "a=rtpmap:126 telephone-event/8000\r\n" + "a=ssrc:2562757057 cname:gr88KGUzymBvrIaJ\r\n" + "a=ssrc:2562757057 msid: b5f69d2c-e753-4eb5-a302-d41ee75f9fcb\r\n" + "a=ssrc:2562757057 mslabel:\r\n" + "a=ssrc:2562757057 label:b5f69d2c-e753-4eb5-a302-d41ee75f9fcb\r\n"; + +static const char* kOfferSdpPlanBSingleAudioSingleVideo = + "v=0\r\n" + "o=- 267029810971159627 2 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "a=group:BUNDLE audio video\r\n" + "a=msid-semantic: WMS 655e92b8-9130-44d8-a188-f5f4633d1a8d " + "b15218e5-f921-4988-9e1f-6e50ecbd24c2\r\n" + "m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 " + "126\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:ErlQ\r\n" + "a=ice-pwd:VCnwY8XlD9EX4gpcOHRhU0HV\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "AC:30:90:F9:3B:CB:9A:0D:C6:FB:F3:D6:D6:97:4F:40:A2:B9:5E:4D:F5:32:DC:A7:" + "B0:3A:33:82:C8:67:FF:7A\r\n" + "a=setup:actpass\r\n" + "a=mid:audio\r\n" + "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n" + "a=sendrecv\r\n" + "a=rtcp-mux\r\n" + "a=rtpmap:111 opus/48000/2\r\n" + "a=rtcp-fb:111 transport-cc\r\n" + "a=fmtp:111 minptime=10;useinbandfec=1\r\n" + "a=rtpmap:103 ISAC/16000\r\n" + "a=rtpmap:104 ISAC/32000\r\n" + "a=rtpmap:9 G722/8000\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:106 CN/32000\r\n" + "a=rtpmap:105 CN/16000\r\n" + "a=rtpmap:13 CN/8000\r\n" + "a=rtpmap:110 telephone-event/48000\r\n" + "a=rtpmap:112 telephone-event/32000\r\n" + "a=rtpmap:113 telephone-event/16000\r\n" + "a=rtpmap:126 telephone-event/8000\r\n" + "a=ssrc:1670492497 cname:rNEKgm1NFupmwR4x\r\n" + "a=ssrc:1670492497 msid:b15218e5-f921-4988-9e1f-6e50ecbd24c2 " + "089fd06c-73e4-4720-a6dc-e182eeaeced7\r\n" + "a=ssrc:1670492497 mslabel:b15218e5-f921-4988-9e1f-6e50ecbd24c2\r\n" + "a=ssrc:1670492497 label:089fd06c-73e4-4720-a6dc-e182eeaeced7\r\n" + "m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:ErlQ\r\n" + "a=ice-pwd:VCnwY8XlD9EX4gpcOHRhU0HV\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "AC:30:90:F9:3B:CB:9A:0D:C6:FB:F3:D6:D6:97:4F:40:A2:B9:5E:4D:F5:32:DC:A7:" + "B0:3A:33:82:C8:67:FF:7A\r\n" + "a=setup:actpass\r\n" + "a=mid:video\r\n" + "a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\n" + "a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n" + "a=extmap:4 urn:3gpp:video-orientation\r\n" + "a=extmap:5 " + "http://www.ietf.org/id/" + "draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n" + "a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\n" + "a=extmap:7 " + "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\n" + "a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\n" + "a=extmap:10 " + "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\n" + "a=sendrecv\r\n" + "a=rtcp-mux\r\n" + "a=rtcp-rsize\r\n" + "a=rtpmap:96 VP8/90000\r\n" + "a=rtcp-fb:96 goog-remb\r\n" + "a=rtcp-fb:96 transport-cc\r\n" + "a=rtcp-fb:96 ccm fir\r\n" + "a=rtcp-fb:96 nack\r\n" + "a=rtcp-fb:96 nack pli\r\n" + "a=rtpmap:97 rtx/90000\r\n" + "a=fmtp:97 apt=96\r\n" + "a=rtpmap:98 VP9/90000\r\n" + "a=rtcp-fb:98 goog-remb\r\n" + "a=rtcp-fb:98 transport-cc\r\n" + "a=rtcp-fb:98 ccm fir\r\n" + "a=rtcp-fb:98 nack\r\n" + "a=rtcp-fb:98 nack pli\r\n" + "a=fmtp:98 x-google-profile-id=0\r\n" + "a=rtpmap:99 rtx/90000\r\n" + "a=fmtp:99 apt=98\r\n" + "a=rtpmap:100 red/90000\r\n" + "a=rtpmap:101 rtx/90000\r\n" + "a=fmtp:101 apt=100\r\n" + "a=rtpmap:102 ulpfec/90000\r\n" + "a=ssrc-group:FID 3263949794 2166305097\r\n" + "a=ssrc:3263949794 cname:rNEKgm1NFupmwR4x\r\n" + "a=ssrc:3263949794 msid:655e92b8-9130-44d8-a188-f5f4633d1a8d " + "6391e0e8-ac1e-42c2-844c-a7299758db6a\r\n" + "a=ssrc:3263949794 mslabel:655e92b8-9130-44d8-a188-f5f4633d1a8d\r\n" + "a=ssrc:3263949794 label:6391e0e8-ac1e-42c2-844c-a7299758db6a\r\n" + "a=ssrc:2166305097 cname:rNEKgm1NFupmwR4x\r\n" + "a=ssrc:2166305097 msid:655e92b8-9130-44d8-a188-f5f4633d1a8d " + "6391e0e8-ac1e-42c2-844c-a7299758db6a\r\n" + "a=ssrc:2166305097 mslabel:655e92b8-9130-44d8-a188-f5f4633d1a8d\r\n" + "a=ssrc:2166305097 label:6391e0e8-ac1e-42c2-844c-a7299758db6a\r\n"; + +static const char* kOfferSdpPlanBMultipleAudioTracks = + "v=0\r\n" + "o=- 6228437149521864740 2 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "a=group:BUNDLE audio\r\n" + "a=msid-semantic: WMS 46f8615e-7599-49f3-9a45-3cf0faf58614 " + "e01b7c23-2b77-4e09-bee7-4b9140e49647\r\n" + "m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 " + "126\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:Nzla\r\n" + "a=ice-pwd:PL1APGM2pr773UoUOsj8jzBI\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "DF:8F:89:33:68:AB:55:26:4E:81:CF:95:8C:71:B7:89:45:E7:05:7A:5D:A8:CF:BF:" + "60:AA:C7:42:F2:85:23:1D\r\n" + "a=setup:actpass\r\n" + "a=mid:audio\r\n" + "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n" + "a=sendrecv\r\n" + "a=rtcp-mux\r\n" + "a=rtpmap:111 opus/48000/2\r\n" + "a=rtcp-fb:111 transport-cc\r\n" + "a=fmtp:111 minptime=10;useinbandfec=1\r\n" + "a=rtpmap:103 ISAC/16000\r\n" + "a=rtpmap:104 ISAC/32000\r\n" + "a=rtpmap:9 G722/8000\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:106 CN/32000\r\n" + "a=rtpmap:105 CN/16000\r\n" + "a=rtpmap:13 CN/8000\r\n" + "a=rtpmap:110 telephone-event/48000\r\n" + "a=rtpmap:112 telephone-event/32000\r\n" + "a=rtpmap:113 telephone-event/16000\r\n" + "a=rtpmap:126 telephone-event/8000\r\n" + "a=ssrc:2716812081 cname:0QgfsHYGSuZjeg5/\r\n" + "a=ssrc:2716812081 msid:e01b7c23-2b77-4e09-bee7-4b9140e49647 " + "d73d8a47-3d3f-408f-a2ce-2270eb44ffc5\r\n" + "a=ssrc:2716812081 mslabel:e01b7c23-2b77-4e09-bee7-4b9140e49647\r\n" + "a=ssrc:2716812081 label:d73d8a47-3d3f-408f-a2ce-2270eb44ffc5\r\n" + "a=ssrc:4092260337 cname:0QgfsHYGSuZjeg5/\r\n" + "a=ssrc:4092260337 msid:46f8615e-7599-49f3-9a45-3cf0faf58614 " + "6b5f436e-f85d-40a1-83e4-acec63ca4b82\r\n" + "a=ssrc:4092260337 mslabel:46f8615e-7599-49f3-9a45-3cf0faf58614\r\n" + "a=ssrc:4092260337 label:6b5f436e-f85d-40a1-83e4-acec63ca4b82\r\n"; + class RTCPeerConnectionTest : public testing::Test { public: - RTCPeerConnection* CreatePC(V8TestingScope& scope) { + RTCPeerConnection* CreatePC(V8TestingScope& scope, + const String& sdpSemantics = String()) { RTCConfiguration config; + config.setSdpSemantics(sdpSemantics); RTCIceServer ice_server; ice_server.setURL("stun:fake.stun.url"); HeapVector<RTCIceServer> ice_servers; @@ -236,4 +572,78 @@ TEST_F(RTCPeerConnectionTest, GetTrackRemoveStreamAndGCWithPersistentStream) { EXPECT_FALSE(pc->GetTrack(track_component)); } +TEST_F(RTCPeerConnectionTest, PlanBSdpWarningNotShownWhenPlanBSpecified) { + V8TestingScope scope; + Persistent<RTCPeerConnection> pc = CreatePC(scope, "plan-b"); + RTCSessionDescriptionInit sdp; + sdp.setType("offer"); + // It doesn't matter the SDP, never show a warning if sdpSemantics was + // specified at construction. + sdp.setSdp(kOfferSdpUnifiedPlanSingleAudioSingleVideo); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpUnifiedPlanMultipleAudioTracks); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpPlanBSingleAudioSingleVideo); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpPlanBMultipleAudioTracks); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); +} + +TEST_F(RTCPeerConnectionTest, PlanBSdpWarningNotShownWhenUnifiedPlanSpecified) { + V8TestingScope scope; + Persistent<RTCPeerConnection> pc = CreatePC(scope, "unified-plan"); + RTCSessionDescriptionInit sdp; + sdp.setType("offer"); + // It doesn't matter the SDP, never show a warning if sdpSemantics was + // specified at construction. + sdp.setSdp(kOfferSdpUnifiedPlanSingleAudioSingleVideo); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpUnifiedPlanMultipleAudioTracks); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpPlanBSingleAudioSingleVideo); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpPlanBMultipleAudioTracks); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); +} + +TEST_F(RTCPeerConnectionTest, PlanBSdpWarningNotShownWhenInvalidSdp) { + V8TestingScope scope; + Persistent<RTCPeerConnection> pc = CreatePC(scope); + RTCSessionDescriptionInit sdp; + sdp.setType("offer"); + sdp.setSdp("invalid sdp"); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); +} + +TEST_F(RTCPeerConnectionTest, PlanBSdpWarningNotShownForSingleTracks) { + V8TestingScope scope; + Persistent<RTCPeerConnection> pc = CreatePC(scope); + RTCSessionDescriptionInit sdp; + sdp.setType("offer"); + // Neither Unified Plan or Plan B SDP should result in a warning if only a + // single track per m= section is used. + sdp.setSdp(kOfferSdpUnifiedPlanSingleAudioSingleVideo); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpPlanBSingleAudioSingleVideo); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); +} + +TEST_F(RTCPeerConnectionTest, PlanBSdpWarningShownForComplexPlanB) { + V8TestingScope scope; + Persistent<RTCPeerConnection> pc = CreatePC(scope); + RTCSessionDescriptionInit sdp; + sdp.setType("offer"); + sdp.setSdp(kOfferSdpPlanBMultipleAudioTracks); + ASSERT_TRUE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); +} + +TEST_F(RTCPeerConnectionTest, PlanBSdpWarningNotShownForComplexUnifiedPlan) { + V8TestingScope scope; + Persistent<RTCPeerConnection> pc = CreatePC(scope); + RTCSessionDescriptionInit sdp; + sdp.setType("offer"); + sdp.setSdp(kOfferSdpUnifiedPlanMultipleAudioTracks); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.cc index ef0cc254f68..66f32031b94 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.cc +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.cc @@ -3,13 +3,20 @@ // found in the LICENSE file. #include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h" +#include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h" namespace blink { -RTCQuicStream::RTCQuicStream(RTCQuicTransport* transport) - : transport_(transport) { +RTCQuicStream::RTCQuicStream(ExecutionContext* context, + RTCQuicTransport* transport, + QuicStreamProxy* stream_proxy) + : EventTargetWithInlineData(), + ContextClient(context), + transport_(transport), + proxy_(stream_proxy) { DCHECK(transport_); + DCHECK(proxy_); } RTCQuicStream::~RTCQuicStream() = default; @@ -42,13 +49,75 @@ uint32_t RTCQuicStream::writeBufferedAmount() const { return write_buffered_amount_; } +void RTCQuicStream::finish() { + if (!writeable_) { + return; + } + proxy_->Finish(); + writeable_ = false; + if (readable_) { + DCHECK_EQ(state_, RTCQuicStreamState::kOpen); + state_ = RTCQuicStreamState::kClosing; + } else { + DCHECK_EQ(state_, RTCQuicStreamState::kClosing); + Close(); + } +} + +void RTCQuicStream::reset() { + if (IsClosed()) { + return; + } + proxy_->Reset(); + writeable_ = false; + readable_ = false; + Close(); +} + void RTCQuicStream::Stop() { + readable_ = false; + writeable_ = false; state_ = RTCQuicStreamState::kClosed; + proxy_ = nullptr; +} + +void RTCQuicStream::Close() { + Stop(); + transport_->RemoveStream(this); +} + +void RTCQuicStream::OnRemoteReset() { + DCHECK_NE(state_, RTCQuicStreamState::kClosed); + Close(); + DispatchEvent(*Event::Create(EventTypeNames::statechange)); +} + +void RTCQuicStream::OnRemoteFinish() { + DCHECK_NE(state_, RTCQuicStreamState::kClosed); + DCHECK(readable_); + readable_ = false; + if (writeable_) { + DCHECK_EQ(state_, RTCQuicStreamState::kOpen); + state_ = RTCQuicStreamState::kClosing; + } else { + DCHECK_EQ(state_, RTCQuicStreamState::kClosing); + Close(); + } + DispatchEvent(*Event::Create(EventTypeNames::statechange)); +} + +const AtomicString& RTCQuicStream::InterfaceName() const { + return EventTargetNames::RTCQuicStream; +} + +ExecutionContext* RTCQuicStream::GetExecutionContext() const { + return ContextClient::GetExecutionContext(); } void RTCQuicStream::Trace(blink::Visitor* visitor) { visitor->Trace(transport_); - ScriptWrappable::Trace(visitor); + EventTargetWithInlineData::Trace(visitor); + ContextClient::Trace(visitor); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h index db56e123ab7..b2952b2cffb 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h @@ -5,8 +5,10 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_STREAM_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_STREAM_H_ +#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" +#include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/modules/modules_export.h" -#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h" namespace blink { @@ -14,29 +16,54 @@ class RTCQuicTransport; enum class RTCQuicStreamState { kNew, kOpening, kOpen, kClosing, kClosed }; -class MODULES_EXPORT RTCQuicStream final : public ScriptWrappable { +class MODULES_EXPORT RTCQuicStream final : public EventTargetWithInlineData, + public ContextClient, + public QuicStreamProxy::Delegate { DEFINE_WRAPPERTYPEINFO(); public: - RTCQuicStream(RTCQuicTransport* transport); + RTCQuicStream(ExecutionContext* context, + RTCQuicTransport* transport, + QuicStreamProxy* stream_proxy); ~RTCQuicStream() override; + // Called from the RTCQuicTransport when it is being stopped. void Stop(); + bool IsClosed() const { return state_ == RTCQuicStreamState::kClosed; } // rtc_quic_stream.idl RTCQuicTransport* transport() const; String state() const; uint32_t readBufferedAmount() const; uint32_t writeBufferedAmount() const; + void finish(); + void reset(); + DEFINE_ATTRIBUTE_EVENT_LISTENER(statechange); + + // EventTarget overrides. + const AtomicString& InterfaceName() const override; + ExecutionContext* GetExecutionContext() const override; // For garbage collection. void Trace(blink::Visitor* visitor) override; private: + // Closes the stream. This will change the state to kClosed and deregister it + // from the RTCQuicTransport. The QuicStreamProxy can no longer be used after + // this point. + void Close(); + + // QuicStreamProxy::Delegate overrides. + void OnRemoteReset() override; + void OnRemoteFinish() override; + Member<RTCQuicTransport> transport_; - RTCQuicStreamState state_ = RTCQuicStreamState::kNew; + RTCQuicStreamState state_ = RTCQuicStreamState::kOpen; + bool readable_ = true; + bool writeable_ = true; uint32_t read_buffered_amount_ = 0; uint32_t write_buffered_amount_ = 0; + QuicStreamProxy* proxy_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl index edc318407df..945d6b4af5d 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl @@ -14,12 +14,15 @@ enum RTCQuicStreamState { // https://w3c.github.io/webrtc-quic/#quicstream* [ Exposed=Window, - RuntimeEnabled=RTCQuicStream -] interface RTCQuicStream { + RuntimeEnabled=RTCQuicTransport +] interface RTCQuicStream : EventTarget { readonly attribute RTCQuicTransport transport; readonly attribute RTCQuicStreamState state; readonly attribute unsigned long readBufferedAmount; readonly attribute unsigned long writeBufferedAmount; + void finish(); + void reset(); + attribute EventHandler onstatechange; // TODO(crbug.com/868068): Implement remaining methods, attributes, and events. }; diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.cc new file mode 100644 index 00000000000..af4228d12f4 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.cc @@ -0,0 +1,45 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event_init.h" + +namespace blink { + +RTCQuicStreamEvent* RTCQuicStreamEvent::Create(RTCQuicStream* stream) { + return new RTCQuicStreamEvent(stream); +} + +RTCQuicStreamEvent* RTCQuicStreamEvent::Create( + const AtomicString& type, + const RTCQuicStreamEventInit& initializer) { + return new RTCQuicStreamEvent(type, initializer); +} + +RTCQuicStreamEvent::RTCQuicStreamEvent(RTCQuicStream* stream) + : Event(EventTypeNames::quicstream, Bubbles::kNo, Cancelable::kNo), + stream_(stream) {} + +RTCQuicStreamEvent::RTCQuicStreamEvent( + const AtomicString& type, + const RTCQuicStreamEventInit& initializer) + : Event(type, initializer), stream_(initializer.stream()) {} + +RTCQuicStreamEvent::~RTCQuicStreamEvent() = default; + +RTCQuicStream* RTCQuicStreamEvent::stream() const { + return stream_.Get(); +} + +const AtomicString& RTCQuicStreamEvent::InterfaceName() const { + return EventNames::RTCQuicStreamEvent; +} + +void RTCQuicStreamEvent::Trace(blink::Visitor* visitor) { + visitor->Trace(stream_); + Event::Trace(visitor); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h new file mode 100644 index 00000000000..6e60d9a40ae --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h @@ -0,0 +1,44 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_STREAM_EVENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_STREAM_EVENT_H_ + +#include "third_party/blink/renderer/modules/event_modules.h" + +namespace blink { + +class RTCQuicStream; +class RTCQuicStreamEventInit; + +class RTCQuicStreamEvent final : public Event { + DEFINE_WRAPPERTYPEINFO(); + + public: + static RTCQuicStreamEvent* Create(RTCQuicStream* stream); + static RTCQuicStreamEvent* Create(const AtomicString& type, + const RTCQuicStreamEventInit& init); + + ~RTCQuicStreamEvent() override; + + // rtc_quic_stream_event.idl + RTCQuicStream* stream() const; + + // Event overrides. + const AtomicString& InterfaceName() const override; + + // For garbage collection. + void Trace(blink::Visitor*) override; + + private: + RTCQuicStreamEvent(RTCQuicStream* stream); + RTCQuicStreamEvent(const AtomicString& type, + const RTCQuicStreamEventInit& init); + + Member<RTCQuicStream> stream_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_STREAM_EVENT_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl new file mode 100644 index 00000000000..ced237c75eb --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl @@ -0,0 +1,12 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://w3c.github.io/webrtc-quic/#rtcquicstreamevent +[ + RuntimeEnabled=RTCQuicTransport, + Constructor(DOMString type, optional RTCQuicStreamEventInit eventInitDict), + Exposed=Window +] interface RTCQuicStreamEvent : Event { + readonly attribute RTCQuicStream stream; +}; diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event_init.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event_init.idl new file mode 100644 index 00000000000..53e3bcd1218 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event_init.idl @@ -0,0 +1,8 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://w3c.github.io/webrtc-quic/#dom-rtcquicstreameventinit +dictionary RTCQuicStreamEventInit : EventInit { + RTCQuicStream stream; +}; diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc index 407a8bb249a..926ba270ffc 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc @@ -4,24 +4,91 @@ #include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h" +#include "net/quic/quic_chromium_alarm_factory.h" +#include "net/third_party/quic/platform/impl/quic_chromium_clock.h" +#include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/dom/events/event.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_certificate.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h" -#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_parameters.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h" namespace blink { +namespace { + +// This class wraps a P2PQuicTransportFactoryImpl but does not construct it +// until CreateQuicTransport is called for the first time. This ensures that it +// is executed on the WebRTC worker thread. +class DefaultP2PQuicTransportFactory : public P2PQuicTransportFactory { + public: + explicit DefaultP2PQuicTransportFactory( + scoped_refptr<base::SingleThreadTaskRunner> host_thread) + : host_thread_(std::move(host_thread)) { + DCHECK(host_thread_); + } + + // P2PQuicTransportFactory overrides. + std::unique_ptr<P2PQuicTransport> CreateQuicTransport( + P2PQuicTransportConfig config) override { + DCHECK(host_thread_->RunsTasksInCurrentSequence()); + return GetFactory()->CreateQuicTransport(std::move(config)); + } + + private: + P2PQuicTransportFactory* GetFactory() { + DCHECK(host_thread_->RunsTasksInCurrentSequence()); + if (!factory_impl_) { + quic::QuicClock* clock = quic::QuicChromiumClock::GetInstance(); + auto alarm_factory = std::make_unique<net::QuicChromiumAlarmFactory>( + host_thread_.get(), clock); + factory_impl_ = std::make_unique<P2PQuicTransportFactoryImpl>( + clock, std::move(alarm_factory)); + } + return factory_impl_.get(); + } + + scoped_refptr<base::SingleThreadTaskRunner> host_thread_; + std::unique_ptr<P2PQuicTransportFactory> factory_impl_; +}; + +} // namespace RTCQuicTransport* RTCQuicTransport::Create( + ExecutionContext* context, RTCIceTransport* transport, const HeapVector<Member<RTCCertificate>>& certificates, ExceptionState& exception_state) { + return Create(context, transport, certificates, exception_state, + std::make_unique<DefaultP2PQuicTransportFactory>( + Platform::Current()->GetWebRtcWorkerThread())); +} + +RTCQuicTransport* RTCQuicTransport::Create( + ExecutionContext* context, + RTCIceTransport* transport, + const HeapVector<Member<RTCCertificate>>& certificates, + ExceptionState& exception_state, + std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory) { + DCHECK(context); + DCHECK(transport); + DCHECK(p2p_quic_transport_factory); if (transport->IsClosed()) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, "Cannot construct an RTCQuicTransport with a closed RTCIceTransport."); return nullptr; } + if (transport->HasConsumer()) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "Cannot construct an RTCQuicTransport " + "with an RTCIceTransport that already " + "has a connected RTCQuicTransport."); + return nullptr; + } for (const auto& certificate : certificates) { if (certificate->expires() < ConvertSecondsToDOMTimeStamp(CurrentTime())) { exception_state.ThrowTypeError( @@ -29,16 +96,38 @@ RTCQuicTransport* RTCQuicTransport::Create( return nullptr; } } - return new RTCQuicTransport(transport, certificates, exception_state); + return new RTCQuicTransport(context, transport, certificates, exception_state, + std::move(p2p_quic_transport_factory)); } RTCQuicTransport::RTCQuicTransport( + ExecutionContext* context, RTCIceTransport* transport, const HeapVector<Member<RTCCertificate>>& certificates, - ExceptionState& exception_state) - : transport_(transport), certificates_(certificates) {} + ExceptionState& exception_state, + std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory) + : ContextLifecycleObserver(context), + transport_(transport), + certificates_(certificates), + p2p_quic_transport_factory_(std::move(p2p_quic_transport_factory)) { + transport->ConnectConsumer(this); +} + +RTCQuicTransport::~RTCQuicTransport() { + DCHECK(!proxy_); +} -RTCQuicTransport::~RTCQuicTransport() = default; +void RTCQuicTransport::Close(RTCQuicTransportState new_state) { + DCHECK(!IsClosed()); + for (RTCQuicStream* stream : streams_) { + stream->Stop(); + } + streams_.clear(); + transport_->DisconnectConsumer(this); + proxy_.reset(); + state_ = new_state; + DCHECK(IsClosed()); +} RTCIceTransport* RTCQuicTransport::transport() const { return transport_; @@ -76,7 +165,7 @@ void RTCQuicTransport::getLocalParameters(RTCQuicParameters& result) const { void RTCQuicTransport::getRemoteParameters( base::Optional<RTCQuicParameters>& result) const { - result = base::nullopt; + result = remote_parameters_; } const HeapVector<Member<RTCCertificate>>& RTCQuicTransport::getCertificates() @@ -89,23 +178,131 @@ RTCQuicTransport::getRemoteCertificates() const { return remote_certificates_; } +static quic::Perspective QuicPerspectiveFromIceRole(cricket::IceRole ice_role) { + switch (ice_role) { + case cricket::ICEROLE_CONTROLLED: + return quic::Perspective::IS_CLIENT; + case cricket::ICEROLE_CONTROLLING: + return quic::Perspective::IS_SERVER; + default: + NOTREACHED(); + } + return quic::Perspective::IS_CLIENT; +} + +void RTCQuicTransport::start(const RTCQuicParameters& remote_parameters, + ExceptionState& exception_state) { + if (RaiseExceptionIfClosed(exception_state)) { + return; + } + if (remote_parameters_) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "Cannot start() multiple times."); + return; + } + remote_parameters_ = remote_parameters; + if (transport_->IsStarted()) { + StartConnection(); + } +} + +static std::unique_ptr<rtc::SSLFingerprint> RTCDtlsFingerprintToSSLFingerprint( + const RTCDtlsFingerprint& dtls_fingerprint) { + std::string algorithm = WebString(dtls_fingerprint.algorithm()).Utf8(); + std::string value = WebString(dtls_fingerprint.value()).Utf8(); + std::unique_ptr<rtc::SSLFingerprint> rtc_fingerprint( + rtc::SSLFingerprint::CreateFromRfc4572(algorithm, value)); + DCHECK(rtc_fingerprint); + return rtc_fingerprint; +} + +void RTCQuicTransport::StartConnection() { + DCHECK_EQ(state_, RTCQuicTransportState::kNew); + DCHECK(remote_parameters_); + + state_ = RTCQuicTransportState::kConnecting; + + std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> rtc_certificates; + for (const auto& certificate : certificates_) { + rtc_certificates.push_back(certificate->Certificate()); + } + IceTransportProxy* transport_proxy = transport_->ConnectConsumer(this); + proxy_.reset(new QuicTransportProxy( + this, transport_proxy, QuicPerspectiveFromIceRole(transport_->GetRole()), + rtc_certificates, std::move(p2p_quic_transport_factory_))); + + std::vector<std::unique_ptr<rtc::SSLFingerprint>> rtc_fingerprints; + for (const RTCDtlsFingerprint& fingerprint : + remote_parameters_->fingerprints()) { + rtc_fingerprints.push_back(RTCDtlsFingerprintToSSLFingerprint(fingerprint)); + } + proxy_->Start(std::move(rtc_fingerprints)); +} + +void RTCQuicTransport::OnTransportStarted() { + // The RTCIceTransport has now been started. + if (remote_parameters_) { + StartConnection(); + } +} + void RTCQuicTransport::stop() { - for (RTCQuicStream* stream : streams_) { - stream->Stop(); + if (IsClosed()) { + return; } - streams_.clear(); - state_ = RTCQuicTransportState::kClosed; + if (proxy_) { + proxy_->Stop(); + } + Close(RTCQuicTransportState::kClosed); } RTCQuicStream* RTCQuicTransport::createStream(ExceptionState& exception_state) { - if (RaiseExceptionIfClosed(exception_state)) { + // TODO(github.com/w3c/webrtc-quic/issues/50): Maybe support createStream in + // the 'new' or 'connecting' states. + if (state_ != RTCQuicTransportState::kConnected) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "RTCQuicTransport.createStream() is only " + "valid in the 'connected' state."); return nullptr; } - RTCQuicStream* stream = new RTCQuicStream(this); + return AddStream(proxy_->CreateStream()); +} + +RTCQuicStream* RTCQuicTransport::AddStream(QuicStreamProxy* stream_proxy) { + auto* stream = new RTCQuicStream(GetExecutionContext(), this, stream_proxy); + stream_proxy->set_delegate(stream); streams_.insert(stream); return stream; } +void RTCQuicTransport::RemoveStream(RTCQuicStream* stream) { + DCHECK(stream); + auto it = streams_.find(stream); + DCHECK(it != streams_.end()); + streams_.erase(it); +} + +void RTCQuicTransport::OnConnected() { + state_ = RTCQuicTransportState::kConnected; + DispatchEvent(*Event::Create(EventTypeNames::statechange)); +} + +void RTCQuicTransport::OnConnectionFailed(const std::string& error_details, + bool from_remote) { + Close(RTCQuicTransportState::kFailed); + DispatchEvent(*Event::Create(EventTypeNames::statechange)); +} + +void RTCQuicTransport::OnRemoteStopped() { + Close(RTCQuicTransportState::kClosed); + DispatchEvent(*Event::Create(EventTypeNames::statechange)); +} + +void RTCQuicTransport::OnStream(QuicStreamProxy* stream_proxy) { + RTCQuicStream* stream = AddStream(stream_proxy); + DispatchEvent(*RTCQuicStreamEvent::Create(stream)); +} + bool RTCQuicTransport::RaiseExceptionIfClosed( ExceptionState& exception_state) const { if (IsClosed()) { @@ -117,12 +314,30 @@ bool RTCQuicTransport::RaiseExceptionIfClosed( return false; } +const AtomicString& RTCQuicTransport::InterfaceName() const { + return EventTargetNames::RTCQuicTransport; +} + +ExecutionContext* RTCQuicTransport::GetExecutionContext() const { + return ContextLifecycleObserver::GetExecutionContext(); +} + +void RTCQuicTransport::ContextDestroyed(ExecutionContext*) { + stop(); +} + +bool RTCQuicTransport::HasPendingActivity() const { + return static_cast<bool>(proxy_); +} + void RTCQuicTransport::Trace(blink::Visitor* visitor) { visitor->Trace(transport_); visitor->Trace(certificates_); visitor->Trace(remote_certificates_); + visitor->Trace(remote_parameters_); visitor->Trace(streams_); - ScriptWrappable::Trace(visitor); + EventTargetWithInlineData::Trace(visitor); + ContextLifecycleObserver::Trace(visitor); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h index 161dd63c873..d469d81ae28 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h @@ -5,8 +5,11 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_H_ +#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" +#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" +#include "third_party/blink/renderer/modules/event_target_modules.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_quic_parameters.h" -#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" namespace blink { @@ -14,8 +17,8 @@ class DOMArrayBuffer; class ExceptionState; class RTCCertificate; class RTCIceTransport; -class RTCQuicParameters; class RTCQuicStream; +class P2PQuicTransportFactory; enum class RTCQuicTransportState { kNew, @@ -25,17 +28,32 @@ enum class RTCQuicTransportState { kFailed }; -class MODULES_EXPORT RTCQuicTransport final : public ScriptWrappable { +class MODULES_EXPORT RTCQuicTransport final + : public EventTargetWithInlineData, + public ActiveScriptWrappable<RTCQuicTransport>, + public ContextLifecycleObserver, + public QuicTransportProxy::Delegate { DEFINE_WRAPPERTYPEINFO(); + USING_GARBAGE_COLLECTED_MIXIN(RTCQuicTransport); public: static RTCQuicTransport* Create( + ExecutionContext* context, RTCIceTransport* transport, const HeapVector<Member<RTCCertificate>>& certificates, ExceptionState& exception_state); + static RTCQuicTransport* Create( + ExecutionContext* context, + RTCIceTransport* transport, + const HeapVector<Member<RTCCertificate>>& certificates, + ExceptionState& exception_state, + std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory); ~RTCQuicTransport() override; + RTCQuicStream* AddStream(QuicStreamProxy* stream_proxy); + void RemoveStream(RTCQuicStream* stream); + // https://w3c.github.io/webrtc-quic/#quic-transport* RTCIceTransport* transport() const; String state() const; @@ -43,24 +61,62 @@ class MODULES_EXPORT RTCQuicTransport final : public ScriptWrappable { void getRemoteParameters(base::Optional<RTCQuicParameters>& result) const; const HeapVector<Member<RTCCertificate>>& getCertificates() const; const HeapVector<Member<DOMArrayBuffer>>& getRemoteCertificates() const; + void start(const RTCQuicParameters& remote_parameters, + ExceptionState& exception_state); void stop(); RTCQuicStream* createStream(ExceptionState& exception_state); + DEFINE_ATTRIBUTE_EVENT_LISTENER(statechange); + DEFINE_ATTRIBUTE_EVENT_LISTENER(error); + DEFINE_ATTRIBUTE_EVENT_LISTENER(quicstream); + + // Called by the RTCIceTransport when its start() method is called. + void OnTransportStarted(); + + // EventTarget overrides. + const AtomicString& InterfaceName() const override; + ExecutionContext* GetExecutionContext() const override; + + // ContextLifecycleObserver overrides. + void ContextDestroyed(ExecutionContext*) override; + + // ActiveScriptWrappable overrides. + bool HasPendingActivity() const override; // For garbage collection. void Trace(blink::Visitor* visitor) override; private: - RTCQuicTransport(RTCIceTransport* transport, - const HeapVector<Member<RTCCertificate>>& certificates, - ExceptionState& exception_state); + RTCQuicTransport( + ExecutionContext* context, + RTCIceTransport* transport, + const HeapVector<Member<RTCCertificate>>& certificates, + ExceptionState& exception_state, + std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory); + + // QuicTransportProxy::Delegate overrides; + void OnConnected() override; + void OnConnectionFailed(const std::string& error_details, + bool from_remote) override; + void OnRemoteStopped() override; + void OnStream(QuicStreamProxy* stream_proxy) override; bool IsClosed() const { return state_ == RTCQuicTransportState::kClosed; } bool RaiseExceptionIfClosed(ExceptionState& exception_state) const; + // Starts the underlying QUIC connection. + void StartConnection(); + + // Close all streams, delete the underlying QUIC transport, and transition to + // the given state, closed or failed. + void Close(RTCQuicTransportState new_state); + Member<RTCIceTransport> transport_; RTCQuicTransportState state_ = RTCQuicTransportState::kNew; HeapVector<Member<RTCCertificate>> certificates_; HeapVector<Member<DOMArrayBuffer>> remote_certificates_; + base::Optional<RTCQuicParameters> remote_parameters_; + std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory_; + std::unique_ptr<QuicTransportProxy> proxy_; HeapHashSet<Member<RTCQuicStream>> streams_; }; diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl index df348136a76..ab25d010506 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl @@ -13,18 +13,23 @@ enum RTCQuicTransportState { // https://w3c.github.io/webrtc-quic/#quic-transport* [ + ActiveScriptWrappable, Constructor(RTCIceTransport transport, sequence<RTCCertificate> certificates), + ConstructorCallWith=ExecutionContext, RaisesException=Constructor, Exposed=Window, RuntimeEnabled=RTCQuicTransport -] interface RTCQuicTransport { +] interface RTCQuicTransport : EventTarget { readonly attribute RTCIceTransport transport; readonly attribute RTCQuicTransportState state; RTCQuicParameters getLocalParameters(); RTCQuicParameters? getRemoteParameters(); sequence<RTCCertificate> getCertificates(); sequence<ArrayBuffer> getRemoteCertificates(); + [RaisesException] void start(RTCQuicParameters remoteParameters); void stop(); - [RaisesException, RuntimeEnabled=RTCQuicStream] RTCQuicStream createStream(); - // TODO(crbug.com/868068): Implement remaining control methods + events. + [RaisesException] RTCQuicStream createStream(); + attribute EventHandler onstatechange; + attribute EventHandler onerror; + attribute EventHandler onquicstream; }; diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc new file mode 100644 index 00000000000..e16b065df82 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc @@ -0,0 +1,235 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file tests the RTCQuicTransport Blink bindings, QuicTransportProxy and +// QuicTransportHost by mocking out the underlying P2PQuicTransport. +// Everything is run on a single thread but with separate TestSimpleTaskRunners +// for the main thread / worker thread. + +#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.h" + +#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_packet_transport.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_gather_options.h" +#include "third_party/webrtc/rtc_base/rtccertificategenerator.h" + +namespace blink { +namespace { + +using testing::_; +using testing::Assign; +using testing::ElementsAre; +using testing::Invoke; +using testing::Mock; + +HeapVector<Member<RTCCertificate>> GenerateLocalRTCCertificates() { + HeapVector<Member<RTCCertificate>> certificates; + certificates.push_back( + new RTCCertificate(rtc::RTCCertificateGenerator::GenerateCertificate( + rtc::KeyParams::ECDSA(), absl::nullopt))); + return certificates; +} + +constexpr char kRemoteFingerprintAlgorithm1[] = "sha-256"; +constexpr char kRemoteFingerprintValue1[] = + "8E:57:5F:8E:65:D2:83:7B:05:97:BB:72:DE:09:DE:03:BD:95:9B:A0:03:10:50:82:" + "5E:73:38:16:4C:E0:C5:84"; + +RTCDtlsFingerprint CreateRemoteFingerprint1() { + RTCDtlsFingerprint dtls_fingerprint; + dtls_fingerprint.setAlgorithm(kRemoteFingerprintAlgorithm1); + dtls_fingerprint.setValue(kRemoteFingerprintValue1); + return dtls_fingerprint; +} + +RTCQuicParameters CreateRemoteRTCQuicParameters1() { + HeapVector<RTCDtlsFingerprint> fingerprints; + fingerprints.push_back(CreateRemoteFingerprint1()); + RTCQuicParameters quic_parameters; + quic_parameters.setFingerprints(fingerprints); + return quic_parameters; +} + +} // namespace + +RTCQuicTransport* RTCQuicTransportTest::CreateQuicTransport( + V8TestingScope& scope, + RTCIceTransport* ice_transport, + const HeapVector<Member<RTCCertificate>>& certificates, + std::unique_ptr<MockP2PQuicTransport> mock_transport, + P2PQuicTransport::Delegate** delegate_out) { + return CreateQuicTransport(scope, ice_transport, certificates, + std::make_unique<MockP2PQuicTransportFactory>( + std::move(mock_transport), delegate_out)); +} + +RTCQuicTransport* RTCQuicTransportTest::CreateQuicTransport( + V8TestingScope& scope, + RTCIceTransport* ice_transport, + const HeapVector<Member<RTCCertificate>>& certificates, + std::unique_ptr<MockP2PQuicTransportFactory> mock_factory) { + return RTCQuicTransport::Create(scope.GetExecutionContext(), ice_transport, + certificates, ASSERT_NO_EXCEPTION, + std::move(mock_factory)); +} + +// Test that calling start() creates a P2PQuicTransport with the correct +// P2PQuicTransportConfig. The config should have: +// 1. The P2PQuicPacketTransport returned by the MockIceTransportAdapter. +// 2. Server mode configured since the ICE role is 'controlling'. +// 3. The certificates passed in the RTCQuicTransport constructor. +TEST_F(RTCQuicTransportTest, P2PQuicTransportConstructedByStart) { + V8TestingScope scope; + + auto quic_packet_transport = std::make_unique<MockP2PQuicPacketTransport>(); + auto* quic_packet_transport_ptr = quic_packet_transport.get(); + auto ice_transport_adapter_mock = std::make_unique<MockIceTransportAdapter>( + std::move(quic_packet_transport)); + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, std::move(ice_transport_adapter_mock)); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling", + ASSERT_NO_EXCEPTION); + + rtc::scoped_refptr<rtc::RTCCertificate> certificate = + rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams::ECDSA(), + absl::nullopt); + auto mock_factory = std::make_unique<MockP2PQuicTransportFactory>( + std::make_unique<MockP2PQuicTransport>()); + EXPECT_CALL(*mock_factory, OnCreateQuicTransport(_)) + .WillOnce(Invoke([quic_packet_transport_ptr, + certificate](const P2PQuicTransportConfig& config) { + EXPECT_EQ(quic_packet_transport_ptr, config.packet_transport); + EXPECT_TRUE(config.is_server); + EXPECT_THAT(config.certificates, ElementsAre(certificate)); + })); + HeapVector<Member<RTCCertificate>> certificates; + certificates.push_back(new RTCCertificate(certificate)); + Persistent<RTCQuicTransport> quic_transport = CreateQuicTransport( + scope, ice_transport, certificates, std::move(mock_factory)); + quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION); +} + +// Test that calling start() creates a P2PQuicTransport with +// |config.is_server| = false if the RTCIceTransport role is 'controlled'. +TEST_F(RTCQuicTransportTest, P2PQuicTransportConstructedByStartClient) { + V8TestingScope scope; + + auto ice_transport_adapter_mock = std::make_unique<MockIceTransportAdapter>( + std::make_unique<MockP2PQuicPacketTransport>()); + Persistent<RTCIceTransport> ice_transport = + CreateIceTransport(scope, std::move(ice_transport_adapter_mock)); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlled", + ASSERT_NO_EXCEPTION); + + auto mock_factory = std::make_unique<MockP2PQuicTransportFactory>( + std::make_unique<MockP2PQuicTransport>()); + EXPECT_CALL(*mock_factory, OnCreateQuicTransport(_)) + .WillOnce(Invoke([](const P2PQuicTransportConfig& config) { + EXPECT_FALSE(config.is_server); + })); + Persistent<RTCQuicTransport> quic_transport = + CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(), + std::move(mock_factory)); + quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION); +} + +// Test that calling start() calls Start() on the P2PQuicTransport with the +// correct remote fingerprints. +TEST_F(RTCQuicTransportTest, StartPassesRemoteFingerprints) { + V8TestingScope scope; + + Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling", + ASSERT_NO_EXCEPTION); + + auto mock_transport = std::make_unique<MockP2PQuicTransport>(); + EXPECT_CALL(*mock_transport, MockStart(_)) + .WillOnce( + Invoke([](const std::vector<std::unique_ptr<rtc::SSLFingerprint>>& + remote_fingerprints) { + ASSERT_EQ(1u, remote_fingerprints.size()); + EXPECT_EQ(kRemoteFingerprintAlgorithm1, + remote_fingerprints[0]->algorithm); + EXPECT_EQ(kRemoteFingerprintValue1, + remote_fingerprints[0]->GetRfc4572Fingerprint()); + })); + Persistent<RTCQuicTransport> quic_transport = + CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(), + std::move(mock_transport)); + quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION); +} + +// Test that calling stop() deletes the underlying P2PQuicTransport. +TEST_F(RTCQuicTransportTest, StopCallsStopThenDeletesQuicTransportAdapter) { + V8TestingScope scope; + + Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling", + ASSERT_NO_EXCEPTION); + + bool mock_deleted = false; + auto mock_transport = std::make_unique<MockP2PQuicTransport>(); + EXPECT_CALL(*mock_transport, Stop()).Times(1); + EXPECT_CALL(*mock_transport, Die()).WillOnce(Assign(&mock_deleted, true)); + + Persistent<RTCQuicTransport> quic_transport = + CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(), + std::move(mock_transport)); + quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION); + + quic_transport->stop(); + RunUntilIdle(); + + EXPECT_TRUE(mock_deleted); +} + +// Test that calling stop() on the underlying RTCIceTransport deletes the +// underlying P2PQuicTransport. +TEST_F(RTCQuicTransportTest, RTCIceTransportStopDeletesP2PQuicTransport) { + V8TestingScope scope; + + Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling", + ASSERT_NO_EXCEPTION); + + bool mock_deleted = false; + auto mock_transport = std::make_unique<MockP2PQuicTransport>(); + EXPECT_CALL(*mock_transport, Die()).WillOnce(Assign(&mock_deleted, true)); + + Persistent<RTCQuicTransport> quic_transport = + CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(), + std::move(mock_transport)); + quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION); + + ice_transport->stop(); + RunUntilIdle(); + + EXPECT_TRUE(mock_deleted); +} + +// Test that the P2PQuicTransport is deleted when the underlying RTCIceTransport +// is ContextDestroyed. +TEST_F(RTCQuicTransportTest, + RTCIceTransportContextDestroyedDeletesP2PQuicTransport) { + V8TestingScope scope; + + Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope); + ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling", + ASSERT_NO_EXCEPTION); + + bool mock_deleted = false; + auto mock_transport = std::make_unique<MockP2PQuicTransport>(); + EXPECT_CALL(*mock_transport, Die()).WillOnce(Assign(&mock_deleted, true)); + + Persistent<RTCQuicTransport> quic_transport = + CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(), + std::move(mock_transport)); + quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION); + + ice_transport->ContextDestroyed(scope.GetExecutionContext()); + RunUntilIdle(); + + EXPECT_TRUE(mock_deleted); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.h b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.h new file mode 100644 index 00000000000..05683f98c4c --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.h @@ -0,0 +1,40 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LQUICNSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_TEST_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_TEST_H_ + +#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport_factory.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_certificate.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h" + +namespace blink { + +class RTCQuicTransportTest : public RTCIceTransportTest { + public: + // Construct a new RTCQuicTransport with the given RTCIceTransport, + // certificates, and mock P2PQuicTransport. + // |delegate_out|, if non-null, will be populated once the P2PQuicTransport is + // constructed on the worker thread. + RTCQuicTransport* CreateQuicTransport( + V8TestingScope& scope, + RTCIceTransport* ice_transport, + const HeapVector<Member<RTCCertificate>>& certificates, + std::unique_ptr<MockP2PQuicTransport> mock_transport, + P2PQuicTransport::Delegate** delegate_out = nullptr); + + // Construct a new RTCQuicTransport with the given RTCIceTransport, + // certificates, and mock P2PQuicTransportFactory. + RTCQuicTransport* CreateQuicTransport( + V8TestingScope& scope, + RTCIceTransport* ice_transport, + const HeapVector<Member<RTCCertificate>>& certificates, + std::unique_ptr<MockP2PQuicTransportFactory> mock_factory); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_TEST_H_ diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc index 789a24c2bea..91e6757baf6 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc @@ -79,9 +79,9 @@ webrtc::RtpTransceiverInit ToRtpTransceiverInit( webrtc_init.stream_ids.push_back(stream->id().Utf8().data()); } DCHECK(init.hasSendEncodings()); - // TODO(orphis,hbos): Pass the encodings down to the lower layer using - // ToRtpEncodingParameters() once implemented in third_party/webrtc. - // https://crbug.com/803494 + for (const auto& encoding : init.sendEncodings()) { + webrtc_init.send_encodings.push_back(ToRtpEncodingParameters(encoding)); + } return webrtc_init; } diff --git a/chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl b/chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl index 9d5e8edd646..d222ccbd270 100644 --- a/chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl +++ b/chromium/third_party/blink/renderer/modules/permissions/permission_descriptor.idl @@ -2,18 +2,27 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// https://w3c.github.io/permissions/#enumdef-permissionname enum PermissionName { "geolocation", - "midi", "notifications", "push", + "midi", "camera", "microphone", + // "speaker", + // "device-info", + "background-fetch", "background-sync", + // "bluetooth", + "persistent-storage", "ambient-light-sensor", "accelerometer", "gyroscope", "magnetometer", + // "clipboard", + + // Non-standard: "accessibility-events", "clipboard-read", "clipboard-write", @@ -23,6 +32,7 @@ enum PermissionName { // The PermissionDescriptor dictionary is a base to describe permissions. Some // permissions will extend it. The methods reading it will re-parse it depending // on the name. +// https://w3c.github.io/permissions/#dictdef-permissiondescriptor dictionary PermissionDescriptor { required PermissionName name; }; diff --git a/chromium/third_party/blink/renderer/modules/permissions/permissions.cc b/chromium/third_party/blink/renderer/modules/permissions/permissions.cc index 20d74e84b64..4b57a3013a2 100644 --- a/chromium/third_party/blink/renderer/modules/permissions/permissions.cc +++ b/chromium/third_party/blink/renderer/modules/permissions/permissions.cc @@ -68,6 +68,8 @@ PermissionDescriptorPtr ParsePermission(ScriptState* script_state, return CreatePermissionDescriptor(PermissionName::AUDIO_CAPTURE); if (name == "notifications") return CreatePermissionDescriptor(PermissionName::NOTIFICATIONS); + if (name == "persistent-storage") + return CreatePermissionDescriptor(PermissionName::DURABLE_STORAGE); if (name == "push") { PushPermissionDescriptor push_permission = NativeValueTraits<PushPermissionDescriptor>::NativeValue( @@ -137,6 +139,14 @@ PermissionDescriptorPtr ParsePermission(ScriptState* script_state, } if (name == "payment-handler") return CreatePermissionDescriptor(PermissionName::PAYMENT_HANDLER); + if (name == "background-fetch") { + if (!OriginTrials::BackgroundFetchEnabled( + ExecutionContext::From(script_state))) { + exception_state.ThrowTypeError("Background Fetch is not enabled."); + return nullptr; + } + return CreatePermissionDescriptor(PermissionName::BACKGROUND_FETCH); + } return nullptr; } @@ -181,13 +191,13 @@ ScriptPromise Permissions::request(ScriptState* script_state, ScriptPromise promise = resolver->Promise(); PermissionDescriptorPtr descriptor_copy = descriptor->Clone(); - Document* doc = ToDocumentOrNull(context); + Document* doc = DynamicTo<Document>(context); LocalFrame* frame = doc ? doc->GetFrame() : nullptr; GetService(ExecutionContext::From(script_state)) .RequestPermission( std::move(descriptor), - Frame::HasTransientUserActivation(frame, - true /* checkIfMainThread */), + LocalFrame::HasTransientUserActivation( + frame, true /* check_if_main_thread */), WTF::Bind(&Permissions::TaskComplete, WrapPersistent(this), WrapPersistent(resolver), WTF::Passed(std::move(descriptor_copy)))); @@ -255,13 +265,13 @@ ScriptPromise Permissions::requestAll( for (const auto& descriptor : internal_permissions) internal_permissions_copy.push_back(descriptor->Clone()); - Document* doc = ToDocumentOrNull(context); + Document* doc = DynamicTo<Document>(context); LocalFrame* frame = doc ? doc->GetFrame() : nullptr; GetService(ExecutionContext::From(script_state)) .RequestPermissions( std::move(internal_permissions), - Frame::HasTransientUserActivation(frame, - true /* checkIfMainThread */), + LocalFrame::HasTransientUserActivation( + frame, true /* check_if_main_thread */), WTF::Bind(&Permissions::BatchTaskComplete, WrapPersistent(this), WrapPersistent(resolver), WTF::Passed(std::move(internal_permissions_copy)), diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/document_picture_in_picture.cc b/chromium/third_party/blink/renderer/modules/picture_in_picture/document_picture_in_picture.cc index 6c2d74cf411..2628c46dc9a 100644 --- a/chromium/third_party/blink/renderer/modules/picture_in_picture/document_picture_in_picture.cc +++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/document_picture_in_picture.cc @@ -33,7 +33,7 @@ ScriptPromise DocumentPictureInPicture::exitPictureInPicture( PictureInPictureControllerImpl& controller = PictureInPictureControllerImpl::From(document); Element* picture_in_picture_element = - controller.PictureInPictureElement(ToTreeScope(document)); + controller.PictureInPictureElement(document); if (!picture_in_picture_element) { return ScriptPromise::RejectWithDOMException( diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc b/chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc index 4b869169e28..a07678ca9c5 100644 --- a/chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc +++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.cc @@ -14,7 +14,6 @@ #include "third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_control.h" #include "third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h" #include "third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_window.h" -#include "third_party/blink/renderer/platform/feature_policy/feature_policy.h" namespace blink { @@ -28,8 +27,6 @@ const char kMetadataNotLoadedError[] = "Metadata for the video element are not loaded yet."; const char kVideoTrackNotAvailableError[] = "The video element has no video track."; -const char kMediaStreamsNotSupportedYet[] = - "Media Streams are not supported yet."; const char kFeaturePolicyBlocked[] = "Access to the feature \"picture-in-picture\" is disallowed by feature " "policy."; @@ -64,11 +61,6 @@ ScriptPromise HTMLVideoElementPictureInPicture::requestPictureInPicture( script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError, kVideoTrackNotAvailableError)); - case Status::kMediaStreamsNotSupportedYet: - return ScriptPromise::RejectWithDOMException( - script_state, - DOMException::Create(DOMExceptionCode::kNotSupportedError, - kMediaStreamsNotSupportedYet)); case Status::kDisabledByFeaturePolicy: return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kSecurityError, @@ -91,7 +83,7 @@ ScriptPromise HTMLVideoElementPictureInPicture::requestPictureInPicture( // `kFrameDetached`. LocalFrame* frame = element.GetFrame(); DCHECK(frame); - if (!Frame::ConsumeTransientUserActivation(frame)) { + if (!LocalFrame::ConsumeTransientUserActivation(frame)) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kNotAllowedError, kUserGestureRequired)); diff --git a/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc index 163159c6508..c8ff90a439d 100644 --- a/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc +++ b/chromium/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc @@ -4,7 +4,7 @@ #include "third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h" -#include "third_party/blink/public/platform/web_media_player.h" +#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/dom/events/event.h" @@ -13,7 +13,6 @@ #include "third_party/blink/renderer/core/html/media/html_video_element.h" #include "third_party/blink/renderer/modules/picture_in_picture/enter_picture_in_picture_event.h" #include "third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_window.h" -#include "third_party/blink/renderer/platform/feature_policy/feature_policy.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" namespace blink { @@ -55,8 +54,9 @@ PictureInPictureControllerImpl::IsDocumentAllowed() const { // If document is not allowed to use the policy-controlled feature named // "picture-in-picture", return kDisabledByFeaturePolicy status. if (RuntimeEnabledFeatures::PictureInPictureAPIEnabled() && - !frame->IsFeatureEnabled( - blink::mojom::FeaturePolicyFeature::kPictureInPicture)) { + !GetSupplementable()->IsFeatureEnabled( + blink::mojom::FeaturePolicyFeature::kPictureInPicture, + ReportOptions::kReportOnFailure)) { return Status::kDisabledByFeaturePolicy; } @@ -79,10 +79,6 @@ PictureInPictureControllerImpl::IsElementAllowed( if (element.FastHasAttribute(HTMLNames::disablepictureinpictureAttr)) return Status::kDisabledByAttribute; - // TODO(crbug.com/806249): Remove this when MediaStreams are supported. - if (element.GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream) - return Status::kMediaStreamsNotSupportedYet; - return Status::kEnabled; } diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_availability.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_availability.cc index a677e26afa3..8c3c92da83a 100644 --- a/chromium/third_party/blink/renderer/modules/presentation/presentation_availability.cc +++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_availability.cc @@ -35,7 +35,7 @@ PresentationAvailability::PresentationAvailability( const WTF::Vector<KURL>& urls, bool value) : PausableObject(execution_context), - PageVisibilityObserver(ToDocument(execution_context)->GetPage()), + PageVisibilityObserver(To<Document>(execution_context)->GetPage()), urls_(urls), value_(value), state_(State::kActive) { @@ -107,7 +107,7 @@ void PresentationAvailability::UpdateListening() { return; if (state_ == State::kActive && - (ToDocument(GetExecutionContext())->GetPageVisibilityState() == + (To<Document>(GetExecutionContext())->GetPageVisibilityState() == mojom::PageVisibilityState::kVisible)) controller->GetAvailabilityState()->AddObserver(this); else diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_availability_state.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_availability_state.cc index ee609bef2f3..ba08fa134d9 100644 --- a/chromium/third_party/blink/renderer/modules/presentation/presentation_availability_state.cc +++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_availability_state.cc @@ -5,9 +5,9 @@ #include "third_party/blink/renderer/modules/presentation/presentation_availability_state.h" #include "third_party/blink/public/platform/platform.h" -#include "third_party/blink/public/platform/web_thread.h" #include "third_party/blink/renderer/modules/presentation/presentation_availability_observer.h" #include "third_party/blink/renderer/modules/presentation/presentation_controller.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/blink/renderer/platform/wtf/functional.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_availability_state_test.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_availability_state_test.cc index f3fc8efe0cc..a828aa58912 100644 --- a/chromium/third_party/blink/renderer/modules/presentation/presentation_availability_state_test.cc +++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_availability_state_test.cc @@ -97,7 +97,7 @@ class PresentationAvailabilityStateTest : public testing::Test { state_.RequestAvailability( urls, std::unique_ptr<MockPresentationAvailabilityCallbacks>(mock_callback)); - for (size_t i = 0; i < urls.size(); i++) + for (wtf_size_t i = 0; i < urls.size(); i++) ChangeURLState(urls[i], states[i]); } diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc index 42711dda72b..68acf374d54 100644 --- a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc +++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.cc @@ -166,29 +166,23 @@ PresentationConnection::~PresentationConnection() { } void PresentationConnection::OnMessage( - mojom::blink::PresentationConnectionMessagePtr message, - OnMessageCallback callback) { - DCHECK(!callback.is_null()); + mojom::blink::PresentationConnectionMessagePtr message) { if (message->is_data()) { const auto& data = message->get_data(); DidReceiveBinaryMessage(&data.front(), data.size()); } else { DidReceiveTextMessage(message->get_message()); } - - std::move(callback).Run(true); } void PresentationConnection::DidChangeState( mojom::blink::PresentationConnectionState state) { + // Closed state is handled in |DidClose()|. + DCHECK_NE(mojom::blink::PresentationConnectionState::CLOSED, state); + if (state_ == state) return; - if (state == mojom::blink::PresentationConnectionState::CLOSED) { - DidClose(); - return; - } - state_ = state; switch (state_) { @@ -197,7 +191,6 @@ void PresentationConnection::DidChangeState( case mojom::blink::PresentationConnectionState::CONNECTED: DispatchStateChangeEvent(Event::Create(EventTypeNames::connect)); return; - // Closed state is handled in |DidClose()|. case mojom::blink::PresentationConnectionState::CLOSED: return; case mojom::blink::PresentationConnectionState::TERMINATED: @@ -207,15 +200,9 @@ void PresentationConnection::DidChangeState( NOTREACHED(); } -void PresentationConnection::RequestClose() { - DidChangeState(mojom::blink::PresentationConnectionState::CLOSED); - - // TODO(crbug.com/749327): Instead of calling DidChangeState, consider - // supplying a callback to RequestClose() and invoking it here. - if (target_connection_) { - target_connection_->DidChangeState( - mojom::blink::PresentationConnectionState::CLOSED); - } +void PresentationConnection::DidClose( + mojom::blink::PresentationConnectionCloseReason reason) { + DidClose(reason, /* message */ String()); } // static @@ -225,9 +212,8 @@ ControllerPresentationConnection* ControllerPresentationConnection::Take( PresentationRequest* request) { DCHECK(resolver); DCHECK(request); - DCHECK(resolver->GetExecutionContext()->IsDocument()); - Document* document = ToDocument(resolver->GetExecutionContext()); + Document* document = To<Document>(resolver->GetExecutionContext()); if (!document->GetFrame()) return nullptr; @@ -271,7 +257,7 @@ ControllerPresentationConnection::ControllerPresentationConnection( const KURL& url) : PresentationConnection(frame, id, url), controller_(controller) {} -ControllerPresentationConnection::~ControllerPresentationConnection() = default; +ControllerPresentationConnection::~ControllerPresentationConnection() {} void ControllerPresentationConnection::Trace(blink::Visitor* visitor) { visitor->Trace(controller_); @@ -295,13 +281,13 @@ void ControllerPresentationConnection::Init( connection_binding_.Bind(std::move(connection_request)); } -void ControllerPresentationConnection::DoClose() { +void ControllerPresentationConnection::CloseInternal() { auto& service = controller_->GetPresentationService(); if (service) service->CloseConnection(url_, id_); } -void ControllerPresentationConnection::DoTerminate() { +void ControllerPresentationConnection::TerminateInternal() { auto& service = controller_->GetPresentationService(); if (service) service->Terminate(url_, id_); @@ -350,15 +336,19 @@ void ReceiverPresentationConnection::Init( void ReceiverPresentationConnection::DidChangeState( mojom::blink::PresentationConnectionState state) { PresentationConnection::DidChangeState(state); - if (state == mojom::blink::PresentationConnectionState::CLOSED) - receiver_->RemoveConnection(this); } -void ReceiverPresentationConnection::DoClose() { +void ReceiverPresentationConnection::DidClose( + mojom::blink::PresentationConnectionCloseReason reason) { + PresentationConnection::DidClose(reason); + receiver_->RemoveConnection(this); +} + +void ReceiverPresentationConnection::CloseInternal() { // No-op } -void ReceiverPresentationConnection::DoTerminate() { +void ReceiverPresentationConnection::TerminateInternal() { // This will close the receiver window. Change the state to TERMINATED now // since ReceiverPresentationConnection won't get a state change notification. if (state_ == mojom::blink::PresentationConnectionState::TERMINATED) @@ -408,6 +398,7 @@ void PresentationConnection::AddedEventListener( } void PresentationConnection::ContextDestroyed(ExecutionContext*) { + DoClose(mojom::blink::PresentationConnectionCloseReason::WENT_AWAY); target_connection_.reset(); connection_binding_.Close(); } @@ -463,6 +454,21 @@ void PresentationConnection::send(Blob* data, ExceptionState& exception_state) { HandleMessageQueue(); } +void PresentationConnection::DoClose( + mojom::blink::PresentationConnectionCloseReason reason) { + if (state_ != mojom::blink::PresentationConnectionState::CONNECTING && + state_ != mojom::blink::PresentationConnectionState::CONNECTED) { + return; + } + + if (target_connection_) + target_connection_->DidClose(reason); + + DidClose(reason); + CloseInternal(); + TearDown(); +} + bool PresentationConnection::CanSendMessage(ExceptionState& exception_state) { if (state_ != mojom::blink::PresentationConnectionState::CONNECTED) { ThrowPresentationDisconnectedError(exception_state); @@ -520,10 +526,8 @@ void PresentationConnection::setBinaryType(const String& binary_type) { void PresentationConnection::SendMessageToTargetConnection( mojom::blink::PresentationConnectionMessagePtr message) { - if (target_connection_) { - target_connection_->OnMessage(std::move(message), - base::OnceCallback<void(bool)>()); - } + if (target_connection_) + target_connection_->OnMessage(std::move(message)); } void PresentationConnection::DidReceiveTextMessage(const WebString& message) { @@ -534,7 +538,7 @@ void PresentationConnection::DidReceiveTextMessage(const WebString& message) { } void PresentationConnection::DidReceiveBinaryMessage(const uint8_t* data, - size_t length) { + uint32_t length) { if (state_ != mojom::blink::PresentationConnectionState::CONNECTED) return; @@ -561,23 +565,14 @@ mojom::blink::PresentationConnectionState PresentationConnection::GetState() } void PresentationConnection::close() { - if (state_ != mojom::blink::PresentationConnectionState::CONNECTING && - state_ != mojom::blink::PresentationConnectionState::CONNECTED) { - return; - } - - if (target_connection_) - target_connection_->RequestClose(); - - DoClose(); - TearDown(); + DoClose(mojom::blink::PresentationConnectionCloseReason::CLOSED); } void PresentationConnection::terminate() { if (state_ != mojom::blink::PresentationConnectionState::CONNECTED) return; - DoTerminate(); + TerminateInternal(); TearDown(); } @@ -598,10 +593,6 @@ void PresentationConnection::DidClose( EventTypeNames::close, ConnectionCloseReasonToString(reason), message)); } -void PresentationConnection::DidClose() { - DidClose(mojom::blink::PresentationConnectionCloseReason::CLOSED, ""); -} - void PresentationConnection::DidFinishLoadingBlob(DOMArrayBuffer* buffer) { DCHECK(!messages_.IsEmpty()); DCHECK_EQ(messages_.front()->type, kMessageTypeBlob); diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.h b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.h index c6adf86ff57..3168d5bad32 100644 --- a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.h +++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection.h @@ -53,7 +53,12 @@ class PresentationConnection : public EventTargetWithInlineData, void send(DOMArrayBuffer*, ExceptionState&); void send(NotShared<DOMArrayBufferView>, ExceptionState&); void send(Blob*, ExceptionState&); + + // Closes the connection to the ongoing presentation. void close(); + + // Terminates the ongoing presentation that this PresentationConnection is + // connected to. void terminate(); String binaryType() const; @@ -73,10 +78,9 @@ class PresentationConnection : public EventTargetWithInlineData, const String& message); // mojom::blink::PresentationConnection implementation. - void OnMessage(mojom::blink::PresentationConnectionMessagePtr, - OnMessageCallback) override; + void OnMessage(mojom::blink::PresentationConnectionMessagePtr) override; void DidChangeState(mojom::blink::PresentationConnectionState) override; - void RequestClose() override; + void DidClose(mojom::blink::PresentationConnectionCloseReason) override; mojom::blink::PresentationConnectionState GetState() const; @@ -118,9 +122,9 @@ class PresentationConnection : public EventTargetWithInlineData, class Message; // Implemented by controller/receiver subclasses to perform additional - // operations. - virtual void DoClose() = 0; - virtual void DoTerminate() = 0; + // operations when close() / terminate() is called. + virtual void CloseInternal() = 0; + virtual void TerminateInternal() = 0; bool CanSendMessage(ExceptionState&); void HandleMessageQueue(); @@ -132,11 +136,11 @@ class PresentationConnection : public EventTargetWithInlineData, void SendMessageToTargetConnection( mojom::blink::PresentationConnectionMessagePtr); void DidReceiveTextMessage(const WebString&); - void DidReceiveBinaryMessage(const uint8_t*, size_t length); + void DidReceiveBinaryMessage(const uint8_t*, uint32_t length); - // Notifies the presentation about its state change to 'closed', with - // "closed" being the reason and empty string as the message. - void DidClose(); + // Closes the PresentationConnection with the given reason and notifies the + // target connection. + void DoClose(mojom::blink::PresentationConnectionCloseReason); // Internal helper function to dispatch state change events asynchronously. void DispatchStateChangeEvent(Event*); @@ -179,8 +183,8 @@ class ControllerPresentationConnection final : public PresentationConnection { private: // PresentationConnection implementation. - void DoClose() override; - void DoTerminate() override; + void CloseInternal() override; + void TerminateInternal() override; Member<PresentationController> controller_; }; @@ -211,16 +215,17 @@ class ReceiverPresentationConnection final : public PresentationConnection { // PresentationConnection override void DidChangeState(mojom::blink::PresentationConnectionState) override; + void DidClose(mojom::blink::PresentationConnectionCloseReason) override; private: // PresentationConnection implementation. - void DoClose() override; + void CloseInternal() override; // Changes the presentation state to TERMINATED and notifies the sender // connection. This method does not dispatch a state change event to the page. // This method is only suitable for use when the presentation receiver frame // containing the connection object is going away. - void DoTerminate() override; + void TerminateInternal() override; Member<PresentationReceiver> receiver_; }; diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks.h b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks.h index bbff94f019f..79c0c3d1d8d 100644 --- a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks.h +++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks.h @@ -6,7 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_PRESENTATION_PRESENTATION_CONNECTION_CALLBACKS_H_ #include "third_party/blink/public/mojom/presentation/presentation.mojom-blink.h" -#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/noncopyable.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_list.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_list.cc index b3e4f0017bc..b706fc951ad 100644 --- a/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_list.cc +++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_connection_list.cc @@ -43,7 +43,7 @@ void PresentationConnectionList::AddConnection( bool PresentationConnectionList::RemoveConnection( ReceiverPresentationConnection* connection) { - for (size_t i = 0; i < connections_.size(); i++) { + for (wtf_size_t i = 0; i < connections_.size(); i++) { if (connections_[i] == connection) { connections_.EraseAt(i); return true; diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_controller.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_controller.cc index a9a3e752cfa..0bb8d0c060e 100644 --- a/chromium/third_party/blink/renderer/modules/presentation/presentation_controller.cc +++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_controller.cc @@ -44,8 +44,7 @@ PresentationController* PresentationController::FromContext( if (!execution_context) return nullptr; - DCHECK(execution_context->IsDocument()); - Document* document = ToDocument(execution_context); + Document* document = To<Document>(execution_context); if (!document->GetFrame()) return nullptr; diff --git a/chromium/third_party/blink/renderer/modules/presentation/presentation_request.cc b/chromium/third_party/blink/renderer/modules/presentation/presentation_request.cc index 4942ca775bd..8d11b2b41cc 100644 --- a/chromium/third_party/blink/renderer/modules/presentation/presentation_request.cc +++ b/chromium/third_party/blink/renderer/modules/presentation/presentation_request.cc @@ -33,7 +33,7 @@ namespace { Settings* GetSettings(ExecutionContext* execution_context) { DCHECK(execution_context); - Document* document = ToDocument(execution_context); + Document* document = To<Document>(execution_context); return document->GetSettings(); } @@ -59,7 +59,7 @@ PresentationRequest* PresentationRequest::Create( ExecutionContext* execution_context, const Vector<String>& urls, ExceptionState& exception_state) { - if (ToDocument(execution_context) + if (To<Document>(execution_context) ->IsSandboxed(kSandboxPresentationController)) { exception_state.ThrowSecurityError( "The document is sandboxed and lacks the 'allow-presentation' flag."); @@ -67,13 +67,13 @@ PresentationRequest* PresentationRequest::Create( } Vector<KURL> parsed_urls; - for (size_t i = 0; i < urls.size(); ++i) { - const KURL& parsed_url = KURL(execution_context->Url(), urls[i]); + for (const auto& url : urls) { + const KURL& parsed_url = KURL(execution_context->Url(), url); if (!parsed_url.IsValid()) { exception_state.ThrowDOMException( DOMExceptionCode::kSyntaxError, - "'" + urls[i] + "' can't be resolved to a valid URL."); + "'" + url + "' can't be resolved to a valid URL."); return nullptr; } @@ -81,7 +81,7 @@ PresentationRequest* PresentationRequest::Create( MixedContentChecker::IsMixedContent( execution_context->GetSecurityOrigin(), parsed_url)) { exception_state.ThrowSecurityError( - "Presentation of an insecure document [" + urls[i] + + "Presentation of an insecure document [" + url + "] is prohibited from a secure context."); return nullptr; } @@ -148,14 +148,14 @@ void PresentationRequest::RecordStartOriginTypeAccess( ScriptPromise PresentationRequest::start(ScriptState* script_state) { ExecutionContext* execution_context = GetExecutionContext(); Settings* context_settings = GetSettings(execution_context); - Document* doc = ToDocumentOrNull(execution_context); + Document* doc = To<Document>(execution_context); bool is_user_gesture_required = !context_settings || context_settings->GetPresentationRequiresUserGesture(); if (is_user_gesture_required && - !Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr)) + !LocalFrame::HasTransientUserActivation(doc->GetFrame())) return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create( diff --git a/chromium/third_party/blink/renderer/modules/push_messaging/push_manager.cc b/chromium/third_party/blink/renderer/modules/push_messaging/push_manager.cc index 6ec4b2964ed..a4760fba894 100644 --- a/chromium/third_party/blink/renderer/modules/push_messaging/push_manager.cc +++ b/chromium/third_party/blink/renderer/modules/push_messaging/push_manager.cc @@ -70,8 +70,8 @@ ScriptPromise PushManager::subscribe(ScriptState* script_state, // The document context is the only reasonable context from which to ask the // user for permission to use the Push API. The embedder should persist the // permission so that later calls in different contexts can succeed. - if (ExecutionContext::From(script_state)->IsDocument()) { - Document* document = ToDocument(ExecutionContext::From(script_state)); + if (auto* document = + DynamicTo<Document>(ExecutionContext::From(script_state))) { LocalFrame* frame = document->GetFrame(); if (!document->domWindow() || !frame) return ScriptPromise::RejectWithDOMException( @@ -80,13 +80,14 @@ ScriptPromise PushManager::subscribe(ScriptState* script_state, "Document is detached from window.")); PushController::ClientFrom(frame).Subscribe( registration_->WebRegistration(), web_options, - Frame::HasTransientUserActivation(frame, true /* checkIfMainThread */), + LocalFrame::HasTransientUserActivation(frame, + true /* check_if_main_thread */), std::make_unique<PushSubscriptionCallbacks>(resolver, registration_)); } else { PushProvider()->Subscribe( registration_->WebRegistration(), web_options, - Frame::HasTransientUserActivation(nullptr, - true /* checkIfMainThread */), + LocalFrame::HasTransientUserActivation(nullptr, + true /* check_if_main_thread */), std::make_unique<PushSubscriptionCallbacks>(resolver, registration_)); } @@ -107,8 +108,8 @@ ScriptPromise PushManager::permissionState( ScriptState* script_state, const PushSubscriptionOptionsInit& options, ExceptionState& exception_state) { - if (ExecutionContext::From(script_state)->IsDocument()) { - Document* document = ToDocument(ExecutionContext::From(script_state)); + if (auto* document = + DynamicTo<Document>(ExecutionContext::From(script_state))) { if (!document->domWindow() || !document->GetFrame()) return ScriptPromise::RejectWithDOMException( script_state, diff --git a/chromium/third_party/blink/renderer/modules/push_messaging/push_message_data.cc b/chromium/third_party/blink/renderer/modules/push_messaging/push_message_data.cc index e5f0b9a6c57..6282e7acfe5 100644 --- a/chromium/third_party/blink/renderer/modules/push_messaging/push_message_data.cc +++ b/chromium/third_party/blink/renderer/modules/push_messaging/push_message_data.cc @@ -43,7 +43,7 @@ PushMessageData* PushMessageData::Create( if (message_data.IsUSVString()) { CString encoded_string = UTF8Encoding().Encode( - message_data.GetAsUSVString(), WTF::kEntitiesForUnencodables); + message_data.GetAsUSVString(), WTF::kNoUnencodables); return new PushMessageData(encoded_string.data(), encoded_string.length()); } diff --git a/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_callbacks.h b/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_callbacks.h index 3f1465aeefc..655af998dfd 100644 --- a/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_callbacks.h +++ b/chromium/third_party/blink/renderer/modules/push_messaging/push_subscription_callbacks.h @@ -6,7 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_PUSH_MESSAGING_PUSH_SUBSCRIPTION_CALLBACKS_H_ #include "third_party/blink/public/platform/modules/push_messaging/web_push_provider.h" -#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/noncopyable.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/modules/quota/deprecated_storage_quota.cc b/chromium/third_party/blink/renderer/modules/quota/deprecated_storage_quota.cc index 2b9c1cb4e92..f0f64389878 100644 --- a/chromium/third_party/blink/renderer/modules/quota/deprecated_storage_quota.cc +++ b/chromium/third_party/blink/renderer/modules/quota/deprecated_storage_quota.cc @@ -164,10 +164,7 @@ void DeprecatedStorageQuota::requestQuota( unsigned long long new_quota_in_bytes, V8StorageQuotaCallback* success_callback, V8StorageErrorCallback* error_callback) { - ExecutionContext* execution_context = ExecutionContext::From(script_state); - DCHECK(execution_context); - DCHECK(execution_context->IsDocument()) - << "Quota requests are not supported in workers"; + ExecutionContext& execution_context = *ExecutionContext::From(script_state); StorageType storage_type = GetStorageType(type_); if (storage_type != StorageType::kTemporary && @@ -183,15 +180,15 @@ void DeprecatedStorageQuota::requestQuota( WrapPersistent(ToV8PersistentCallbackFunction(success_callback)), WrapPersistent(ToV8PersistentCallbackFunction(error_callback))); - Document* document = ToDocument(execution_context); - const SecurityOrigin* security_origin = document->GetSecurityOrigin(); + Document& document = To<Document>(execution_context); + const SecurityOrigin* security_origin = document.GetSecurityOrigin(); if (security_origin->IsOpaque()) { // Unique origins cannot store persistent state. std::move(callback).Run(blink::mojom::QuotaStatusCode::kErrorAbort, 0, 0); return; } - GetQuotaHost(execution_context) + GetQuotaHost(&execution_context) .RequestStorageQuota( WrapRefCounted(security_origin), storage_type, new_quota_in_bytes, mojo::WrapCallbackWithDefaultInvokeIfNotRun( diff --git a/chromium/third_party/blink/renderer/modules/quota/storage_manager.cc b/chromium/third_party/blink/renderer/modules/quota/storage_manager.cc index 297e370f686..609ec79ad5c 100644 --- a/chromium/third_party/blink/renderer/modules/quota/storage_manager.cc +++ b/chromium/third_party/blink/renderer/modules/quota/storage_manager.cc @@ -64,12 +64,11 @@ ScriptPromise StorageManager::persist(ScriptState* script_state) { return promise; } - DCHECK(execution_context->IsDocument()); - Document* doc = ToDocumentOrNull(execution_context); + Document* doc = To<Document>(execution_context); GetPermissionService(ExecutionContext::From(script_state)) .RequestPermission( CreatePermissionDescriptor(PermissionName::DURABLE_STORAGE), - Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr), + LocalFrame::HasTransientUserActivation(doc->GetFrame()), WTF::Bind(&StorageManager::PermissionRequestComplete, WrapPersistent(this), WrapPersistent(resolver))); diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/availability_callback_wrapper.h b/chromium/third_party/blink/renderer/modules/remoteplayback/availability_callback_wrapper.h index 12b81f08264..14cfc15eaac 100644 --- a/chromium/third_party/blink/renderer/modules/remoteplayback/availability_callback_wrapper.h +++ b/chromium/third_party/blink/renderer/modules/remoteplayback/availability_callback_wrapper.h @@ -10,7 +10,7 @@ #include "base/callback.h" #include "third_party/blink/renderer/platform/bindings/name_client.h" #include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h" -#include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/wtf/compiler.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc index 4f50a227565..d20885bc586 100644 --- a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc +++ b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc @@ -184,7 +184,7 @@ ScriptPromise RemotePlayback::prompt(ScriptState* script_state) { return promise; } - if (!Frame::HasTransientUserActivation(media_element_->GetFrame())) { + if (!LocalFrame::HasTransientUserActivation(media_element_->GetFrame())) { resolver->Reject(DOMException::Create( DOMExceptionCode::kInvalidAccessError, "RemotePlayback::prompt() requires user gesture.")); @@ -227,8 +227,7 @@ bool RemotePlayback::HasPendingActivity() const { } void RemotePlayback::ContextDestroyed(ExecutionContext*) { - target_presentation_connection_.reset(); - presentation_connection_binding_.Close(); + CleanupConnections(); } void RemotePlayback::PromptInternal() { @@ -369,7 +368,9 @@ void RemotePlayback::StateChanged(WebRemotePlaybackState state) { ->MediaRemotingStopped( WebLocalizedString::kMediaRemotingStopNoText); } + CleanupConnections(); presentation_id_ = ""; + presentation_url_ = KURL(); media_element_->FlingingStopped(); } break; @@ -465,6 +466,11 @@ void RemotePlayback::RemotePlaybackDisabled() { } } +void RemotePlayback::CleanupConnections() { + target_presentation_connection_.reset(); + presentation_connection_binding_.Close(); +} + void RemotePlayback::AvailabilityChanged( mojom::blink::ScreenAvailability availability) { DCHECK(RuntimeEnabledFeatures::NewRemotePlaybackPipelineEnabled()); @@ -511,7 +517,6 @@ void RemotePlayback::OnConnectionSuccess( StateChanged(WebRemotePlaybackState::kConnecting); - // TODO(imcheng): Reset binding when remote playback stops. DCHECK(!presentation_connection_binding_.is_bound()); auto* presentation_controller = PresentationController::FromContext(GetExecutionContext()); @@ -548,10 +553,8 @@ void RemotePlayback::HandlePresentationResponse( } void RemotePlayback::OnMessage( - mojom::blink::PresentationConnectionMessagePtr message, - OnMessageCallback callback) { + mojom::blink::PresentationConnectionMessagePtr message) { // Messages are ignored. - std::move(callback).Run(true); } void RemotePlayback::DidChangeState( @@ -566,7 +569,8 @@ void RemotePlayback::DidChangeState( StateChanged(remote_playback_state); } -void RemotePlayback::RequestClose() { +void RemotePlayback::DidClose( + mojom::blink::PresentationConnectionCloseReason reason) { StateChanged(WebRemotePlaybackState::kDisconnected); } diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.h b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.h index fdf5b795580..9e5a48d9ada 100644 --- a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.h +++ b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback.h @@ -106,10 +106,9 @@ class MODULES_EXPORT RemotePlayback final void OnConnectionError(const mojom::blink::PresentationError&); // mojom::blink::PresentationConnection implementation. - void OnMessage(mojom::blink::PresentationConnectionMessagePtr, - OnMessageCallback) override; + void OnMessage(mojom::blink::PresentationConnectionMessagePtr) override; void DidChangeState(mojom::blink::PresentationConnectionState) override; - void RequestClose() override; + void DidClose(mojom::blink::PresentationConnectionCloseReason) override; // WebRemotePlaybackClient implementation. void StateChanged(WebRemotePlaybackState) override; @@ -151,6 +150,9 @@ class MODULES_EXPORT RemotePlayback final // May be called more than once in a row. void StopListeningForAvailability(); + // Clears bindings after remote playback stops. + void CleanupConnections(); + WebRemotePlaybackState state_; WebRemotePlaybackAvailability availability_; HeapHashMap<int, TraceWrapperMember<AvailabilityCallbackWrapper>> diff --git a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_test.cc b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_test.cc index fa7b972603c..f283e8f2561 100644 --- a/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_test.cc +++ b/chromium/third_party/blink/renderer/modules/remoteplayback/remote_playback_test.cc @@ -97,8 +97,9 @@ TEST_F(RemotePlaybackTest, PromptCancelledRejectsWithNotAllowedError) { EXPECT_CALL(*resolve, Call(testing::_)).Times(0); EXPECT_CALL(*reject, Call(testing::_)).Times(1); - std::unique_ptr<UserGestureIndicator> indicator = Frame::NotifyUserActivation( - &page_holder->GetFrame(), UserGestureToken::kNewGesture); + std::unique_ptr<UserGestureIndicator> indicator = + LocalFrame::NotifyUserActivation(&page_holder->GetFrame(), + UserGestureToken::kNewGesture); remote_playback->prompt(scope.GetScriptState()) .Then(resolve->Bind(), reject->Bind()); CancelPrompt(remote_playback); @@ -130,8 +131,9 @@ TEST_F(RemotePlaybackTest, PromptConnectedRejectsWhenCancelled) { SetState(remote_playback, WebRemotePlaybackState::kConnected); - std::unique_ptr<UserGestureIndicator> indicator = Frame::NotifyUserActivation( - &page_holder->GetFrame(), UserGestureToken::kNewGesture); + std::unique_ptr<UserGestureIndicator> indicator = + LocalFrame::NotifyUserActivation(&page_holder->GetFrame(), + UserGestureToken::kNewGesture); remote_playback->prompt(scope.GetScriptState()) .Then(resolve->Bind(), reject->Bind()); CancelPrompt(remote_playback); @@ -163,8 +165,9 @@ TEST_F(RemotePlaybackTest, PromptConnectedResolvesWhenDisconnected) { SetState(remote_playback, WebRemotePlaybackState::kConnected); - std::unique_ptr<UserGestureIndicator> indicator = Frame::NotifyUserActivation( - &page_holder->GetFrame(), UserGestureToken::kNewGesture); + std::unique_ptr<UserGestureIndicator> indicator = + LocalFrame::NotifyUserActivation(&page_holder->GetFrame(), + UserGestureToken::kNewGesture); remote_playback->prompt(scope.GetScriptState()) .Then(resolve->Bind(), reject->Bind()); @@ -239,8 +242,9 @@ TEST_F(RemotePlaybackTest, EXPECT_CALL(*resolve, Call(testing::_)).Times(0); EXPECT_CALL(*reject, Call(testing::_)).Times(1); - std::unique_ptr<UserGestureIndicator> indicator = Frame::NotifyUserActivation( - &page_holder->GetFrame(), UserGestureToken::kNewGesture); + std::unique_ptr<UserGestureIndicator> indicator = + LocalFrame::NotifyUserActivation(&page_holder->GetFrame(), + UserGestureToken::kNewGesture); remote_playback->prompt(scope.GetScriptState()) .Then(resolve->Bind(), reject->Bind()); HTMLMediaElementRemotePlayback::SetBooleanAttribute( @@ -314,8 +318,9 @@ TEST_F(RemotePlaybackTest, PromptThrowsWhenBackendDisabled) { EXPECT_CALL(*resolve, Call(testing::_)).Times(0); EXPECT_CALL(*reject, Call(testing::_)).Times(1); - std::unique_ptr<UserGestureIndicator> indicator = Frame::NotifyUserActivation( - &page_holder->GetFrame(), UserGestureToken::kNewGesture); + std::unique_ptr<UserGestureIndicator> indicator = + LocalFrame::NotifyUserActivation(&page_holder->GetFrame(), + UserGestureToken::kNewGesture); remote_playback->prompt(scope.GetScriptState()) .Then(resolve->Bind(), reject->Bind()); diff --git a/chromium/third_party/blink/renderer/modules/screen_orientation/lock_orientation_callback.h b/chromium/third_party/blink/renderer/modules/screen_orientation/lock_orientation_callback.h index 88b83dc8260..b700ad9b18c 100644 --- a/chromium/third_party/blink/renderer/modules/screen_orientation/lock_orientation_callback.h +++ b/chromium/third_party/blink/renderer/modules/screen_orientation/lock_orientation_callback.h @@ -8,7 +8,7 @@ #include "base/memory/scoped_refptr.h" #include "third_party/blink/public/common/screen_orientation/web_screen_orientation_type.h" #include "third_party/blink/renderer/modules/screen_orientation/web_lock_orientation_callback.h" -#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/noncopyable.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.cc b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.cc index 9d514753652..67512ed90df 100644 --- a/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.cc +++ b/chromium/third_party/blink/renderer/modules/screen_orientation/screen_orientation_dispatcher.cc @@ -11,10 +11,10 @@ namespace blink { ScreenOrientationDispatcher& ScreenOrientationDispatcher::Instance() { - DEFINE_STATIC_LOCAL(ScreenOrientationDispatcher, + DEFINE_STATIC_LOCAL(Persistent<ScreenOrientationDispatcher>, screen_orientation_dispatcher, (new ScreenOrientationDispatcher)); - return screen_orientation_dispatcher; + return *screen_orientation_dispatcher; } ScreenOrientationDispatcher::ScreenOrientationDispatcher() = default; diff --git a/chromium/third_party/blink/renderer/modules/sensor/OWNERS b/chromium/third_party/blink/renderer/modules/sensor/OWNERS index 655a26ab830..5419ed8e331 100644 --- a/chromium/third_party/blink/renderer/modules/sensor/OWNERS +++ b/chromium/third_party/blink/renderer/modules/sensor/OWNERS @@ -1,4 +1,3 @@ -alexander.shalamov@intel.com reillyg@chromium.org rijubrata.bhaumik@intel.com timvolodine@chromium.org diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor.cc b/chromium/third_party/blink/renderer/modules/sensor/sensor.cc index 484baee05b1..36fc02340d9 100644 --- a/chromium/third_party/blink/renderer/modules/sensor/sensor.cc +++ b/chromium/third_party/blink/renderer/modules/sensor/sensor.cc @@ -6,6 +6,7 @@ #include "services/device/public/cpp/generic_sensor/sensor_traits.h" #include "services/device/public/mojom/sensor.mojom-blink.h" +#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" @@ -14,7 +15,6 @@ #include "third_party/blink/renderer/core/timing/window_performance.h" #include "third_party/blink/renderer/modules/sensor/sensor_error_event.h" #include "third_party/blink/renderer/modules/sensor/sensor_provider_proxy.h" -#include "third_party/blink/renderer/platform/feature_policy/feature_policy.h" #include "third_party/blink/renderer/platform/layout_test_support.h" namespace blink { @@ -22,11 +22,11 @@ namespace blink { namespace { const double kWaitingIntervalThreshold = 0.01; -bool AreFeaturesEnabled(LocalFrame* frame, +bool AreFeaturesEnabled(Document* document, const Vector<mojom::FeaturePolicyFeature>& features) { return std::all_of(features.begin(), features.end(), - [frame](mojom::FeaturePolicyFeature feature) { - return frame->IsFeatureEnabled(feature); + [document](mojom::FeaturePolicyFeature feature) { + return document->IsFeatureEnabled(feature); }); } @@ -45,9 +45,9 @@ Sensor::Sensor(ExecutionContext* execution_context, // [SecureContext] in idl. DCHECK(execution_context->IsSecureContext()); DCHECK(!features.IsEmpty()); - LocalFrame* frame = ToDocument(execution_context)->GetFrame(); + Document* document = To<Document>(execution_context); - if (!frame || !AreFeaturesEnabled(frame, features)) { + if (!AreFeaturesEnabled(document, features)) { exception_state.ThrowSecurityError( "Access to sensor features is disallowed by feature policy"); return; @@ -173,11 +173,11 @@ void Sensor::InitSensorProxyIfNeeded() { if (sensor_proxy_) return; - Document* document = ToDocument(GetExecutionContext()); + Document* document = To<Document>(GetExecutionContext()); if (!document || !document->GetFrame()) return; - auto* provider = SensorProviderProxy::From(document->GetFrame()); + auto* provider = SensorProviderProxy::From(document); sensor_proxy_ = provider->GetSensorProxy(type_); if (!sensor_proxy_) diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_inspector_agent.cc b/chromium/third_party/blink/renderer/modules/sensor/sensor_inspector_agent.cc index d1acd73b023..296d24383da 100644 --- a/chromium/third_party/blink/renderer/modules/sensor/sensor_inspector_agent.cc +++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_inspector_agent.cc @@ -13,8 +13,8 @@ namespace blink { -SensorInspectorAgent::SensorInspectorAgent(LocalFrame* frame) - : provider_(SensorProviderProxy::From(frame)) {} +SensorInspectorAgent::SensorInspectorAgent(Document* document) + : provider_(SensorProviderProxy::From(document)) {} void SensorInspectorAgent::Trace(blink::Visitor* visitor) { visitor->Trace(provider_); @@ -59,11 +59,24 @@ const char kInspectorConsoleMessage[] = } // namespace +void SensorInspectorAgent::DidCommitLoadForLocalFrame(LocalFrame* frame) { + Document* current_document = provider_->GetSupplementable(); + Document* new_document = frame->GetDocument(); + if (current_document != new_document) { + // We need to manually reset |provider_| to drop the strong reference it + // has to an old document that would otherwise be prevented from being + // deleted. + bool inspector_mode = provider_->inspector_mode(); + provider_ = SensorProviderProxy::From(new_document); + provider_->set_inspector_mode(inspector_mode); + } +} + void SensorInspectorAgent::SetOrientationSensorOverride(double alpha, double beta, double gamma) { if (!provider_->inspector_mode()) { - Document* document = provider_->GetSupplementable()->GetDocument(); + Document* document = provider_->GetSupplementable(); if (document) { ConsoleMessage* console_message = ConsoleMessage::Create( kJSMessageSource, kInfoMessageLevel, kInspectorConsoleMessage); diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_inspector_agent.h b/chromium/third_party/blink/renderer/modules/sensor/sensor_inspector_agent.h index 42e3beada0f..932017e201c 100644 --- a/chromium/third_party/blink/renderer/modules/sensor/sensor_inspector_agent.h +++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_inspector_agent.h @@ -9,14 +9,17 @@ namespace blink { +class Document; class LocalFrame; class SensorProviderProxy; class SensorInspectorAgent : public GarbageCollected<SensorInspectorAgent> { public: - explicit SensorInspectorAgent(LocalFrame* frame); + explicit SensorInspectorAgent(Document* document); virtual void Trace(blink::Visitor*); + void DidCommitLoadForLocalFrame(LocalFrame* frame); + void SetOrientationSensorOverride(double alpha, double beta, double gamma); void Disable(); diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.cc b/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.cc index 33df93deadf..d0cb3372ca1 100644 --- a/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.cc +++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.cc @@ -13,14 +13,14 @@ namespace blink { // SensorProviderProxy -SensorProviderProxy::SensorProviderProxy(LocalFrame& frame) - : Supplement<LocalFrame>(frame), inspector_mode_(false) {} +SensorProviderProxy::SensorProviderProxy(Document& document) + : Supplement<Document>(document), inspector_mode_(false) {} void SensorProviderProxy::InitializeIfNeeded() { if (IsInitialized()) return; - GetSupplementable()->GetInterfaceProvider().GetInterface( + GetSupplementable()->GetInterfaceProvider()->GetInterface( mojo::MakeRequest(&sensor_provider_)); sensor_provider_.set_connection_error_handler( WTF::Bind(&SensorProviderProxy::OnSensorProviderConnectionError, @@ -31,13 +31,13 @@ void SensorProviderProxy::InitializeIfNeeded() { const char SensorProviderProxy::kSupplementName[] = "SensorProvider"; // static -SensorProviderProxy* SensorProviderProxy::From(LocalFrame* frame) { - DCHECK(frame); +SensorProviderProxy* SensorProviderProxy::From(Document* document) { + DCHECK(document); SensorProviderProxy* provider_proxy = - Supplement<LocalFrame>::From<SensorProviderProxy>(*frame); + Supplement<Document>::From<SensorProviderProxy>(*document); if (!provider_proxy) { - provider_proxy = new SensorProviderProxy(*frame); - Supplement<LocalFrame>::ProvideTo(*frame, provider_proxy); + provider_proxy = new SensorProviderProxy(*document); + Supplement<Document>::ProvideTo(*document, provider_proxy); } provider_proxy->InitializeIfNeeded(); return provider_proxy; @@ -47,7 +47,7 @@ SensorProviderProxy::~SensorProviderProxy() = default; void SensorProviderProxy::Trace(blink::Visitor* visitor) { visitor->Trace(sensor_proxies_); - Supplement<LocalFrame>::Trace(visitor); + Supplement<Document>::Trace(visitor); } SensorProxy* SensorProviderProxy::CreateSensorProxy( diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.h b/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.h index bad04f7d31f..324ca953dbd 100644 --- a/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.h +++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_provider_proxy.h @@ -7,7 +7,7 @@ #include "services/device/public/mojom/sensor.mojom-blink.h" #include "services/device/public/mojom/sensor_provider.mojom-blink.h" -#include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/supplementable.h" @@ -19,14 +19,14 @@ class SensorProxy; // 'SensorProxy' instances. class SensorProviderProxy final : public GarbageCollectedFinalized<SensorProviderProxy>, - public Supplement<LocalFrame> { + public Supplement<Document> { USING_GARBAGE_COLLECTED_MIXIN(SensorProviderProxy); WTF_MAKE_NONCOPYABLE(SensorProviderProxy); public: static const char kSupplementName[]; - static SensorProviderProxy* From(LocalFrame*); + static SensorProviderProxy* From(Document*); ~SensorProviderProxy(); @@ -50,7 +50,7 @@ class SensorProviderProxy final const SensorsSet& sensor_proxies() const { return sensor_proxies_; } // For SensorProviderProxy personal use. - explicit SensorProviderProxy(LocalFrame&); + explicit SensorProviderProxy(Document&); void InitializeIfNeeded(); bool IsInitialized() const { return sensor_provider_.is_bound(); } void OnSensorProviderConnectionError(); diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.cc b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.cc index 584ecf60106..ec5b6d73e63 100644 --- a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.cc +++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy.cc @@ -14,6 +14,7 @@ #include "third_party/blink/renderer/modules/sensor/sensor_provider_proxy.h" #include "third_party/blink/renderer/modules/sensor/sensor_reading_remapper.h" #include "third_party/blink/renderer/platform/layout_test_support.h" +#include "third_party/blink/renderer/platform/weborigin/security_origin.h" namespace blink { @@ -114,10 +115,11 @@ bool SensorProxy::ShouldSuspendUpdates() const { return true; LocalFrame* focused_frame = GetPage()->GetFocusController().FocusedFrame(); - if (!focused_frame) + LocalFrame* this_frame = provider_->GetSupplementable()->GetFrame(); + + if (!focused_frame || !this_frame) return true; - LocalFrame* this_frame = provider_->GetSupplementable(); if (focused_frame == this_frame) return false; diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h index ac0329b8ba4..c4a435e9eef 100644 --- a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h +++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h @@ -9,6 +9,7 @@ #include "mojo/public/cpp/bindings/binding.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/timer.h" #include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_inspector_impl.cc b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_inspector_impl.cc index 67bb5840d19..f4bf5646020 100644 --- a/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_inspector_impl.cc +++ b/chromium/third_party/blink/renderer/modules/sensor/sensor_proxy_inspector_impl.cc @@ -7,9 +7,9 @@ #include "services/device/public/cpp/generic_sensor/sensor_traits.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/task_type.h" -#include "third_party/blink/public/platform/web_thread.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/modules/sensor/sensor_reading_remapper.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/modules/serial/BUILD.gn b/chromium/third_party/blink/renderer/modules/serial/BUILD.gn new file mode 100644 index 00000000000..f135be87463 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/BUILD.gn @@ -0,0 +1,18 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/blink/renderer/modules/modules.gni") + +blink_modules_sources("serial") { + sources = [ + "navigator_serial.cc", + "navigator_serial.h", + "serial.cc", + "serial.h", + "serial_port.cc", + "serial_port.h", + "worker_navigator_serial.cc", + "worker_navigator_serial.h", + ] +} diff --git a/chromium/third_party/blink/renderer/modules/serial/navigator_serial.cc b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.cc new file mode 100644 index 00000000000..e9f8bd406b4 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.cc @@ -0,0 +1,42 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/serial/navigator_serial.h" + +#include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/modules/serial/serial.h" + +namespace blink { + +const char NavigatorSerial::kSupplementName[] = "NavigatorSerial"; + +NavigatorSerial& NavigatorSerial::From(Navigator& navigator) { + NavigatorSerial* supplement = + Supplement<Navigator>::From<NavigatorSerial>(navigator); + if (!supplement) { + supplement = new NavigatorSerial(navigator); + ProvideTo(navigator, supplement); + } + return *supplement; +} + +Serial* NavigatorSerial::serial(Navigator& navigator) { + return NavigatorSerial::From(navigator).serial(); +} + +void NavigatorSerial::Trace(blink::Visitor* visitor) { + visitor->Trace(serial_); + Supplement<Navigator>::Trace(visitor); +} + +NavigatorSerial::NavigatorSerial(Navigator& navigator) + : Supplement<Navigator>(navigator) { + if (navigator.GetFrame()) { + DCHECK(navigator.GetFrame()->GetDocument()); + serial_ = Serial::Create(*navigator.GetFrame()->GetDocument()); + } +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/serial/navigator_serial.h b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.h new file mode 100644 index 00000000000..7267c3597ec --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.h @@ -0,0 +1,38 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_NAVIGATOR_SERIAL_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_NAVIGATOR_SERIAL_H_ + +#include "third_party/blink/renderer/core/frame/navigator.h" +#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/supplementable.h" + +namespace blink { + +class Serial; + +class NavigatorSerial final : public GarbageCollected<NavigatorSerial>, + public Supplement<Navigator> { + USING_GARBAGE_COLLECTED_MIXIN(NavigatorSerial); + + public: + static const char kSupplementName[]; + + static NavigatorSerial& From(Navigator&); + + static Serial* serial(Navigator&); + Serial* serial() { return serial_; } + + void Trace(Visitor*) override; + + private: + explicit NavigatorSerial(Navigator&); + + Member<Serial> serial_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_NAVIGATOR_SERIAL_H_ diff --git a/chromium/third_party/blink/renderer/modules/serial/navigator_serial.idl b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.idl new file mode 100644 index 00000000000..380dbca369c --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/navigator_serial.idl @@ -0,0 +1,13 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://wicg.github.io/serial + +[ + ImplementedAs=NavigatorSerial, + RuntimeEnabled=Serial, + SecureContext +] partial interface Navigator { + [SameObject] readonly attribute Serial serial; +}; diff --git a/chromium/third_party/blink/renderer/modules/serial/serial.cc b/chromium/third_party/blink/renderer/modules/serial/serial.cc new file mode 100644 index 00000000000..8c3a6407147 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/serial.cc @@ -0,0 +1,43 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/serial/serial.h" +#include "third_party/blink/renderer/core/dom/dom_exception.h" +#include "third_party/blink/renderer/modules/event_target_modules_names.h" + +namespace blink { + +// static +Serial* Serial::Create(ExecutionContext& execution_context) { + return new Serial(execution_context); +} + +ExecutionContext* Serial::GetExecutionContext() const { + return ContextLifecycleObserver::GetExecutionContext(); +} + +const AtomicString& Serial::InterfaceName() const { + return EventTargetNames::Serial; +} + +ScriptPromise Serial::getPorts(ScriptState* script_state) { + return ScriptPromise::RejectWithDOMException( + script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError)); +} + +ScriptPromise Serial::requestPort(ScriptState* script_state, + const SerialPortRequestOptions& options) { + return ScriptPromise::RejectWithDOMException( + script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError)); +} + +void Serial::Trace(Visitor* visitor) { + EventTargetWithInlineData::Trace(visitor); + ContextLifecycleObserver::Trace(visitor); +} + +Serial::Serial(ExecutionContext& execution_context) + : ContextLifecycleObserver(&execution_context) {} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/serial/serial.h b/chromium/third_party/blink/renderer/modules/serial/serial.h new file mode 100644 index 00000000000..ead1ec0cbe5 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/serial.h @@ -0,0 +1,46 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_H_ + +#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" +#include "third_party/blink/renderer/core/dom/events/event_target.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/heap/handle.h" + +namespace blink { + +class ExecutionContext; +class ScriptState; +class SerialPortRequestOptions; + +class Serial final : public EventTargetWithInlineData, + public ContextLifecycleObserver { + DEFINE_WRAPPERTYPEINFO(); + USING_GARBAGE_COLLECTED_MIXIN(Serial); + + public: + static Serial* Create(ExecutionContext& executionContext); + + // EventTarget + ExecutionContext* GetExecutionContext() const override; + const AtomicString& InterfaceName() const override; + + DEFINE_ATTRIBUTE_EVENT_LISTENER(connect); + DEFINE_ATTRIBUTE_EVENT_LISTENER(disconnect); + ScriptPromise getPorts(ScriptState*); + ScriptPromise requestPort(ScriptState*, const SerialPortRequestOptions&); + + void Trace(Visitor*) override; + + private: + explicit Serial(ExecutionContext&); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_H_ diff --git a/chromium/third_party/blink/renderer/modules/serial/serial.idl b/chromium/third_party/blink/renderer/modules/serial/serial.idl new file mode 100644 index 00000000000..b883b8e0939 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/serial.idl @@ -0,0 +1,19 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://wicg.github.io/serial + +[ + Exposed(Window Serial,DedicatedWorker Serial), + SecureContext +] interface Serial : EventTarget { + attribute EventHandler onconnect; + attribute EventHandler ondisconnect; + + [CallWith=ScriptState, MeasureAs=SerialGetPorts] + Promise<sequence<SerialPort>> getPorts(); + + [CallWith=ScriptState, MeasureAs=SerialRequestPort, Exposed=Window] + Promise<SerialPort> requestPort(SerialPortRequestOptions options); +}; diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_options.idl b/chromium/third_party/blink/renderer/modules/serial/serial_options.idl new file mode 100644 index 00000000000..ccb1446965c --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/serial_options.idl @@ -0,0 +1,20 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://wicg.github.io/serial + +enum ParityType { + "none", + "even", + "odd", +}; + +dictionary SerialOptions { + long baudrate = 9600; + octet databits = 8; + octet stopbits = 1; + ParityType parity = "none"; + long buffersize = 255; + boolean rtscts = false; +}; diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_port.cc b/chromium/third_party/blink/renderer/modules/serial/serial_port.cc new file mode 100644 index 00000000000..10739a4db1e --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/serial_port.cc @@ -0,0 +1,29 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/serial/serial_port.h" +#include "third_party/blink/renderer/core/dom/dom_exception.h" + +namespace blink { + +ScriptValue SerialPort::in(ScriptState* script_state) { + return ScriptValue::CreateNull(script_state); +} + +ScriptValue SerialPort::out(ScriptState* script_state) { + return ScriptValue::CreateNull(script_state); +} + +ScriptPromise SerialPort::open(ScriptState* script_state, + const SerialOptions& options) { + return ScriptPromise::RejectWithDOMException( + script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError)); +} + +ScriptPromise SerialPort::close(ScriptState* script_state) { + return ScriptPromise::RejectWithDOMException( + script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError)); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_port.h b/chromium/third_party/blink/renderer/modules/serial/serial_port.h new file mode 100644 index 00000000000..baadd7b0601 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/serial_port.h @@ -0,0 +1,30 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_PORT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_PORT_H_ + +#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/heap/handle.h" + +namespace blink { + +class ScriptState; +class SerialOptions; + +class SerialPort final : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + ScriptValue in(ScriptState*); + ScriptValue out(ScriptState*); + + ScriptPromise open(ScriptState*, const SerialOptions& options); + ScriptPromise close(ScriptState*); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_PORT_H_ diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_port.idl b/chromium/third_party/blink/renderer/modules/serial/serial_port.idl new file mode 100644 index 00000000000..794b9875eca --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/serial_port.idl @@ -0,0 +1,22 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://wicg.github.io/serial + +[ + Exposed(Window Serial,DedicatedWorker Serial), + SecureContext +] interface SerialPort { + // TODO(https://crbug.com/888165): "any" is used here because the IDL + // processor does not recognize ReadableStream or WritableStream when + // implemented with V8 extras. + [CallWith=ScriptState] readonly attribute any in; + [CallWith=ScriptState] readonly attribute any out; + + [CallWith=ScriptState, MeasureAs=SerialPortOpen] + Promise<void> open(SerialOptions options); + + [CallWith=ScriptState, MeasureAs=SerialPortClose] + Promise<void> close(); +}; diff --git a/chromium/third_party/blink/renderer/modules/serial/serial_port_request_options.idl b/chromium/third_party/blink/renderer/modules/serial/serial_port_request_options.idl new file mode 100644 index 00000000000..8e9c05c5439 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/serial_port_request_options.idl @@ -0,0 +1,8 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://wicg.github.io/serial + +dictionary SerialPortRequestOptions { +}; diff --git a/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc new file mode 100644 index 00000000000..a5a6b08694c --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc @@ -0,0 +1,49 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/serial/worker_navigator_serial.h" + +#include "third_party/blink/renderer/modules/serial/serial.h" + +namespace blink { + +const char WorkerNavigatorSerial::kSupplementName[] = "WorkerNavigatorSerial"; + +WorkerNavigatorSerial& WorkerNavigatorSerial::From(WorkerNavigator& navigator) { + WorkerNavigatorSerial* supplement = + Supplement<WorkerNavigator>::From<WorkerNavigatorSerial>(navigator); + if (!supplement) { + supplement = new WorkerNavigatorSerial(navigator); + ProvideTo(navigator, supplement); + } + return *supplement; +} + +Serial* WorkerNavigatorSerial::serial(ScriptState* script_state, + WorkerNavigator& navigator) { + return WorkerNavigatorSerial::From(navigator).serial(script_state); +} + +Serial* WorkerNavigatorSerial::serial(ScriptState* script_state) { + if (!serial_) { + auto* execution_context = ExecutionContext::From(script_state); + DCHECK(execution_context); + + // TODO(https://crbug.com/839117): Remove this check once the Exposed + // attribute is fixed to only expose this property in dedicated workers. + if (execution_context->IsDedicatedWorkerGlobalScope()) + serial_ = Serial::Create(*execution_context); + } + return serial_; +} + +void WorkerNavigatorSerial::Trace(blink::Visitor* visitor) { + visitor->Trace(serial_); + Supplement<WorkerNavigator>::Trace(visitor); +} + +WorkerNavigatorSerial::WorkerNavigatorSerial(WorkerNavigator& navigator) + : Supplement<WorkerNavigator>(navigator) {} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.h b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.h new file mode 100644 index 00000000000..8ff078d3503 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.h @@ -0,0 +1,40 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_WORKER_NAVIGATOR_SERIAL_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_WORKER_NAVIGATOR_SERIAL_H_ + +#include "third_party/blink/renderer/core/workers/worker_navigator.h" +#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/supplementable.h" + +namespace blink { + +class ScriptState; +class Serial; + +class WorkerNavigatorSerial final + : public GarbageCollected<WorkerNavigatorSerial>, + public Supplement<WorkerNavigator> { + USING_GARBAGE_COLLECTED_MIXIN(WorkerNavigatorSerial); + + public: + static const char kSupplementName[]; + + static WorkerNavigatorSerial& From(WorkerNavigator&); + + static Serial* serial(ScriptState*, WorkerNavigator&); + Serial* serial(ScriptState*); + + void Trace(Visitor*) override; + + private: + explicit WorkerNavigatorSerial(WorkerNavigator&); + + Member<Serial> serial_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_WORKER_NAVIGATOR_SERIAL_H_ diff --git a/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl new file mode 100644 index 00000000000..c95d2b0885f --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl @@ -0,0 +1,14 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://wicg.github.io/serial + +[ + Exposed=DedicatedWorker, + ImplementedAs=WorkerNavigatorSerial, + RuntimeEnabled=Serial, + SecureContext +] partial interface WorkerNavigator { + [CallWith=ScriptState, SameObject] readonly attribute Serial serial; +}; diff --git a/chromium/third_party/blink/renderer/modules/service_worker/BUILD.gn b/chromium/third_party/blink/renderer/modules/service_worker/BUILD.gn index 15340c6fc0b..fbe04fd2759 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/service_worker/BUILD.gn @@ -54,8 +54,8 @@ blink_modules_sources("service_worker") { "service_worker_thread.h", "service_worker_window_client.cc", "service_worker_window_client.h", - "service_worker_window_client_callback.cc", - "service_worker_window_client_callback.h", + "thread_safe_script_container.cc", + "thread_safe_script_container.h", "wait_until_observer.cc", "wait_until_observer.h", ] @@ -63,4 +63,8 @@ blink_modules_sources("service_worker") { public_deps = [ "//third_party/blink/renderer/platform", ] + + deps = [ + "//base", + ] } diff --git a/chromium/third_party/blink/renderer/modules/service_worker/DEPS b/chromium/third_party/blink/renderer/modules/service_worker/DEPS index 2a04715c1b4..a6301afa47f 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/DEPS +++ b/chromium/third_party/blink/renderer/modules/service_worker/DEPS @@ -1,4 +1,7 @@ include_rules = [ + "+base/barrier_closure.h", + "+base/threading/thread_checker.h", + "+mojo/public/cpp/bindings/strong_binding.h", "+mojo/public/cpp/system/data_pipe.h", "+services/network/public/mojom", "-third_party/blink/renderer/modules", @@ -18,4 +21,11 @@ specific_include_rules = { "+third_party/blink/renderer/modules/payments", "+third_party/blink/renderer/modules/push_messaging", ], + "service_worker_installed_scripts_manager_test\.cc": [ + "+base/run_loop.h", + "+mojo/public/cpp/bindings/binding.h", + ], + "web_embedded_worker_impl_test\.cc": [ + "+third_party/blink/renderer/modules/exported", + ], } diff --git a/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc b/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc index a499d4c2239..b790caea27f 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc @@ -10,7 +10,7 @@ #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/core/dom/abort_signal.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" -#include "third_party/blink/renderer/core/fetch/bytes_consumer_for_data_consumer_handle.h" +#include "third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.h" #include "third_party/blink/renderer/core/fetch/request.h" #include "third_party/blink/renderer/core/fetch/response.h" #include "third_party/blink/renderer/core/frame/use_counter.h" @@ -107,21 +107,22 @@ FetchEvent::~FetchEvent() = default; void FetchEvent::OnNavigationPreloadResponse( ScriptState* script_state, std::unique_ptr<WebURLResponse> response, - std::unique_ptr<WebDataConsumerHandle> data_consume_handle) { + mojo::ScopedDataPipeConsumerHandle data_pipe) { if (!script_state->ContextIsValid()) return; DCHECK(preload_response_property_); DCHECK(!preload_response_); ScriptState::Scope scope(script_state); preload_response_ = std::move(response); + if (data_pipe.is_valid()) { + data_pipe_consumer_ = new DataPipeBytesConsumer( + ExecutionContext::From(script_state), std::move(data_pipe)); + } // TODO(ricea): Verify that this response can't be aborted from JS. FetchResponseData* response_data = - data_consume_handle + data_pipe_consumer_ ? FetchResponseData::CreateWithBuffer(new BodyStreamBuffer( - script_state, - new BytesConsumerForDataConsumerHandle( - ExecutionContext::From(script_state), - std::move(data_consume_handle)), + script_state, data_pipe_consumer_, new AbortSignal(ExecutionContext::From(script_state)))) : FetchResponseData::Create(); Vector<KURL> url_list(1); @@ -149,6 +150,10 @@ void FetchEvent::OnNavigationPreloadError( std::unique_ptr<WebServiceWorkerError> error) { if (!script_state->ContextIsValid()) return; + if (data_pipe_consumer_) { + data_pipe_consumer_->SignalError(); + data_pipe_consumer_ = nullptr; + } DCHECK(preload_response_property_); if (preload_response_property_->GetState() != PreloadResponseProperty::kPending) { @@ -165,6 +170,10 @@ void FetchEvent::OnNavigationPreloadComplete( int64_t encoded_body_length, int64_t decoded_body_length) { DCHECK(preload_response_); + if (data_pipe_consumer_) { + data_pipe_consumer_->SignalComplete(); + data_pipe_consumer_ = nullptr; + } std::unique_ptr<WebURLResponse> response = std::move(preload_response_); ResourceResponse resource_response = response->ToResourceResponse(); resource_response.SetEncodedDataLength(encoded_data_length); @@ -188,6 +197,7 @@ void FetchEvent::Trace(blink::Visitor* visitor) { visitor->Trace(observer_); visitor->Trace(request_); visitor->Trace(preload_response_property_); + visitor->Trace(data_pipe_consumer_); ExtendableEvent::Trace(visitor); ContextClient::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.h b/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.h index 1bf70d4484b..5482c436e63 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.h @@ -22,12 +22,12 @@ namespace blink { +class DataPipeBytesConsumer; class ExceptionState; class FetchRespondWithObserver; class Request; class Response; class ScriptState; -class WebDataConsumerHandle; struct WebServiceWorkerError; class WebURLResponse; class WorkerGlobalScope; @@ -67,7 +67,7 @@ class MODULES_EXPORT FetchEvent final void OnNavigationPreloadResponse(ScriptState*, std::unique_ptr<WebURLResponse>, - std::unique_ptr<WebDataConsumerHandle>); + mojo::ScopedDataPipeConsumerHandle); void OnNavigationPreloadError(ScriptState*, std::unique_ptr<WebServiceWorkerError>); void OnNavigationPreloadComplete(WorkerGlobalScope*, @@ -96,6 +96,7 @@ class MODULES_EXPORT FetchEvent final TraceWrapperMember<Request> request_; Member<PreloadResponseProperty> preload_response_property_; std::unique_ptr<WebURLResponse> preload_response_; + Member<DataPipeBytesConsumer> data_pipe_consumer_; String client_id_; bool is_reload_; }; diff --git a/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc b/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc index 2aabdee38fb..7860b3bc2a4 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc @@ -7,6 +7,8 @@ #include <memory> #include <utility> +#include "base/feature_list.h" +#include "base/metrics/histogram_macros.h" #include "services/network/public/mojom/fetch_api.mojom-blink.h" #include "services/network/public/mojom/request_context_frame_type.mojom-blink.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h" @@ -112,10 +114,10 @@ bool IsNavigationRequest(network::mojom::RequestContextFrameType frame_type) { } bool IsClientRequest(network::mojom::RequestContextFrameType frame_type, - WebURLRequest::RequestContext request_context) { + mojom::RequestContextType request_context) { return IsNavigationRequest(frame_type) || - request_context == WebURLRequest::kRequestContextSharedWorker || - request_context == WebURLRequest::kRequestContextWorker; + request_context == mojom::RequestContextType::SHARED_WORKER || + request_context == mojom::RequestContextType::WORKER; } // Notifies the result of FetchDataLoader to |handle_|. |handle_| pass through @@ -127,25 +129,67 @@ class FetchLoaderClient final USING_GARBAGE_COLLECTED_MIXIN(FetchLoaderClient); public: - explicit FetchLoaderClient( - std::unique_ptr<WebServiceWorkerStreamHandle> handle) - : handle_(std::move(handle)) {} + FetchLoaderClient() {} - void DidFetchDataLoadedDataPipe() override { handle_->Completed(); } - void DidFetchDataLoadFailed() override { handle_->Aborted(); } + void DidFetchDataStartedDataPipe( + mojo::ScopedDataPipeConsumerHandle pipe) override { + DCHECK(!handle_); + handle_ = std::make_unique<WebServiceWorkerStreamHandle>(std::move(pipe)); + } + void DidFetchDataLoadedDataPipe() override { + DCHECK(handle_); + // If this method is called synchronously from StartLoading() then we need + // to delay notifying the handle until after + // RespondToFetchEventWithResponseStream() is called. + if (!started_) { + pending_complete_ = true; + return; + } + pending_complete_ = false; + handle_->Completed(); + } + void DidFetchDataLoadFailed() override { + // If this method is called synchronously from StartLoading() then we need + // to delay notifying the handle until after + // RespondToFetchEventWithResponseStream() is called. + if (!started_) { + pending_failure_ = true; + return; + } + pending_failure_ = false; + if (handle_) + handle_->Aborted(); + } void Abort() override { // A fetch() aborted via AbortSignal in the ServiceWorker will just look // like an ordinary failure to the page. // TODO(ricea): Should a fetch() on the page get an AbortError instead? - handle_->Aborted(); + if (handle_) + handle_->Aborted(); + } + + void SetStarted() { + DCHECK(!started_); + // Note that RespondToFetchEventWithResponseStream() has been called and + // flush any pending operation. + started_ = true; + if (pending_complete_) + DidFetchDataLoadedDataPipe(); + else if (pending_failure_) + DidFetchDataLoadFailed(); } + WebServiceWorkerStreamHandle* Handle() const { return handle_.get(); } + void Trace(blink::Visitor* visitor) override { FetchDataLoader::Client::Trace(visitor); } private: std::unique_ptr<WebServiceWorkerStreamHandle> handle_; + bool started_ = false; + bool pending_complete_ = false; + bool pending_failure_ = false; }; } // namespace @@ -157,7 +201,7 @@ FetchRespondWithObserver* FetchRespondWithObserver::Create( network::mojom::FetchRequestMode request_mode, network::mojom::FetchRedirectMode redirect_mode, network::mojom::RequestContextFrameType frame_type, - WebURLRequest::RequestContext request_context, + mojom::RequestContextType request_context, WaitUntilObserver* observer) { return new FetchRespondWithObserver(context, fetch_event_id, request_url, request_mode, redirect_mode, frame_type, @@ -179,7 +223,8 @@ void FetchRespondWithObserver::OnResponseRejected( WebServiceWorkerResponse web_response; web_response.SetError(error); ServiceWorkerGlobalScopeClient::From(GetExecutionContext()) - ->RespondToFetchEvent(event_id_, web_response, event_dispatch_time_); + ->RespondToFetchEvent(event_id_, web_response, event_dispatch_time_, + base::TimeTicks::Now()); } void FetchRespondWithObserver::OnResponseFulfilled( @@ -283,44 +328,45 @@ void FetchRespondWithObserver::OnResponseFulfilled( // Handle the blob response body. web_response.SetBlobDataHandle(blob_data_handle); ServiceWorkerGlobalScopeClient::From(GetExecutionContext()) - ->RespondToFetchEvent(event_id_, web_response, event_dispatch_time_); + ->RespondToFetchEvent(event_id_, web_response, event_dispatch_time_, + base::TimeTicks::Now()); return; } - // Handle the stream response body. - mojo::ScopedDataPipeProducerHandle producer; - mojo::ScopedDataPipeConsumerHandle consumer; - MojoResult result = mojo::CreateDataPipe(nullptr, &producer, &consumer); - if (result != MOJO_RESULT_OK) { - OnResponseRejected(ServiceWorkerResponseError::kDataPipeCreationFailed); - return; - } - DCHECK(producer.is_valid()); - DCHECK(consumer.is_valid()); - std::unique_ptr<WebServiceWorkerStreamHandle> body_stream_handle = - std::make_unique<WebServiceWorkerStreamHandle>(std::move(consumer)); - ServiceWorkerGlobalScopeClient::From(GetExecutionContext()) - ->RespondToFetchEventWithResponseStream(event_id_, web_response, - body_stream_handle.get(), - event_dispatch_time_); - - buffer->StartLoading(FetchDataLoader::CreateLoaderAsDataPipe( - std::move(producer), task_runner_), - new FetchLoaderClient(std::move(body_stream_handle)), - exception_state); + // Load the Response as a mojo::DataPipe. The resulting pipe consumer + // handle will be passed to the FetchLoaderClient on start. + FetchLoaderClient* fetch_loader_client = new FetchLoaderClient(); + buffer->StartLoading(FetchDataLoader::CreateLoaderAsDataPipe(task_runner_), + fetch_loader_client, exception_state); if (exception_state.HadException()) { OnResponseRejected(ServiceWorkerResponseError::kResponseBodyBroken); return; } + + // If we failed to create the WebServiceWorkerStreamHandle then we must + // have failed to allocate the mojo::DataPipe. + if (!fetch_loader_client->Handle()) { + OnResponseRejected(ServiceWorkerResponseError::kDataPipeCreationFailed); + return; + } + + ServiceWorkerGlobalScopeClient::From(GetExecutionContext()) + ->RespondToFetchEventWithResponseStream( + event_id_, web_response, fetch_loader_client->Handle(), + event_dispatch_time_, base::TimeTicks::Now()); + + fetch_loader_client->SetStarted(); return; } ServiceWorkerGlobalScopeClient::From(GetExecutionContext()) - ->RespondToFetchEvent(event_id_, web_response, event_dispatch_time_); + ->RespondToFetchEvent(event_id_, web_response, event_dispatch_time_, + base::TimeTicks::Now()); } void FetchRespondWithObserver::OnNoResponse() { ServiceWorkerGlobalScopeClient::From(GetExecutionContext()) - ->RespondToFetchEventWithNoResponse(event_id_, event_dispatch_time_); + ->RespondToFetchEventWithNoResponse(event_id_, event_dispatch_time_, + base::TimeTicks::Now()); } FetchRespondWithObserver::FetchRespondWithObserver( @@ -330,7 +376,7 @@ FetchRespondWithObserver::FetchRespondWithObserver( network::mojom::FetchRequestMode request_mode, network::mojom::FetchRedirectMode redirect_mode, network::mojom::RequestContextFrameType frame_type, - WebURLRequest::RequestContext request_context, + mojom::RequestContextType request_context, WaitUntilObserver* observer) : RespondWithObserver(context, fetch_event_id, observer), request_url_(request_url), diff --git a/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h b/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h index 394d7e066ad..892927e5aa4 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h @@ -31,7 +31,7 @@ class MODULES_EXPORT FetchRespondWithObserver : public RespondWithObserver { network::mojom::FetchRequestMode, network::mojom::FetchRedirectMode, network::mojom::RequestContextFrameType, - WebURLRequest::RequestContext, + mojom::RequestContextType, WaitUntilObserver*); void OnResponseRejected(mojom::ServiceWorkerResponseError) override; @@ -50,7 +50,7 @@ class MODULES_EXPORT FetchRespondWithObserver : public RespondWithObserver { network::mojom::FetchRequestMode, network::mojom::FetchRedirectMode, network::mojom::RequestContextFrameType, - WebURLRequest::RequestContext, + mojom::RequestContextType, WaitUntilObserver*); private: @@ -58,7 +58,7 @@ class MODULES_EXPORT FetchRespondWithObserver : public RespondWithObserver { const network::mojom::FetchRequestMode request_mode_; const network::mojom::FetchRedirectMode redirect_mode_; const network::mojom::RequestContextFrameType frame_type_; - const WebURLRequest::RequestContext request_context_; + const mojom::RequestContextType request_context_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_; }; diff --git a/chromium/third_party/blink/renderer/modules/service_worker/registration_options.idl b/chromium/third_party/blink/renderer/modules/service_worker/registration_options.idl index 4442ea6b261..3730e774f16 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/registration_options.idl +++ b/chromium/third_party/blink/renderer/modules/service_worker/registration_options.idl @@ -5,5 +5,6 @@ // https://w3c.github.io/ServiceWorker/#dictdef-registrationoptions dictionary RegistrationOptions { USVString scope; + WorkerType type = "classic"; ServiceWorkerUpdateViaCache updateViaCache = "imports"; }; diff --git a/chromium/third_party/blink/renderer/modules/service_worker/respond_with_observer.cc b/chromium/third_party/blink/renderer/modules/service_worker/respond_with_observer.cc index 564b748a583..216334f6947 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/respond_with_observer.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/respond_with_observer.cc @@ -27,7 +27,7 @@ void RespondWithObserver::ContextDestroyed(ExecutionContext*) { } void RespondWithObserver::WillDispatchEvent() { - event_dispatch_time_ = WTF::CurrentTime(); + event_dispatch_time_ = WTF::CurrentTimeTicks(); } void RespondWithObserver::DidDispatchEvent( diff --git a/chromium/third_party/blink/renderer/modules/service_worker/respond_with_observer.h b/chromium/third_party/blink/renderer/modules/service_worker/respond_with_observer.h index ed0547e7ec3..8b03e7f0d53 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/respond_with_observer.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/respond_with_observer.h @@ -59,7 +59,7 @@ class MODULES_EXPORT RespondWithObserver protected: RespondWithObserver(ExecutionContext*, int event_id, WaitUntilObserver*); const int event_id_; - double event_dispatch_time_ = 0; + TimeTicks event_dispatch_time_; private: class ThenFunction; diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker.cc index 20ff71cf4f4..e16880a2b11 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker.cc @@ -33,7 +33,7 @@ #include <memory> #include "third_party/blink/public/mojom/service_worker/service_worker_state.mojom-blink.h" #include "third_party/blink/public/platform/web_string.h" -#include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h" #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" @@ -42,6 +42,7 @@ #include "third_party/blink/renderer/core/messaging/post_message_options.h" #include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_container_client.h" +#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" @@ -65,9 +66,7 @@ void ServiceWorker::postMessage(ScriptState* script_state, const ScriptValue& message, const PostMessageOptions& options, ExceptionState& exception_state) { - ServiceWorkerContainerClient* client = - ServiceWorkerContainerClient::From(GetExecutionContext()); - if (!client || !client->Provider()) { + if (!GetExecutionContext()) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, "Failed to post a message: No associated provider is available."); @@ -92,35 +91,35 @@ void ServiceWorker::postMessage(ScriptState* script_state, if (exception_state.HadException()) return; - if (handle_->ServiceWorker()->GetState() == - mojom::blink::ServiceWorkerState::kRedundant) { + if (state_ == mojom::blink::ServiceWorkerState::kRedundant) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, "ServiceWorker is in redundant state."); return; } - handle_->ServiceWorker()->PostMessageToServiceWorker( - ToTransferableMessage(std::move(msg))); + host_->PostMessageToServiceWorker(std::move(msg)); } ScriptPromise ServiceWorker::InternalsTerminate(ScriptState* script_state) { ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); - handle_->ServiceWorker()->TerminateForTesting( - std::make_unique<CallbackPromiseAdapter<void, void>>(resolver)); + host_->TerminateForTesting( + WTF::Bind([](ScriptPromiseResolver* resolver) { resolver->Resolve(); }, + WrapPersistent(resolver))); return promise; } -void ServiceWorker::DispatchStateChangeEvent() { +void ServiceWorker::StateChanged(mojom::blink::ServiceWorkerState new_state) { + state_ = new_state; this->DispatchEvent(*Event::Create(EventTypeNames::statechange)); } String ServiceWorker::scriptURL() const { - return handle_->ServiceWorker()->Url().GetString(); + return url_.GetString(); } String ServiceWorker::state() const { - switch (handle_->ServiceWorker()->GetState()) { + switch (state_) { case mojom::blink::ServiceWorkerState::kUnknown: // The web platform should never see this internal state NOTREACHED(); @@ -140,46 +139,45 @@ String ServiceWorker::state() const { return g_null_atom; } -ServiceWorker* ServiceWorker::From( - ExecutionContext* execution_context, - std::unique_ptr<WebServiceWorker::Handle> handle) { - return GetOrCreate(execution_context, std::move(handle)); +ServiceWorker* ServiceWorker::From(ExecutionContext* context, + WebServiceWorkerObjectInfo info) { + if (!context) + return nullptr; + if (info.version_id == mojom::blink::kInvalidServiceWorkerVersionId) + return nullptr; + + if (context->IsServiceWorkerGlobalScope()) { + return ToServiceWorkerGlobalScope(context)->GetOrCreateServiceWorker( + std::move(info)); + } + + return ServiceWorkerContainerClient::From(To<Document>(context)) + ->GetOrCreateServiceWorker(std::move(info)); } bool ServiceWorker::HasPendingActivity() const { if (was_stopped_) return false; - return handle_->ServiceWorker()->GetState() != - mojom::blink::ServiceWorkerState::kRedundant; + return state_ != mojom::blink::ServiceWorkerState::kRedundant; } void ServiceWorker::ContextDestroyed(ExecutionContext*) { was_stopped_ = true; } -ServiceWorker* ServiceWorker::GetOrCreate( - ExecutionContext* execution_context, - std::unique_ptr<WebServiceWorker::Handle> handle) { - if (!handle) - return nullptr; - - ServiceWorker* existing_worker = - static_cast<ServiceWorker*>(handle->ServiceWorker()->Proxy()); - if (existing_worker) { - DCHECK_EQ(existing_worker->GetExecutionContext(), execution_context); - return existing_worker; - } - - return new ServiceWorker(execution_context, std::move(handle)); -} - ServiceWorker::ServiceWorker(ExecutionContext* execution_context, - std::unique_ptr<WebServiceWorker::Handle> handle) + WebServiceWorkerObjectInfo info) : AbstractWorker(execution_context), - handle_(std::move(handle)), - was_stopped_(false) { - DCHECK(handle_); - handle_->ServiceWorker()->SetProxy(this); + was_stopped_(false), + url_(info.url), + state_(info.state), + binding_(this) { + DCHECK_NE(mojom::blink::kInvalidServiceWorkerVersionId, info.version_id); + host_.Bind(mojom::blink::ServiceWorkerObjectHostAssociatedPtrInfo( + std::move(info.host_ptr_info), + mojom::blink::ServiceWorkerObjectHost::Version_)); + binding_.Bind(mojom::blink::ServiceWorkerObjectAssociatedRequest( + std::move(info.request))); } ServiceWorker::~ServiceWorker() = default; diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker.h index be575e131f5..f6d3cb7b5ff 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker.h @@ -33,8 +33,9 @@ #include <memory> #include "base/memory/scoped_refptr.h" -#include "third_party/blink/public/platform/modules/service_worker/web_service_worker.h" -#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_proxy.h" +#include "mojo/public/cpp/bindings/associated_binding.h" +#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-blink.h" +#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_object_info.h" #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h" @@ -49,14 +50,14 @@ class ScriptState; class MODULES_EXPORT ServiceWorker final : public AbstractWorker, public ActiveScriptWrappable<ServiceWorker>, - public WebServiceWorkerProxy { + public mojom::blink::ServiceWorkerObject { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(ServiceWorker); public: - static ServiceWorker* From(ExecutionContext*, - std::unique_ptr<WebServiceWorker::Handle>); + static ServiceWorker* From(ExecutionContext*, WebServiceWorkerObjectInfo); + ServiceWorker(ExecutionContext*, WebServiceWorkerObjectInfo); ~ServiceWorker() override; void Trace(blink::Visitor*) override; @@ -81,25 +82,33 @@ class MODULES_EXPORT ServiceWorker final // ScriptWrappable overrides. bool HasPendingActivity() const final; - // WebServiceWorkerProxy overrides. - void DispatchStateChangeEvent() override; - // AbstractWorker overrides. const AtomicString& InterfaceName() const override; + // Implements mojom::blink::ServiceWorkerObject. + void StateChanged(mojom::blink::ServiceWorkerState new_state) override; + ScriptPromise InternalsTerminate(ScriptState*); private: - static ServiceWorker* GetOrCreate(ExecutionContext*, - std::unique_ptr<WebServiceWorker::Handle>); - ServiceWorker(ExecutionContext*, std::unique_ptr<WebServiceWorker::Handle>); - // PausableObject overrides. void ContextDestroyed(ExecutionContext*) override; - // A handle to the service worker representation in the embedder. - std::unique_ptr<WebServiceWorker::Handle> handle_; bool was_stopped_; + const KURL url_; + mojom::blink::ServiceWorkerState state_; + // Both |host_| and |binding_| are associated with + // content.mojom.ServiceWorkerContainer interface for a Document, and + // content.mojom.ServiceWorker interface for a ServiceWorkerGlobalScope. + // + // |host_| keeps the Mojo connection to the + // browser-side ServiceWorkerObjectHost, whose lifetime is bound + // to |host_| via the Mojo connection. + mojom::blink::ServiceWorkerObjectHostAssociatedPtr host_; + // |binding_| keeps the Mojo binding to serve its other Mojo endpoint (i.e. + // the caller end) held by the content::ServiceWorkerObjectHost in the browser + // process. + mojo::AssociatedBinding<mojom::blink::ServiceWorkerObject> binding_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_client.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_client.cc index 959f27b1a02..a6c32d2b03b 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_client.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_client.cc @@ -8,7 +8,6 @@ #include <memory> #include "base/memory/scoped_refptr.h" #include "services/network/public/mojom/request_context_frame_type.mojom-blink.h" -#include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom-blink.h" #include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h" #include "third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h" @@ -22,27 +21,13 @@ namespace blink { -ServiceWorkerClient* ServiceWorkerClient::Take( - ScriptPromiseResolver*, - std::unique_ptr<WebServiceWorkerClientInfo> web_client) { - if (!web_client) - return nullptr; - - switch (web_client->client_type) { - case mojom::ServiceWorkerClientType::kWindow: - return ServiceWorkerWindowClient::Create(*web_client); - case mojom::ServiceWorkerClientType::kSharedWorker: - return ServiceWorkerClient::Create(*web_client); - case mojom::ServiceWorkerClientType::kAll: - NOTREACHED(); - return nullptr; - } - NOTREACHED(); - return nullptr; +ServiceWorkerClient* ServiceWorkerClient::Create( + const WebServiceWorkerClientInfo& info) { + return new ServiceWorkerClient(info); } ServiceWorkerClient* ServiceWorkerClient::Create( - const WebServiceWorkerClientInfo& info) { + const mojom::blink::ServiceWorkerClientInfo& info) { return new ServiceWorkerClient(info); } @@ -52,6 +37,13 @@ ServiceWorkerClient::ServiceWorkerClient(const WebServiceWorkerClientInfo& info) type_(info.client_type), frame_type_(info.frame_type) {} +ServiceWorkerClient::ServiceWorkerClient( + const mojom::blink::ServiceWorkerClientInfo& info) + : uuid_(info.client_uuid), + url_(info.url.GetString()), + type_(info.client_type), + frame_type_(info.frame_type) {} + ServiceWorkerClient::~ServiceWorkerClient() = default; String ServiceWorkerClient::type() const { @@ -120,7 +112,7 @@ void ServiceWorkerClient::postMessage(ScriptState* script_state, return; ServiceWorkerGlobalScopeClient::From(context)->PostMessageToClient( - uuid_, ToTransferableMessage(std::move(msg))); + uuid_, std::move(msg)); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_client.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_client.h index 8dc40463664..e6c44cb9762 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_client.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_client.h @@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_CLIENT_H_ #include <memory> +#include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom-blink.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/modules/modules_export.h" @@ -16,19 +17,15 @@ namespace blink { class PostMessageOptions; -class ScriptPromiseResolver; class ScriptState; class MODULES_EXPORT ServiceWorkerClient : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: - // To be used by CallbackPromiseAdapter. - using WebType = std::unique_ptr<WebServiceWorkerClientInfo>; - - static ServiceWorkerClient* Take(ScriptPromiseResolver*, - std::unique_ptr<WebServiceWorkerClientInfo>); static ServiceWorkerClient* Create(const WebServiceWorkerClientInfo&); + static ServiceWorkerClient* Create( + const mojom::blink::ServiceWorkerClientInfo&); ~ServiceWorkerClient() override; @@ -48,6 +45,7 @@ class MODULES_EXPORT ServiceWorkerClient : public ScriptWrappable { protected: explicit ServiceWorkerClient(const WebServiceWorkerClientInfo&); + explicit ServiceWorkerClient(const mojom::blink::ServiceWorkerClientInfo&); String Uuid() const { return uuid_; } diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_clients.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_clients.cc index d717f2161ac..af1a97e11d5 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_clients.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_clients.cc @@ -7,10 +7,10 @@ #include <memory> #include <utility> +#include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/memory/scoped_refptr.h" #include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom-blink.h" -#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_client_query_options.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h" #include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" @@ -21,7 +21,6 @@ #include "third_party/blink/renderer/modules/service_worker/service_worker_error.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_window_client.h" -#include "third_party/blink/renderer/modules/service_worker/service_worker_window_client_callback.h" #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h" #include "third_party/blink/renderer/platform/wtf/vector.h" @@ -29,28 +28,6 @@ namespace blink { namespace { -class ClientArray { - public: - using WebType = const WebServiceWorkerClientsInfo&; - static HeapVector<Member<ServiceWorkerClient>> Take( - ScriptPromiseResolver*, - const WebServiceWorkerClientsInfo& web_clients) { - HeapVector<Member<ServiceWorkerClient>> clients; - for (size_t i = 0; i < web_clients.clients.size(); ++i) { - const WebServiceWorkerClientInfo& client = web_clients.clients[i]; - if (client.client_type == mojom::ServiceWorkerClientType::kWindow) - clients.push_back(ServiceWorkerWindowClient::Create(client)); - else - clients.push_back(ServiceWorkerClient::Create(client)); - } - return clients; - } - - private: - WTF_MAKE_NONCOPYABLE(ClientArray); - ClientArray() = delete; -}; - mojom::ServiceWorkerClientType GetClientType(const String& type) { if (type == "window") return mojom::ServiceWorkerClientType::kWindow; @@ -62,37 +39,67 @@ mojom::ServiceWorkerClientType GetClientType(const String& type) { return mojom::ServiceWorkerClientType::kWindow; } -class GetCallback : public WebServiceWorkerClientCallbacks { - public: - explicit GetCallback(ScriptPromiseResolver* resolver) : resolver_(resolver) {} - ~GetCallback() override = default; - - void OnSuccess( - std::unique_ptr<WebServiceWorkerClientInfo> web_client) override { - std::unique_ptr<WebServiceWorkerClientInfo> client = - base::WrapUnique(web_client.release()); - if (!resolver_->GetExecutionContext() || - resolver_->GetExecutionContext()->IsContextDestroyed()) - return; - if (!client) { - // Resolve the promise with undefined. - resolver_->Resolve(); - return; - } - resolver_->Resolve(ServiceWorkerClient::Take(resolver_, std::move(client))); +void DidGetClient(ScriptPromiseResolver* resolver, + mojom::blink::ServiceWorkerClientInfoPtr info) { + if (!resolver->GetExecutionContext() || + resolver->GetExecutionContext()->IsContextDestroyed()) { + return; } - void OnError(const WebServiceWorkerError& error) override { - if (!resolver_->GetExecutionContext() || - resolver_->GetExecutionContext()->IsContextDestroyed()) + if (!info) { + // Resolve the promise with undefined. + resolver->Resolve(); + return; + } + ServiceWorkerClient* client = nullptr; + switch (info->client_type) { + case mojom::ServiceWorkerClientType::kWindow: + client = ServiceWorkerWindowClient::Create(*info); + break; + case mojom::ServiceWorkerClientType::kSharedWorker: + client = ServiceWorkerClient::Create(*info); + break; + case mojom::ServiceWorkerClientType::kAll: + NOTREACHED(); return; - resolver_->Reject(ServiceWorkerError::Take(resolver_.Get(), error)); } + resolver->Resolve(client); +} - private: - Persistent<ScriptPromiseResolver> resolver_; - WTF_MAKE_NONCOPYABLE(GetCallback); -}; +void DidClaim(ScriptPromiseResolver* resolver, + mojom::blink::ServiceWorkerErrorType error, + const String& error_msg) { + if (!resolver->GetExecutionContext() || + resolver->GetExecutionContext()->IsContextDestroyed()) { + return; + } + + if (error != mojom::blink::ServiceWorkerErrorType::kNone) { + DCHECK(!error_msg.IsNull()); + resolver->Reject( + ServiceWorkerError::GetException(resolver, error, error_msg)); + return; + } + DCHECK(error_msg.IsNull()); + resolver->Resolve(); +} + +void DidGetClients(ScriptPromiseResolver* resolver, + Vector<mojom::blink::ServiceWorkerClientInfoPtr> infos) { + if (!resolver->GetExecutionContext() || + resolver->GetExecutionContext()->IsContextDestroyed()) { + return; + } + + HeapVector<Member<ServiceWorkerClient>> clients; + for (const auto& info : infos) { + if (info->client_type == mojom::blink::ServiceWorkerClientType::kWindow) + clients.push_back(ServiceWorkerWindowClient::Create(*info)); + else + clients.push_back(ServiceWorkerClient::Create(*info)); + } + resolver->Resolve(std::move(clients)); +} } // namespace @@ -111,11 +118,9 @@ ScriptPromise ServiceWorkerClients::get(ScriptState* script_state, return ScriptPromise(); ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); - ScriptPromise promise = resolver->Promise(); - ServiceWorkerGlobalScopeClient::From(execution_context) - ->GetClient(id, std::make_unique<GetCallback>(resolver)); - return promise; + ->GetClient(id, WTF::Bind(&DidGetClient, WrapPersistent(resolver))); + return resolver->Promise(); } ScriptPromise ServiceWorkerClients::matchAll( @@ -127,17 +132,12 @@ ScriptPromise ServiceWorkerClients::matchAll( return ScriptPromise(); ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); - ScriptPromise promise = resolver->Promise(); - - WebServiceWorkerClientQueryOptions web_options; - web_options.client_type = GetClientType(options.type()); - web_options.include_uncontrolled = options.includeUncontrolled(); ServiceWorkerGlobalScopeClient::From(execution_context) - ->GetClients(web_options, - std::make_unique< - CallbackPromiseAdapter<ClientArray, ServiceWorkerError>>( - resolver)); - return promise; + ->GetClients( + mojom::blink::ServiceWorkerClientQueryOptions::New( + options.includeUncontrolled(), GetClientType(options.type())), + WTF::Bind(&DidGetClients, WrapPersistent(resolver))); + return resolver->Promise(); } ScriptPromise ServiceWorkerClients::claim(ScriptState* script_state) { @@ -148,14 +148,9 @@ ScriptPromise ServiceWorkerClients::claim(ScriptState* script_state) { return ScriptPromise(); ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); - ScriptPromise promise = resolver->Promise(); - - auto callbacks = - std::make_unique<CallbackPromiseAdapter<void, ServiceWorkerError>>( - resolver); ServiceWorkerGlobalScopeClient::From(execution_context) - ->Claim(std::move(callbacks)); - return promise; + ->Claim(WTF::Bind(&DidClaim, WrapPersistent(resolver))); + return resolver->Promise(); } ScriptPromise ServiceWorkerClients::openWindow(ScriptState* script_state, @@ -186,7 +181,7 @@ ScriptPromise ServiceWorkerClients::openWindow(ScriptState* script_state, context->ConsumeWindowInteraction(); ServiceWorkerGlobalScopeClient::From(context)->OpenWindowForClients( - parsed_url, std::make_unique<NavigateClientCallback>(resolver)); + parsed_url, resolver); return promise; } diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.cc index b86eca316ed..3ef322ab040 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.cc @@ -31,8 +31,9 @@ #include <memory> #include <utility> + +#include "base/macros.h" #include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom-blink.h" -#include "third_party/blink/public/platform/modules/service_worker/web_service_worker.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_registration.h" #include "third_party/blink/public/platform/web_string.h" @@ -50,6 +51,7 @@ #include "third_party/blink/renderer/core/frame/deprecation.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/use_counter.h" +#include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/messaging/blink_transferable_message.h" #include "third_party/blink/renderer/core/messaging/message_port.h" #include "third_party/blink/renderer/modules/event_target_modules.h" @@ -78,6 +80,15 @@ mojom::ServiceWorkerUpdateViaCache ParseUpdateViaCache(const String& value) { return mojom::ServiceWorkerUpdateViaCache::kImports; } +mojom::ScriptType ParseScriptType(const String& type) { + if (type == "classic") + return mojom::ScriptType::kClassic; + if (type == "module") + return mojom::ScriptType::kModule; + NOTREACHED() << "Invalid type: " << type; + return mojom::ScriptType::kClassic; +} + class GetRegistrationCallback : public WebServiceWorkerProvider:: WebServiceWorkerGetRegistrationCallbacks { public: @@ -108,7 +119,7 @@ class GetRegistrationCallback : public WebServiceWorkerProvider:: private: Persistent<ScriptPromiseResolver> resolver_; - WTF_MAKE_NONCOPYABLE(GetRegistrationCallback); + DISALLOW_COPY_AND_ASSIGN(GetRegistrationCallback); }; } // namespace @@ -134,7 +145,7 @@ class ServiceWorkerContainer::GetRegistrationForReadyCallback private: Persistent<ReadyProperty> ready_; - WTF_MAKE_NONCOPYABLE(GetRegistrationForReadyCallback); + DISALLOW_COPY_AND_ASSIGN(GetRegistrationForReadyCallback); }; ServiceWorkerContainer* ServiceWorkerContainer::Create( @@ -179,6 +190,17 @@ ScriptPromise ServiceWorkerContainer::registerServiceWorker( return promise; } + // TODO(asamidoi): Remove this check after module loading for + // ServiceWorker is enabled by default (https://crbug.com/824647). + if (options.type() == "module" && + !RuntimeEnabledFeatures::ModuleServiceWorkerEnabled()) { + resolver->Reject(DOMException::Create( + DOMExceptionCode::kNotSupportedError, + "type 'module' in RegistrationOptions is not implemented yet." + "See https://crbug.com/824647 for details.")); + return promise; + } + auto callbacks = std::make_unique<CallbackPromiseAdapter< ServiceWorkerRegistration, ServiceWorkerErrorForUpdate>>(resolver); @@ -268,7 +290,7 @@ ScriptPromise ServiceWorkerContainer::registerServiceWorker( ContentSecurityPolicy* csp = execution_context->GetContentSecurityPolicy(); if (csp) { if (!csp->AllowRequestWithoutIntegrity( - WebURLRequest::kRequestContextServiceWorker, script_url) || + mojom::RequestContextType::SERVICE_WORKER, script_url) || !csp->AllowWorkerContextFromSource( script_url, ResourceRequest::RedirectStatus::kNoRedirect, SecurityViolationReportingPolicy::kReport)) { @@ -284,9 +306,10 @@ ScriptPromise ServiceWorkerContainer::registerServiceWorker( mojom::ServiceWorkerUpdateViaCache update_via_cache = ParseUpdateViaCache(options.updateViaCache()); + mojom::ScriptType type = ParseScriptType(options.type()); - provider_->RegisterServiceWorker(pattern_url, script_url, update_via_cache, - std::move(callbacks)); + provider_->RegisterServiceWorker(pattern_url, script_url, type, + update_via_cache, std::move(callbacks)); return promise; } @@ -382,11 +405,6 @@ ScriptPromise ServiceWorkerContainer::getRegistrations( return promise; } -ServiceWorkerContainer::ReadyProperty* -ServiceWorkerContainer::CreateReadyProperty() { - return new ReadyProperty(GetExecutionContext(), this, ReadyProperty::kReady); -} - ScriptPromise ServiceWorkerContainer::ready(ScriptState* caller_state) { if (!GetExecutionContext()) return ScriptPromise(); @@ -412,11 +430,11 @@ ScriptPromise ServiceWorkerContainer::ready(ScriptState* caller_state) { } void ServiceWorkerContainer::SetController( - std::unique_ptr<WebServiceWorker::Handle> handle, + WebServiceWorkerObjectInfo info, bool should_notify_controller_change) { if (!GetExecutionContext()) return; - controller_ = ServiceWorker::From(GetExecutionContext(), std::move(handle)); + controller_ = ServiceWorker::From(GetExecutionContext(), std::move(info)); if (controller_) { UseCounter::Count(GetExecutionContext(), WebFeature::kServiceWorkerControlledPage); @@ -426,7 +444,7 @@ void ServiceWorkerContainer::SetController( } void ServiceWorkerContainer::DispatchMessageEvent( - std::unique_ptr<WebServiceWorker::Handle> handle, + WebServiceWorkerObjectInfo info, TransferableMessage message) { if (!GetExecutionContext() || !GetExecutionContext()->ExecutingWindow()) return; @@ -434,7 +452,7 @@ void ServiceWorkerContainer::DispatchMessageEvent( MessagePortArray* ports = MessagePort::EntanglePorts(*GetExecutionContext(), std::move(msg.ports)); ServiceWorker* source = - ServiceWorker::From(GetExecutionContext(), std::move(handle)); + ServiceWorker::From(GetExecutionContext(), std::move(info)); MessageEvent* event; if (!msg.locked_agent_cluster_id || GetExecutionContext()->IsSameAgentCluster(*msg.locked_agent_cluster_id)) { @@ -472,11 +490,16 @@ ServiceWorkerContainer::ServiceWorkerContainer( return; if (ServiceWorkerContainerClient* client = - ServiceWorkerContainerClient::From(execution_context)) { + ServiceWorkerContainerClient::From(To<Document>(execution_context))) { provider_ = client->Provider(); if (provider_) provider_->SetClient(this); } } +ServiceWorkerContainer::ReadyProperty* +ServiceWorkerContainer::CreateReadyProperty() { + return new ReadyProperty(GetExecutionContext(), this, ReadyProperty::kReady); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.h index ea5bc3e4f53..d45a9db839d 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container.h @@ -51,7 +51,6 @@ namespace blink { class ExecutionContext; class NavigatorServiceWorker; -class WebServiceWorker; class WebServiceWorkerProvider; class MODULES_EXPORT ServiceWorkerContainer final @@ -84,9 +83,9 @@ class MODULES_EXPORT ServiceWorkerContainer final void ContextDestroyed(ExecutionContext*) override; // WebServiceWorkerProviderClient implementation. - void SetController(std::unique_ptr<WebServiceWorker::Handle>, + void SetController(WebServiceWorkerObjectInfo, bool should_notify_controller_change) override; - void DispatchMessageEvent(std::unique_ptr<WebServiceWorker::Handle>, + void DispatchMessageEvent(WebServiceWorkerObjectInfo, TransferableMessage) override; void CountFeature(mojom::WebFeature) override; diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_client.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_client.cc index c1af3c5b759..3f37a5898fb 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_client.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_client.cc @@ -6,11 +6,8 @@ #include <memory> #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h" -#include "third_party/blink/renderer/core/dom/document.h" -#include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_client.h" -#include "third_party/blink/renderer/core/workers/worker_global_scope.h" namespace blink { @@ -19,30 +16,27 @@ ServiceWorkerContainerClient::ServiceWorkerContainerClient( std::unique_ptr<WebServiceWorkerProvider> provider) : Supplement<Document>(document), provider_(std::move(provider)) {} -ServiceWorkerContainerClient::ServiceWorkerContainerClient( - WorkerClients& clients, - std::unique_ptr<WebServiceWorkerProvider> provider) - : Supplement<WorkerClients>(clients), provider_(std::move(provider)) {} - ServiceWorkerContainerClient::~ServiceWorkerContainerClient() = default; const char ServiceWorkerContainerClient::kSupplementName[] = "ServiceWorkerContainerClient"; -ServiceWorkerContainerClient* ServiceWorkerContainerClient::From( - ExecutionContext* context) { - if (!context) +ServiceWorker* ServiceWorkerContainerClient::GetOrCreateServiceWorker( + WebServiceWorkerObjectInfo info) { + if (info.version_id == mojom::blink::kInvalidServiceWorkerVersionId) return nullptr; - if (context->IsWorkerGlobalScope()) { - WorkerClients* worker_clients = ToWorkerGlobalScope(context)->Clients(); - DCHECK(worker_clients); - ServiceWorkerContainerClient* client = - Supplement<WorkerClients>::From<ServiceWorkerContainerClient>( - worker_clients); - DCHECK(client); - return client; + ServiceWorker* worker = service_worker_objects_.at(info.version_id); + if (!worker) { + worker = new ServiceWorker(GetSupplementable(), std::move(info)); + service_worker_objects_.Set(info.version_id, worker); } - Document* document = ToDocument(context); + return worker; +} + +ServiceWorkerContainerClient* ServiceWorkerContainerClient::From( + Document* document) { + if (!document) + return nullptr; if (!document->GetFrame() || !document->GetFrame()->Client()) return nullptr; @@ -57,11 +51,9 @@ ServiceWorkerContainerClient* ServiceWorkerContainerClient::From( return client; } -void ProvideServiceWorkerContainerClientToWorker( - WorkerClients* clients, - std::unique_ptr<WebServiceWorkerProvider> provider) { - clients->ProvideSupplement( - new ServiceWorkerContainerClient(*clients, std::move(provider))); +void ServiceWorkerContainerClient::Trace(blink::Visitor* visitor) { + visitor->Trace(service_worker_objects_); + Supplement<Document>::Trace(visitor); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_client.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_client.h index 639bcb27662..91cdb99791d 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_client.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_client.h @@ -6,44 +6,44 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_CONTAINER_CLIENT_H_ #include <memory> + +#include "base/macros.h" #include "third_party/blink/renderer/core/dom/document.h" -#include "third_party/blink/renderer/core/workers/worker_clients.h" #include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/modules/service_worker/service_worker.h" #include "third_party/blink/renderer/platform/bindings/name_client.h" +#include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/wtf/forward.h" namespace blink { -class ExecutionContext; class WebServiceWorkerProvider; // This mainly exists to provide access to WebServiceWorkerProvider. -// Owned by Document (or WorkerClients). +// Owned by Document. class MODULES_EXPORT ServiceWorkerContainerClient final : public GarbageCollectedFinalized<ServiceWorkerContainerClient>, public Supplement<Document>, - public Supplement<WorkerClients>, public NameClient { USING_GARBAGE_COLLECTED_MIXIN(ServiceWorkerContainerClient); - WTF_MAKE_NONCOPYABLE(ServiceWorkerContainerClient); public: static const char kSupplementName[]; ServiceWorkerContainerClient(Document&, std::unique_ptr<WebServiceWorkerProvider>); - ServiceWorkerContainerClient(WorkerClients&, - std::unique_ptr<WebServiceWorkerProvider>); virtual ~ServiceWorkerContainerClient(); + // Returns the ServiceWorker object described by the object info in current + // execution context. Creates a new object if needed, or else returns the + // existing one. + ServiceWorker* GetOrCreateServiceWorker(WebServiceWorkerObjectInfo); + WebServiceWorkerProvider* Provider() { return provider_.get(); } - static ServiceWorkerContainerClient* From(ExecutionContext*); + static ServiceWorkerContainerClient* From(Document*); - void Trace(blink::Visitor* visitor) override { - Supplement<Document>::Trace(visitor); - Supplement<WorkerClients>::Trace(visitor); - } + void Trace(blink::Visitor* visitor) override; const char* NameInHeapSnapshot() const override { return "ServiceWorkerContainerClient"; @@ -51,11 +51,16 @@ class MODULES_EXPORT ServiceWorkerContainerClient final private: std::unique_ptr<WebServiceWorkerProvider> provider_; -}; + // Map from service worker version id to JavaScript ServiceWorker object in + // current execution context. + HeapHashMap<int64_t, + WeakMember<ServiceWorker>, + WTF::IntHash<int64_t>, + WTF::UnsignedWithZeroKeyHashTraits<int64_t>> + service_worker_objects_; -MODULES_EXPORT void ProvideServiceWorkerContainerClientToWorker( - WorkerClients*, - std::unique_ptr<WebServiceWorkerProvider>); + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContainerClient); +}; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc index 6099c2337ba..a750ba02712 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc @@ -131,6 +131,7 @@ class NotReachedWebServiceWorkerProvider : public WebServiceWorkerProvider { void RegisterServiceWorker( const WebURL& pattern, const WebURL& script_url, + blink::mojom::ScriptType script_type, mojom::ServiceWorkerUpdateViaCache update_via_cache, std::unique_ptr<WebServiceWorkerRegistrationCallbacks> callbacks) override { @@ -251,6 +252,7 @@ class StubWebServiceWorkerProvider { StubWebServiceWorkerProvider() : register_call_count_(0), get_registration_call_count_(0), + script_type_(mojom::ScriptType::kClassic), update_via_cache_(mojom::ServiceWorkerUpdateViaCache::kImports) {} // Creates a WebServiceWorkerProvider. This can outlive the @@ -266,6 +268,7 @@ class StubWebServiceWorkerProvider { const WebURL& RegisterScriptURL() { return register_script_url_; } size_t GetRegistrationCallCount() { return get_registration_call_count_; } const WebURL& GetRegistrationURL() { return get_registration_url_; } + mojom::ScriptType ScriptType() const { return script_type_; } mojom::ServiceWorkerUpdateViaCache UpdateViaCache() const { return update_via_cache_; } @@ -281,12 +284,14 @@ class StubWebServiceWorkerProvider { void RegisterServiceWorker( const WebURL& pattern, const WebURL& script_url, + blink::mojom::ScriptType script_type, mojom::ServiceWorkerUpdateViaCache update_via_cache, std::unique_ptr<WebServiceWorkerRegistrationCallbacks> callbacks) override { owner_.register_call_count_++; owner_.register_scope_ = pattern; owner_.register_script_url_ = script_url; + owner_.script_type_ = script_type; owner_.update_via_cache_ = update_via_cache; registration_callbacks_to_delete_.push_back(std::move(callbacks)); } @@ -320,6 +325,7 @@ class StubWebServiceWorkerProvider { WebURL register_script_url_; size_t get_registration_call_count_; WebURL get_registration_url_; + mojom::ScriptType script_type_; mojom::ServiceWorkerUpdateViaCache update_via_cache_; }; @@ -346,6 +352,7 @@ TEST_F(ServiceWorkerContainerTest, stub_provider.RegisterScope()); EXPECT_EQ(WebURL(KURL("http://localhost/x/y/worker.js")), stub_provider.RegisterScriptURL()); + EXPECT_EQ(mojom::ScriptType::kClassic, stub_provider.ScriptType()); EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kImports, stub_provider.UpdateViaCache()); } @@ -367,6 +374,7 @@ TEST_F(ServiceWorkerContainerTest, EXPECT_EQ(1ul, stub_provider.GetRegistrationCallCount()); EXPECT_EQ(WebURL(KURL("http://localhost/x/index.html")), stub_provider.GetRegistrationURL()); + EXPECT_EQ(mojom::ScriptType::kClassic, stub_provider.ScriptType()); EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kImports, stub_provider.UpdateViaCache()); } @@ -395,10 +403,39 @@ TEST_F(ServiceWorkerContainerTest, stub_provider.RegisterScope()); EXPECT_EQ(WebURL(KURL(KURL(), "http://localhost/x/y/worker.js")), stub_provider.RegisterScriptURL()); + EXPECT_EQ(mojom::ScriptType::kClassic, stub_provider.ScriptType()); EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kNone, stub_provider.UpdateViaCache()); } } +TEST_F(ServiceWorkerContainerTest, Register_TypeOptionDelegatesToProvider) { + SetPageURL("http://localhost/x/index.html"); + + StubWebServiceWorkerProvider stub_provider; + Provide(stub_provider.Provider()); + + ServiceWorkerContainer* container = ServiceWorkerContainer::Create( + GetExecutionContext(), GetNavigatorServiceWorker()); + + // register + { + ScriptState::Scope script_scope(GetScriptState()); + RegistrationOptions options; + options.setType("module"); + container->registerServiceWorker(GetScriptState(), "/x/y/worker.js", + options); + + EXPECT_EQ(1ul, stub_provider.RegisterCallCount()); + EXPECT_EQ(WebURL(KURL(KURL(), "http://localhost/x/y/")), + stub_provider.RegisterScope()); + EXPECT_EQ(WebURL(KURL(KURL(), "http://localhost/x/y/worker.js")), + stub_provider.RegisterScriptURL()); + EXPECT_EQ(mojom::ScriptType::kModule, stub_provider.ScriptType()); + EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kImports, + stub_provider.UpdateViaCache()); + } +} + } // namespace } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_error.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_error.cc index 3502f8a7dc3..e958fc84a3b 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_error.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_error.cc @@ -127,6 +127,14 @@ DOMException* ServiceWorkerError::Take(ScriptPromiseResolver*, } // static +DOMException* ServiceWorkerError::GetException( + ScriptPromiseResolver* resolver, + mojom::blink::ServiceWorkerErrorType error, + const String& error_msg) { + return Take(resolver, WebServiceWorkerError(error, error_msg)); +} + +// static v8::Local<v8::Value> ServiceWorkerErrorForUpdate::Take( ScriptPromiseResolver* resolver, const WebServiceWorkerError& web_error) { diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_error.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_error.h index f6d34c61eb7..27f011d1985 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_error.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_error.h @@ -31,6 +31,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_ERROR_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_ERROR_H_ +#include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom-blink.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "v8/include/v8.h" @@ -48,6 +49,12 @@ class ServiceWorkerError { using WebType = const WebServiceWorkerError&; static DOMException* Take(ScriptPromiseResolver*, const WebServiceWorkerError& web_error); + + // TODO(crbug.com/879019): Eventually we'll remove WebServiceWorkerError and + // use this GetException() everywhere instead of the above Take(). + static DOMException* GetException(ScriptPromiseResolver*, + mojom::blink::ServiceWorkerErrorType error, + const String& error_msg); }; class ServiceWorkerErrorForUpdate : public ServiceWorkerError { diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc index 3bea7b455ec..1430d951115 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc @@ -40,11 +40,10 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/bindings/core/v8/source_location.h" +#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h" #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/fetch/global_fetch.h" -#include "third_party/blink/renderer/core/frame/deprecation.h" -#include "third_party/blink/renderer/core/frame/use_counter.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/inspector/worker_inspector_controller.h" #include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h" @@ -53,6 +52,7 @@ #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" #include "third_party/blink/renderer/core/workers/installed_scripts_manager.h" #include "third_party/blink/renderer/core/workers/worker_clients.h" +#include "third_party/blink/renderer/core/workers/worker_module_tree_client.h" #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h" #include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/modules/service_worker/respond_with_observer.h" @@ -74,6 +74,20 @@ namespace blink { +namespace { + +void DidSkipWaiting(ScriptPromiseResolver* resolver, bool success) { + if (!resolver->GetExecutionContext() || + resolver->GetExecutionContext()->IsContextDestroyed()) + return; + // Per spec the promise returned by skipWaiting() can never reject. + if (!success) + return; + resolver->Resolve(); +} + +} // namespace + ServiceWorkerGlobalScope* ServiceWorkerGlobalScope::Create( ServiceWorkerThread* thread, std::unique_ptr<GlobalScopeCreationParams> creation_params, @@ -114,6 +128,7 @@ void ServiceWorkerGlobalScope::ReadyToEvaluateScript() { void ServiceWorkerGlobalScope::EvaluateClassicScript( const KURL& script_url, + AccessControlStatus access_control_status, String source_code, std::unique_ptr<Vector<char>> cached_meta_data) { DCHECK(IsContextThread()); @@ -121,8 +136,8 @@ void ServiceWorkerGlobalScope::EvaluateClassicScript( if (!evaluate_script_ready_) { evaluate_script_ = WTF::Bind(&ServiceWorkerGlobalScope::EvaluateClassicScript, - WrapWeakPersistent(this), script_url, std::move(source_code), - std::move(cached_meta_data)); + WrapWeakPersistent(this), script_url, access_control_status, + std::move(source_code), std::move(cached_meta_data)); return; } @@ -132,37 +147,37 @@ void ServiceWorkerGlobalScope::EvaluateClassicScript( if (installed_scripts_manager && installed_scripts_manager->IsScriptInstalled(script_url)) { // GetScriptData blocks until the script is received from the browser. - InstalledScriptsManager::ScriptData script_data; - InstalledScriptsManager::ScriptStatus status = - installed_scripts_manager->GetScriptData(script_url, &script_data); - if (status == InstalledScriptsManager::ScriptStatus::kFailed) { + std::unique_ptr<InstalledScriptsManager::ScriptData> script_data = + installed_scripts_manager->GetScriptData(script_url); + if (!script_data) { close(); return; } DCHECK(source_code.IsEmpty()); DCHECK(!cached_meta_data); - source_code = script_data.TakeSourceText(); - cached_meta_data = script_data.TakeMetaData(); + source_code = script_data->TakeSourceText(); + cached_meta_data = script_data->TakeMetaData(); base::Optional<ContentSecurityPolicyResponseHeaders> content_security_policy_raw_headers = - script_data.GetContentSecurityPolicyResponseHeaders(); + script_data->GetContentSecurityPolicyResponseHeaders(); ApplyContentSecurityPolicyFromHeaders( content_security_policy_raw_headers.value()); - String referrer_policy = script_data.GetReferrerPolicy(); + String referrer_policy = script_data->GetReferrerPolicy(); if (!referrer_policy.IsNull()) ParseAndSetReferrerPolicy(referrer_policy); std::unique_ptr<Vector<String>> origin_trial_tokens = - script_data.CreateOriginTrialTokens(); + script_data->CreateOriginTrialTokens(); OriginTrialContext::AddTokens(this, origin_trial_tokens.get()); ReportingProxy().DidLoadInstalledScript(); } - WorkerGlobalScope::EvaluateClassicScript(script_url, source_code, + WorkerGlobalScope::EvaluateClassicScript(script_url, access_control_status, + source_code, std::move(cached_meta_data)); } @@ -170,13 +185,24 @@ void ServiceWorkerGlobalScope::ImportModuleScript( const KURL& module_url_record, FetchClientSettingsObjectSnapshot* outside_settings_object, network::mojom::FetchCredentialsMode credentials_mode) { - // TODO(nhiroki): Implement module loading for service workers. - // (https://crbug.com/824647) - NOTREACHED(); + Modulator* modulator = Modulator::From(ScriptController()->GetScriptState()); + + FetchModuleScript(module_url_record, outside_settings_object, + mojom::RequestContextType::SERVICE_WORKER, credentials_mode, + ModuleScriptCustomFetchType::kWorkerConstructor, + new WorkerModuleTreeClient(modulator)); +} + +void ServiceWorkerGlobalScope::Dispose() { + DCHECK(IsContextThread()); + ServiceWorkerGlobalScopeClient::From(GetExecutionContext()) + ->WillDestroyWorkerContext(); + WorkerGlobalScope::Dispose(); } void ServiceWorkerGlobalScope::CountWorkerScript(size_t script_size, size_t cached_metadata_size) { + DCHECK_EQ(GetScriptType(), ScriptType::kClassic); DEFINE_THREAD_SAFE_STATIC_LOCAL( CustomCountHistogram, script_size_histogram, ("ServiceWorker.ScriptSize", 1000, 5000000, 50)); @@ -189,23 +215,29 @@ void ServiceWorkerGlobalScope::CountWorkerScript(size_t script_size, script_cached_metadata_size_histogram.Count(cached_metadata_size); } - RecordScriptSize(script_size, cached_metadata_size); + CountScriptInternal(script_size, cached_metadata_size); } void ServiceWorkerGlobalScope::CountImportedScript( size_t script_size, size_t cached_metadata_size) { - RecordScriptSize(script_size, cached_metadata_size); + DCHECK_EQ(GetScriptType(), ScriptType::kClassic); + CountScriptInternal(script_size, cached_metadata_size); } -void ServiceWorkerGlobalScope::RecordScriptSize(size_t script_size, - size_t cached_metadata_size) { - ++script_count_; - script_total_size_ += script_size; - script_cached_metadata_total_size_ += cached_metadata_size; -} +void ServiceWorkerGlobalScope::DidEvaluateScript() { + DCHECK(!did_evaluate_script_); + did_evaluate_script_ = true; -void ServiceWorkerGlobalScope::DidEvaluateClassicScript() { + // Skip recording UMAs for module scripts because there're no ways to get the + // number of static-imported scripts and the total size of the imported + // scripts. + if (GetScriptType() == ScriptType::kModule) { + return; + } + + // TODO(asamidoi,nhiroki): Record the UMAs for module scripts, or remove them + // if they're no longer used. DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, script_count_histogram, ("ServiceWorker.ScriptCount", 1, 1000, 50)); script_count_histogram.Count(script_count_); @@ -219,14 +251,14 @@ void ServiceWorkerGlobalScope::DidEvaluateClassicScript() { ("ServiceWorker.ScriptCachedMetadataTotalSize", 1000, 50000000, 50)); cached_metadata_histogram.Count(script_cached_metadata_total_size_); } - did_evaluate_script_ = true; } -ScriptPromise ServiceWorkerGlobalScope::fetch(ScriptState* script_state, - const RequestInfo& input, - const RequestInit& init, - ExceptionState& exception_state) { - return GlobalFetch::fetch(script_state, *this, input, init, exception_state); +void ServiceWorkerGlobalScope::CountScriptInternal( + size_t script_size, + size_t cached_metadata_size) { + ++script_count_; + script_total_size_ += script_size; + script_cached_metadata_total_size_ += cached_metadata_size; } ServiceWorkerClients* ServiceWorkerGlobalScope::clients() { @@ -247,12 +279,15 @@ ScriptPromise ServiceWorkerGlobalScope::skipWaiting(ScriptState* script_state) { return ScriptPromise(); ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); - ScriptPromise promise = resolver->Promise(); - ServiceWorkerGlobalScopeClient::From(execution_context) - ->SkipWaiting( - std::make_unique<CallbackPromiseAdapter<void, void>>(resolver)); - return promise; + ->SkipWaiting(WTF::Bind(&DidSkipWaiting, WrapPersistent(resolver))); + return resolver->Promise(); +} + +void ServiceWorkerGlobalScope::BindServiceWorkerHost( + mojom::blink::ServiceWorkerHostAssociatedPtrInfo service_worker_host) { + ServiceWorkerGlobalScopeClient::From(GetExecutionContext()) + ->BindServiceWorkerHost(std::move(service_worker_host)); } void ServiceWorkerGlobalScope::SetRegistration( @@ -263,6 +298,18 @@ void ServiceWorkerGlobalScope::SetRegistration( GetExecutionContext(), base::WrapUnique(handle.release())); } +ServiceWorker* ServiceWorkerGlobalScope::GetOrCreateServiceWorker( + WebServiceWorkerObjectInfo info) { + if (info.version_id == mojom::blink::kInvalidServiceWorkerVersionId) + return nullptr; + ServiceWorker* worker = service_worker_objects_.at(info.version_id); + if (!worker) { + worker = new ServiceWorker(this, std::move(info)); + service_worker_objects_.Set(info.version_id, worker); + } + return worker; +} + bool ServiceWorkerGlobalScope::AddEventListenerInternal( const AtomicString& event_type, EventListener* listener, @@ -310,6 +357,7 @@ void ServiceWorkerGlobalScope::DispatchExtendableEventWithRespondWith( void ServiceWorkerGlobalScope::Trace(blink::Visitor* visitor) { visitor->Trace(clients_); visitor->Trace(registration_); + visitor->Trace(service_worker_objects_); WorkerGlobalScope::Trace(visitor); } @@ -319,22 +367,21 @@ void ServiceWorkerGlobalScope::importScripts(const Vector<String>& urls, GetThread()->GetInstalledScriptsManager(); for (auto& url : urls) { KURL completed_url = CompleteURL(url); - // Counts the usage of importScripts() of new scripts after installation - // because we want to deprecate such usage (https://crbug.com/719052). - // This will undercount because installed scripts manager is only provided - // to installed service workers on startup, but this gives us an idea of - // the usage. - if (installed_scripts_manager && - !installed_scripts_manager->IsScriptInstalled(completed_url)) { - DCHECK(installed_scripts_manager->IsScriptInstalled(Url())); - CountFeature(WebFeature::kServiceWorkerImportScriptNotInstalled); - Deprecation::CountDeprecation( - this, WebFeature::kServiceWorkerImportScriptNotInstalled); - } // Bust the MemoryCache to ensure script requests reach the browser-side // and get added to and retrieved from the ServiceWorker's script cache. // FIXME: Revisit in light of the solution to crbug/388375. RemoveURLFromMemoryCache(completed_url); + + if (installed_scripts_manager && + !installed_scripts_manager->IsScriptInstalled(completed_url)) { + DCHECK(installed_scripts_manager->IsScriptInstalled(Url())); + exception_state.ThrowDOMException( + DOMExceptionCode::kNetworkError, + "Failed to import '" + completed_url.ElidedString() + + "'. importScripts() of new scripts after service worker " + "installation is not allowed."); + return; + } } WorkerGlobalScope::importScripts(urls, exception_state); } @@ -347,6 +394,13 @@ ServiceWorkerGlobalScope::CreateWorkerScriptCachedMetadataHandler( meta_data); } +ScriptPromise ServiceWorkerGlobalScope::fetch(ScriptState* script_state, + const RequestInfo& input, + const RequestInit& init, + ExceptionState& exception_state) { + return GlobalFetch::fetch(script_state, *this, input, init, exception_state); +} + void ServiceWorkerGlobalScope::ExceptionThrown(ErrorEvent* event) { WorkerGlobalScope::ExceptionThrown(event); if (WorkerThreadDebugger* debugger = diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h index f00b65661e5..4fc509a1165 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h @@ -31,11 +31,13 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_GLOBAL_SCOPE_H_ #include <memory> +#include "third_party/blink/public/mojom/service_worker/service_worker.mojom-blink.h" #include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_registration.h" #include "third_party/blink/renderer/bindings/core/v8/request_or_usv_string.h" #include "third_party/blink/renderer/core/workers/worker_global_scope.h" #include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/modules/service_worker/service_worker.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" #include "third_party/blink/renderer/platform/wtf/forward.h" @@ -70,12 +72,14 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final : public WorkerGlobalScope { // Implements WorkerGlobalScope. void EvaluateClassicScript( const KURL& script_url, + AccessControlStatus access_control_status, String source_code, std::unique_ptr<Vector<char>> cached_meta_data) override; void ImportModuleScript( const KURL& module_url_record, FetchClientSettingsObjectSnapshot* outside_settings_object, network::mojom::FetchCredentialsMode) override; + void Dispose() override; // Counts an evaluated script and its size. Called for the main worker script. void CountWorkerScript(size_t script_size, size_t cached_metadata_size); @@ -85,7 +89,7 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final : public WorkerGlobalScope { void CountImportedScript(size_t script_size, size_t cached_metadata_size); // Called when the main worker script is evaluated. - void DidEvaluateClassicScript(); + void DidEvaluateScript(); // ServiceWorkerGlobalScope.idl ServiceWorkerClients* clients(); @@ -98,8 +102,15 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final : public WorkerGlobalScope { ScriptPromise skipWaiting(ScriptState*); + void BindServiceWorkerHost(mojom::blink::ServiceWorkerHostAssociatedPtrInfo); + void SetRegistration(std::unique_ptr<WebServiceWorkerRegistration::Handle>); + // Returns the ServiceWorker object described by the object info in current + // execution context. Creates a new object if needed, or else returns the + // existing one. + ServiceWorker* GetOrCreateServiceWorker(WebServiceWorkerObjectInfo); + // EventTarget const AtomicString& InterfaceName() const override; @@ -146,12 +157,19 @@ class MODULES_EXPORT ServiceWorkerGlobalScope final : public WorkerGlobalScope { const Vector<char>* meta_data) override; void ExceptionThrown(ErrorEvent*) override; - // Records the |script_size| and |cached_metadata_size| for UMA to measure the + // Counts the |script_size| and |cached_metadata_size| for UMA to measure the // number of scripts and the total bytes of scripts. - void RecordScriptSize(size_t script_size, size_t cached_metadata_size); + void CountScriptInternal(size_t script_size, size_t cached_metadata_size); Member<ServiceWorkerClients> clients_; Member<ServiceWorkerRegistration> registration_; + // Map from service worker version id to JavaScript ServiceWorker object in + // current execution context. + HeapHashMap<int64_t, + WeakMember<ServiceWorker>, + WTF::IntHash<int64_t>, + WTF::UnsignedWithZeroKeyHashTraits<int64_t>> + service_worker_objects_; bool did_evaluate_script_ = false; size_t script_count_ = 0; size_t script_total_size_ = 0; diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc index ae17974d99b..5810258d03b 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc @@ -33,64 +33,130 @@ #include <memory> #include <utility> #include "third_party/blink/public/platform/modules/payments/web_payment_handler_response.h" +#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h" -#include "third_party/blink/public/platform/web_url.h" #include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/fetch/response.h" #include "third_party/blink/renderer/core/workers/worker_global_scope.h" +#include "third_party/blink/renderer/modules/service_worker/service_worker_window_client.h" +#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { +namespace { + +void DidNavigateOrOpenWindow(ScriptPromiseResolver* resolver, + bool success, + mojom::blink::ServiceWorkerClientInfoPtr info, + const String& error_msg) { + if (!resolver->GetExecutionContext() || + resolver->GetExecutionContext()->IsContextDestroyed()) { + return; + } + + if (!success) { + DCHECK(!info); + DCHECK(!error_msg.IsNull()); + ScriptState::Scope scope(resolver->GetScriptState()); + resolver->Reject(V8ThrowException::CreateTypeError( + resolver->GetScriptState()->GetIsolate(), error_msg)); + return; + } + ServiceWorkerWindowClient* window_client = nullptr; + // Even if the open/navigation succeeded, |info| may be null if information of + // the opened/navigated window could not be obtained (this can happen for a + // cross-origin window, or if the browser process could not get the + // information in time before the window was closed). + if (info) + window_client = ServiceWorkerWindowClient::Create(*info); + resolver->Resolve(window_client); +} + +} // namespace + ServiceWorkerGlobalScopeClient::ServiceWorkerGlobalScopeClient( WebServiceWorkerContextClient& client) : client_(client) {} -void ServiceWorkerGlobalScopeClient::GetClient( - const WebString& id, - std::unique_ptr<WebServiceWorkerClientCallbacks> callbacks) { - client_.GetClient(id, std::move(callbacks)); +void ServiceWorkerGlobalScopeClient::GetClient(const String& id, + GetClientCallback callback) { + service_worker_host_->GetClient(id, std::move(callback)); } void ServiceWorkerGlobalScopeClient::GetClients( - const WebServiceWorkerClientQueryOptions& options, - std::unique_ptr<WebServiceWorkerClientsCallbacks> callbacks) { - client_.GetClients(options, std::move(callbacks)); + mojom::blink::ServiceWorkerClientQueryOptionsPtr options, + GetClientsCallback callback) { + service_worker_host_->GetClients(std::move(options), std::move(callback)); } void ServiceWorkerGlobalScopeClient::OpenWindowForClients( - const WebURL& url, - std::unique_ptr<WebServiceWorkerClientCallbacks> callbacks) { - client_.OpenNewTab(url, std::move(callbacks)); + const KURL& url, + ScriptPromiseResolver* resolver) { + service_worker_host_->OpenNewTab( + url, WTF::Bind(&DidNavigateOrOpenWindow, WrapPersistent(resolver))); } void ServiceWorkerGlobalScopeClient::OpenWindowForPaymentHandler( - const WebURL& url, - std::unique_ptr<WebServiceWorkerClientCallbacks> callbacks) { - client_.OpenPaymentHandlerWindow(url, std::move(callbacks)); + const KURL& url, + ScriptPromiseResolver* resolver) { + service_worker_host_->OpenPaymentHandlerWindow( + url, WTF::Bind(&DidNavigateOrOpenWindow, WrapPersistent(resolver))); } -void ServiceWorkerGlobalScopeClient::SetCachedMetadata(const WebURL& url, +void ServiceWorkerGlobalScopeClient::SetCachedMetadata(const KURL& url, const char* data, size_t size) { - client_.SetCachedMetadata(url, data, size); + Vector<uint8_t> meta_data; + meta_data.Append(data, size); + service_worker_host_->SetCachedMetadata(url, meta_data); +} + +void ServiceWorkerGlobalScopeClient::ClearCachedMetadata(const KURL& url) { + service_worker_host_->ClearCachedMetadata(url); +} + +void ServiceWorkerGlobalScopeClient::PostMessageToClient( + const String& client_uuid, + BlinkTransferableMessage message) { + service_worker_host_->PostMessageToClient(client_uuid, std::move(message)); +} + +void ServiceWorkerGlobalScopeClient::SkipWaiting(SkipWaitingCallback callback) { + service_worker_host_->SkipWaiting(std::move(callback)); +} + +void ServiceWorkerGlobalScopeClient::Claim(ClaimCallback callback) { + service_worker_host_->ClaimClients(std::move(callback)); } -void ServiceWorkerGlobalScopeClient::ClearCachedMetadata(const WebURL& url) { - client_.ClearCachedMetadata(url); +void ServiceWorkerGlobalScopeClient::Focus(const String& client_uuid, + FocusCallback callback) { + service_worker_host_->FocusClient(client_uuid, std::move(callback)); +} + +void ServiceWorkerGlobalScopeClient::Navigate(const String& client_uuid, + const KURL& url, + ScriptPromiseResolver* resolver) { + service_worker_host_->NavigateClient( + client_uuid, url, + WTF::Bind(&DidNavigateOrOpenWindow, WrapPersistent(resolver))); } void ServiceWorkerGlobalScopeClient::DidHandleActivateEvent( int event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleActivateEvent(event_id, status, event_dispatch_time); } void ServiceWorkerGlobalScopeClient::DidHandleBackgroundFetchAbortEvent( int event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleBackgroundFetchAbortEvent(event_id, status, event_dispatch_time); } @@ -98,7 +164,7 @@ void ServiceWorkerGlobalScopeClient::DidHandleBackgroundFetchAbortEvent( void ServiceWorkerGlobalScopeClient::DidHandleBackgroundFetchClickEvent( int event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleBackgroundFetchClickEvent(event_id, status, event_dispatch_time); } @@ -106,7 +172,7 @@ void ServiceWorkerGlobalScopeClient::DidHandleBackgroundFetchClickEvent( void ServiceWorkerGlobalScopeClient::DidHandleBackgroundFetchFailEvent( int event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleBackgroundFetchFailEvent(event_id, status, event_dispatch_time); } @@ -114,7 +180,7 @@ void ServiceWorkerGlobalScopeClient::DidHandleBackgroundFetchFailEvent( void ServiceWorkerGlobalScopeClient::DidHandleBackgroundFetchSuccessEvent( int event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleBackgroundFetchSuccessEvent(event_id, status, event_dispatch_time); } @@ -122,45 +188,50 @@ void ServiceWorkerGlobalScopeClient::DidHandleBackgroundFetchSuccessEvent( void ServiceWorkerGlobalScopeClient::DidHandleCookieChangeEvent( int event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleCookieChangeEvent(event_id, status, event_dispatch_time); } void ServiceWorkerGlobalScopeClient::DidHandleExtendableMessageEvent( int event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleExtendableMessageEvent(event_id, status, event_dispatch_time); } void ServiceWorkerGlobalScopeClient::RespondToFetchEventWithNoResponse( int fetch_event_id, - double event_dispatch_time) { - client_.RespondToFetchEventWithNoResponse(fetch_event_id, - event_dispatch_time); + base::TimeTicks event_dispatch_time, + base::TimeTicks respond_with_settled_time) { + client_.RespondToFetchEventWithNoResponse(fetch_event_id, event_dispatch_time, + respond_with_settled_time); } void ServiceWorkerGlobalScopeClient::RespondToFetchEvent( int fetch_event_id, const WebServiceWorkerResponse& response, - double event_dispatch_time) { - client_.RespondToFetchEvent(fetch_event_id, response, event_dispatch_time); + base::TimeTicks event_dispatch_time, + base::TimeTicks respond_with_settled_time) { + client_.RespondToFetchEvent(fetch_event_id, response, event_dispatch_time, + respond_with_settled_time); } void ServiceWorkerGlobalScopeClient::RespondToFetchEventWithResponseStream( int fetch_event_id, const WebServiceWorkerResponse& response, WebServiceWorkerStreamHandle* stream_handle, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time, + base::TimeTicks respond_with_settled_time) { client_.RespondToFetchEventWithResponseStream( - fetch_event_id, response, stream_handle, event_dispatch_time); + fetch_event_id, response, stream_handle, event_dispatch_time, + respond_with_settled_time); } void ServiceWorkerGlobalScopeClient::RespondToAbortPaymentEvent( int event_id, bool abort_payment, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.RespondToAbortPaymentEvent(event_id, abort_payment, event_dispatch_time); } @@ -168,35 +239,35 @@ void ServiceWorkerGlobalScopeClient::RespondToAbortPaymentEvent( void ServiceWorkerGlobalScopeClient::RespondToCanMakePaymentEvent( int event_id, bool response, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.RespondToCanMakePaymentEvent(event_id, response, event_dispatch_time); } void ServiceWorkerGlobalScopeClient::RespondToPaymentRequestEvent( int event_id, const WebPaymentHandlerResponse& response, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.RespondToPaymentRequestEvent(event_id, response, event_dispatch_time); } void ServiceWorkerGlobalScopeClient::DidHandleFetchEvent( int fetch_event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleFetchEvent(fetch_event_id, status, event_dispatch_time); } void ServiceWorkerGlobalScopeClient::DidHandleInstallEvent( int install_event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleInstallEvent(install_event_id, status, event_dispatch_time); } void ServiceWorkerGlobalScopeClient::DidHandleNotificationClickEvent( int event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleNotificationClickEvent(event_id, status, event_dispatch_time); } @@ -204,7 +275,7 @@ void ServiceWorkerGlobalScopeClient::DidHandleNotificationClickEvent( void ServiceWorkerGlobalScopeClient::DidHandleNotificationCloseEvent( int event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleNotificationCloseEvent(event_id, status, event_dispatch_time); } @@ -212,21 +283,21 @@ void ServiceWorkerGlobalScopeClient::DidHandleNotificationCloseEvent( void ServiceWorkerGlobalScopeClient::DidHandlePushEvent( int push_event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandlePushEvent(push_event_id, status, event_dispatch_time); } void ServiceWorkerGlobalScopeClient::DidHandleSyncEvent( int sync_event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleSyncEvent(sync_event_id, status, event_dispatch_time); } void ServiceWorkerGlobalScopeClient::DidHandleAbortPaymentEvent( int abort_payment_event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleAbortPaymentEvent(abort_payment_event_id, status, event_dispatch_time); } @@ -234,7 +305,7 @@ void ServiceWorkerGlobalScopeClient::DidHandleAbortPaymentEvent( void ServiceWorkerGlobalScopeClient::DidHandleCanMakePaymentEvent( int payment_request_event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandleCanMakePaymentEvent(payment_request_event_id, status, event_dispatch_time); } @@ -242,38 +313,20 @@ void ServiceWorkerGlobalScopeClient::DidHandleCanMakePaymentEvent( void ServiceWorkerGlobalScopeClient::DidHandlePaymentRequestEvent( int payment_request_event_id, mojom::ServiceWorkerEventStatus status, - double event_dispatch_time) { + base::TimeTicks event_dispatch_time) { client_.DidHandlePaymentRequestEvent(payment_request_event_id, status, event_dispatch_time); } -void ServiceWorkerGlobalScopeClient::PostMessageToClient( - const WebString& client_uuid, - TransferableMessage message) { - client_.PostMessageToClient(client_uuid, std::move(message)); -} - -void ServiceWorkerGlobalScopeClient::SkipWaiting( - std::unique_ptr<WebServiceWorkerSkipWaitingCallbacks> callbacks) { - client_.SkipWaiting(std::move(callbacks)); -} - -void ServiceWorkerGlobalScopeClient::Claim( - std::unique_ptr<WebServiceWorkerClientsClaimCallbacks> callbacks) { - client_.Claim(std::move(callbacks)); -} - -void ServiceWorkerGlobalScopeClient::Focus( - const WebString& client_uuid, - std::unique_ptr<WebServiceWorkerClientCallbacks> callback) { - client_.Focus(client_uuid, std::move(callback)); +void ServiceWorkerGlobalScopeClient::BindServiceWorkerHost( + mojom::blink::ServiceWorkerHostAssociatedPtrInfo service_worker_host) { + DCHECK(service_worker_host.is_valid()); + DCHECK(!service_worker_host_); + service_worker_host_.Bind(std::move(service_worker_host)); } -void ServiceWorkerGlobalScopeClient::Navigate( - const WebString& client_uuid, - const WebURL& url, - std::unique_ptr<WebServiceWorkerClientCallbacks> callback) { - client_.Navigate(client_uuid, url, std::move(callback)); +void ServiceWorkerGlobalScopeClient::WillDestroyWorkerContext() { + service_worker_host_.reset(); } const char ServiceWorkerGlobalScopeClient::kSupplementName[] = diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h index 91096359d82..a5336ece430 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h @@ -32,128 +32,138 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_GLOBAL_SCOPE_CLIENT_H_ #include <memory> -#include "third_party/blink/public/common/message_port/transferable_message.h" + +#include "base/macros.h" +#include "third_party/blink/public/common/messaging/transferable_message.h" +#include "third_party/blink/public/mojom/service_worker/service_worker.mojom-blink.h" #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-blink.h" -#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_claim_callbacks.h" -#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h" -#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_skip_waiting_callbacks.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_stream_handle.h" #include "third_party/blink/renderer/core/messaging/message_port.h" #include "third_party/blink/renderer/core/workers/worker_clients.h" #include "third_party/blink/renderer/modules/modules_export.h" -#include "third_party/blink/renderer/platform/wtf/forward.h" -#include "third_party/blink/renderer/platform/wtf/noncopyable.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { struct WebPaymentHandlerResponse; -struct WebServiceWorkerClientQueryOptions; class ExecutionContext; +class KURL; +class ScriptPromiseResolver; class WebServiceWorkerContextClient; class WebServiceWorkerResponse; -class WebURL; class WorkerClients; // See WebServiceWorkerContextClient for documentation for the methods in this // class. -class MODULES_EXPORT ServiceWorkerGlobalScopeClient - : public GarbageCollected<ServiceWorkerGlobalScopeClient>, +class MODULES_EXPORT ServiceWorkerGlobalScopeClient final + : public GarbageCollectedFinalized<ServiceWorkerGlobalScopeClient>, public Supplement<WorkerClients> { USING_GARBAGE_COLLECTED_MIXIN(ServiceWorkerGlobalScopeClient); - WTF_MAKE_NONCOPYABLE(ServiceWorkerGlobalScopeClient); public: + using ClaimCallback = mojom::blink::ServiceWorkerHost::ClaimClientsCallback; + using SkipWaitingCallback = + mojom::blink::ServiceWorkerHost::SkipWaitingCallback; + using GetClientCallback = mojom::blink::ServiceWorkerHost::GetClientCallback; + using GetClientsCallback = + mojom::blink::ServiceWorkerHost::GetClientsCallback; + using FocusCallback = mojom::blink::ServiceWorkerHost::FocusClientCallback; + static const char kSupplementName[]; explicit ServiceWorkerGlobalScopeClient(WebServiceWorkerContextClient&); // Called from ServiceWorkerClients. - void GetClient(const WebString&, - std::unique_ptr<WebServiceWorkerClientCallbacks>); - void GetClients(const WebServiceWorkerClientQueryOptions&, - std::unique_ptr<WebServiceWorkerClientsCallbacks>); - void OpenWindowForClients(const WebURL&, - std::unique_ptr<WebServiceWorkerClientCallbacks>); - void OpenWindowForPaymentHandler( - const WebURL&, - std::unique_ptr<WebServiceWorkerClientCallbacks>); - void SetCachedMetadata(const WebURL&, const char*, size_t); - void ClearCachedMetadata(const WebURL&); + void GetClient(const String&, GetClientCallback); + void GetClients(mojom::blink::ServiceWorkerClientQueryOptionsPtr, + GetClientsCallback); + void OpenWindowForClients(const KURL&, ScriptPromiseResolver*); + void OpenWindowForPaymentHandler(const KURL&, ScriptPromiseResolver*); + void SetCachedMetadata(const KURL&, const char*, size_t); + void ClearCachedMetadata(const KURL&); + void PostMessageToClient(const String& client_uuid, BlinkTransferableMessage); + void SkipWaiting(SkipWaitingCallback); + void Claim(ClaimCallback); + void Focus(const String& client_uuid, FocusCallback); + void Navigate(const String& client_uuid, const KURL&, ScriptPromiseResolver*); void DidHandleActivateEvent(int event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void DidHandleBackgroundFetchAbortEvent(int event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void DidHandleBackgroundFetchClickEvent(int event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void DidHandleBackgroundFetchFailEvent(int event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); - void DidHandleBackgroundFetchSuccessEvent(int event_id, - mojom::ServiceWorkerEventStatus, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); + void DidHandleBackgroundFetchSuccessEvent( + int event_id, + mojom::ServiceWorkerEventStatus, + base::TimeTicks event_dispatch_time); void DidHandleCookieChangeEvent(int event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void DidHandleExtendableMessageEvent(int event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); - void RespondToFetchEventWithNoResponse(int fetch_event_id, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); + void RespondToFetchEventWithNoResponse( + int fetch_event_id, + base::TimeTicks event_dispatch_time, + base::TimeTicks respond_with_settled_time); void RespondToFetchEvent(int fetch_event_id, const WebServiceWorkerResponse&, - double event_dispatch_time); - void RespondToFetchEventWithResponseStream(int fetch_event_id, - const WebServiceWorkerResponse&, - WebServiceWorkerStreamHandle*, - double event_dispatch_time); + base::TimeTicks event_dispatch_time, + base::TimeTicks respond_with_settled_time); + void RespondToFetchEventWithResponseStream( + int fetch_event_id, + const WebServiceWorkerResponse&, + WebServiceWorkerStreamHandle*, + base::TimeTicks event_dispatch_time, + base::TimeTicks respond_with_settled_time); void RespondToAbortPaymentEvent(int event_id, bool abort_payment, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void RespondToCanMakePaymentEvent(int event_id, bool can_make_payment, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void RespondToPaymentRequestEvent(int event_id, const WebPaymentHandlerResponse&, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void DidHandleFetchEvent(int fetch_event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void DidHandleInstallEvent(int install_event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void DidHandleNotificationClickEvent(int event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void DidHandleNotificationCloseEvent(int event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void DidHandlePushEvent(int push_event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void DidHandleSyncEvent(int sync_event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void DidHandleAbortPaymentEvent(int abort_payment_event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void DidHandleCanMakePaymentEvent(int payment_request_event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); + base::TimeTicks event_dispatch_time); void DidHandlePaymentRequestEvent(int payment_request_event_id, mojom::ServiceWorkerEventStatus, - double event_dispatch_time); - void PostMessageToClient(const WebString& client_uuid, TransferableMessage); - void SkipWaiting(std::unique_ptr<WebServiceWorkerSkipWaitingCallbacks>); - void Claim(std::unique_ptr<WebServiceWorkerClientsClaimCallbacks>); - void Focus(const WebString& client_uuid, - std::unique_ptr<WebServiceWorkerClientCallbacks>); - void Navigate(const WebString& client_uuid, - const WebURL&, - std::unique_ptr<WebServiceWorkerClientCallbacks>); + base::TimeTicks event_dispatch_time); + + void BindServiceWorkerHost( + mojom::blink::ServiceWorkerHostAssociatedPtrInfo service_worker_host); + + void WillDestroyWorkerContext(); static ServiceWorkerGlobalScopeClient* From(ExecutionContext*); @@ -161,6 +171,14 @@ class MODULES_EXPORT ServiceWorkerGlobalScopeClient private: WebServiceWorkerContextClient& client_; + + // Lives on the service worker thread, is bound by BindServiceWorkerHost() + // which is triggered by the first Mojo call received on the service worker + // thread content::mojom::ServiceWorker::InitializeGlobalScope(), and is + // closed by WillDestroyWorkerContext(). + mojom::blink::ServiceWorkerHostAssociatedPtr service_worker_host_; + + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerGlobalScopeClient); }; MODULES_EXPORT void ProvideServiceWorkerGlobalScopeClientToWorker( diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc index f55fc9ae2e1..f5dd6631a21 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc @@ -34,9 +34,9 @@ #include <utility> #include "base/memory/ptr_util.h" +#include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h" #include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom-blink.h" #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-blink.h" -#include "third_party/blink/public/platform/modules/notifications/notification.mojom-blink.h" #include "third_party/blink/public/platform/modules/notifications/web_notification_data.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h" #include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h" @@ -182,8 +182,13 @@ void ServiceWorkerGlobalScopeProxy::Trace(blink::Visitor* visitor) { visitor->Trace(parent_execution_context_task_runners_); } -void ServiceWorkerGlobalScopeProxy::ReadyToEvaluateScript() { - WorkerGlobalScope()->ReadyToEvaluateScript(); +void ServiceWorkerGlobalScopeProxy::BindServiceWorkerHost( + mojo::ScopedInterfaceEndpointHandle service_worker_host) { + DCHECK(WorkerGlobalScope()->IsContextThread()); + WorkerGlobalScope()->BindServiceWorkerHost( + mojom::blink::ServiceWorkerHostAssociatedPtrInfo( + std::move(service_worker_host), + mojom::blink::ServiceWorkerHost::Version_)); } void ServiceWorkerGlobalScopeProxy::SetRegistration( @@ -192,6 +197,10 @@ void ServiceWorkerGlobalScopeProxy::SetRegistration( WorkerGlobalScope()->SetRegistration(std::move(handle)); } +void ServiceWorkerGlobalScopeProxy::ReadyToEvaluateScript() { + WorkerGlobalScope()->ReadyToEvaluateScript(); +} + void ServiceWorkerGlobalScopeProxy::DispatchBackgroundFetchAbortEvent( int event_id, const WebBackgroundFetchRegistration& registration) { @@ -348,7 +357,7 @@ void ServiceWorkerGlobalScopeProxy::DispatchExtendableMessageEvent( int event_id, TransferableMessage message, const WebSecurityOrigin& source_origin, - std::unique_ptr<WebServiceWorker::Handle> handle) { + WebServiceWorkerObjectInfo info) { DCHECK(WorkerGlobalScope()->IsContextThread()); auto msg = ToBlinkTransferableMessage(std::move(message)); MessagePortArray* ports = @@ -356,9 +365,8 @@ void ServiceWorkerGlobalScopeProxy::DispatchExtendableMessageEvent( String origin; if (!source_origin.IsOpaque()) origin = source_origin.ToString(); - ServiceWorker* source = - ServiceWorker::From(worker_global_scope_->GetExecutionContext(), - base::WrapUnique(handle.release())); + ServiceWorker* source = ServiceWorker::From( + worker_global_scope_->GetExecutionContext(), std::move(info)); WaitUntilObserver* observer = WaitUntilObserver::Create( WorkerGlobalScope(), WaitUntilObserver::kMessage, event_id); @@ -409,7 +417,7 @@ void ServiceWorkerGlobalScopeProxy::DispatchFetchEvent( void ServiceWorkerGlobalScopeProxy::OnNavigationPreloadResponse( int fetch_event_id, std::unique_ptr<WebURLResponse> response, - std::unique_ptr<WebDataConsumerHandle> data_consume_handle) { + mojo::ScopedDataPipeConsumerHandle data_pipe) { DCHECK(WorkerGlobalScope()->IsContextThread()); auto it = pending_preload_fetch_events_.find(fetch_event_id); DCHECK(it != pending_preload_fetch_events_.end()); @@ -417,7 +425,7 @@ void ServiceWorkerGlobalScopeProxy::OnNavigationPreloadResponse( DCHECK(fetch_event); fetch_event->OnNavigationPreloadResponse( WorkerGlobalScope()->ScriptController()->GetScriptState(), - std::move(response), std::move(data_consume_handle)); + std::move(response), std::move(data_pipe)); } void ServiceWorkerGlobalScopeProxy::OnNavigationPreloadError( @@ -426,11 +434,15 @@ void ServiceWorkerGlobalScopeProxy::OnNavigationPreloadError( DCHECK(WorkerGlobalScope()->IsContextThread()); FetchEvent* fetch_event = pending_preload_fetch_events_.Take(fetch_event_id); DCHECK(fetch_event); - // Display an unsanitized console message. - if (!error->unsanitized_message.IsEmpty()) { + // Display an error message to the console, preferring the unsanitized one if + // available. + const WebString& error_message = error->unsanitized_message.IsEmpty() + ? error->message + : error->unsanitized_message; + if (!error_message.IsEmpty()) { WorkerGlobalScope()->AddConsoleMessage(ConsoleMessage::Create( kWorkerMessageSource, blink::MessageLevel::kErrorMessageLevel, - error->unsanitized_message)); + error_message)); } // Reject the preloadResponse promise. fetch_event->OnNavigationPreloadError( @@ -650,8 +662,11 @@ void ServiceWorkerGlobalScopeProxy::WillEvaluateClassicScript( size_t script_size, size_t cached_metadata_size) { DCHECK(WorkerGlobalScope()->IsContextThread()); + // TODO(asamidoi): Remove CountWorkerScript which is called for recording + // metrics if the metrics are no longer referenced, and then merge + // WillEvaluateClassicScript and WillEvaluateModuleScript for cleanup. worker_global_scope_->CountWorkerScript(script_size, cached_metadata_size); - Client().WillEvaluateClassicScript(); + Client().WillEvaluateScript(); } void ServiceWorkerGlobalScopeProxy::WillEvaluateImportedClassicScript( @@ -661,10 +676,21 @@ void ServiceWorkerGlobalScopeProxy::WillEvaluateImportedClassicScript( worker_global_scope_->CountImportedScript(script_size, cached_metadata_size); } +void ServiceWorkerGlobalScopeProxy::WillEvaluateModuleScript() { + DCHECK(WorkerGlobalScope()->IsContextThread()); + Client().WillEvaluateScript(); +} + void ServiceWorkerGlobalScopeProxy::DidEvaluateClassicScript(bool success) { DCHECK(WorkerGlobalScope()->IsContextThread()); - WorkerGlobalScope()->DidEvaluateClassicScript(); - Client().DidEvaluateClassicScript(success); + WorkerGlobalScope()->DidEvaluateScript(); + Client().DidEvaluateScript(success); +} + +void ServiceWorkerGlobalScopeProxy::DidEvaluateModuleScript(bool success) { + DCHECK(WorkerGlobalScope()->IsContextThread()); + WorkerGlobalScope()->DidEvaluateScript(); + Client().DidEvaluateScript(success); } void ServiceWorkerGlobalScopeProxy::DidCloseWorkerGlobalScope() { diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h index aad7210a856..374e56e66e7 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h @@ -38,7 +38,7 @@ #include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h" #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h" #include "third_party/blink/renderer/platform/heap/handle.h" -#include "third_party/blink/renderer/platform/heap/heap_allocator.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/time.h" @@ -48,7 +48,6 @@ namespace blink { class FetchEvent; class ParentExecutionContextTaskRunners; class ServiceWorkerGlobalScope; -class WebDataConsumerHandle; class WebEmbeddedWorkerImpl; class WebServiceWorkerContextClient; struct WebServiceWorkerError; @@ -77,9 +76,13 @@ class ServiceWorkerGlobalScopeProxy final ~ServiceWorkerGlobalScopeProxy() override; // WebServiceWorkerContextProxy overrides: - void ReadyToEvaluateScript() override; + void BindServiceWorkerHost( + mojo::ScopedInterfaceEndpointHandle service_worker_host) override; void SetRegistration( std::unique_ptr<WebServiceWorkerRegistration::Handle>) override; + // Must be called after the above BindServiceWorkerHost() and + // SetRegistration() got called. + void ReadyToEvaluateScript() override; void DispatchActivateEvent(int) override; void DispatchBackgroundFetchAbortEvent( int event_id, @@ -102,11 +105,10 @@ class ServiceWorkerGlobalScopeProxy final TransferableMessage, const WebSecurityOrigin& source_origin, const WebServiceWorkerClientInfo&) override; - void DispatchExtendableMessageEvent( - int event_id, - TransferableMessage, - const WebSecurityOrigin& source_origin, - std::unique_ptr<WebServiceWorker::Handle>) override; + void DispatchExtendableMessageEvent(int event_id, + TransferableMessage, + const WebSecurityOrigin& source_origin, + WebServiceWorkerObjectInfo) override; void DispatchFetchEvent(int fetch_event_id, const WebServiceWorkerRequest&, bool navigation_preload_sent) override; @@ -130,7 +132,7 @@ class ServiceWorkerGlobalScopeProxy final void OnNavigationPreloadResponse( int fetch_event_id, std::unique_ptr<WebURLResponse>, - std::unique_ptr<WebDataConsumerHandle>) override; + mojo::ScopedDataPipeConsumerHandle data_pipe) override; void OnNavigationPreloadError( int fetch_event_id, std::unique_ptr<WebServiceWorkerError>) override; @@ -158,7 +160,9 @@ class ServiceWorkerGlobalScopeProxy final size_t cached_metadata_size) override; void WillEvaluateImportedClassicScript(size_t script_size, size_t cached_metadata_size) override; + void WillEvaluateModuleScript() override; void DidEvaluateClassicScript(bool success) override; + void DidEvaluateModuleScript(bool success) override; void DidCloseWorkerGlobalScope() override; void WillDestroyWorkerGlobalScope() override; void DidTerminateWorkerThread() override; diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc index 8138d1b4290..b42870a6348 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.cc @@ -7,36 +7,269 @@ #include <memory> #include <utility> +#include "base/barrier_closure.h" +#include "base/threading/thread_checker.h" +#include "mojo/public/cpp/bindings/strong_binding.h" #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_thread.h" +#include "third_party/blink/renderer/platform/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/wtf/functional.h" +#include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { +using RawScriptData = ThreadSafeScriptContainer::RawScriptData; + +namespace { + +// Receiver is a class to read a Mojo data pipe. Received data are stored in +// chunks. Lives on the IO thread. Receiver is owned by Internal via +// BundledReceivers. It is created to read the script body or metadata from a +// data pipe, and is destroyed when the read finishes. +class Receiver { + public: + using BytesChunk = Vector<char>; + + Receiver(mojo::ScopedDataPipeConsumerHandle handle, + uint64_t total_bytes, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : handle_(std::move(handle)), + watcher_(FROM_HERE, + mojo::SimpleWatcher::ArmingPolicy::MANUAL, + std::move(task_runner)), + remaining_bytes_(total_bytes) {} + + void Start(base::OnceClosure callback) { + if (!handle_.is_valid()) { + std::move(callback).Run(); + return; + } + callback_ = std::move(callback); + // Unretained is safe because |watcher_| is owned by |this|. + MojoResult rv = watcher_.Watch( + handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, + WTF::BindRepeating(&Receiver::OnReadable, WTF::Unretained(this))); + DCHECK_EQ(MOJO_RESULT_OK, rv); + watcher_.ArmOrNotify(); + } + + void OnReadable(MojoResult) { + // It isn't necessary to handle MojoResult here since BeginReadDataRaw() + // returns an equivalent error. + const void* buffer = nullptr; + uint32_t bytes_read = 0; + MojoResult rv = + handle_->BeginReadData(&buffer, &bytes_read, MOJO_READ_DATA_FLAG_NONE); + switch (rv) { + case MOJO_RESULT_BUSY: + case MOJO_RESULT_INVALID_ARGUMENT: + NOTREACHED(); + return; + case MOJO_RESULT_FAILED_PRECONDITION: + // Closed by peer. + OnCompleted(); + return; + case MOJO_RESULT_SHOULD_WAIT: + watcher_.ArmOrNotify(); + return; + case MOJO_RESULT_OK: + break; + default: + // mojo::BeginReadDataRaw() should not return any other values. + // Notify the error to the browser by resetting the handle even though + // it's in the middle of data transfer. + OnCompleted(); + return; + } + + if (bytes_read > 0) { + BytesChunk chunk; + chunk.Append(static_cast<const char*>(buffer), bytes_read); + chunks_.emplace_back(std::move(chunk)); + } + rv = handle_->EndReadData(bytes_read); + DCHECK_EQ(rv, MOJO_RESULT_OK); + CHECK_GE(remaining_bytes_, bytes_read); + remaining_bytes_ -= bytes_read; + watcher_.ArmOrNotify(); + } + + bool is_running() const { return handle_.is_valid(); } + bool has_received_all_data() const { return remaining_bytes_ == 0; } + + Vector<BytesChunk> TakeChunks() { + DCHECK(!is_running()); + return std::move(chunks_); + } + + private: + void OnCompleted() { + handle_.reset(); + watcher_.Cancel(); + if (!has_received_all_data()) + chunks_.clear(); + DCHECK(callback_); + std::move(callback_).Run(); + } + + base::OnceClosure callback_; + mojo::ScopedDataPipeConsumerHandle handle_; + mojo::SimpleWatcher watcher_; + + Vector<BytesChunk> chunks_; + uint64_t remaining_bytes_; +}; + +// BundledReceivers is a helper class to wait for the end of reading body and +// meta data. Lives on the IO thread. +class BundledReceivers { + public: + BundledReceivers(mojo::ScopedDataPipeConsumerHandle meta_data_handle, + uint64_t meta_data_size, + mojo::ScopedDataPipeConsumerHandle body_handle, + uint64_t body_size, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : meta_data_(std::move(meta_data_handle), meta_data_size, task_runner), + body_(std::move(body_handle), body_size, std::move(task_runner)) {} + + // Starts reading the pipes and invokes |callback| when both are finished. + void Start(base::OnceClosure callback) { + base::RepeatingClosure wait_all_closure = + base::BarrierClosure(2, std::move(callback)); + meta_data_.Start(wait_all_closure); + body_.Start(wait_all_closure); + } + + Receiver* meta_data() { return &meta_data_; } + Receiver* body() { return &body_; } + + private: + Receiver meta_data_; + Receiver body_; +}; + +// Internal lives on the IO thread. This receives +// mojom::blink::ServiceWorkerScriptInfo for all installed scripts and then +// starts reading the body and meta data from the browser. This instance will be +// kept alive as long as the Mojo's connection is established. +class Internal : public mojom::blink::ServiceWorkerInstalledScriptsManager { + public: + // Called on the IO thread. + // Creates and binds a new Internal instance to |request|. + static void Create( + scoped_refptr<ThreadSafeScriptContainer> script_container, + mojom::blink::ServiceWorkerInstalledScriptsManagerRequest request, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + mojo::MakeStrongBinding( + std::make_unique<Internal>(std::move(script_container), + std::move(task_runner)), + std::move(request)); + } + + Internal(scoped_refptr<ThreadSafeScriptContainer> script_container, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : script_container_(std::move(script_container)), + task_runner_(std::move(task_runner)), + weak_factory_(this) {} + + ~Internal() override { + DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_); + // Wake up a waiting thread so it does not wait forever. If the script has + // not been added yet, that means something went wrong. From here, + // script_container_->Wait() will return false if the script hasn't been + // added yet. + script_container_->OnAllDataAddedOnIOThread(); + } + + // Implements mojom::blink::ServiceWorkerInstalledScriptsManager. + // Called on the IO thread. + void TransferInstalledScript( + mojom::blink::ServiceWorkerScriptInfoPtr script_info) override { + DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_); + KURL script_url(script_info->script_url); + auto receivers = std::make_unique<BundledReceivers>( + std::move(script_info->meta_data), script_info->meta_data_size, + std::move(script_info->body), script_info->body_size, task_runner_); + receivers->Start(WTF::Bind(&Internal::OnScriptReceived, + weak_factory_.GetWeakPtr(), + std::move(script_info))); + DCHECK(!running_receivers_.Contains(script_url)); + running_receivers_.insert(script_url, std::move(receivers)); + } + + // Called on the IO thread. + void OnScriptReceived(mojom::blink::ServiceWorkerScriptInfoPtr script_info) { + DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_); + auto iter = running_receivers_.find(script_info->script_url); + DCHECK(iter != running_receivers_.end()); + std::unique_ptr<BundledReceivers> receivers = std::move(iter->value); + DCHECK(receivers); + if (!receivers->body()->has_received_all_data() || + !receivers->meta_data()->has_received_all_data()) { + script_container_->AddOnIOThread(script_info->script_url, + nullptr /* data */); + running_receivers_.erase(iter); + return; + } + + auto script_data = RawScriptData::Create( + script_info->encoding, receivers->body()->TakeChunks(), + receivers->meta_data()->TakeChunks()); + for (const auto& entry : script_info->headers) + script_data->AddHeader(entry.key, entry.value); + script_container_->AddOnIOThread(script_info->script_url, + std::move(script_data)); + running_receivers_.erase(iter); + } + + private: + THREAD_CHECKER(io_thread_checker_); + HashMap<KURL, std::unique_ptr<BundledReceivers>> running_receivers_; + scoped_refptr<ThreadSafeScriptContainer> script_container_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + base::WeakPtrFactory<Internal> weak_factory_; +}; + +} // namespace + ServiceWorkerInstalledScriptsManager::ServiceWorkerInstalledScriptsManager( - std::unique_ptr<WebServiceWorkerInstalledScriptsManager> manager) - : manager_(std::move(manager)) { - DCHECK(manager_); + const Vector<KURL>& installed_urls, + mojom::blink::ServiceWorkerInstalledScriptsManagerRequest manager_request, + mojom::blink::ServiceWorkerInstalledScriptsManagerHostPtrInfo + manager_host_ptr, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) + : script_container_(base::MakeRefCounted<ThreadSafeScriptContainer>()), + manager_host_( + mojom::blink::ThreadSafeServiceWorkerInstalledScriptsManagerHostPtr:: + Create(mojom::blink::ServiceWorkerInstalledScriptsManagerHostPtr( + std::move(manager_host_ptr)))) { + // We're on the main thread now, but |installed_urls_| will be accessed on the + // worker thread later, so make a deep copy of |url| as key. + for (const KURL& url : installed_urls) + installed_urls_.insert(url.Copy()); + io_task_runner->PostTask( + FROM_HERE, ConvertToBaseCallback(CrossThreadBind( + &Internal::Create, script_container_, + WTF::Passed(std::move(manager_request)), io_task_runner))); } bool ServiceWorkerInstalledScriptsManager::IsScriptInstalled( const KURL& script_url) const { - return manager_->IsScriptInstalled(script_url); + return installed_urls_.Contains(script_url); } -InstalledScriptsManager::ScriptStatus -ServiceWorkerInstalledScriptsManager::GetScriptData( - const KURL& script_url, - InstalledScriptsManager::ScriptData* out_script_data) { +std::unique_ptr<InstalledScriptsManager::ScriptData> +ServiceWorkerInstalledScriptsManager::GetScriptData(const KURL& script_url) { DCHECK(!IsMainThread()); + if (!IsScriptInstalled(script_url)) + return nullptr; + // This blocks until the script is received from the browser. - std::unique_ptr<WebServiceWorkerInstalledScriptsManager::RawScriptData> - raw_script_data = manager_->GetRawScriptData(script_url); - DCHECK(raw_script_data); - if (!raw_script_data->IsValid()) { - *out_script_data = InstalledScriptsManager::ScriptData(); - return ScriptStatus::kFailed; - } + std::unique_ptr<RawScriptData> raw_script_data = GetRawScriptData(script_url); + if (!raw_script_data) + return nullptr; // This is from WorkerClassicScriptLoader::DidReceiveData. std::unique_ptr<TextResourceDecoder> decoder = @@ -48,7 +281,7 @@ ServiceWorkerInstalledScriptsManager::GetScriptData( StringBuilder source_text_builder; for (const auto& chunk : raw_script_data->ScriptTextChunks()) - source_text_builder.Append(decoder->Decode(chunk.Data(), chunk.size())); + source_text_builder.Append(decoder->Decode(chunk.data(), chunk.size())); std::unique_ptr<Vector<char>> meta_data; if (raw_script_data->MetaDataChunks().size() > 0) { @@ -58,14 +291,43 @@ ServiceWorkerInstalledScriptsManager::GetScriptData( meta_data = std::make_unique<Vector<char>>(); meta_data->ReserveInitialCapacity(total_metadata_size); for (const auto& chunk : raw_script_data->MetaDataChunks()) - meta_data->Append(chunk.Data(), chunk.size()); + meta_data->Append(chunk.data(), chunk.size()); } - InstalledScriptsManager::ScriptData script_data( + return std::make_unique<InstalledScriptsManager::ScriptData>( script_url, source_text_builder.ToString(), std::move(meta_data), raw_script_data->TakeHeaders()); - *out_script_data = std::move(script_data); - return ScriptStatus::kSuccess; +} + +std::unique_ptr<RawScriptData> +ServiceWorkerInstalledScriptsManager::GetRawScriptData(const KURL& script_url) { + ThreadSafeScriptContainer::ScriptStatus status = + script_container_->GetStatusOnWorkerThread(script_url); + // If the script has already been taken, request the browser to send the + // script. + if (status == ThreadSafeScriptContainer::ScriptStatus::kTaken) { + script_container_->ResetOnWorkerThread(script_url); + (*manager_host_)->RequestInstalledScript(script_url); + status = script_container_->GetStatusOnWorkerThread(script_url); + } + + // If the script has not been received at this point, wait for arrival by + // blocking the worker thread. + if (status == ThreadSafeScriptContainer::ScriptStatus::kPending) { + // Wait for arrival of the script. + const bool success = script_container_->WaitOnWorkerThread(script_url); + // It can fail due to an error on Mojo pipes. + if (!success) + return nullptr; + status = script_container_->GetStatusOnWorkerThread(script_url); + DCHECK_NE(ThreadSafeScriptContainer::ScriptStatus::kPending, status); + } + + if (status == ThreadSafeScriptContainer::ScriptStatus::kFailed) + return nullptr; + DCHECK_EQ(ThreadSafeScriptContainer::ScriptStatus::kReceived, status); + + return script_container_->TakeOnWorkerThread(script_url); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.h index 91e909807ca..1312019537f 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.h @@ -5,29 +5,47 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_INSTALLED_SCRIPTS_MANAGER_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_INSTALLED_SCRIPTS_MANAGER_H_ -#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_installed_scripts_manager.h" +#include "third_party/blink/public/mojom/service_worker/service_worker_installed_scripts_manager.mojom-blink.h" #include "third_party/blink/renderer/core/workers/installed_scripts_manager.h" +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/modules/service_worker/thread_safe_script_container.h" +#include "third_party/blink/renderer/platform/weborigin/kurl.h" +#include "third_party/blink/renderer/platform/weborigin/kurl_hash.h" +#include "third_party/blink/renderer/platform/wtf/hash_set.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { // ServiceWorkerInstalledScriptsManager provides the main script and imported // scripts of an installed service worker. The scripts are streamed from the // browser process in parallel with worker thread initialization. -class ServiceWorkerInstalledScriptsManager final +class MODULES_EXPORT ServiceWorkerInstalledScriptsManager : public InstalledScriptsManager { public: - explicit ServiceWorkerInstalledScriptsManager( - std::unique_ptr<WebServiceWorkerInstalledScriptsManager>); + ServiceWorkerInstalledScriptsManager( + const Vector<KURL>& installed_urls, + mojom::blink::ServiceWorkerInstalledScriptsManagerRequest, + mojom::blink::ServiceWorkerInstalledScriptsManagerHostPtrInfo, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); + virtual ~ServiceWorkerInstalledScriptsManager() = default; // InstalledScriptsManager implementation. bool IsScriptInstalled(const KURL& script_url) const override; - ScriptStatus GetScriptData(const KURL& script_url, - ScriptData* out_script_data) override; + std::unique_ptr<ScriptData> GetScriptData(const KURL& script_url) override; private: - std::unique_ptr<WebServiceWorkerInstalledScriptsManager> manager_; + friend class ServiceWorkerInstalledScriptsManagerTest; + + std::unique_ptr<ThreadSafeScriptContainer::RawScriptData> GetRawScriptData( + const KURL& script_url); + + HashSet<KURL> installed_urls_; + scoped_refptr<ThreadSafeScriptContainer> script_container_; + scoped_refptr< + mojom::blink::ThreadSafeServiceWorkerInstalledScriptsManagerHostPtr> + manager_host_; }; } // namespace blink -#endif // WorkerInstalledScriptsManager_h +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_INSTALLED_SCRIPTS_MANAGER_H_ diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager_test.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager_test.cc new file mode 100644 index 00000000000..2c41d7c7168 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager_test.cc @@ -0,0 +1,428 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.h" + +#include "base/run_loop.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/mojom/service_worker/service_worker_installed_scripts_manager.mojom-blink.h" +#include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/renderer/platform/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" +#include "third_party/blink/renderer/platform/waitable_event.h" +#include "third_party/blink/renderer/platform/web_task_runner.h" +#include "third_party/blink/renderer/platform/wtf/functional.h" + +namespace blink { + +namespace { + +class BrowserSideSender + : mojom::blink::ServiceWorkerInstalledScriptsManagerHost { + public: + BrowserSideSender() : binding_(this) {} + ~BrowserSideSender() override = default; + + mojom::blink::ServiceWorkerInstalledScriptsInfoPtr CreateAndBind( + const Vector<KURL>& installed_urls) { + EXPECT_FALSE(manager_.is_bound()); + EXPECT_FALSE(body_handle_.is_valid()); + EXPECT_FALSE(meta_data_handle_.is_valid()); + auto scripts_info = mojom::blink::ServiceWorkerInstalledScriptsInfo::New(); + scripts_info->installed_urls = installed_urls; + scripts_info->manager_request = mojo::MakeRequest(&manager_); + binding_.Bind(mojo::MakeRequest(&scripts_info->manager_host_ptr)); + return scripts_info; + } + + void TransferInstalledScript(const KURL& script_url, + const String& encoding, + const HashMap<String, String>& headers, + int64_t body_size, + int64_t meta_data_size) { + EXPECT_FALSE(body_handle_.is_valid()); + EXPECT_FALSE(meta_data_handle_.is_valid()); + auto script_info = mojom::blink::ServiceWorkerScriptInfo::New(); + script_info->script_url = script_url; + script_info->encoding = encoding; + script_info->headers = headers; + EXPECT_EQ(MOJO_RESULT_OK, + mojo::CreateDataPipe(nullptr, &body_handle_, &script_info->body)); + EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(nullptr, &meta_data_handle_, + &script_info->meta_data)); + script_info->body_size = body_size; + script_info->meta_data_size = meta_data_size; + manager_->TransferInstalledScript(std::move(script_info)); + } + + void PushBody(const std::string& data) { + PushDataPipe(data, body_handle_.get()); + } + + void PushMetaData(const std::string& data) { + PushDataPipe(data, meta_data_handle_.get()); + } + + void FinishTransferBody() { body_handle_.reset(); } + + void FinishTransferMetaData() { meta_data_handle_.reset(); } + + void ResetManager() { manager_.reset(); } + + void WaitForRequestInstalledScript(const KURL& script_url) { + waiting_requested_url_ = script_url; + base::RunLoop loop; + requested_script_closure_ = loop.QuitClosure(); + loop.Run(); + } + + private: + void RequestInstalledScript(const KURL& script_url) override { + EXPECT_EQ(waiting_requested_url_, script_url); + ASSERT_TRUE(requested_script_closure_); + std::move(requested_script_closure_).Run(); + } + + void PushDataPipe(const std::string& data, + const mojo::DataPipeProducerHandle& handle) { + // Send |data| with null terminator. + ASSERT_TRUE(handle.is_valid()); + uint32_t written_bytes = data.size() + 1; + MojoResult rv = handle.WriteData(data.c_str(), &written_bytes, + MOJO_WRITE_DATA_FLAG_NONE); + ASSERT_EQ(MOJO_RESULT_OK, rv); + ASSERT_EQ(data.size() + 1, written_bytes); + } + + base::OnceClosure requested_script_closure_; + KURL waiting_requested_url_; + + mojom::blink::ServiceWorkerInstalledScriptsManagerPtr manager_; + mojo::Binding<mojom::blink::ServiceWorkerInstalledScriptsManagerHost> + binding_; + + mojo::ScopedDataPipeProducerHandle body_handle_; + mojo::ScopedDataPipeProducerHandle meta_data_handle_; + + DISALLOW_COPY_AND_ASSIGN(BrowserSideSender); +}; + +CrossThreadHTTPHeaderMapData ToCrossThreadHTTPHeaderMapData( + const HashMap<String, String>& headers) { + CrossThreadHTTPHeaderMapData data; + for (const auto& entry : headers) + data.emplace_back(entry.key, entry.value); + return data; +} + +} // namespace + +class ServiceWorkerInstalledScriptsManagerTest : public testing::Test { + public: + ServiceWorkerInstalledScriptsManagerTest() + : io_thread_(Platform::Current()->CreateThread( + ThreadCreationParams(WebThreadType::kTestThread) + .SetThreadNameForTest("io thread"))), + worker_thread_(Platform::Current()->CreateThread( + ThreadCreationParams(WebThreadType::kTestThread) + .SetThreadNameForTest("worker thread"))) {} + + protected: + using RawScriptData = ThreadSafeScriptContainer::RawScriptData; + + void CreateInstalledScriptsManager( + mojom::blink::ServiceWorkerInstalledScriptsInfoPtr + installed_scripts_info) { + installed_scripts_manager_ = + std::make_unique<ServiceWorkerInstalledScriptsManager>( + std::move(installed_scripts_info->installed_urls), + std::move(installed_scripts_info->manager_request), + std::move(installed_scripts_info->manager_host_ptr), + io_thread_->GetTaskRunner()); + } + + WaitableEvent* IsScriptInstalledOnWorkerThread(const String& script_url, + bool* out_installed) { + PostCrossThreadTask( + *worker_thread_->GetTaskRunner(), FROM_HERE, + CrossThreadBind( + [](ServiceWorkerInstalledScriptsManager* installed_scripts_manager, + const String& script_url, bool* out_installed, + WaitableEvent* waiter) { + *out_installed = installed_scripts_manager->IsScriptInstalled( + KURL(script_url)); + waiter->Signal(); + }, + CrossThreadUnretained(installed_scripts_manager_.get()), script_url, + CrossThreadUnretained(out_installed), + CrossThreadUnretained(&worker_waiter_))); + return &worker_waiter_; + } + + WaitableEvent* GetRawScriptDataOnWorkerThread( + const String& script_url, + std::unique_ptr<RawScriptData>* out_data) { + PostCrossThreadTask( + *worker_thread_->GetTaskRunner(), FROM_HERE, + CrossThreadBind( + &ServiceWorkerInstalledScriptsManagerTest::CallGetRawScriptData, + CrossThreadUnretained(this), script_url, + CrossThreadUnretained(out_data), + CrossThreadUnretained(&worker_waiter_))); + return &worker_waiter_; + } + + private: + void CallGetRawScriptData(const String& script_url, + std::unique_ptr<RawScriptData>* out_data, + WaitableEvent* waiter) { + *out_data = installed_scripts_manager_->GetRawScriptData(KURL(script_url)); + waiter->Signal(); + } + + std::unique_ptr<Thread> io_thread_; + std::unique_ptr<Thread> worker_thread_; + + WaitableEvent worker_waiter_; + + std::unique_ptr<ServiceWorkerInstalledScriptsManager> + installed_scripts_manager_; + + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerInstalledScriptsManagerTest); +}; + +TEST_F(ServiceWorkerInstalledScriptsManagerTest, GetRawScriptData) { + const KURL kScriptUrl("https://example.com/installed1.js"); + const KURL kUnknownScriptUrl("https://example.com/not_installed.js"); + + BrowserSideSender sender; + CreateInstalledScriptsManager(sender.CreateAndBind({kScriptUrl})); + + { + bool result = false; + IsScriptInstalledOnWorkerThread(kScriptUrl, &result)->Wait(); + // IsScriptInstalled returns correct answer even before script transfer + // hasn't been started yet. + EXPECT_TRUE(result); + } + + { + bool result = true; + IsScriptInstalledOnWorkerThread(kUnknownScriptUrl, &result)->Wait(); + // IsScriptInstalled returns correct answer even before script transfer + // hasn't been started yet. + EXPECT_FALSE(result); + } + + { + std::unique_ptr<RawScriptData> script_data; + const std::string kExpectedBody = "This is a script body."; + const std::string kExpectedMetaData = "This is a meta data."; + const String kScriptInfoEncoding("utf8"); + const HashMap<String, String> kScriptInfoHeaders( + {{"Cache-Control", "no-cache"}, {"User-Agent", "Chrome"}}); + + WaitableEvent* get_raw_script_data_waiter = + GetRawScriptDataOnWorkerThread(kScriptUrl, &script_data); + + // Start transferring the script. +1 for null terminator. + sender.TransferInstalledScript(kScriptUrl, kScriptInfoEncoding, + kScriptInfoHeaders, kExpectedBody.size() + 1, + kExpectedMetaData.size() + 1); + sender.PushBody(kExpectedBody); + sender.PushMetaData(kExpectedMetaData); + // GetRawScriptData should be blocked until body and meta data transfer are + // finished. + EXPECT_FALSE(get_raw_script_data_waiter->IsSignaled()); + sender.FinishTransferBody(); + sender.FinishTransferMetaData(); + + // Wait for the script's arrival. + get_raw_script_data_waiter->Wait(); + EXPECT_TRUE(script_data); + ASSERT_EQ(1u, script_data->ScriptTextChunks().size()); + ASSERT_EQ(kExpectedBody.size() + 1, + script_data->ScriptTextChunks()[0].size()); + EXPECT_STREQ(kExpectedBody.data(), + script_data->ScriptTextChunks()[0].data()); + ASSERT_EQ(1u, script_data->MetaDataChunks().size()); + ASSERT_EQ(kExpectedMetaData.size() + 1, + script_data->MetaDataChunks()[0].size()); + EXPECT_STREQ(kExpectedMetaData.data(), + script_data->MetaDataChunks()[0].data()); + EXPECT_EQ(kScriptInfoEncoding, script_data->Encoding()); + EXPECT_EQ(ToCrossThreadHTTPHeaderMapData(kScriptInfoHeaders), + *(script_data->TakeHeaders())); + } + + { + std::unique_ptr<RawScriptData> script_data; + const std::string kExpectedBody = "This is another script body."; + const std::string kExpectedMetaData = "This is another meta data."; + const String kScriptInfoEncoding("ASCII"); + const HashMap<String, String> kScriptInfoHeaders( + {{"Connection", "keep-alive"}, {"Content-Length", "512"}}); + + // Request the same script again. + WaitableEvent* get_raw_script_data_waiter = + GetRawScriptDataOnWorkerThread(kScriptUrl, &script_data); + + // It should call a Mojo IPC "RequestInstalledScript()" to the browser. + sender.WaitForRequestInstalledScript(kScriptUrl); + + // Start transferring the script. +1 for null terminator. + sender.TransferInstalledScript(kScriptUrl, kScriptInfoEncoding, + kScriptInfoHeaders, kExpectedBody.size() + 1, + kExpectedMetaData.size() + 1); + sender.PushBody(kExpectedBody); + sender.PushMetaData(kExpectedMetaData); + // GetRawScriptData should be blocked until body and meta data transfer are + // finished. + EXPECT_FALSE(get_raw_script_data_waiter->IsSignaled()); + sender.FinishTransferBody(); + sender.FinishTransferMetaData(); + + // Wait for the script's arrival. + get_raw_script_data_waiter->Wait(); + EXPECT_TRUE(script_data); + ASSERT_EQ(1u, script_data->ScriptTextChunks().size()); + ASSERT_EQ(kExpectedBody.size() + 1, + script_data->ScriptTextChunks()[0].size()); + EXPECT_STREQ(kExpectedBody.data(), + script_data->ScriptTextChunks()[0].data()); + ASSERT_EQ(1u, script_data->MetaDataChunks().size()); + ASSERT_EQ(kExpectedMetaData.size() + 1, + script_data->MetaDataChunks()[0].size()); + EXPECT_STREQ(kExpectedMetaData.data(), + script_data->MetaDataChunks()[0].data()); + EXPECT_EQ(kScriptInfoEncoding, script_data->Encoding()); + EXPECT_EQ(ToCrossThreadHTTPHeaderMapData(kScriptInfoHeaders), + *(script_data->TakeHeaders())); + } +} + +TEST_F(ServiceWorkerInstalledScriptsManagerTest, EarlyDisconnectionBody) { + const KURL kScriptUrl("https://example.com/installed1.js"); + const KURL kUnknownScriptUrl("https://example.com/not_installed.js"); + + BrowserSideSender sender; + CreateInstalledScriptsManager(sender.CreateAndBind({kScriptUrl})); + + { + std::unique_ptr<RawScriptData> script_data; + const std::string kExpectedBody = "This is a script body."; + const std::string kExpectedMetaData = "This is a meta data."; + WaitableEvent* get_raw_script_data_waiter = + GetRawScriptDataOnWorkerThread(kScriptUrl, &script_data); + + // Start transferring the script. + // Body is expected to be 100 bytes larger than kExpectedBody, but sender + // only sends kExpectedBody and a null byte (kExpectedBody.size() + 1 bytes + // in total). + sender.TransferInstalledScript( + kScriptUrl, String::FromUTF8("utf8"), HashMap<String, String>(), + kExpectedBody.size() + 100, kExpectedMetaData.size() + 1); + sender.PushBody(kExpectedBody); + sender.PushMetaData(kExpectedMetaData); + // GetRawScriptData should be blocked until body and meta data transfer are + // finished. + EXPECT_FALSE(get_raw_script_data_waiter->IsSignaled()); + sender.FinishTransferBody(); + sender.FinishTransferMetaData(); + + // Wait for the script's arrival. + get_raw_script_data_waiter->Wait(); + // |script_data| should be null since the data pipe for body + // gets disconnected during sending. + EXPECT_FALSE(script_data); + } + + { + std::unique_ptr<RawScriptData> script_data; + GetRawScriptDataOnWorkerThread(kScriptUrl, &script_data)->Wait(); + // |script_data| should be null since the data wasn't received on the + // renderer process. + EXPECT_FALSE(script_data); + } +} + +TEST_F(ServiceWorkerInstalledScriptsManagerTest, EarlyDisconnectionMetaData) { + const KURL kScriptUrl("https://example.com/installed1.js"); + const KURL kUnknownScriptUrl("https://example.com/not_installed.js"); + + BrowserSideSender sender; + CreateInstalledScriptsManager(sender.CreateAndBind({kScriptUrl})); + + { + std::unique_ptr<RawScriptData> script_data; + const std::string kExpectedBody = "This is a script body."; + const std::string kExpectedMetaData = "This is a meta data."; + WaitableEvent* get_raw_script_data_waiter = + GetRawScriptDataOnWorkerThread(kScriptUrl, &script_data); + + // Start transferring the script. + // Meta data is expected to be 100 bytes larger than kExpectedMetaData, but + // sender only sends kExpectedMetaData and a null byte + // (kExpectedMetaData.size() + 1 bytes in total). + sender.TransferInstalledScript( + kScriptUrl, String::FromUTF8("utf8"), HashMap<String, String>(), + kExpectedBody.size() + 1, kExpectedMetaData.size() + 100); + sender.PushBody(kExpectedBody); + sender.PushMetaData(kExpectedMetaData); + // GetRawScriptData should be blocked until body and meta data transfer are + // finished. + EXPECT_FALSE(get_raw_script_data_waiter->IsSignaled()); + sender.FinishTransferBody(); + sender.FinishTransferMetaData(); + + // Wait for the script's arrival. + get_raw_script_data_waiter->Wait(); + // |script_data| should be null since the data pipe for meta data gets + // disconnected during sending. + EXPECT_FALSE(script_data); + } + + { + std::unique_ptr<RawScriptData> script_data; + GetRawScriptDataOnWorkerThread(kScriptUrl, &script_data)->Wait(); + // |script_data| should be null since the data wasn't received on the + // renderer process. + EXPECT_FALSE(script_data); + } +} + +TEST_F(ServiceWorkerInstalledScriptsManagerTest, EarlyDisconnectionManager) { + const KURL kScriptUrl("https://example.com/installed1.js"); + const KURL kUnknownScriptUrl("https://example.com/not_installed.js"); + + BrowserSideSender sender; + CreateInstalledScriptsManager(sender.CreateAndBind({kScriptUrl})); + + { + std::unique_ptr<RawScriptData> script_data; + WaitableEvent* get_raw_script_data_waiter = + GetRawScriptDataOnWorkerThread(kScriptUrl, &script_data); + + // Reset the Mojo connection before sending the script. + EXPECT_FALSE(get_raw_script_data_waiter->IsSignaled()); + sender.ResetManager(); + + // Wait for the script's arrival. + get_raw_script_data_waiter->Wait(); + // |script_data| should be nullptr since no data will arrive. + EXPECT_FALSE(script_data); + } + + { + std::unique_ptr<RawScriptData> script_data; + // This should not be blocked because data will not arrive anymore. + GetRawScriptDataOnWorkerThread(kScriptUrl, &script_data)->Wait(); + // |script_data| should be null since the data wasn't received on the + // renderer process. + EXPECT_FALSE(script_data); + } +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc index f65cf9c6ce9..bb515811db5 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc @@ -40,28 +40,22 @@ void ServiceWorkerRegistration::DispatchUpdateFoundEvent() { DispatchEvent(*Event::Create(EventTypeNames::updatefound)); } -void ServiceWorkerRegistration::SetInstalling( - std::unique_ptr<WebServiceWorker::Handle> handle) { +void ServiceWorkerRegistration::SetInstalling(WebServiceWorkerObjectInfo info) { if (!GetExecutionContext()) return; - installing_ = ServiceWorker::From(GetExecutionContext(), - base::WrapUnique(handle.release())); + installing_ = ServiceWorker::From(GetExecutionContext(), std::move(info)); } -void ServiceWorkerRegistration::SetWaiting( - std::unique_ptr<WebServiceWorker::Handle> handle) { +void ServiceWorkerRegistration::SetWaiting(WebServiceWorkerObjectInfo info) { if (!GetExecutionContext()) return; - waiting_ = ServiceWorker::From(GetExecutionContext(), - base::WrapUnique(handle.release())); + waiting_ = ServiceWorker::From(GetExecutionContext(), std::move(info)); } -void ServiceWorkerRegistration::SetActive( - std::unique_ptr<WebServiceWorker::Handle> handle) { +void ServiceWorkerRegistration::SetActive(WebServiceWorkerObjectInfo info) { if (!GetExecutionContext()) return; - active_ = ServiceWorker::From(GetExecutionContext(), - base::WrapUnique(handle.release())); + active_ = ServiceWorker::From(GetExecutionContext(), std::move(info)); } ServiceWorkerRegistration* ServiceWorkerRegistration::GetOrCreate( @@ -103,16 +97,13 @@ String ServiceWorkerRegistration::updateViaCache() const { } ScriptPromise ServiceWorkerRegistration::update(ScriptState* script_state) { - ServiceWorkerContainerClient* client = - ServiceWorkerContainerClient::From(GetExecutionContext()); - if (!client || !client->Provider()) { + if (!GetExecutionContext()) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError, "Failed to update a ServiceWorkerRegistration: No " "associated provider is available.")); } - ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); handle_->Registration()->Update( @@ -123,9 +114,7 @@ ScriptPromise ServiceWorkerRegistration::update(ScriptState* script_state) { } ScriptPromise ServiceWorkerRegistration::unregister(ScriptState* script_state) { - ServiceWorkerContainerClient* client = - ServiceWorkerContainerClient::From(GetExecutionContext()); - if (!client || !client->Provider()) { + if (!GetExecutionContext()) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError, @@ -133,7 +122,6 @@ ScriptPromise ServiceWorkerRegistration::unregister(ScriptState* script_state) { "ServiceWorkerRegistration: No " "associated provider is available.")); } - ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); handle_->Registration()->Unregister( diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.h index fbb096a32ad..70d5bbfed0a 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.h @@ -8,6 +8,7 @@ #include <memory> #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_registration.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_registration_proxy.h" +#include "third_party/blink/public/platform/web_vector.h" #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" @@ -54,9 +55,9 @@ class ServiceWorkerRegistration final // WebServiceWorkerRegistrationProxy overrides. void DispatchUpdateFoundEvent() override; - void SetInstalling(std::unique_ptr<WebServiceWorker::Handle>) override; - void SetWaiting(std::unique_ptr<WebServiceWorker::Handle>) override; - void SetActive(std::unique_ptr<WebServiceWorker::Handle>) override; + void SetInstalling(WebServiceWorkerObjectInfo) override; + void SetWaiting(WebServiceWorkerObjectInfo) override; + void SetActive(WebServiceWorkerObjectInfo) override; // Returns an existing registration object for the handle if it exists. // Otherwise, returns a new registration object. diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.idl b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.idl index a50faeb704d..21795936964 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.idl +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_registration.idl @@ -3,9 +3,7 @@ // found in the LICENSE file. // https://w3c.github.io/ServiceWorker/#enumdef-serviceworkerupdateviacache -[ - RuntimeEnabled=ServiceWorkerUpdateViaCache -] enum ServiceWorkerUpdateViaCache { +enum ServiceWorkerUpdateViaCache { "imports", "all", "none" @@ -23,7 +21,7 @@ readonly attribute NavigationPreloadManager navigationPreload; readonly attribute USVString scope; - [RuntimeEnabled=ServiceWorkerUpdateViaCache] readonly attribute ServiceWorkerUpdateViaCache updateViaCache; + readonly attribute ServiceWorkerUpdateViaCache updateViaCache; [CallWith=ScriptState] Promise<ServiceWorkerRegistration> update(); [CallWith=ScriptState] Promise<boolean> unregister(); diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.cc index 1cec901709b..338ac091918 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_thread.cc @@ -47,8 +47,8 @@ ServiceWorkerThread::ServiceWorkerThread( mojom::blink::CacheStoragePtrInfo cache_storage_info) : WorkerThread(*global_scope_proxy), global_scope_proxy_(global_scope_proxy), - worker_backing_thread_(WorkerBackingThread::Create( - WebThreadCreationParams(GetThreadType()))), + worker_backing_thread_( + WorkerBackingThread::Create(ThreadCreationParams(GetThreadType()))), installed_scripts_manager_(std::move(installed_scripts_manager)), cache_storage_info_(std::move(cache_storage_info)) {} diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.cc index d3849e40e7e..6e9f32087dd 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.cc @@ -16,19 +16,39 @@ #include "third_party/blink/renderer/core/workers/worker_location.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_error.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h" -#include "third_party/blink/renderer/modules/service_worker/service_worker_window_client_callback.h" #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h" namespace blink { -ServiceWorkerWindowClient* ServiceWorkerWindowClient::Take( - ScriptPromiseResolver*, - std::unique_ptr<WebServiceWorkerClientInfo> web_client) { - return web_client ? ServiceWorkerWindowClient::Create(*web_client) : nullptr; +namespace { + +void DidFocus(ScriptPromiseResolver* resolver, + mojom::blink::ServiceWorkerClientInfoPtr client) { + if (!resolver->GetExecutionContext() || + resolver->GetExecutionContext()->IsContextDestroyed()) { + return; + } + + if (!client) { + resolver->Reject(ServiceWorkerError::GetException( + resolver, mojom::blink::ServiceWorkerErrorType::kNotFound, + "The client was not found.")); + return; + } + resolver->Resolve(ServiceWorkerWindowClient::Create(*client)); } +} // namespace + ServiceWorkerWindowClient* ServiceWorkerWindowClient::Create( const WebServiceWorkerClientInfo& info) { + DCHECK_EQ(mojom::blink::ServiceWorkerClientType::kWindow, info.client_type); + return new ServiceWorkerWindowClient(info); +} + +ServiceWorkerWindowClient* ServiceWorkerWindowClient::Create( + const mojom::blink::ServiceWorkerClientInfo& info) { + DCHECK_EQ(mojom::blink::ServiceWorkerClientType::kWindow, info.client_type); return new ServiceWorkerWindowClient(info); } @@ -38,6 +58,12 @@ ServiceWorkerWindowClient::ServiceWorkerWindowClient( page_visibility_state_(info.page_visibility_state), is_focused_(info.is_focused) {} +ServiceWorkerWindowClient::ServiceWorkerWindowClient( + const mojom::blink::ServiceWorkerClientInfo& info) + : ServiceWorkerClient(info), + page_visibility_state_(info.page_visibility_state), + is_focused_(info.is_focused) {} + ServiceWorkerWindowClient::~ServiceWorkerWindowClient() = default; String ServiceWorkerWindowClient::visibilityState() const { @@ -56,10 +82,7 @@ ScriptPromise ServiceWorkerWindowClient::focus(ScriptState* script_state) { ExecutionContext::From(script_state)->ConsumeWindowInteraction(); ServiceWorkerGlobalScopeClient::From(ExecutionContext::From(script_state)) - ->Focus(Uuid(), - std::make_unique<CallbackPromiseAdapter<ServiceWorkerWindowClient, - ServiceWorkerError>>( - resolver)); + ->Focus(Uuid(), WTF::Bind(&DidFocus, WrapPersistent(resolver))); return promise; } @@ -82,8 +105,8 @@ ScriptPromise ServiceWorkerWindowClient::navigate(ScriptState* script_state, return promise; } - ServiceWorkerGlobalScopeClient::From(context)->Navigate( - Uuid(), parsed_url, std::make_unique<NavigateClientCallback>(resolver)); + ServiceWorkerGlobalScopeClient::From(context)->Navigate(Uuid(), parsed_url, + resolver); return promise; } diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.h index 1b81d633637..863d318f4b2 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client.h @@ -14,7 +14,6 @@ namespace blink { -class ScriptPromiseResolver; class ScriptState; class MODULES_EXPORT ServiceWorkerWindowClient final @@ -22,14 +21,9 @@ class MODULES_EXPORT ServiceWorkerWindowClient final DEFINE_WRAPPERTYPEINFO(); public: - // To be used by CallbackPromiseAdapter. - using WebType = std::unique_ptr<WebServiceWorkerClientInfo>; - - static ServiceWorkerWindowClient* Take( - ScriptPromiseResolver*, - std::unique_ptr<WebServiceWorkerClientInfo>); - static ServiceWorkerWindowClient* Create(const WebServiceWorkerClientInfo&); + static ServiceWorkerWindowClient* Create( + const mojom::blink::ServiceWorkerClientInfo&); ~ServiceWorkerWindowClient() override; // WindowClient.idl @@ -42,6 +36,8 @@ class MODULES_EXPORT ServiceWorkerWindowClient final private: explicit ServiceWorkerWindowClient(const WebServiceWorkerClientInfo&); + explicit ServiceWorkerWindowClient( + const mojom::blink::ServiceWorkerClientInfo&); mojom::PageVisibilityState page_visibility_state_; bool is_focused_; diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client_callback.cc b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client_callback.cc deleted file mode 100644 index 2400813dc70..00000000000 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client_callback.cc +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2015 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/service_worker/service_worker_window_client_callback.h" - -#include <memory> - -#include "base/memory/ptr_util.h" -#include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom-blink.h" -#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" -#include "third_party/blink/renderer/core/dom/dom_exception.h" -#include "third_party/blink/renderer/modules/service_worker/service_worker_error.h" -#include "third_party/blink/renderer/modules/service_worker/service_worker_window_client.h" -#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h" - -namespace blink { - -void NavigateClientCallback::OnSuccess( - std::unique_ptr<WebServiceWorkerClientInfo> client_info) { - if (!resolver_->GetExecutionContext() || - resolver_->GetExecutionContext()->IsContextDestroyed()) - return; - resolver_->Resolve(ServiceWorkerWindowClient::Take( - resolver_.Get(), base::WrapUnique(client_info.release()))); -} - -void NavigateClientCallback::OnError(const WebServiceWorkerError& error) { - if (!resolver_->GetExecutionContext() || - resolver_->GetExecutionContext()->IsContextDestroyed()) - return; - - if (error.error_type == mojom::blink::ServiceWorkerErrorType::kNavigation) { - ScriptState::Scope scope(resolver_->GetScriptState()); - resolver_->Reject(V8ThrowException::CreateTypeError( - resolver_->GetScriptState()->GetIsolate(), error.message)); - return; - } - - resolver_->Reject(ServiceWorkerError::Take(resolver_.Get(), error)); -} - -} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client_callback.h b/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client_callback.h deleted file mode 100644 index cf82b10dc2e..00000000000 --- a/chromium/third_party/blink/renderer/modules/service_worker/service_worker_window_client_callback.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2015 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_SERVICE_WORKER_SERVICE_WORKER_WINDOW_CLIENT_CALLBACK_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_WINDOW_CLIENT_CALLBACK_H_ - -#include "base/macros.h" -#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h" -#include "third_party/blink/renderer/platform/heap/handle.h" - -namespace blink { - -class ScriptPromiseResolver; - -class NavigateClientCallback : public WebServiceWorkerClientCallbacks { - public: - explicit NavigateClientCallback(ScriptPromiseResolver* resolver) - : resolver_(resolver) {} - - void OnSuccess(std::unique_ptr<WebServiceWorkerClientInfo>) override; - void OnError(const WebServiceWorkerError&) override; - - private: - Persistent<ScriptPromiseResolver> resolver_; - DISALLOW_COPY_AND_ASSIGN(NavigateClientCallback); -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_WINDOW_CLIENT_CALLBACK_H_ diff --git a/chromium/third_party/blink/renderer/modules/service_worker/thread_safe_script_container.cc b/chromium/third_party/blink/renderer/modules/service_worker/thread_safe_script_container.cc new file mode 100644 index 00000000000..4d0db13a062 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/service_worker/thread_safe_script_container.cc @@ -0,0 +1,108 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/service_worker/thread_safe_script_container.h" + +#include "base/memory/ptr_util.h" + +namespace blink { + +// static +std::unique_ptr<ThreadSafeScriptContainer::RawScriptData> +ThreadSafeScriptContainer::RawScriptData::Create(const String& encoding, + Vector<BytesChunk> script_text, + Vector<BytesChunk> meta_data) { + return base::WrapUnique(new RawScriptData(encoding, std::move(script_text), + std::move(meta_data))); +} + +ThreadSafeScriptContainer::RawScriptData::RawScriptData( + const String& encoding, + Vector<BytesChunk> script_text, + Vector<BytesChunk> meta_data) + : encoding_(encoding.IsolatedCopy()), + script_text_(std::move(script_text)), + meta_data_(std::move(meta_data)), + headers_(std::make_unique<CrossThreadHTTPHeaderMapData>()) {} + +ThreadSafeScriptContainer::RawScriptData::~RawScriptData() = default; + +void ThreadSafeScriptContainer::RawScriptData::AddHeader(const String& key, + const String& value) { + headers_->emplace_back(key.IsolatedCopy(), value.IsolatedCopy()); +} + +ThreadSafeScriptContainer::ThreadSafeScriptContainer() + : waiting_cv_(mutex_), are_all_data_added_(false) {} + +void ThreadSafeScriptContainer::AddOnIOThread( + const KURL& url, + std::unique_ptr<RawScriptData> data) { + MutexLocker locker(mutex_); + DCHECK_EQ(script_data_.end(), script_data_.find(url)); + ScriptStatus status = data ? ScriptStatus::kReceived : ScriptStatus::kFailed; + // |script_data_| is also accessed on the worker thread, so make a deep copy + // of |url| as key. + script_data_.Set(url.Copy(), std::make_pair(status, std::move(data))); + if (url == waiting_url_) + waiting_cv_.Signal(); +} + +ThreadSafeScriptContainer::ScriptStatus +ThreadSafeScriptContainer::GetStatusOnWorkerThread(const KURL& url) { + MutexLocker locker(mutex_); + auto it = script_data_.find(url); + if (it == script_data_.end()) + return ScriptStatus::kPending; + return it->value.first; +} + +void ThreadSafeScriptContainer::ResetOnWorkerThread(const KURL& url) { + MutexLocker locker(mutex_); + script_data_.erase(url); +} + +bool ThreadSafeScriptContainer::WaitOnWorkerThread(const KURL& url) { + MutexLocker locker(mutex_); + DCHECK(!waiting_url_.IsValid()) + << "The script container is unexpectedly shared among worker threads."; + // |waiting_url_| is also accessed on the IO thread later, so make a deep copy + // of |url|. + waiting_url_ = url.Copy(); + while (script_data_.find(url) == script_data_.end()) { + // If waiting script hasn't been added yet though all data are received, + // that means something went wrong. + if (are_all_data_added_) { + waiting_url_ = KURL(); + return false; + } + // This is possible to be waken up spuriously, so that it's necessary to + // check if the entry is really added. + waiting_cv_.Wait(); + } + waiting_url_ = KURL(); + return true; +} + +std::unique_ptr<ThreadSafeScriptContainer::RawScriptData> +ThreadSafeScriptContainer::TakeOnWorkerThread(const KURL& url) { + MutexLocker locker(mutex_); + auto it = script_data_.find(url); + DCHECK(it != script_data_.end()) + << "Script should have been received before calling Take"; + std::pair<ScriptStatus, std::unique_ptr<RawScriptData>>& pair = it->value; + DCHECK_EQ(ScriptStatus::kReceived, pair.first); + pair.first = ScriptStatus::kTaken; + return std::move(pair.second); +} + +void ThreadSafeScriptContainer::OnAllDataAddedOnIOThread() { + MutexLocker locker(mutex_); + are_all_data_added_ = true; + waiting_cv_.Broadcast(); +} + +ThreadSafeScriptContainer::~ThreadSafeScriptContainer() = default; + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/service_worker/thread_safe_script_container.h b/chromium/third_party/blink/renderer/modules/service_worker/thread_safe_script_container.h new file mode 100644 index 00000000000..a495a8ae2f4 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/service_worker/thread_safe_script_container.h @@ -0,0 +1,138 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_THREAD_SAFE_SCRIPT_CONTAINER_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_THREAD_SAFE_SCRIPT_CONTAINER_H_ + +#include <memory> +#include <utility> + +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/platform/network/http_header_map.h" +#include "third_party/blink/renderer/platform/weborigin/kurl.h" +#include "third_party/blink/renderer/platform/weborigin/kurl_hash.h" +#include "third_party/blink/renderer/platform/wtf/hash_map.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" +#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" +#include "third_party/blink/renderer/platform/wtf/threading_primitives.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" + +namespace blink { + +// ThreadSafeScriptContainer stores the scripts of a service worker for +// startup. This container is created for each service worker. The IO thread +// adds scripts to the container, and the worker thread takes the scripts. +// Note: Due to the above explanations about multi-threads access on this +// container, all the non-thread-safe members like KURL and String need to be +// deep-copied. +// +// This class uses explicit synchronization because it needs to support +// synchronous importScripts() from the worker thread. +// +// This class is RefCounted because there is no ordering guarantee of lifetime +// of its owners, i.e. ServiceWorkerInstalledScriptsManager and its +// Internal class. ServiceWorkerInstalledScriptsManager is destroyed earlier +// than Internal if the worker is terminated before all scripts are streamed, +// and Internal is destroyed earlier if all of scripts are received before +// finishing script evaluation. +class MODULES_EXPORT ThreadSafeScriptContainer + : public WTF::ThreadSafeRefCounted<ThreadSafeScriptContainer> { + public: + using BytesChunk = Vector<char>; + + // Container of a script. All the fields of this class need to be + // cross-thread-transfer-safe. + class MODULES_EXPORT RawScriptData { + public: + static std::unique_ptr<RawScriptData> Create(const String& encoding, + Vector<BytesChunk> script_text, + Vector<BytesChunk> meta_data); + + ~RawScriptData(); + + void AddHeader(const String& key, const String& value); + + // The encoding of the script text. + const String& Encoding() const { return encoding_; } + // An array of raw byte chunks of the script text. + const Vector<BytesChunk>& ScriptTextChunks() const { return script_text_; } + // An array of raw byte chunks of the scripts's meta data from the script's + // V8 code cache. + const Vector<BytesChunk>& MetaDataChunks() const { return meta_data_; } + + // The HTTP headers of the script. + std::unique_ptr<CrossThreadHTTPHeaderMapData> TakeHeaders() { + return std::move(headers_); + } + + private: + RawScriptData(const String& encoding, + Vector<BytesChunk> script_text, + Vector<BytesChunk> meta_data); + String encoding_; + Vector<BytesChunk> script_text_; + Vector<BytesChunk> meta_data_; + std::unique_ptr<CrossThreadHTTPHeaderMapData> headers_; + }; + + REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE(); + ThreadSafeScriptContainer(); + + enum class ScriptStatus { + // The script data has been received. + kReceived, + // The script data has been received but it has already been taken. + kTaken, + // Receiving the script has failed. + kFailed, + // The script data has not been received yet. + kPending + }; + + // Adds a script for the |url| to the container, and records status of the + // script as kReceived when |data| is non-null, or kFailed when |data| is + // nullptr. Called on the IO thread. + void AddOnIOThread(const KURL& url, std::unique_ptr<RawScriptData> data); + + // Called on the worker thread. + ScriptStatus GetStatusOnWorkerThread(const KURL& url); + + // Removes the script. After calling this, ScriptStatus for the + // script will be kPending. + // Called on the worker thread. + void ResetOnWorkerThread(const KURL& url); + + // Waits until the script is added. The thread is blocked until the script is + // available or receiving the script fails. Returns false if an error happens + // and the waiting script won't be available forever. + // Called on the worker thread. + bool WaitOnWorkerThread(const KURL& url); + + // Called on the worker thread. + std::unique_ptr<RawScriptData> TakeOnWorkerThread(const KURL& url); + + // Called if no more data will be added. + // Called on the IO thread. + void OnAllDataAddedOnIOThread(); + + private: + friend class WTF::ThreadSafeRefCounted<ThreadSafeScriptContainer>; + ~ThreadSafeScriptContainer(); + + // |mutex_| protects |waiting_cv_|, |script_data_|, |waiting_url_| and + // |are_all_data_added_|. + Mutex mutex_; + // |waiting_cv_| is signaled when a script whose url matches to |waiting_url| + // is added, or OnAllDataAdded is called. The worker thread waits on this, and + // the IO thread signals it. + ThreadCondition waiting_cv_; + HashMap<KURL, std::pair<ScriptStatus, std::unique_ptr<RawScriptData>>> + script_data_; + KURL waiting_url_; + bool are_all_data_added_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_THREAD_SAFE_SCRIPT_CONTAINER_H_ diff --git a/chromium/third_party/blink/renderer/modules/service_worker/thread_safe_script_container_test.cc b/chromium/third_party/blink/renderer/modules/service_worker/thread_safe_script_container_test.cc new file mode 100644 index 00000000000..b04d2a84135 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/service_worker/thread_safe_script_container_test.cc @@ -0,0 +1,217 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/service_worker/thread_safe_script_container.h" + +#include <memory> + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/renderer/platform/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" +#include "third_party/blink/renderer/platform/waitable_event.h" +#include "third_party/blink/renderer/platform/web_task_runner.h" +#include "third_party/blink/renderer/platform/wtf/functional.h" + +namespace blink { + +using ScriptStatus = ThreadSafeScriptContainer::ScriptStatus; + +const char kKeyUrl[] = "https://example.com/key"; + +class ThreadSafeScriptContainerTest : public ::testing::Test { + public: + ThreadSafeScriptContainerTest() + : writer_thread_(Platform::Current()->CreateThread( + ThreadCreationParams(WebThreadType::kTestThread) + .SetThreadNameForTest("writer_thread"))), + reader_thread_(Platform::Current()->CreateThread( + ThreadCreationParams(WebThreadType::kTestThread) + .SetThreadNameForTest("reader_thread"))), + container_(base::MakeRefCounted<ThreadSafeScriptContainer>()) {} + + protected: + WaitableEvent* AddOnWriterThread( + ThreadSafeScriptContainer::RawScriptData** out_data) { + PostCrossThreadTask( + *writer_thread_->GetTaskRunner(), FROM_HERE, + CrossThreadBind( + [](scoped_refptr<ThreadSafeScriptContainer> container, + ThreadSafeScriptContainer::RawScriptData** out_data, + WaitableEvent* waiter) { + auto data = ThreadSafeScriptContainer::RawScriptData::Create( + String::FromUTF8("utf-8") /* encoding */, + Vector<Vector<char>>() /* script_text */, + Vector<Vector<char>>() /* meta_data */); + *out_data = data.get(); + container->AddOnIOThread(KURL(kKeyUrl), std::move(data)); + waiter->Signal(); + }, + container_, CrossThreadUnretained(out_data), + CrossThreadUnretained(&writer_waiter_))); + return &writer_waiter_; + } + + WaitableEvent* OnAllDataAddedOnWriterThread() { + PostCrossThreadTask( + *writer_thread_->GetTaskRunner(), FROM_HERE, + CrossThreadBind( + [](scoped_refptr<ThreadSafeScriptContainer> container, + WaitableEvent* waiter) { + container->OnAllDataAddedOnIOThread(); + waiter->Signal(); + }, + container_, CrossThreadUnretained(&writer_waiter_))); + return &writer_waiter_; + } + + WaitableEvent* GetStatusOnReaderThread(ScriptStatus* out_status) { + PostCrossThreadTask( + *reader_thread_->GetTaskRunner(), FROM_HERE, + CrossThreadBind( + [](scoped_refptr<ThreadSafeScriptContainer> container, + ScriptStatus* out_status, WaitableEvent* waiter) { + *out_status = container->GetStatusOnWorkerThread(KURL(kKeyUrl)); + waiter->Signal(); + }, + container_, CrossThreadUnretained(out_status), + CrossThreadUnretained(&reader_waiter_))); + return &reader_waiter_; + } + + WaitableEvent* WaitOnReaderThread(bool* out_exists) { + PostCrossThreadTask( + *reader_thread_->GetTaskRunner(), FROM_HERE, + CrossThreadBind( + [](scoped_refptr<ThreadSafeScriptContainer> container, + bool* out_exists, WaitableEvent* waiter) { + *out_exists = container->WaitOnWorkerThread(KURL(kKeyUrl)); + waiter->Signal(); + }, + container_, CrossThreadUnretained(out_exists), + CrossThreadUnretained(&reader_waiter_))); + return &reader_waiter_; + } + + WaitableEvent* TakeOnReaderThread( + ThreadSafeScriptContainer::RawScriptData** out_data) { + PostCrossThreadTask( + *reader_thread_->GetTaskRunner(), FROM_HERE, + CrossThreadBind( + [](scoped_refptr<ThreadSafeScriptContainer> container, + ThreadSafeScriptContainer::RawScriptData** out_data, + WaitableEvent* waiter) { + auto data = container->TakeOnWorkerThread(KURL(kKeyUrl)); + *out_data = data.get(); + waiter->Signal(); + }, + container_, CrossThreadUnretained(out_data), + CrossThreadUnretained(&reader_waiter_))); + return &reader_waiter_; + } + + private: + std::unique_ptr<Thread> writer_thread_; + std::unique_ptr<Thread> reader_thread_; + + WaitableEvent writer_waiter_; + WaitableEvent reader_waiter_; + + scoped_refptr<ThreadSafeScriptContainer> container_; +}; + +TEST_F(ThreadSafeScriptContainerTest, WaitExistingKey) { + { + ScriptStatus result = ScriptStatus::kReceived; + GetStatusOnReaderThread(&result)->Wait(); + EXPECT_EQ(ScriptStatus::kPending, result); + } + + ThreadSafeScriptContainer::RawScriptData* added_data; + { + bool result = false; + WaitableEvent* pending_wait = WaitOnReaderThread(&result); + // This should not be signaled until data is added. + EXPECT_FALSE(pending_wait->IsSignaled()); + WaitableEvent* pending_write = AddOnWriterThread(&added_data); + pending_wait->Wait(); + pending_write->Wait(); + EXPECT_TRUE(result); + } + + { + ScriptStatus result = ScriptStatus::kFailed; + GetStatusOnReaderThread(&result)->Wait(); + EXPECT_EQ(ScriptStatus::kReceived, result); + } + + { + ThreadSafeScriptContainer::RawScriptData* taken_data; + TakeOnReaderThread(&taken_data)->Wait(); + EXPECT_EQ(added_data, taken_data); + } + + { + ScriptStatus result = ScriptStatus::kFailed; + GetStatusOnReaderThread(&result)->Wait(); + // The record should exist though it's already taken. + EXPECT_EQ(ScriptStatus::kTaken, result); + } + + { + bool result = false; + WaitOnReaderThread(&result)->Wait(); + // Waiting for the record being already taken should succeed. + EXPECT_TRUE(result); + + // The record status should still be |kTaken|. + ScriptStatus status = ScriptStatus::kFailed; + GetStatusOnReaderThread(&status)->Wait(); + EXPECT_EQ(ScriptStatus::kTaken, status); + } + + // Finish adding data. + OnAllDataAddedOnWriterThread()->Wait(); + + { + bool result = false; + WaitOnReaderThread(&result)->Wait(); + // The record is in |kTaken| status, so Wait shouldn't fail. + EXPECT_TRUE(result); + + // The status of record should still be |kTaken|. + ScriptStatus status = ScriptStatus::kFailed; + GetStatusOnReaderThread(&status)->Wait(); + EXPECT_EQ(ScriptStatus::kTaken, status); + } +} + +TEST_F(ThreadSafeScriptContainerTest, WaitNonExistingKey) { + { + ScriptStatus result = ScriptStatus::kReceived; + GetStatusOnReaderThread(&result)->Wait(); + EXPECT_EQ(ScriptStatus::kPending, result); + } + + { + bool result = true; + WaitableEvent* pending_wait = WaitOnReaderThread(&result); + // This should not be signaled until OnAllDataAdded is called. + EXPECT_FALSE(pending_wait->IsSignaled()); + WaitableEvent* pending_on_all_data_added = OnAllDataAddedOnWriterThread(); + pending_wait->Wait(); + pending_on_all_data_added->Wait(); + // Aborted wait should return false. + EXPECT_FALSE(result); + } + + { + bool result = true; + WaitOnReaderThread(&result)->Wait(); + // Wait fails immediately because OnAllDataAdded is called. + EXPECT_FALSE(result); + } +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc b/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc index ecbfbbdb272..ceb65d2efd8 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc @@ -14,6 +14,7 @@ #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h" #include "third_party/blink/renderer/platform/bindings/microtask.h" #include "third_party/blink/renderer/platform/layout_test_support.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" #include "v8/include/v8.h" @@ -110,14 +111,16 @@ WaitUntilObserver* WaitUntilObserver::Create(ExecutionContext* context, } void WaitUntilObserver::WillDispatchEvent() { - event_dispatch_time_ = WTF::CurrentTime(); - // When handling a notificationclick or paymentrequest event, we want to - // allow one window to be focused or opened. These calls are allowed between - // the call to willDispatchEvent() and the last call to + event_dispatch_time_ = WTF::CurrentTimeTicks(); + // When handling a notificationclick, paymentrequest, or backgroundfetchclick + // event, we want to allow one window to be focused or opened. These calls are + // allowed between the call to willDispatchEvent() and the last call to // DecrementPendingPromiseCount(). If waitUntil() isn't called, that means // between willDispatchEvent() and didDispatchEvent(). - if (type_ == kNotificationClick || type_ == kPaymentRequest) + if (type_ == kNotificationClick || type_ == kPaymentRequest || + type_ == kBackgroundFetchClick) { execution_context_->AllowWindowInteraction(); + } DCHECK_EQ(EventDispatchState::kInitial, event_dispatch_state_); event_dispatch_state_ = EventDispatchState::kDispatching; @@ -179,11 +182,17 @@ void WaitUntilObserver::WaitUntil(ScriptState* script_state, } IncrementPendingPromiseCount(); + + // Call Then() separately for fulfilled and rejected cases. This ensures + // throwing an exception in |on_promise_fulfilled| doesn't invoke + // |on_promise_rejected|. script_promise.Then( ThenFunction::CreateFunction(script_state, this, ThenFunction::kFulfilled, std::move(on_promise_fulfilled)), - ThenFunction::CreateFunction(script_state, this, ThenFunction::kRejected, - std::move(on_promise_rejected))); + {}); + script_promise.Then({}, ThenFunction::CreateFunction( + script_state, this, ThenFunction::kRejected, + std::move(on_promise_rejected))); } WaitUntilObserver::WaitUntilObserver(ExecutionContext* context, diff --git a/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.h b/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.h index 47560c2d683..fa322d6e0c2 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.h +++ b/chromium/third_party/blink/renderer/modules/service_worker/wait_until_observer.h @@ -110,7 +110,7 @@ class MODULES_EXPORT WaitUntilObserver final int pending_promises_ = 0; EventDispatchState event_dispatch_state_ = EventDispatchState::kInitial; bool has_rejected_promise_ = false; - double event_dispatch_time_ = 0; + TimeTicks event_dispatch_time_; TaskRunnerTimer<WaitUntilObserver> consume_window_interaction_timer_; }; diff --git a/chromium/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc b/chromium/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc index 231bb6286bb..c8dbc3143e4 100644 --- a/chromium/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc +++ b/chromium/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc @@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/public/web/web_embedded_worker.h" +#include "third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h" #include <memory> + #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/public/common/message_port/message_port_channel.h" -#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_installed_scripts_manager.h" +#include "third_party/blink/public/common/messaging/message_port_channel.h" +#include "third_party/blink/public/mojom/service_worker/service_worker_installed_scripts_manager.mojom-blink.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h" -#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_content_settings_client.h" #include "third_party/blink/public/platform/web_url_loader_mock_factory.h" @@ -19,6 +19,8 @@ #include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h" #include "third_party/blink/public/web/web_embedded_worker_start_data.h" #include "third_party/blink/public/web/web_settings.h" +#include "third_party/blink/renderer/modules/service_worker/service_worker_installed_scripts_manager.h" +#include "third_party/blink/renderer/modules/service_worker/thread_safe_script_container.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_error.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" @@ -43,61 +45,18 @@ class MockServiceWorkerContextClient : public WebServiceWorkerContextClient { // message. proxy->ReadyToEvaluateScript(); } - void DidEvaluateClassicScript(bool /* success */) override { + void DidEvaluateScript(bool /* success */) override { script_evaluated_event_.Signal(); } // Work-around for mocking a method that return unique_ptr. MOCK_METHOD0(CreateServiceWorkerNetworkProviderProxy, WebServiceWorkerNetworkProvider*()); - MOCK_METHOD0(CreateServiceWorkerProviderProxy, WebServiceWorkerProvider*()); std::unique_ptr<WebServiceWorkerNetworkProvider> CreateServiceWorkerNetworkProvider() override { return std::unique_ptr<WebServiceWorkerNetworkProvider>( CreateServiceWorkerNetworkProviderProxy()); } - std::unique_ptr<WebServiceWorkerProvider> CreateServiceWorkerProvider() - override { - return std::unique_ptr<WebServiceWorkerProvider>( - CreateServiceWorkerProviderProxy()); - } - void GetClient(const WebString&, - std::unique_ptr<WebServiceWorkerClientCallbacks>) override { - NOTREACHED(); - } - void GetClients(const WebServiceWorkerClientQueryOptions&, - std::unique_ptr<WebServiceWorkerClientsCallbacks>) override { - NOTREACHED(); - } - void OpenNewTab(const WebURL&, - std::unique_ptr<WebServiceWorkerClientCallbacks>) override { - NOTREACHED(); - } - void OpenPaymentHandlerWindow( - const WebURL&, - std::unique_ptr<WebServiceWorkerClientCallbacks>) override { - NOTREACHED(); - } - void PostMessageToClient(const WebString& uuid, - TransferableMessage) override { - NOTREACHED(); - } - void SkipWaiting( - std::unique_ptr<WebServiceWorkerSkipWaitingCallbacks>) override { - NOTREACHED(); - } - void Claim(std::unique_ptr<WebServiceWorkerClientsClaimCallbacks>) override { - NOTREACHED(); - } - void Focus(const WebString& uuid, - std::unique_ptr<WebServiceWorkerClientCallbacks>) override { - NOTREACHED(); - } - void Navigate(const WebString& uuid, - const WebURL&, - std::unique_ptr<WebServiceWorkerClientCallbacks>) override { - NOTREACHED(); - } void WorkerContextDestroyed() override { termination_event_.Signal(); } void WaitUntilScriptEvaluated() { script_evaluated_event_.Wait(); } @@ -109,11 +68,27 @@ class MockServiceWorkerContextClient : public WebServiceWorkerContextClient { }; class MockServiceWorkerInstalledScriptsManager - : public WebServiceWorkerInstalledScriptsManager { + : public ServiceWorkerInstalledScriptsManager { public: - MOCK_CONST_METHOD1(IsScriptInstalled, bool(const WebURL& script_url)); + MockServiceWorkerInstalledScriptsManager() + : ServiceWorkerInstalledScriptsManager( + Vector<KURL>() /* installed_urls */, + mojom::blink::ServiceWorkerInstalledScriptsManagerRequest( + mojo::MessagePipe().handle1), + mojom::blink::ServiceWorkerInstalledScriptsManagerHostPtrInfo( + mojo::MessagePipe().handle0, + mojom::blink::ServiceWorkerInstalledScriptsManagerHost:: + Version_), + // Pass a temporary task runner to ensure + // ServiceWorkerInstalledScriptsManager construction succeeds. + Platform::Current() + ->CreateThread(ThreadCreationParams(WebThreadType::kTestThread) + .SetThreadNameForTest("io thread")) + ->GetTaskRunner()){}; + MOCK_CONST_METHOD1(IsScriptInstalled, bool(const KURL& script_url)); MOCK_METHOD1(GetRawScriptData, - std::unique_ptr<RawScriptData>(const WebURL& script_url)); + std::unique_ptr<ThreadSafeScriptContainer::RawScriptData>( + const KURL& script_url)); }; class WebEmbeddedWorkerImplTest : public testing::Test { @@ -124,10 +99,8 @@ class WebEmbeddedWorkerImplTest : public testing::Test { std::make_unique<MockServiceWorkerInstalledScriptsManager>(); mock_client_ = client.get(); mock_installed_scripts_manager_ = installed_scripts_manager.get(); - worker_ = WebEmbeddedWorker::Create( - std::move(client), std::move(installed_scripts_manager), - mojo::ScopedMessagePipeHandle(), mojo::ScopedMessagePipeHandle(), - mojo::ScopedMessagePipeHandle()); + worker_ = WebEmbeddedWorkerImpl::CreateForTesting( + std::move(client), std::move(installed_scripts_manager)); WebURL script_url = URLTestHelpers::ToKURL("https://www.example.com/sw.js"); WebURLResponse response(script_url); @@ -138,6 +111,7 @@ class WebEmbeddedWorkerImplTest : public testing::Test { start_data_.script_url = script_url; start_data_.user_agent = WebString("dummy user agent"); + start_data_.script_type = mojom::ScriptType::kClassic; start_data_.pause_after_download_mode = WebEmbeddedWorkerStartData::kDontPauseAfterDownload; start_data_.wait_for_debugger_mode = @@ -154,7 +128,7 @@ class WebEmbeddedWorkerImplTest : public testing::Test { WebEmbeddedWorkerStartData start_data_; MockServiceWorkerContextClient* mock_client_; MockServiceWorkerInstalledScriptsManager* mock_installed_scripts_manager_; - std::unique_ptr<WebEmbeddedWorker> worker_; + std::unique_ptr<WebEmbeddedWorkerImpl> worker_; }; } // namespace @@ -190,7 +164,7 @@ TEST_F(WebEmbeddedWorkerImplTest, TerminateWhileLoadingScript) { EXPECT_CALL(*mock_client_, CreateServiceWorkerNetworkProviderProxy()) .WillOnce(testing::Return(nullptr)); EXPECT_CALL(*mock_installed_scripts_manager_, - IsScriptInstalled(start_data_.script_url)) + IsScriptInstalled(KURL(start_data_.script_url))) .Times(testing::AtLeast(1)) .WillRepeatedly(testing::Return(false)); Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests(); @@ -214,7 +188,7 @@ TEST_F(WebEmbeddedWorkerImplTest, TerminateWhilePausedAfterDownload) { EXPECT_CALL(*mock_client_, CreateServiceWorkerNetworkProviderProxy()) .WillOnce(testing::Return(nullptr)); EXPECT_CALL(*mock_installed_scripts_manager_, - IsScriptInstalled(start_data_.script_url)) + IsScriptInstalled(KURL(start_data_.script_url))) .Times(testing::AtLeast(1)) .WillRepeatedly(testing::Return(false)); @@ -224,12 +198,10 @@ TEST_F(WebEmbeddedWorkerImplTest, TerminateWhilePausedAfterDownload) { // Load the script. EXPECT_CALL(*mock_client_, WorkerScriptLoaded()).Times(1); - EXPECT_CALL(*mock_client_, CreateServiceWorkerProviderProxy()).Times(0); Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests(); testing::Mock::VerifyAndClearExpectations(mock_client_); // Terminate before resuming after download. - EXPECT_CALL(*mock_client_, CreateServiceWorkerProviderProxy()).Times(0); EXPECT_CALL(*mock_client_, WorkerContextFailedToStart()).Times(1); worker_->TerminateWorkerContext(); testing::Mock::VerifyAndClearExpectations(mock_client_); @@ -254,7 +226,7 @@ TEST_F(WebEmbeddedWorkerImplTest, ScriptNotFound) { EXPECT_CALL(*mock_client_, CreateServiceWorkerNetworkProviderProxy()) .WillOnce(testing::Return(nullptr)); EXPECT_CALL(*mock_installed_scripts_manager_, - IsScriptInstalled(start_data_.script_url)) + IsScriptInstalled(KURL(start_data_.script_url))) .Times(testing::AtLeast(1)) .WillRepeatedly(testing::Return(false)); @@ -264,7 +236,6 @@ TEST_F(WebEmbeddedWorkerImplTest, ScriptNotFound) { // Load the script. EXPECT_CALL(*mock_client_, WorkerScriptLoaded()).Times(0); - EXPECT_CALL(*mock_client_, CreateServiceWorkerProviderProxy()).Times(0); EXPECT_CALL(*mock_client_, WorkerContextFailedToStart()).Times(1); Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests(); testing::Mock::VerifyAndClearExpectations(mock_client_); @@ -286,7 +257,7 @@ TEST_F(WebEmbeddedWorkerImplTest, MAYBE_DontPauseAfterDownload) { EXPECT_CALL(*mock_client_, CreateServiceWorkerNetworkProviderProxy()) .WillOnce(testing::Return(nullptr)); EXPECT_CALL(*mock_installed_scripts_manager_, - IsScriptInstalled(start_data_.script_url)) + IsScriptInstalled(KURL(start_data_.script_url))) .Times(testing::AtLeast(1)) .WillRepeatedly(testing::Return(false)); Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests(); @@ -295,11 +266,9 @@ TEST_F(WebEmbeddedWorkerImplTest, MAYBE_DontPauseAfterDownload) { // Load the script. EXPECT_CALL(*mock_client_, WorkerScriptLoaded()).Times(1); - EXPECT_CALL(*mock_client_, CreateServiceWorkerProviderProxy()) - .WillOnce(testing::Return(nullptr)); // This is called on the worker thread. EXPECT_CALL(*mock_installed_scripts_manager_, - IsScriptInstalled(start_data_.script_url)) + IsScriptInstalled(KURL(start_data_.script_url))) .Times(testing::AtLeast(1)) .WillRepeatedly(testing::Return(false)); Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests(); @@ -331,7 +300,7 @@ TEST_F(WebEmbeddedWorkerImplTest, MAYBE_PauseAfterDownload) { EXPECT_CALL(*mock_client_, CreateServiceWorkerNetworkProviderProxy()) .WillOnce(testing::Return(nullptr)); EXPECT_CALL(*mock_installed_scripts_manager_, - IsScriptInstalled(start_data_.script_url)) + IsScriptInstalled(KURL(start_data_.script_url))) .Times(testing::AtLeast(1)) .WillRepeatedly(testing::Return(false)); Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests(); @@ -340,16 +309,13 @@ TEST_F(WebEmbeddedWorkerImplTest, MAYBE_PauseAfterDownload) { // Load the script. EXPECT_CALL(*mock_client_, WorkerScriptLoaded()).Times(1); - EXPECT_CALL(*mock_client_, CreateServiceWorkerProviderProxy()).Times(0); Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests(); testing::Mock::VerifyAndClearExpectations(mock_client_); // Resume after download. - EXPECT_CALL(*mock_client_, CreateServiceWorkerProviderProxy()) - .WillOnce(testing::Return(nullptr)); // This is called on the worker thread. EXPECT_CALL(*mock_installed_scripts_manager_, - IsScriptInstalled(start_data_.script_url)) + IsScriptInstalled(KURL(start_data_.script_url))) .Times(testing::AtLeast(1)) .WillRepeatedly(testing::Return(false)); worker_->ResumeAfterDownload(); diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.cc b/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.cc index 402e2f647cc..09cafa69fe5 100644 --- a/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.cc +++ b/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.cc @@ -4,6 +4,7 @@ #include "third_party/blink/renderer/modules/shapedetection/detected_barcode.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h" #include "third_party/blink/renderer/core/geometry/dom_rect.h" namespace blink { @@ -39,6 +40,21 @@ DetectedBarcode::DetectedBarcode(String raw_value, bounding_box_(bounding_box), corner_points_(corner_points) {} +ScriptValue DetectedBarcode::toJSONForBinding(ScriptState* script_state) const { + V8ObjectBuilder result(script_state); + result.AddString("rawValue", rawValue()); + result.Add("boundingBox", boundingBox()->toJSONForBinding(script_state)); + Vector<ScriptValue> corner_points; + for (const auto& corner_point : corner_points_) { + V8ObjectBuilder builder(script_state); + builder.AddNumber("x", corner_point.x()); + builder.AddNumber("y", corner_point.y()); + corner_points.push_back(builder.GetScriptValue()); + } + result.Add("cornerPoints", corner_points); + return result.GetScriptValue(); +} + void DetectedBarcode::Trace(blink::Visitor* visitor) { visitor->Trace(bounding_box_); visitor->Trace(corner_points_); diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.h b/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.h index 69dcfd9ddde..c6f2fe11c65 100644 --- a/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.h +++ b/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.h @@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SHAPEDETECTION_DETECTED_BARCODE_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SHAPEDETECTION_DETECTED_BARCODE_H_ +#include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/modules/imagecapture/point_2d.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" @@ -24,6 +25,8 @@ class MODULES_EXPORT DetectedBarcode final : public ScriptWrappable { const String& rawValue() const; DOMRectReadOnly* boundingBox() const; const HeapVector<Point2D>& cornerPoints() const; + + ScriptValue toJSONForBinding(ScriptState*) const; void Trace(blink::Visitor*) override; private: diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.idl b/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.idl index 8d6aa759712..7df4129c703 100644 --- a/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.idl +++ b/chromium/third_party/blink/renderer/modules/shapedetection/detected_barcode.idl @@ -6,6 +6,7 @@ [ Constructor, + Serializable, OriginTrialEnabled=ShapeDetection ] interface DetectedBarcode { // TODO(mcasas): Implement missing fields. https://crbug.com/646083 @@ -14,4 +15,6 @@ // 4 corner points in clockwise direction starting with top-left. Due to // possible perspective distortions, this is not necessarily a rectangle. [SameObject, SaveSameObject] readonly attribute FrozenArray<Point2D> cornerPoints; + + serializer = { attribute }; }; diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.cc b/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.cc index 00863ffbbb7..8228b01bf5a 100644 --- a/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.cc +++ b/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.cc @@ -4,6 +4,7 @@ #include "third_party/blink/renderer/modules/shapedetection/detected_face.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h" #include "third_party/blink/renderer/core/geometry/dom_rect.h" namespace blink { @@ -36,6 +37,27 @@ DetectedFace::DetectedFace(DOMRectReadOnly* bounding_box, const HeapVector<Landmark>& landmarks) : bounding_box_(bounding_box), landmarks_(landmarks) {} +ScriptValue DetectedFace::toJSONForBinding(ScriptState* script_state) const { + V8ObjectBuilder result(script_state); + result.Add("boundingBox", boundingBox()->toJSONForBinding(script_state)); + Vector<ScriptValue> landmarks; + for (const auto& landmark : landmarks_) { + V8ObjectBuilder landmark_builder(script_state); + landmark_builder.AddString("type", landmark.type()); + Vector<ScriptValue> locations; + for (const auto& location : landmark.locations()) { + V8ObjectBuilder location_builder(script_state); + location_builder.AddNumber("x", location.x()); + location_builder.AddNumber("y", location.y()); + locations.push_back(location_builder.GetScriptValue()); + } + landmark_builder.Add("locations", locations); + landmarks.push_back(landmark_builder.GetScriptValue()); + } + result.Add("landmarks", landmarks); + return result.GetScriptValue(); +} + void DetectedFace::Trace(blink::Visitor* visitor) { visitor->Trace(bounding_box_); visitor->Trace(landmarks_); diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.h b/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.h index 0e5268aa2de..6935e84330d 100644 --- a/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.h +++ b/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.h @@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SHAPEDETECTION_DETECTED_FACE_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SHAPEDETECTION_DETECTED_FACE_H_ +#include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/shapedetection/landmark.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" @@ -24,6 +25,7 @@ class MODULES_EXPORT DetectedFace final : public ScriptWrappable { DOMRectReadOnly* boundingBox() const; const HeapVector<Landmark>& landmarks() const; + ScriptValue toJSONForBinding(ScriptState*) const; void Trace(blink::Visitor*) override; private: diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.idl b/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.idl index fda03e7c2f0..f367b6af6b9 100644 --- a/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.idl +++ b/chromium/third_party/blink/renderer/modules/shapedetection/detected_face.idl @@ -6,9 +6,12 @@ [ Constructor, + Serializable, OriginTrialEnabled=ShapeDetection ] interface DetectedFace { // TODO(xianglu): Implement any other fields. https://crbug.com/646083 [SameObject] readonly attribute DOMRectReadOnly boundingBox; [SameObject, SaveSameObject] readonly attribute FrozenArray<Landmark> landmarks; + + serializer = { attribute }; }; diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.cc b/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.cc index 7240b5c502c..7a03de27916 100644 --- a/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.cc +++ b/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.cc @@ -4,6 +4,7 @@ #include "third_party/blink/renderer/modules/shapedetection/detected_text.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h" #include "third_party/blink/renderer/core/geometry/dom_rect.h" namespace blink { @@ -39,6 +40,21 @@ DetectedText::DetectedText(String raw_value, bounding_box_(bounding_box), corner_points_(corner_points) {} +ScriptValue DetectedText::toJSONForBinding(ScriptState* script_state) const { + V8ObjectBuilder result(script_state); + result.AddString("rawValue", rawValue()); + result.Add("boundingBox", boundingBox()->toJSONForBinding(script_state)); + Vector<ScriptValue> corner_points; + for (const auto& corner_point : corner_points_) { + V8ObjectBuilder builder(script_state); + builder.AddNumber("x", corner_point.x()); + builder.AddNumber("y", corner_point.y()); + corner_points.push_back(builder.GetScriptValue()); + } + result.Add("cornerPoints", corner_points); + return result.GetScriptValue(); +} + void DetectedText::Trace(blink::Visitor* visitor) { visitor->Trace(bounding_box_); visitor->Trace(corner_points_); diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.h b/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.h index 342072d3e57..09f43783bc6 100644 --- a/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.h +++ b/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.h @@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SHAPEDETECTION_DETECTED_TEXT_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SHAPEDETECTION_DETECTED_TEXT_H_ +#include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/modules/imagecapture/point_2d.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" @@ -24,6 +25,8 @@ class MODULES_EXPORT DetectedText final : public ScriptWrappable { const String& rawValue() const; DOMRectReadOnly* boundingBox() const; const HeapVector<Point2D>& cornerPoints() const; + + ScriptValue toJSONForBinding(ScriptState*) const; void Trace(blink::Visitor*) override; private: diff --git a/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.idl b/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.idl index 8b08cde053c..7afa4c66f2b 100644 --- a/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.idl +++ b/chromium/third_party/blink/renderer/modules/shapedetection/detected_text.idl @@ -6,6 +6,7 @@ [ Constructor, + Serializable, OriginTrialEnabled=ShapeDetection ] interface DetectedText { [SameObject] readonly attribute DOMString rawValue; @@ -13,4 +14,6 @@ // 4 corner points in clockwise direction starting with top-left. Due to // possible perspective distortions, this is not necessarily a rectangle. [SameObject] readonly attribute FrozenArray<Point2D> cornerPoints; + + serializer = { attribute }; }; diff --git a/chromium/third_party/blink/renderer/modules/speech/BUILD.gn b/chromium/third_party/blink/renderer/modules/speech/BUILD.gn index df1bbde0c12..5597ba5fa8e 100644 --- a/chromium/third_party/blink/renderer/modules/speech/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/speech/BUILD.gn @@ -30,6 +30,8 @@ blink_modules_sources("speech") { "speech_recognition_result_list.h", "speech_synthesis.cc", "speech_synthesis.h", + "speech_synthesis_error_event.cc", + "speech_synthesis_error_event.h", "speech_synthesis_event.cc", "speech_synthesis_event.h", "speech_synthesis_utterance.cc", diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_grammar.cc b/chromium/third_party/blink/renderer/modules/speech/speech_grammar.cc index 0e60f9ac463..59982229e20 100644 --- a/chromium/third_party/blink/renderer/modules/speech/speech_grammar.cc +++ b/chromium/third_party/blink/renderer/modules/speech/speech_grammar.cc @@ -39,7 +39,7 @@ SpeechGrammar* SpeechGrammar::Create(const KURL& src, double weight) { } void SpeechGrammar::setSrc(ScriptState* script_state, const String& src) { - Document* document = ToDocument(ExecutionContext::From(script_state)); + Document* document = To<Document>(ExecutionContext::From(script_state)); src_ = document->CompleteURL(src); } diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_grammar_list.cc b/chromium/third_party/blink/renderer/modules/speech/speech_grammar_list.cc index 531a0a42f38..2c7ce846f9c 100644 --- a/chromium/third_party/blink/renderer/modules/speech/speech_grammar_list.cc +++ b/chromium/third_party/blink/renderer/modules/speech/speech_grammar_list.cc @@ -45,7 +45,7 @@ SpeechGrammar* SpeechGrammarList::item(unsigned index) const { void SpeechGrammarList::addFromUri(ScriptState* script_state, const String& src, double weight) { - Document* document = ToDocument(ExecutionContext::From(script_state)); + Document* document = To<Document>(ExecutionContext::From(script_state)); grammars_.push_back( SpeechGrammar::Create(document->CompleteURL(src), weight)); } diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_recognition.cc b/chromium/third_party/blink/renderer/modules/speech/speech_recognition.cc index 9f2d5589ba9..5047cac243d 100644 --- a/chromium/third_party/blink/renderer/modules/speech/speech_recognition.cc +++ b/chromium/third_party/blink/renderer/modules/speech/speech_recognition.cc @@ -37,11 +37,8 @@ namespace blink { SpeechRecognition* SpeechRecognition::Create(ExecutionContext* context) { - DCHECK(context); - DCHECK(context->IsDocument()); - Document* document = ToDocument(context); - DCHECK(document); - return new SpeechRecognition(document->GetFrame(), context); + Document& document = To<Document>(*context); + return new SpeechRecognition(document.GetFrame(), context); } void SpeechRecognition::start(ExceptionState& exception_state) { @@ -96,7 +93,7 @@ void SpeechRecognition::ResultRetrieved( auto* it = std::stable_partition( results.begin(), results.end(), [](const auto& result) { return !result->is_provisional; }); - size_t provisional_count = results.end() - it; + wtf_size_t provisional_count = static_cast<wtf_size_t>(results.end() - it); // Add the new results to the previous final results. HeapVector<Member<SpeechRecognitionResult>> aggregated_results = diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_recognition.h b/chromium/third_party/blink/renderer/modules/speech/speech_recognition.h index b4e08c6ccf8..ed6259ee8d8 100644 --- a/chromium/third_party/blink/renderer/modules/speech/speech_recognition.h +++ b/chromium/third_party/blink/renderer/modules/speech/speech_recognition.h @@ -129,7 +129,7 @@ class MODULES_EXPORT SpeechRecognition final String lang_; bool continuous_; bool interim_results_; - unsigned long max_alternatives_; + uint32_t max_alternatives_; Member<SpeechRecognitionController> controller_; bool started_; diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_controller.cc b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_controller.cc index 6bd603d0da6..c16ed4933c7 100644 --- a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_controller.cc +++ b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_controller.cc @@ -56,7 +56,7 @@ void SpeechRecognitionController::Start( const String& lang, bool continuous, bool interim_results, - unsigned long max_alternatives) { + uint32_t max_alternatives) { mojom::blink::StartSpeechRecognitionRequestParamsPtr msg_params = mojom::blink::StartSpeechRecognitionRequestParams::New(); for (unsigned i = 0; i < grammars.length(); i++) { diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_controller.h b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_controller.h index 1f98f355d1f..06c4c2a9080 100644 --- a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_controller.h +++ b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_controller.h @@ -52,7 +52,7 @@ class SpeechRecognitionController final const String& lang, bool continuous, bool interim_results, - unsigned long max_alternatives); + uint32_t max_alternatives); static SpeechRecognitionController* Create(LocalFrame& frame); static SpeechRecognitionController* From(LocalFrame* frame) { diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.cc b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.cc index 8c77fcda614..5236cc5eaa4 100644 --- a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.cc +++ b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.cc @@ -36,7 +36,7 @@ SpeechRecognitionEvent* SpeechRecognitionEvent::Create( } SpeechRecognitionEvent* SpeechRecognitionEvent::CreateResult( - unsigned long result_index, + uint32_t result_index, const HeapVector<Member<SpeechRecognitionResult>>& results) { return new SpeechRecognitionEvent( EventTypeNames::result, result_index, @@ -72,7 +72,7 @@ SpeechRecognitionEvent::SpeechRecognitionEvent( SpeechRecognitionEvent::SpeechRecognitionEvent( const AtomicString& event_name, - unsigned long result_index, + uint32_t result_index, SpeechRecognitionResultList* results) : Event(event_name, Bubbles::kNo, Cancelable::kNo), result_index_(result_index), diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.h b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.h index 7348f0489e9..5bf5b563ec4 100644 --- a/chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.h +++ b/chromium/third_party/blink/renderer/modules/speech/speech_recognition_event.h @@ -45,11 +45,11 @@ class SpeechRecognitionEvent final : public Event { ~SpeechRecognitionEvent() override; static SpeechRecognitionEvent* CreateResult( - unsigned long result_index, + uint32_t result_index, const HeapVector<Member<SpeechRecognitionResult>>& results); static SpeechRecognitionEvent* CreateNoMatch(SpeechRecognitionResult*); - unsigned long resultIndex() const { return result_index_; } + uint32_t resultIndex() const { return result_index_; } SpeechRecognitionResultList* results() const { return results_; } // These two methods are here to satisfy the specification which requires @@ -66,10 +66,10 @@ class SpeechRecognitionEvent final : public Event { SpeechRecognitionEvent(const AtomicString&, const SpeechRecognitionEventInit&); SpeechRecognitionEvent(const AtomicString& event_name, - unsigned long result_index, + uint32_t result_index, SpeechRecognitionResultList* results); - unsigned long result_index_; + uint32_t result_index_; Member<SpeechRecognitionResultList> results_; }; diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.cc b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.cc index b873d8ed6b9..c86e56d786b 100644 --- a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.cc +++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.cc @@ -32,7 +32,10 @@ #include "third_party/blink/renderer/core/html/media/autoplay_policy.h" #include "third_party/blink/renderer/core/timing/dom_window_performance.h" #include "third_party/blink/renderer/core/timing/performance.h" +#include "third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h" +#include "third_party/blink/renderer/modules/speech/speech_synthesis_error_event_init.h" #include "third_party/blink/renderer/modules/speech/speech_synthesis_event.h" +#include "third_party/blink/renderer/modules/speech/speech_synthesis_event_init.h" #include "third_party/blink/renderer/platform/speech/platform_speech_synthesis_voice.h" namespace blink { @@ -67,9 +70,8 @@ const HeapVector<Member<SpeechSynthesisVoice>>& SpeechSynthesis::getVoices() { // platform again. const Vector<scoped_refptr<PlatformSpeechSynthesisVoice>>& platform_voices = platform_speech_synthesizer_->GetVoiceList(); - size_t voice_count = platform_voices.size(); - for (size_t k = 0; k < voice_count; k++) - voice_list_.push_back(SpeechSynthesisVoice::Create(platform_voices[k])); + for (auto voice : platform_voices) + voice_list_.push_back(SpeechSynthesisVoice::Create(voice)); return voice_list_; } @@ -106,14 +108,10 @@ void SpeechSynthesis::StartSpeakingImmediately() { void SpeechSynthesis::speak(SpeechSynthesisUtterance* utterance) { DCHECK(utterance); - Document* document = ToDocument(GetExecutionContext()); + Document* document = To<Document>(GetExecutionContext()); if (!document) return; - // If SpeechSynthesis followed autoplay policy, we could simply fire an error - // here and ignore this utterance. For now, just log some UseCounters to - // evaluate potential breakage. - // // Note: Non-UseCounter based TTS metrics are of the form TextToSpeech.* and // are generally global, whereas these are scoped to a single page load. UseCounter::Count(document, WebFeature::kTextToSpeech_Speak); @@ -122,6 +120,8 @@ void SpeechSynthesis::speak(SpeechSynthesisUtterance* utterance) { if (!IsAllowedToStartByAutoplay()) { Deprecation::CountDeprecation( document, WebFeature::kTextToSpeech_SpeakDisallowedByAutoplay); + FireErrorEvent(utterance, 0 /* char_index */, "not-allowed"); + return; } utterance_queue_.push_back(utterance); @@ -152,15 +152,34 @@ void SpeechSynthesis::resume() { void SpeechSynthesis::FireEvent(const AtomicString& type, SpeechSynthesisUtterance* utterance, - unsigned long char_index, + uint32_t char_index, const String& name) { double millis; if (!GetElapsedTimeMillis(&millis)) return; - double elapsed_time_millis = millis - utterance->StartTime() * 1000.0; - utterance->DispatchEvent(*SpeechSynthesisEvent::Create( - type, utterance, char_index, elapsed_time_millis, name)); + SpeechSynthesisEventInit init; + init.setUtterance(utterance); + init.setCharIndex(char_index); + init.setElapsedTime(millis - (utterance->StartTime() * 1000.0)); + init.setName(name); + utterance->DispatchEvent(*SpeechSynthesisEvent::Create(type, init)); +} + +void SpeechSynthesis::FireErrorEvent(SpeechSynthesisUtterance* utterance, + unsigned long char_index, + const String& error) { + double millis; + if (!GetElapsedTimeMillis(&millis)) + return; + + SpeechSynthesisErrorEventInit init; + init.setUtterance(utterance); + init.setCharIndex(char_index); + init.setElapsedTime(millis - (utterance->StartTime() * 1000.0)); + init.setError(error); + utterance->DispatchEvent( + *SpeechSynthesisErrorEvent::Create(EventTypeNames::error, init)); } void SpeechSynthesis::HandleSpeakingCompleted( @@ -180,8 +199,13 @@ void SpeechSynthesis::HandleSpeakingCompleted( // sent an event on an utterance before it got the message that we // canceled it, and we should always report to the user what actually // happened. - FireEvent(error_occurred ? EventTypeNames::error : EventTypeNames::end, - utterance, 0, String()); + if (error_occurred) { + // TODO(csharrison): Actually pass the correct message. For now just use a + // generic error. + FireErrorEvent(utterance, 0, "synthesis-failed"); + } else { + FireEvent(EventTypeNames::end, utterance, 0, String()); + } // Start the next utterance if we just finished one and one was pending. if (should_start_speaking && !utterance_queue_.IsEmpty()) @@ -274,7 +298,7 @@ void SpeechSynthesis::Trace(blink::Visitor* visitor) { bool SpeechSynthesis::GetElapsedTimeMillis(double* millis) { if (!GetExecutionContext()) return false; - Document* delegate_document = ToDocument(GetExecutionContext()); + Document* delegate_document = To<Document>(GetExecutionContext()); if (!delegate_document || delegate_document->IsStopped()) return false; LocalDOMWindow* delegate_dom_window = delegate_document->domWindow(); @@ -286,7 +310,7 @@ bool SpeechSynthesis::GetElapsedTimeMillis(double* millis) { } bool SpeechSynthesis::IsAllowedToStartByAutoplay() const { - Document* document = ToDocument(GetExecutionContext()); + Document* document = To<Document>(GetExecutionContext()); DCHECK(document); // Note: could check the utterance->volume here, but that could be overriden diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.h b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.h index 4b87c237429..850407dad5a 100644 --- a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.h +++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis.h @@ -89,9 +89,13 @@ class MODULES_EXPORT SpeechSynthesis final void HandleSpeakingCompleted(SpeechSynthesisUtterance*, bool error_occurred); void FireEvent(const AtomicString& type, SpeechSynthesisUtterance*, - unsigned long char_index, + uint32_t char_index, const String& name); + void FireErrorEvent(SpeechSynthesisUtterance*, + unsigned long char_index, + const String& error); + // Returns the utterance at the front of the queue. SpeechSynthesisUtterance* CurrentSpeechUtterance() const; diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.cc b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.cc new file mode 100644 index 00000000000..40801425425 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.cc @@ -0,0 +1,26 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h" + +namespace blink { + +// static +SpeechSynthesisErrorEvent* SpeechSynthesisErrorEvent::Create( + const AtomicString& type, + const SpeechSynthesisErrorEventInit& init) { + return new SpeechSynthesisErrorEvent(type, init); +} + +SpeechSynthesisErrorEvent::SpeechSynthesisErrorEvent( + const AtomicString& type, + const SpeechSynthesisErrorEventInit& init) + : SpeechSynthesisEvent(type, + init.utterance(), + init.charIndex(), + init.elapsedTime(), + init.name()), + error_(init.error()) {} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h new file mode 100644 index 00000000000..24be96080e0 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.h @@ -0,0 +1,33 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_ERROR_EVENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_ERROR_EVENT_H_ + +#include "third_party/blink/renderer/modules/event_modules.h" +#include "third_party/blink/renderer/modules/speech/speech_synthesis_error_event_init.h" +#include "third_party/blink/renderer/modules/speech/speech_synthesis_event.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace blink { + +class SpeechSynthesisErrorEvent : public SpeechSynthesisEvent { + DEFINE_WRAPPERTYPEINFO(); + + public: + static SpeechSynthesisErrorEvent* Create( + const AtomicString& type, + const SpeechSynthesisErrorEventInit& init); + + const String error() const { return error_; } + + private: + SpeechSynthesisErrorEvent(const AtomicString& type, + const SpeechSynthesisErrorEventInit& init); + const String error_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_ERROR_EVENT_H_ diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.idl b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.idl new file mode 100644 index 00000000000..ec5d7809207 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event.idl @@ -0,0 +1,28 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://w3c.github.io/speech-api/#enumdef-speechsynthesiserrorcode +enum SpeechSynthesisErrorCode { + "canceled", + "interrupted", + "audio-busy", + "audio-hardware", + "network", + "synthesis-unavailable", + "synthesis-failed", + "language-unavailable", + "voice-unavailable", + "text-too-long", + "invalid-argument", + "not-allowed", +}; + +// https://w3c.github.io/speech-api/#speechsynthesiserrorevent +[ + Exposed=Window, + Constructor(DOMString type, SpeechSynthesisErrorEventInit eventInitDict), + RuntimeEnabled=ScriptedSpeech +] interface SpeechSynthesisErrorEvent : SpeechSynthesisEvent { + readonly attribute SpeechSynthesisErrorCode error; +}; diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event_init.idl b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event_init.idl new file mode 100644 index 00000000000..d6d201e6f99 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_error_event_init.idl @@ -0,0 +1,8 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://w3c.github.io/speech-api/#dictdef-speechsynthesiseventinit +dictionary SpeechSynthesisErrorEventInit : SpeechSynthesisEventInit { + required SpeechSynthesisErrorCode error; +}; diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event.cc b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event.cc index d8e51cd8f56..6e0ab68cdbc 100644 --- a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event.cc +++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event.cc @@ -27,22 +27,13 @@ namespace blink { -SpeechSynthesisEvent* SpeechSynthesisEvent::Create() { - return new SpeechSynthesisEvent; -} - SpeechSynthesisEvent* SpeechSynthesisEvent::Create( const AtomicString& type, - SpeechSynthesisUtterance* utterance, - unsigned char_index, - float elapsed_time, - const String& name) { - return new SpeechSynthesisEvent(type, utterance, char_index, elapsed_time, - name); + const SpeechSynthesisEventInit& init) { + return new SpeechSynthesisEvent(type, init.utterance(), init.charIndex(), + init.elapsedTime(), init.name()); } -SpeechSynthesisEvent::SpeechSynthesisEvent() = default; - SpeechSynthesisEvent::SpeechSynthesisEvent(const AtomicString& type, SpeechSynthesisUtterance* utterance, unsigned char_index, diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event.h b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event.h index 2a55b6f8528..71fbf3e31e4 100644 --- a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event.h +++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event.h @@ -27,20 +27,17 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_EVENT_H_ #include "third_party/blink/renderer/modules/event_modules.h" +#include "third_party/blink/renderer/modules/speech/speech_synthesis_event_init.h" #include "third_party/blink/renderer/modules/speech/speech_synthesis_utterance.h" namespace blink { -class SpeechSynthesisEvent final : public Event { +class SpeechSynthesisEvent : public Event { DEFINE_WRAPPERTYPEINFO(); public: - static SpeechSynthesisEvent* Create(); static SpeechSynthesisEvent* Create(const AtomicString& type, - SpeechSynthesisUtterance*, - unsigned char_index, - float elapsed_time, - const String& name); + const SpeechSynthesisEventInit& init); SpeechSynthesisUtterance* utterance() const { return utterance_; } unsigned charIndex() const { return char_index_; } @@ -53,14 +50,14 @@ class SpeechSynthesisEvent final : public Event { void Trace(blink::Visitor*) override; - private: - SpeechSynthesisEvent(); + protected: SpeechSynthesisEvent(const AtomicString& type, SpeechSynthesisUtterance*, unsigned char_index, float elapsed_time, const String& name); + private: Member<SpeechSynthesisUtterance> utterance_; unsigned char_index_; float elapsed_time_; diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event.idl b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event.idl index 4c35b5d5b25..0f9e01be747 100644 --- a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event.idl +++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event.idl @@ -23,10 +23,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// https://dvcs.w3.org/hg/speech-api/raw-file/tip/webspeechapi.html#tts-section - +// https://w3c.github.io/speech-api/#speechsynthesisevent [ - RuntimeEnabled=ScriptedSpeech + RuntimeEnabled=ScriptedSpeech, + Constructor(DOMString type, SpeechSynthesisEventInit eventInitDict) ] interface SpeechSynthesisEvent : Event { readonly attribute SpeechSynthesisUtterance utterance; readonly attribute unsigned long charIndex; diff --git a/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event_init.idl b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event_init.idl new file mode 100644 index 00000000000..0c1386f94be --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/speech/speech_synthesis_event_init.idl @@ -0,0 +1,11 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://w3c.github.io/speech-api/#dictdef-speechsynthesiseventinit +dictionary SpeechSynthesisEventInit : EventInit { + required SpeechSynthesisUtterance utterance; + unsigned long charIndex = 0; + float elapsedTime = 0; + DOMString name = ""; +}; diff --git a/chromium/third_party/blink/renderer/modules/storage/BUILD.gn b/chromium/third_party/blink/renderer/modules/storage/BUILD.gn index 4a5dba165ea..b76fee95b96 100644 --- a/chromium/third_party/blink/renderer/modules/storage/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/storage/BUILD.gn @@ -18,12 +18,12 @@ blink_modules_sources("storage") { "storage_area.h", "storage_area_map.cc", "storage_area_map.h", + "storage_controller.cc", + "storage_controller.h", "storage_event.cc", "storage_event.h", "storage_namespace.cc", "storage_namespace.h", - "storage_namespace_controller.cc", - "storage_namespace_controller.h", ] } @@ -32,6 +32,8 @@ jumbo_source_set("unit_tests") { sources = [ "cached_storage_area_test.cc", "storage_area_map_test.cc", + "storage_controller_test.cc", + "storage_namespace_test.cc", "testing/fake_area_source.h", "testing/mock_storage_area.cc", "testing/mock_storage_area.h", diff --git a/chromium/third_party/blink/renderer/modules/storage/README.md b/chromium/third_party/blink/renderer/modules/storage/README.md index 1b1875d7e38..68e29ac989c 100644 --- a/chromium/third_party/blink/renderer/modules/storage/README.md +++ b/chromium/third_party/blink/renderer/modules/storage/README.md @@ -1,25 +1,101 @@ # `blink/renderer/modules/storage` -This diretory contains the renderer side implementation of the DOM Storage API. -This API is defined in the -[HTML Spec](https://html.spec.whatwg.org/multipage/webstorage.html)'s section on -Web Storage. +This directory contains the renderer side implementation of the DOM Storage API. This API is defined in the [HTML Spec](https://html.spec.whatwg.org/multipage/webstorage.html)'s section on Web Storage. The browser side code for this lives in `content/browser/dom_storage/`. -## Class structure +*TODO(dmurph): Delete this paragraph after onion-souping is complete. +https://crbug.com/781870* +This file describes only the post-onion-souped version of the code, where +`features::kOnionSoupDOMStorage` is turned on. This is not yet the default. -`StorageArea` implements the WebIDL `Storage` interface. Instances of this class -will in the future hold a reference to a shared `CachedStorageArea` instance. -All `StorageArea` instances representing the same area will use the same -`CachedStorageArea` instance. Today instead each `StorageArea` owns a separate -`WebStorageArea` instance, implemented by the content layer. +## Class Responsibilities +### [`DOMWindowStorage`](dom_storage_window.h) +This implements the partial `Window` interface in +[window_storage.idl](window_storage.idl), and provides bindings for +`window.localStorage` and `window.sessionStorage` to the web platform. This +creates & owns the `StorageArea` objects. +### [`StorageArea`](storage_area.h) +This implements the WebIDL `Storage` interface in [storage.idl](storage.idl), +and provides access to `localStorage` and `sessionStorage`. This class holds a +shared reference to a `CachedStorageArea` (which can be shared between multiple +`StorageArea`s), and basically delegates most calls here. -`CachedStorageArea` will be responsible for communicating with the browser -process over the `StorageArea` mojom interface. It will also cache all the data -for a area in a `StorageAreaMap` instance, and will dispatch events it receives -to the relevant `StorageArea` and `InspectorDOMStorageAgent` instances. +This is also temporarily created & used by `InspectorDOMStorageAgent` to make modifications to local & session storage. +### [`CachedStorageArea`](cached_storage_area.h) +This is responsible for + * keeping a local cache of the localStorage or sessionStorage data (which it + does using a [`StorageAreaMap`](storage_area_map.h)), + * keeping track of `Source`s that are using this cached storage area (which + are `StorageAreas`), + * loading and saving data with a + [`StorageArea`](../../../public/mojom/dom_storage/storage_area.mojom) mojo + interface, and + * observing changes from that `StorageArea` interface and communicating these + to all `Source`s, and `InspectorEventListener`s. +### [`StorageAreaMap`](storage_area_map.h) +This represents an in-memory cache of a storage area. It holds key-value +storage and keeps track of the total size of the bytes stored. +### [`StorageNamespace`](storage_namespace.h) +This class is responsible for + * creating & caching `CachedStorageArea`s on a per-origin basis, + * holding weak references to `DOMStorageInspectorAgent`s & telling them when a + storage event was dispatched, + * interacting with the + [`StoragePartitionService`](../../../public/mojom/dom_storage/storage_partition_service.mojom) + and + [`SessionStorageNamespace`](../../../public/mojom/dom_storage/session_storage_namespace.mojom) + mojo interfaces to create `StorageArea` mojo ptrs for the `CachedStorageArea`s + and clone namespaces for SessionStorage. +* accounting for all storage used in it's cached areas, and +* cleaning up unused caches areas on demand. -`StorageAreaMap` represents the in-memory version of the data in a particular -storage area. It will be owned by a instance of the (yet-to-be-written) -`CachedStorageArea` class. +There are two versions of this class - one version is the SessionStorage +version, which holds a +[`SessionStorageNamespace`](../../../public/mojom/dom_storage/session_storage_namespace.mojom) +mojo ptr and lives on a `Page` as a Page Supplement. The other version is for +LocalStorage, which just uses the +[`StoragePartitionService`](../../../public/mojom/dom_storage/storage_partition_service.mojom) +to open the `StorageAreas`, and is owned by the `StorageController`. + +### [`StorageController`](storage_controller.h) +This is a singleton that is responsible for keeping track of all +`StorageNamespace`s and provide access to the functionality of it's single +LocalStorage `StorageNamespace` that it owns. It holds weak references to all +of the SessionStorage `StorageNamespace`s so it can account for the total +amount of memory used by all of DOMStorage. If this gets too high, it can ask +all namespaces to prune all unused `CacheStorageArea`s. +### [`InspectorDOMStorageAgent`](inspector_dom_storage_agent.h) +This is used by the Inspector (DevTools) code to listen to and modify local & +session storage. The `StorageNamespace` class allows these agents to be added & +removed by the Inspector system, and all events that are dispatched on that +namespace are sent to its `InspectorDOMStorageAgent`s. + +This class also creates a temporary `StorageArea` to query & modify local & +session storage. +## Class Ownership Structure +`StorageArea` lives on the `window`. Instances of this class hold a reference +to a `CachedStorageArea` instance. All `StorageArea` instances representing the +same area use the same `CachedStorageArea` instance (which is reference +counted). Two classes are used to create and manage `CachedStorageArea`s - the +`StorageController`, and `StorageNamespace`s. + +The `StorageNamespace` represents a SessionStorage namespace, but can also be +used for LocalStorage. It creates & manages `CachedStorageArea`s per-origin. It +keeps a reference to all `CachedStorageArea`s it creates for memory accounting +and object re-use. It also contains weak references to +`InspectorDOMStorageAgent`s that it notifies when StorageEvents are dispatched. + +SessionStorage `StorageNamespace` objects live as supplements on the `Page`, so +each `Page` owns one. The LocalStorage `StorageNamespace` object lives in the +`StorageController`. + +The `StorageController` is a singleton. It owns the LocalStorage +`StorageNamespace`, and hold weak references to each SessionStorage +`StorageNamespace`. + +Finally - `InspectorDomStorageAgent` will create temporary `StorageArea` +objects when it wants to query or modify DOMStorage. + +![Object ownership graph](docs/ownership.png) +[Image Source](https://docs.google.com/drawings/d/1YlaLMyJT5G8jqU_wHnldWIA3LEtGBPFs39gLkikAzyc/edit?usp=sharing) diff --git a/chromium/third_party/blink/renderer/modules/storage/cached_storage_area.cc b/chromium/third_party/blink/renderer/modules/storage/cached_storage_area.cc index 0cf518029b5..afc5524c536 100644 --- a/chromium/third_party/blink/renderer/modules/storage/cached_storage_area.cc +++ b/chromium/third_party/blink/renderer/modules/storage/cached_storage_area.cc @@ -64,18 +64,20 @@ void UnpackSource(const String& source, scoped_refptr<CachedStorageArea> CachedStorageArea::CreateForLocalStorage( scoped_refptr<const SecurityOrigin> origin, mojo::InterfacePtr<mojom::blink::StorageArea> area, - scoped_refptr<base::SingleThreadTaskRunner> ipc_runner) { + scoped_refptr<base::SingleThreadTaskRunner> ipc_runner, + InspectorEventListener* listener) { return base::AdoptRef(new CachedStorageArea( - std::move(origin), std::move(area), std::move(ipc_runner))); + std::move(origin), std::move(area), std::move(ipc_runner), listener)); } // static scoped_refptr<CachedStorageArea> CachedStorageArea::CreateForSessionStorage( scoped_refptr<const SecurityOrigin> origin, mojo::AssociatedInterfacePtr<mojom::blink::StorageArea> area, - scoped_refptr<base::SingleThreadTaskRunner> ipc_runner) { + scoped_refptr<base::SingleThreadTaskRunner> ipc_runner, + InspectorEventListener* listener) { return base::AdoptRef(new CachedStorageArea( - std::move(origin), std::move(area), std::move(ipc_runner))); + std::move(origin), std::move(area), std::move(ipc_runner), listener)); } unsigned CachedStorageArea::GetLength() { @@ -96,7 +98,7 @@ String CachedStorageArea::GetItem(const String& key) { bool CachedStorageArea::SetItem(const String& key, const String& value, Source* source) { - DCHECK(areas_.Contains(source)); + DCHECK(areas_->Contains(source)); // A quick check to reject obviously overbudget items to avoid priming the // cache. @@ -123,7 +125,7 @@ bool CachedStorageArea::SetItem(const String& key, optional_old_value = StringToUint8Vector(old_value, value_format); KURL page_url = source->GetPageUrl(); - String source_id = areas_.at(source); + String source_id = areas_->at(source); blink::WebScopedVirtualTimePauser virtual_time_pauser = source->CreateWebScopedVirtualTimePauser( @@ -136,17 +138,13 @@ bool CachedStorageArea::SetItem(const String& key, WTF::Bind(&CachedStorageArea::OnSetItemComplete, weak_factory_.GetWeakPtr(), key, std::move(virtual_time_pauser))); - if (IsSessionStorage() && old_value != value) { - for (const auto& area : areas_) { - if (area.key != source) - area.key->EnqueueStorageEvent(key, old_value, value, page_url); - } - } + if (IsSessionStorage() && old_value != value) + EnqueueStorageEvent(key, old_value, value, page_url, source_id); return true; } void CachedStorageArea::RemoveItem(const String& key, Source* source) { - DCHECK(areas_.Contains(source)); + DCHECK(areas_->Contains(source)); EnsureLoaded(); String old_value; @@ -167,7 +165,7 @@ void CachedStorageArea::RemoveItem(const String& key, Source* source) { optional_old_value = StringToUint8Vector(old_value, value_format); KURL page_url = source->GetPageUrl(); - String source_id = areas_.at(source); + String source_id = areas_->at(source); blink::WebScopedVirtualTimePauser virtual_time_pauser = source->CreateWebScopedVirtualTimePauser( @@ -179,16 +177,13 @@ void CachedStorageArea::RemoveItem(const String& key, Source* source) { WTF::Bind(&CachedStorageArea::OnRemoveItemComplete, weak_factory_.GetWeakPtr(), key, std::move(virtual_time_pauser))); - if (IsSessionStorage()) { - for (const auto& area : areas_) { - if (area.key != source) - area.key->EnqueueStorageEvent(key, old_value, String(), page_url); - } - } + + if (IsSessionStorage()) + EnqueueStorageEvent(key, old_value, String(), page_url, source_id); } void CachedStorageArea::Clear(Source* source) { - DCHECK(areas_.Contains(source)); + DCHECK(areas_->Contains(source)); bool already_empty = false; if (IsSessionStorage()) { @@ -202,7 +197,7 @@ void CachedStorageArea::Clear(Source* source) { ignore_all_mutations_ = true; KURL page_url = source->GetPageUrl(); - String source_id = areas_.at(source); + String source_id = areas_->at(source); blink::WebScopedVirtualTimePauser virtual_time_pauser = source->CreateWebScopedVirtualTimePauser( @@ -213,42 +208,46 @@ void CachedStorageArea::Clear(Source* source) { PackSource(page_url, source_id), WTF::Bind(&CachedStorageArea::OnClearComplete, weak_factory_.GetWeakPtr(), std::move(virtual_time_pauser))); - if (IsSessionStorage() && !already_empty) { - for (const auto& area : areas_) { - if (area.key != source) - area.key->EnqueueStorageEvent(String(), String(), String(), page_url); - } - } + if (IsSessionStorage() && !already_empty) + EnqueueStorageEvent(String(), String(), String(), page_url, source_id); } String CachedStorageArea::RegisterSource(Source* source) { String id = String::Number(base::RandUint64()); - areas_.insert(source, id); + areas_->insert(source, id); return id; } +// LocalStorage constructor. CachedStorageArea::CachedStorageArea( scoped_refptr<const SecurityOrigin> origin, mojo::InterfacePtr<mojom::blink::StorageArea> area, - scoped_refptr<base::SingleThreadTaskRunner> ipc_runner) + scoped_refptr<base::SingleThreadTaskRunner> ipc_runner, + InspectorEventListener* listener) : origin_(std::move(origin)), + inspector_event_listener_(listener), mojo_area_(area.get()), mojo_area_ptr_(std::move(area)), binding_(this), + areas_(new HeapHashMap<WeakMember<Source>, String>), weak_factory_(this) { mojom::blink::StorageAreaObserverAssociatedPtrInfo ptr_info; binding_.Bind(mojo::MakeRequest(&ptr_info), std::move(ipc_runner)); mojo_area_->AddObserver(std::move(ptr_info)); } +// SessionStorage constructor. CachedStorageArea::CachedStorageArea( scoped_refptr<const SecurityOrigin> origin, mojo::AssociatedInterfacePtr<mojom::blink::StorageArea> area, - scoped_refptr<base::SingleThreadTaskRunner> ipc_runner) + scoped_refptr<base::SingleThreadTaskRunner> ipc_runner, + InspectorEventListener* listener) : origin_(std::move(origin)), + inspector_event_listener_(listener), mojo_area_(area.get()), mojo_area_associated_ptr_(std::move(area)), binding_(this), + areas_(new HeapHashMap<WeakMember<Source>, String>), weak_factory_(this) { mojom::blink::StorageAreaObserverAssociatedPtrInfo ptr_info; binding_.Bind(mojo::MakeRequest(&ptr_info), std::move(ipc_runner)); @@ -287,18 +286,14 @@ void CachedStorageArea::KeyDeleted(const Vector<uint8_t>& key, Uint8VectorToString(key, FormatOption::kLocalStorageDetectFormat); bool from_local_area = false; - for (const auto& area : areas_) { + String old_value_string = + Uint8VectorToString(old_value, FormatOption::kLocalStorageDetectFormat); + for (const auto& area : *areas_) { if (area.value == storage_area_id) { from_local_area = true; - } else { - area.key->EnqueueStorageEvent( - key_string, - Uint8VectorToString(old_value, - FormatOption::kLocalStorageDetectFormat), - String(), page_url); + break; } } - if (map_ && !from_local_area) { // This was from another process or the storage area is gone. If the former, // remove it from our cache if we haven't already changed it and are waiting @@ -308,6 +303,8 @@ void CachedStorageArea::KeyDeleted(const Vector<uint8_t>& key, ignore_key_mutations_.find(key_string) == ignore_key_mutations_.end()) map_->RemoveItem(key_string, nullptr); } + EnqueueStorageEvent(key_string, old_value_string, String(), page_url, + storage_area_id); } void CachedStorageArea::AllDeleted(const String& source) { @@ -316,14 +313,12 @@ void CachedStorageArea::AllDeleted(const String& source) { UnpackSource(source, &page_url, &storage_area_id); bool from_local_area = false; - for (const auto& area : areas_) { + for (const auto& area : *areas_) { if (area.value == storage_area_id) { from_local_area = true; - } else { - area.key->EnqueueStorageEvent(String(), String(), String(), page_url); + break; } } - if (map_ && !from_local_area && !ignore_all_mutations_) { auto old = std::move(map_); map_ = std::make_unique<StorageAreaMap>( @@ -339,6 +334,7 @@ void CachedStorageArea::AllDeleted(const String& source) { ++iter; } } + EnqueueStorageEvent(String(), String(), String(), page_url, storage_area_id); } void CachedStorageArea::ShouldSendOldValueOnMutations(bool value) { @@ -361,15 +357,12 @@ void CachedStorageArea::KeyAddedOrChanged(const Vector<uint8_t>& key, Uint8VectorToString(new_value, FormatOption::kLocalStorageDetectFormat); bool from_local_area = false; - for (const auto& area : areas_) { + for (const auto& area : *areas_) { if (area.value == storage_area_id) { from_local_area = true; - } else { - area.key->EnqueueStorageEvent(key_string, old_value, new_value_string, - page_url); + break; } } - if (map_ && !from_local_area) { // This was from another process or the storage area is gone. If the former, // apply it to our cache if we haven't already changed it and are waiting @@ -382,6 +375,8 @@ void CachedStorageArea::KeyAddedOrChanged(const Vector<uint8_t>& key, map_->SetItemIgnoringQuota(key_string, new_value_string); } } + EnqueueStorageEvent(key_string, old_value, new_value_string, page_url, + storage_area_id); } void CachedStorageArea::OnSetItemComplete(const String& key, @@ -491,6 +486,24 @@ bool CachedStorageArea::IsSessionStorage() const { return mojo_area_associated_ptr_.is_bound(); } +void CachedStorageArea::EnqueueStorageEvent(const String& key, + const String& old_value, + const String& new_value, + const String& url, + const String& storage_area_id) { + HeapVector<Member<Source>, 1> areas_to_remove_; + for (const auto& area : *areas_) { + if (area.value != storage_area_id) { + bool keep = area.key->EnqueueStorageEvent(key, old_value, new_value, url); + if (!keep) + areas_to_remove_.push_back(area.key); + } + } + areas_->RemoveAll(areas_to_remove_); + inspector_event_listener_->DidDispatchStorageEvent(origin_.get(), key, + old_value, new_value); +} + // static String CachedStorageArea::Uint8VectorToString(const Vector<uint8_t>& input, FormatOption format_option) { diff --git a/chromium/third_party/blink/renderer/modules/storage/cached_storage_area.h b/chromium/third_party/blink/renderer/modules/storage/cached_storage_area.h index 006552e5420..fcf1110f69e 100644 --- a/chromium/third_party/blink/renderer/modules/storage/cached_storage_area.h +++ b/chromium/third_party/blink/renderer/modules/storage/cached_storage_area.h @@ -38,9 +38,10 @@ class MODULES_EXPORT CachedStorageArea // should have been registered first by calling RegisterSource. class Source : public GarbageCollectedMixin { public: - virtual ~Source() {} + virtual ~Source() = default; virtual KURL GetPageUrl() const = 0; - virtual void EnqueueStorageEvent(const String& key, + // Return 'true' to continue receiving events, and 'false' to stop. + virtual bool EnqueueStorageEvent(const String& key, const String& old_value, const String& new_value, const String& url) = 0; @@ -49,14 +50,26 @@ class MODULES_EXPORT CachedStorageArea WebScopedVirtualTimePauser::VirtualTaskDuration duration) = 0; }; + // Used to send events to the InspectorDOMStorageAgent. + class InspectorEventListener { + public: + virtual ~InspectorEventListener() = default; + virtual void DidDispatchStorageEvent(const SecurityOrigin* origin, + const String& key, + const String& old_value, + const String& new_value) = 0; + }; + static scoped_refptr<CachedStorageArea> CreateForLocalStorage( scoped_refptr<const SecurityOrigin> origin, mojo::InterfacePtr<mojom::blink::StorageArea> area, - scoped_refptr<base::SingleThreadTaskRunner> ipc_runner); + scoped_refptr<base::SingleThreadTaskRunner> ipc_runner, + InspectorEventListener* listener); static scoped_refptr<CachedStorageArea> CreateForSessionStorage( scoped_refptr<const SecurityOrigin> origin, mojo::AssociatedInterfacePtr<mojom::blink::StorageArea> area, - scoped_refptr<base::SingleThreadTaskRunner> ipc_runner); + scoped_refptr<base::SingleThreadTaskRunner> ipc_runner, + InspectorEventListener* listener); // These correspond to blink::Storage. unsigned GetLength(); @@ -83,11 +96,13 @@ class MODULES_EXPORT CachedStorageArea private: CachedStorageArea(scoped_refptr<const SecurityOrigin> origin, mojo::InterfacePtr<mojom::blink::StorageArea> area, - scoped_refptr<base::SingleThreadTaskRunner> ipc_runner); + scoped_refptr<base::SingleThreadTaskRunner> ipc_runner, + InspectorEventListener* listener); CachedStorageArea( scoped_refptr<const SecurityOrigin> origin, mojo::AssociatedInterfacePtr<mojom::blink::StorageArea> area, - scoped_refptr<base::SingleThreadTaskRunner> ipc_runner); + scoped_refptr<base::SingleThreadTaskRunner> ipc_runner, + InspectorEventListener* listener); friend class RefCounted<CachedStorageArea>; ~CachedStorageArea() override; @@ -134,12 +149,19 @@ class MODULES_EXPORT CachedStorageArea FormatOption GetKeyFormat() const; FormatOption GetValueFormat() const; + void EnqueueStorageEvent(const String& key, + const String& old_value, + const String& new_value, + const String& url, + const String& storage_area_id); + static String Uint8VectorToString(const Vector<uint8_t>& input, FormatOption format_option); static Vector<uint8_t> StringToUint8Vector(const String& input, FormatOption format_option); scoped_refptr<const SecurityOrigin> origin_; + InspectorEventListener* inspector_event_listener_; std::unique_ptr<StorageAreaMap> map_; @@ -158,7 +180,7 @@ class MODULES_EXPORT CachedStorageArea mojo_area_associated_ptr_; mojo::AssociatedBinding<mojom::blink::StorageAreaObserver> binding_; - PersistentHeapHashMap<WeakMember<Source>, String> areas_; + Persistent<HeapHashMap<WeakMember<Source>, String>> areas_; base::WeakPtrFactory<CachedStorageArea> weak_factory_; diff --git a/chromium/third_party/blink/renderer/modules/storage/cached_storage_area_test.cc b/chromium/third_party/blink/renderer/modules/storage/cached_storage_area_test.cc index e38be688b90..c85494858cb 100644 --- a/chromium/third_party/blink/renderer/modules/storage/cached_storage_area_test.cc +++ b/chromium/third_party/blink/renderer/modules/storage/cached_storage_area_test.cc @@ -15,7 +15,8 @@ namespace blink { using FormatOption = CachedStorageArea::FormatOption; -class CachedStorageAreaTest : public testing::Test { +class CachedStorageAreaTest : public testing::Test, + public CachedStorageArea::InspectorEventListener { public: const scoped_refptr<SecurityOrigin> kOrigin = SecurityOrigin::CreateFromString("http://dom_storage/"); @@ -31,11 +32,11 @@ class CachedStorageAreaTest : public testing::Test { if (IsSessionStorage()) { cached_area_ = CachedStorageArea::CreateForSessionStorage( kOrigin, mock_storage_area_.GetAssociatedInterfacePtr(), - renderer_scheduler_->IPCTaskRunner()); + renderer_scheduler_->IPCTaskRunner(), this); } else { cached_area_ = CachedStorageArea::CreateForLocalStorage( kOrigin, mock_storage_area_.GetInterfacePtr(), - renderer_scheduler_->IPCTaskRunner()); + renderer_scheduler_->IPCTaskRunner(), this); } source_area_ = new FakeAreaSource(kPageUrl); source_area_id_ = cached_area_->RegisterSource(source_area_); @@ -44,6 +45,11 @@ class CachedStorageAreaTest : public testing::Test { cached_area_->RegisterSource(source_area2_); } + void DidDispatchStorageEvent(const SecurityOrigin* origin, + const String& key, + const String& old_value, + const String& new_value) override {} + virtual bool IsSessionStorage() { return false; } bool IsCacheLoaded() { return cached_area_->map_.get(); } diff --git a/chromium/third_party/blink/renderer/modules/storage/docs/ownership.png b/chromium/third_party/blink/renderer/modules/storage/docs/ownership.png Binary files differnew file mode 100644 index 00000000000..a001516f503 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/storage/docs/ownership.png diff --git a/chromium/third_party/blink/renderer/modules/storage/dom_window_storage.cc b/chromium/third_party/blink/renderer/modules/storage/dom_window_storage.cc index 848aebe7a10..e62490bd038 100644 --- a/chromium/third_party/blink/renderer/modules/storage/dom_window_storage.cc +++ b/chromium/third_party/blink/renderer/modules/storage/dom_window_storage.cc @@ -12,8 +12,9 @@ #include "third_party/blink/renderer/core/frame/use_counter.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/modules/storage/storage_area.h" +#include "third_party/blink/renderer/modules/storage/storage_controller.h" #include "third_party/blink/renderer/modules/storage/storage_namespace.h" -#include "third_party/blink/renderer/modules/storage/storage_namespace_controller.h" +#include "third_party/blink/renderer/platform/weborigin/security_origin.h" namespace blink { @@ -88,9 +89,8 @@ StorageArea* DOMWindowStorage::sessionStorage( if (!page) return nullptr; - auto storage_area = - StorageNamespaceController::From(page)->SessionStorage()->GetStorageArea( - document->GetSecurityOrigin()); + auto storage_area = StorageNamespace::From(page)->GetWebStorageArea( + document->GetSecurityOrigin()); session_storage_ = StorageArea::Create(document->GetFrame(), std::move(storage_area), StorageArea::StorageType::kSessionStorage); @@ -136,8 +136,8 @@ StorageArea* DOMWindowStorage::localStorage( Page* page = document->GetPage(); if (!page || !page->GetSettings().GetLocalStorageEnabled()) return nullptr; - auto storage_area = - StorageNamespace::LocalStorageArea(document->GetSecurityOrigin()); + auto storage_area = StorageController::GetInstance()->GetWebLocalStorageArea( + document->GetSecurityOrigin()); local_storage_ = StorageArea::Create(document->GetFrame(), std::move(storage_area), StorageArea::StorageType::kLocalStorage); diff --git a/chromium/third_party/blink/renderer/modules/storage/inspector_dom_storage_agent.cc b/chromium/third_party/blink/renderer/modules/storage/inspector_dom_storage_agent.cc index 0f48ab2f9dd..708b67262c5 100644 --- a/chromium/third_party/blink/renderer/modules/storage/inspector_dom_storage_agent.cc +++ b/chromium/third_party/blink/renderer/modules/storage/inspector_dom_storage_agent.cc @@ -35,9 +35,10 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/inspector/inspected_frames.h" #include "third_party/blink/renderer/core/page/page.h" +#include "third_party/blink/renderer/modules/storage/cached_storage_area.h" #include "third_party/blink/renderer/modules/storage/storage_area.h" +#include "third_party/blink/renderer/modules/storage/storage_controller.h" #include "third_party/blink/renderer/modules/storage/storage_namespace.h" -#include "third_party/blink/renderer/modules/storage/storage_namespace_controller.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" @@ -74,9 +75,11 @@ void InspectorDOMStorageAgent::Restore() { } void InspectorDOMStorageAgent::InnerEnable() { - if (StorageNamespaceController* controller = StorageNamespaceController::From( - inspected_frames_->Root()->GetPage())) - controller->SetInspectorAgent(this); + StorageController::GetInstance()->AddLocalStorageInspectorStorageAgent(this); + StorageNamespace* ns = + StorageNamespace::From(inspected_frames_->Root()->GetPage()); + if (ns) + ns->AddInspectorStorageAgent(this); } Response InspectorDOMStorageAgent::enable() { @@ -91,9 +94,12 @@ Response InspectorDOMStorageAgent::disable() { if (!enabled_.Get()) return Response::OK(); enabled_.Set(false); - if (StorageNamespaceController* controller = StorageNamespaceController::From( - inspected_frames_->Root()->GetPage())) - controller->SetInspectorAgent(nullptr); + StorageController::GetInstance()->RemoveLocalStorageInspectorStorageAgent( + this); + StorageNamespace* ns = + StorageNamespace::From(inspected_frames_->Root()->GetPage()); + if (ns) + ns->RemoveInspectorStorageAgent(this); return Response::OK(); } @@ -213,23 +219,25 @@ Response InspectorDOMStorageAgent::FindStorageArea( if (is_local_storage) { if (!frame->GetDocument()->GetSecurityOrigin()->CanAccessLocalStorage()) return Response::Error("Security origin cannot access local storage"); - storage_area = - StorageArea::Create(frame, - StorageNamespace::LocalStorageArea( - frame->GetDocument()->GetSecurityOrigin()), - StorageArea::StorageType::kLocalStorage); + storage_area = StorageArea::Create( + frame, + StorageController::GetInstance()->GetWebLocalStorageArea( + frame->GetDocument()->GetSecurityOrigin()), + StorageArea::StorageType::kLocalStorage); return Response::OK(); } if (!frame->GetDocument()->GetSecurityOrigin()->CanAccessSessionStorage()) return Response::Error("Security origin cannot access session storage"); - StorageNamespace* session_storage = - StorageNamespaceController::From(frame->GetPage())->SessionStorage(); - if (!session_storage) + StorageNamespace* session_namespace = + StorageNamespace::From(frame->GetPage()); + if (!session_namespace) return Response::Error("SessionStorage is not supported"); + DCHECK(session_namespace->IsSessionStorage()); + storage_area = StorageArea::Create(frame, - session_storage->GetStorageArea( + session_namespace->GetWebStorageArea( frame->GetDocument()->GetSecurityOrigin()), StorageArea::StorageType::kSessionStorage); return Response::OK(); diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_area.cc b/chromium/third_party/blink/renderer/modules/storage/storage_area.cc index 15d31039c25..9aa7c7a460e 100644 --- a/chromium/third_party/blink/renderer/modules/storage/storage_area.cc +++ b/chromium/third_party/blink/renderer/modules/storage/storage_area.cc @@ -27,14 +27,16 @@ #include "base/memory/scoped_refptr.h" #include "third_party/blink/public/platform/web_storage_area.h" +#include "third_party/blink/public/platform/web_storage_namespace.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/modules/storage/dom_window_storage.h" #include "third_party/blink/renderer/modules/storage/inspector_dom_storage_agent.h" +#include "third_party/blink/renderer/modules/storage/storage_controller.h" #include "third_party/blink/renderer/modules/storage/storage_event.h" #include "third_party/blink/renderer/modules/storage/storage_namespace.h" -#include "third_party/blink/renderer/modules/storage/storage_namespace_controller.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { @@ -166,12 +168,8 @@ bool StorageArea::CanAccessStorage() const { if (did_check_can_access_storage_) return can_access_storage_cached_result_; - StorageNamespaceController* controller = - StorageNamespaceController::From(frame->GetPage()); - if (!controller) - return false; can_access_storage_cached_result_ = - controller->CanAccessStorageArea(frame, storage_type_); + StorageController::CanAccessStorageArea(frame, storage_type_); did_check_can_access_storage_ = true; return can_access_storage_cached_result_; } @@ -179,14 +177,11 @@ bool StorageArea::CanAccessStorage() const { namespace { Page* FindPageWithSessionStorageNamespace( const WebStorageNamespace& session_namespace) { - // Iterate over all pages that have a StorageNamespaceController supplement. + // Iterate over all pages that have a StorageNamespace supplement. + String namespace_str = session_namespace.GetNamespaceId(); for (Page* page : Page::OrdinaryPages()) { - const bool kDontCreateIfMissing = false; - StorageNamespace* storage_namespace = - StorageNamespaceController::From(page)->SessionStorage( - kDontCreateIfMissing); - if (storage_namespace && - storage_namespace->IsSameNamespace(session_namespace)) + StorageNamespace* storage_namespace = StorageNamespace::From(page); + if (storage_namespace && storage_namespace->namespace_id() == namespace_str) return page; } return nullptr; @@ -206,7 +201,7 @@ void StorageArea::DispatchLocalStorageEvent( const SecurityOrigin* security_origin, const KURL& page_url, WebStorageArea* source_area_instance) { - // Iterate over all pages that have a StorageNamespaceController supplement. + // Iterate over all pages that have a LocalStorage area created. for (Page* page : Page::OrdinaryPages()) { for (Frame* frame = page->MainFrame(); frame; frame = frame->Tree().TraverseNext()) { @@ -229,12 +224,8 @@ void StorageArea::DispatchLocalStorageEvent( TaskType::kDOMManipulation); } } - if (InspectorDOMStorageAgent* agent = - StorageNamespaceController::From(page)->InspectorAgent()) { - agent->DidDispatchDOMStorageEvent(key, old_value, new_value, - StorageType::kLocalStorage, - security_origin); - } + StorageController::GetInstance()->DidDispatchLocalStorageEvent( + security_origin, key, old_value, new_value); } } @@ -270,12 +261,8 @@ void StorageArea::DispatchSessionStorageEvent( TaskType::kDOMManipulation); } } - if (InspectorDOMStorageAgent* agent = - StorageNamespaceController::From(page)->InspectorAgent()) { - agent->DidDispatchDOMStorageEvent(key, old_value, new_value, - StorageType::kSessionStorage, - security_origin); - } + StorageNamespace::From(page)->DidDispatchStorageEvent(security_origin, key, + old_value, new_value); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_controller.cc b/chromium/third_party/blink/renderer/modules/storage/storage_controller.cc new file mode 100644 index 00000000000..855e3ba7254 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/storage/storage_controller.cc @@ -0,0 +1,170 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/storage/storage_controller.h" + +#include "base/feature_list.h" +#include "base/sys_info.h" +#include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/platform/interface_provider.h" +#include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/public/platform/web_storage_area.h" +#include "third_party/blink/public/platform/web_storage_namespace.h" +#include "third_party/blink/renderer/core/frame/content_settings_client.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/modules/storage/cached_storage_area.h" +#include "third_party/blink/renderer/modules/storage/storage_namespace.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" +#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h" + +namespace blink { +namespace { + +#define STATIC_ASSERT_MATCHING_ENUM(enum_name1, enum_name2) \ + static_assert(static_cast<int>(enum_name1) == static_cast<int>(enum_name2), \ + "mismatching enums: " #enum_name1) +STATIC_ASSERT_MATCHING_ENUM(StorageArea::StorageType::kLocalStorage, + ContentSettingsClient::StorageType::kLocal); +STATIC_ASSERT_MATCHING_ENUM(StorageArea::StorageType::kSessionStorage, + ContentSettingsClient::StorageType::kSession); + +const size_t kStorageControllerTotalCacheLimitInBytesLowEnd = 1 * 1024 * 1024; +const size_t kStorageControllerTotalCacheLimitInBytes = 5 * 1024 * 1024; + +mojom::blink::StoragePartitionServicePtr GetAndCreateStorageInterface() { + mojom::blink::StoragePartitionServicePtr ptr; + Platform::Current()->GetInterfaceProvider()->GetInterface( + mojo::MakeRequest(&ptr)); + return ptr; +} +} // namespace + +// static +StorageController* StorageController::GetInstance() { + DEFINE_STATIC_LOCAL( + StorageController, gCachedStorageAreaController, + (Platform::Current()->MainThread()->Scheduler()->IPCTaskRunner(), + GetAndCreateStorageInterface(), + base::SysInfo::IsLowEndDevice() + ? kStorageControllerTotalCacheLimitInBytesLowEnd + : kStorageControllerTotalCacheLimitInBytes)); + return &gCachedStorageAreaController; +} + +// static +bool StorageController::CanAccessStorageArea(LocalFrame* frame, + StorageArea::StorageType type) { + DCHECK(frame->GetContentSettingsClient()); + return frame->GetContentSettingsClient()->AllowStorage( + static_cast<ContentSettingsClient::StorageType>(type)); +} + +StorageController::StorageController( + scoped_refptr<base::SingleThreadTaskRunner> ipc_runner, + mojom::blink::StoragePartitionServicePtr storage_partition_service, + size_t total_cache_limit) + : ipc_runner_(std::move(ipc_runner)), + namespaces_(new HeapHashMap<String, WeakMember<StorageNamespace>>()), + total_cache_limit_(total_cache_limit), + storage_partition_service_(std::move(storage_partition_service)) {} + +StorageNamespace* StorageController::CreateSessionStorageNamespace( + const String& namespace_id) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // There is an edge case where a user closes a tab that has other tabs in the + // same process, then restores that tab. The old namespace might still be + // around. + auto it = namespaces_->find(namespace_id); + if (it != namespaces_->end()) + return it->value; + StorageNamespace* ns = nullptr; + if (base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage)) { + ns = new StorageNamespace(this, namespace_id); + } else { + auto namespace_str = StringUTF8Adaptor(namespace_id); + auto web_namespace = Platform::Current()->CreateSessionStorageNamespace( + namespace_str.AsStringPiece()); + if (!web_namespace) + return nullptr; + ns = new StorageNamespace(std::move(web_namespace)); + } + namespaces_->insert(namespace_id, ns); + return ns; +} + +size_t StorageController::TotalCacheSize() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + size_t total = 0; + if (local_storage_namespace_) + total = local_storage_namespace_->TotalCacheSize(); + for (const auto& pair : *namespaces_) + total += pair.value->TotalCacheSize(); + return total; +} + +void StorageController::ClearAreasIfNeeded() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (TotalCacheSize() < total_cache_limit_) + return; + if (local_storage_namespace_) + local_storage_namespace_->CleanUpUnusedAreas(); + for (auto& pair : *namespaces_) + pair.value->CleanUpUnusedAreas(); +} + +scoped_refptr<CachedStorageArea> StorageController::GetLocalStorageArea( + const SecurityOrigin* origin) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + CHECK(base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage)); + EnsureLocalStorageNamespaceCreated(); + return local_storage_namespace_->GetCachedArea(origin); +} + +std::unique_ptr<WebStorageArea> StorageController::GetWebLocalStorageArea( + const SecurityOrigin* origin) { + DCHECK(IsMainThread()); + CHECK(!base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage)); + EnsureLocalStorageNamespaceCreated(); + return local_storage_namespace_->GetWebStorageArea(origin); +} + +void StorageController::AddLocalStorageInspectorStorageAgent( + InspectorDOMStorageAgent* agent) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + EnsureLocalStorageNamespaceCreated(); + local_storage_namespace_->AddInspectorStorageAgent(agent); +} + +void StorageController::RemoveLocalStorageInspectorStorageAgent( + InspectorDOMStorageAgent* agent) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + EnsureLocalStorageNamespaceCreated(); + local_storage_namespace_->RemoveInspectorStorageAgent(agent); +} + +void StorageController::DidDispatchLocalStorageEvent( + const SecurityOrigin* origin, + const String& key, + const String& old_value, + const String& new_value) { + if (local_storage_namespace_) { + local_storage_namespace_->DidDispatchStorageEvent(origin, key, old_value, + new_value); + } +} + +void StorageController::EnsureLocalStorageNamespaceCreated() { + if (local_storage_namespace_) + return; + if (base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage)) { + local_storage_namespace_ = new StorageNamespace(this); + } else { + local_storage_namespace_ = new StorageNamespace( + Platform::Current()->CreateLocalStorageNamespace()); + } +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_controller.h b/chromium/third_party/blink/renderer/modules/storage/storage_controller.h new file mode 100644 index 00000000000..f706c84df2f --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/storage/storage_controller.h @@ -0,0 +1,110 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_STORAGE_CONTROLLER_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_STORAGE_CONTROLLER_H_ + +#include <memory> + +#include "base/sequence_checker.h" +#include "third_party/blink/public/common/dom_storage/session_storage_namespace_id.h" +#include "third_party/blink/public/mojom/dom_storage/storage_partition_service.mojom-blink.h" +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/modules/storage/storage_area.h" +#include "third_party/blink/renderer/platform/heap/heap_allocator.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" + +namespace base { +class SingleThreadTaskRunner; +} + +namespace blink { + +class CachedStorageArea; +class InspectorDOMStorageAgent; +class LocalFrame; +class SecurityOrigin; +class StorageNamespace; +class WebStorageArea; + +// Singleton that manages the creation & accounting for DOMStorage objects. It +// does this by holding weak references to all session storage namespaces, and +// owning the local storage namespace internally. The total cache size is +// exposed with |TotalCacheSize()|, and |ClearAreasIfNeeded()| will - if our +// total cache size is larger than |total_cache_limit| - clear away any cache +// areas in live namespaces that no longer have references from Blink objects. +// +// SessionStorage StorageNamespace objects are created with +// |CreateSessionStorageNamespace| and live as a supplement on the Page. +// +// The LocalStorage StorageNamespace object is owned internally, and +// StorageController delegates the following methods to that namespace: +// GetLocalStorageArea, GetWebLocalStorageArea, +// AddLocalStorageInspectorStorageAgent, +// RemoveLocalStorageInspectorStorageAgent, DidDispatchLocalStorageEvent +class MODULES_EXPORT StorageController { + public: + // Returns the one global StorageController instance. + static StorageController* GetInstance(); + + static bool CanAccessStorageArea(LocalFrame* frame, + StorageArea::StorageType type); + + // Visible for testing. + StorageController( + scoped_refptr<base::SingleThreadTaskRunner> ipc_runner, + mojom::blink::StoragePartitionServicePtr storage_partition_service, + size_t total_cache_limit); + + // Creates a new StorageNamespace for Session storage, and holds a weak + // reference for accounting & clearing. If there is already a StorageNamespace + // created for the given id, it is returned. + StorageNamespace* CreateSessionStorageNamespace(const String& namespace_id); + + // Returns the total size of all cached areas in namespaces this controller + // knows of. + size_t TotalCacheSize() const; + + // Cleans up unused areas if the total cache size is over the cache limit. + void ClearAreasIfNeeded(); + + // Methods that delegate to the internal SessionNamespace used for + // LocalStorage: + + scoped_refptr<CachedStorageArea> GetLocalStorageArea(const SecurityOrigin*); + // TODO(dmurph): Remove this once DOMStorage is Onion Soupified. + std::unique_ptr<WebStorageArea> GetWebLocalStorageArea(const SecurityOrigin*); + void AddLocalStorageInspectorStorageAgent(InspectorDOMStorageAgent* agent); + void RemoveLocalStorageInspectorStorageAgent(InspectorDOMStorageAgent* agent); + // TODO(dmurph): Remove this once DOMStorage is Onion Soupified. + void DidDispatchLocalStorageEvent(const SecurityOrigin* origin, + const String& key, + const String& old_value, + const String& new_value); + + mojom::blink::StoragePartitionService* storage_partition_service() const { + return storage_partition_service_.get(); + } + + scoped_refptr<base::SingleThreadTaskRunner> IPCTaskRunner() { + return ipc_runner_; + } + + private: + void EnsureLocalStorageNamespaceCreated(); + + scoped_refptr<base::SingleThreadTaskRunner> ipc_runner_; + Persistent<HeapHashMap<String, WeakMember<StorageNamespace>>> namespaces_; + Persistent<StorageNamespace> local_storage_namespace_; + size_t total_cache_limit_; + + // Onion-soup state. + mojom::blink::StoragePartitionServicePtr storage_partition_service_; + + SEQUENCE_CHECKER(sequence_checker_); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_STORAGE_CONTROLLER_H_ diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_controller_test.cc b/chromium/third_party/blink/renderer/modules/storage/storage_controller_test.cc new file mode 100644 index 00000000000..ff0d8a140a4 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/storage/storage_controller_test.cc @@ -0,0 +1,176 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/storage/storage_controller.h" + +#include "base/task/post_task.h" +#include "base/test/scoped_feature_list.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/platform/scheduler/test/fake_renderer_scheduler.h" +#include "third_party/blink/renderer/modules/storage/storage_namespace.h" +#include "third_party/blink/renderer/modules/storage/testing/fake_area_source.h" +#include "third_party/blink/renderer/modules/storage/testing/mock_storage_area.h" +#include "third_party/blink/renderer/platform/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/uuid.h" +#include "third_party/blink/renderer/platform/web_task_runner.h" +#include "third_party/blink/renderer/platform/wtf/functional.h" + +namespace blink { +namespace { + +const size_t kTestCacheLimit = 100; +class MockStoragePartitionService + : public mojom::blink::StoragePartitionService { + public: + void OpenLocalStorage(const scoped_refptr<const SecurityOrigin>& origin, + mojom::blink::StorageAreaRequest request) override {} + + void OpenSessionStorage( + const String& namespace_id, + mojom::blink::SessionStorageNamespaceRequest request) override { + session_storage_opens++; + } + + void GetSessionStorageUsage(int32_t* out) const { + *out = session_storage_opens; + } + + int32_t session_storage_opens = 0; +}; + +} // namespace + +TEST(StorageControllerTest, CacheLimit) { + base::test::ScopedFeatureList features; + features.InitAndEnableFeature(features::kOnionSoupDOMStorage); + const auto kOrigin = SecurityOrigin::CreateFromString("http://dom_storage1/"); + const auto kOrigin2 = + SecurityOrigin::CreateFromString("http://dom_storage2/"); + const auto kOrigin3 = + SecurityOrigin::CreateFromString("http://dom_storage3/"); + const String kKey("key"); + const String kValue("value"); + const KURL kPageUrl("http://dom_storage/page"); + Persistent<FakeAreaSource> source_area = new FakeAreaSource(kPageUrl); + + blink::scheduler::FakeRendererScheduler renderer_scheduler; + + mojom::blink::StoragePartitionServicePtr storage_partition_service_ptr; + PostCrossThreadTask( + *base::CreateSequencedTaskRunnerWithTraits({}), FROM_HERE, + CrossThreadBind( + [](mojom::blink::StoragePartitionServiceRequest request) { + mojo::MakeStrongBinding( + std::make_unique<MockStoragePartitionService>(), + std::move(request)); + }, + WTF::Passed(MakeRequest(&storage_partition_service_ptr)))); + + StorageController controller(renderer_scheduler.IPCTaskRunner(), + std::move(storage_partition_service_ptr), + kTestCacheLimit); + + auto cached_area1 = controller.GetLocalStorageArea(kOrigin.get()); + cached_area1->RegisterSource(source_area); + cached_area1->SetItem(kKey, kValue, source_area); + const auto* area1_ptr = cached_area1.get(); + size_t expected_total = (kKey.length() + kValue.length()) * 2; + EXPECT_EQ(expected_total, cached_area1->memory_used()); + EXPECT_EQ(expected_total, controller.TotalCacheSize()); + cached_area1 = nullptr; + + auto cached_area2 = controller.GetLocalStorageArea(kOrigin2.get()); + cached_area2->RegisterSource(source_area); + cached_area2->SetItem(kKey, kValue, source_area); + // Area for kOrigin should still be alive. + EXPECT_EQ(2 * cached_area2->memory_used(), controller.TotalCacheSize()); + EXPECT_EQ(area1_ptr, controller.GetLocalStorageArea(kOrigin.get())); + + String long_value(Vector<UChar>(kTestCacheLimit, 'a')); + cached_area2->SetItem(kKey, long_value, source_area); + // Cache is cleared when a new area is opened. + auto cached_area3 = controller.GetLocalStorageArea(kOrigin3.get()); + EXPECT_EQ(cached_area2->memory_used(), controller.TotalCacheSize()); +} + +TEST(StorageControllerTest, CacheLimitSessionStorage) { + base::test::ScopedFeatureList features; + features.InitAndEnableFeature(features::kOnionSoupDOMStorage); + const String kNamespace1 = CreateCanonicalUUIDString(); + const String kNamespace2 = CreateCanonicalUUIDString(); + const auto kOrigin = SecurityOrigin::CreateFromString("http://dom_storage1/"); + const auto kOrigin2 = + SecurityOrigin::CreateFromString("http://dom_storage2/"); + const auto kOrigin3 = + SecurityOrigin::CreateFromString("http://dom_storage3/"); + const String kKey("key"); + const String kValue("value"); + const KURL kPageUrl("http://dom_storage/page"); + + Persistent<FakeAreaSource> source_area = new FakeAreaSource(kPageUrl); + + blink::scheduler::FakeRendererScheduler renderer_scheduler; + auto task_runner = base::CreateSequencedTaskRunnerWithTraits({}); + + auto mock_storage_partition_service = + std::make_unique<MockStoragePartitionService>(); + MockStoragePartitionService* storage_partition_ptr = + mock_storage_partition_service.get(); + + mojom::blink::StoragePartitionServicePtr storage_partition_service_ptr; + PostCrossThreadTask( + *task_runner, FROM_HERE, + CrossThreadBind( + [](std::unique_ptr<MockStoragePartitionService> storage_partition_ptr, + mojom::blink::StoragePartitionServiceRequest request) { + mojo::MakeStrongBinding(std::move(storage_partition_ptr), + std::move(request)); + }, + WTF::Passed(std::move(mock_storage_partition_service)), + WTF::Passed(MakeRequest(&storage_partition_service_ptr)))); + StorageController controller(renderer_scheduler.IPCTaskRunner(), + std::move(storage_partition_service_ptr), + kTestCacheLimit); + + StorageNamespace* ns1 = controller.CreateSessionStorageNamespace(kNamespace1); + StorageNamespace* ns2 = controller.CreateSessionStorageNamespace(kNamespace2); + + auto cached_area1 = ns1->GetCachedArea(kOrigin.get()); + cached_area1->RegisterSource(source_area); + cached_area1->SetItem(kKey, kValue, source_area); + const auto* area1_ptr = cached_area1.get(); + size_t expected_total = (kKey.length() + kValue.length()) * 2; + EXPECT_EQ(expected_total, cached_area1->memory_used()); + EXPECT_EQ(expected_total, controller.TotalCacheSize()); + cached_area1 = nullptr; + + auto cached_area2 = ns2->GetCachedArea(kOrigin2.get()); + cached_area2->RegisterSource(source_area); + cached_area2->SetItem(kKey, kValue, source_area); + // Area for kOrigin should still be alive. + EXPECT_EQ(2 * cached_area2->memory_used(), controller.TotalCacheSize()); + EXPECT_EQ(area1_ptr, ns1->GetCachedArea(kOrigin.get())); + + String long_value(Vector<UChar>(kTestCacheLimit, 'a')); + cached_area2->SetItem(kKey, long_value, source_area); + // Cache is cleared when a new area is opened. + auto cached_area3 = ns1->GetCachedArea(kOrigin3.get()); + EXPECT_EQ(cached_area2->memory_used(), controller.TotalCacheSize()); + + int32_t opens = 0; + { + base::RunLoop loop; + task_runner->PostTaskAndReply( + FROM_HERE, + base::BindOnce(&MockStoragePartitionService::GetSessionStorageUsage, + base::Unretained(storage_partition_ptr), &opens), + loop.QuitClosure()); + loop.Run(); + } + EXPECT_EQ(opens, 2); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_namespace.cc b/chromium/third_party/blink/renderer/modules/storage/storage_namespace.cc index 617817f297f..fdc44083b4c 100644 --- a/chromium/third_party/blink/renderer/modules/storage/storage_namespace.cc +++ b/chromium/third_party/blink/renderer/modules/storage/storage_namespace.cc @@ -27,42 +27,171 @@ #include <memory> +#include "base/feature_list.h" #include "base/memory/ptr_util.h" +#include "base/metrics/histogram_macros.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_security_origin.h" #include "third_party/blink/public/platform/web_storage_area.h" #include "third_party/blink/public/platform/web_storage_namespace.h" +#include "third_party/blink/public/web/web_view_client.h" +#include "third_party/blink/renderer/modules/storage/cached_storage_area.h" +#include "third_party/blink/renderer/modules/storage/inspector_dom_storage_agent.h" +#include "third_party/blink/renderer/modules/storage/storage_area.h" +#include "third_party/blink/renderer/modules/storage/storage_controller.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" namespace blink { +const char StorageNamespace::kSupplementName[] = "SessionStorageNamespace"; + +StorageNamespace::StorageNamespace(StorageController* controller) + : controller_(controller) { + CHECK(base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage)); +} +StorageNamespace::StorageNamespace(StorageController* controller, + const String& namespace_id) + : controller_(controller), namespace_id_(namespace_id) { + CHECK(base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage)); +} + StorageNamespace::StorageNamespace( std::unique_ptr<WebStorageNamespace> web_storage_namespace) - : web_storage_namespace_(std::move(web_storage_namespace)) {} + : controller_(nullptr), + namespace_id_(web_storage_namespace->GetNamespaceId()), + web_storage_namespace_(std::move(web_storage_namespace)) { + CHECK(!base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage)); +} StorageNamespace::~StorageNamespace() = default; -std::unique_ptr<WebStorageArea> StorageNamespace::LocalStorageArea( - const SecurityOrigin* origin) { - DCHECK(IsMainThread()); - static std::unique_ptr<WebStorageNamespace> local_storage_namespace = nullptr; - if (!local_storage_namespace) - local_storage_namespace = - Platform::Current()->CreateLocalStorageNamespace(); - return base::WrapUnique( - local_storage_namespace->CreateStorageArea(WebSecurityOrigin(origin))); +// static +void StorageNamespace::ProvideSessionStorageNamespaceTo(Page& page, + WebViewClient* client) { + if (client) { + if (client->GetSessionStorageNamespaceId().empty()) + return; + auto* ss_namespace = + StorageController::GetInstance()->CreateSessionStorageNamespace( + String(client->GetSessionStorageNamespaceId().data(), + client->GetSessionStorageNamespaceId().size())); + if (!ss_namespace) + return; + ProvideTo(page, ss_namespace); + } +} + +scoped_refptr<CachedStorageArea> StorageNamespace::GetCachedArea( + const SecurityOrigin* origin_ptr) { + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. + enum class CacheMetrics { + kMiss = 0, // Area not in cache. + kHit = 1, // Area with refcount = 0 loaded from cache. + kUnused = 2, // Cache was not used. Area had refcount > 0. + kMaxValue = kUnused, + }; + + CacheMetrics metric = CacheMetrics::kMiss; + scoped_refptr<CachedStorageArea> result; + auto cache_it = cached_areas_.find(origin_ptr); + if (cache_it != cached_areas_.end()) { + metric = cache_it->value->HasOneRef() ? CacheMetrics::kHit + : CacheMetrics::kUnused; + result = cache_it->value; + } + if (IsSessionStorage()) + LOCAL_HISTOGRAM_ENUMERATION("SessionStorage.RendererAreaCacheHit", metric); + else + UMA_HISTOGRAM_ENUMERATION("LocalStorage.RendererAreaCacheHit", metric); + + if (result) + return result; + + scoped_refptr<const SecurityOrigin> origin(origin_ptr); + + controller_->ClearAreasIfNeeded(); + if (IsSessionStorage()) { + EnsureConnected(); + mojom::blink::StorageAreaAssociatedPtr area_ptr; + namespace_->OpenArea(origin, + MakeRequest(&area_ptr, controller_->IPCTaskRunner())); + result = CachedStorageArea::CreateForSessionStorage( + origin, std::move(area_ptr), controller_->IPCTaskRunner(), this); + } else { + mojom::blink::StorageAreaPtr area_ptr; + controller_->storage_partition_service()->OpenLocalStorage( + origin, MakeRequest(&area_ptr, controller_->IPCTaskRunner())); + result = CachedStorageArea::CreateForLocalStorage( + origin, std::move(area_ptr), controller_->IPCTaskRunner(), this); + } + cached_areas_.insert(std::move(origin), result); + return result; } -std::unique_ptr<WebStorageArea> StorageNamespace::GetStorageArea( +void StorageNamespace::CloneTo(const String& target) { + DCHECK(IsSessionStorage()) << "Cannot clone a local storage namespace."; + EnsureConnected(); + namespace_->Clone(target); +} + +size_t StorageNamespace::TotalCacheSize() const { + size_t total = 0; + for (const auto& it : cached_areas_) + total += it.value->memory_used(); + return total; +} + +void StorageNamespace::CleanUpUnusedAreas() { + Vector<const SecurityOrigin*, 16> to_remove; + for (const auto& area : cached_areas_) { + if (area.value->HasOneRef()) + to_remove.push_back(area.key.get()); + } + cached_areas_.RemoveAll(to_remove); +} + +void StorageNamespace::AddInspectorStorageAgent( + InspectorDOMStorageAgent* agent) { + inspector_agents_.insert(agent); +} +void StorageNamespace::RemoveInspectorStorageAgent( + InspectorDOMStorageAgent* agent) { + inspector_agents_.erase(agent); +} + +void StorageNamespace::Trace(Visitor* visitor) { + visitor->Trace(inspector_agents_); + Supplement<Page>::Trace(visitor); +} + +void StorageNamespace::DidDispatchStorageEvent(const SecurityOrigin* origin, + const String& key, + const String& old_value, + const String& new_value) { + for (InspectorDOMStorageAgent* agent : inspector_agents_) { + agent->DidDispatchDOMStorageEvent( + key, old_value, new_value, + IsSessionStorage() ? StorageArea::StorageType::kSessionStorage + : StorageArea::StorageType::kLocalStorage, + origin); + } +} +std::unique_ptr<WebStorageArea> StorageNamespace::GetWebStorageArea( const SecurityOrigin* origin) { + CHECK(!base::FeatureList::IsEnabled(features::kOnionSoupDOMStorage)); return base::WrapUnique( web_storage_namespace_->CreateStorageArea(WebSecurityOrigin(origin))); } -bool StorageNamespace::IsSameNamespace( - const WebStorageNamespace& session_namespace) const { - return web_storage_namespace_ && - web_storage_namespace_->IsSameNamespace(session_namespace); +void StorageNamespace::EnsureConnected() { + DCHECK(IsSessionStorage()); + if (namespace_) + return; + auto request = MakeRequest(&namespace_, controller_->IPCTaskRunner()); + controller_->storage_partition_service()->OpenSessionStorage( + namespace_id_, std::move(request)); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_namespace.h b/chromium/third_party/blink/renderer/modules/storage/storage_namespace.h index c3b3be0ebcd..4c316e429b9 100644 --- a/chromium/third_party/blink/renderer/modules/storage/storage_namespace.h +++ b/chromium/third_party/blink/renderer/modules/storage/storage_namespace.h @@ -27,29 +27,112 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_STORAGE_NAMESPACE_H_ #include <memory> + +#include "third_party/blink/public/mojom/dom_storage/session_storage_namespace.mojom-blink.h" +#include "third_party/blink/public/mojom/dom_storage/storage_partition_service.mojom-blink.h" #include "third_party/blink/public/platform/web_storage_area.h" +#include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/modules/storage/cached_storage_area.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/heap_allocator.h" +#include "third_party/blink/renderer/platform/supplementable.h" +#include "third_party/blink/renderer/platform/weborigin/security_origin_hash.h" +#include "third_party/blink/renderer/platform/wtf/hash_map.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { -class WebStorageNamespace; +class InspectorDOMStorageAgent; +class StorageController; class SecurityOrigin; +class WebStorageNamespace; +class WebViewClient; -class MODULES_EXPORT StorageNamespace { - USING_FAST_MALLOC(StorageNamespace); +// Contains DOMStorage storage areas for origins & handles inspector agents. A +// namespace is either a SessionStorage namespace with a namespace_id, or a +// LocalStorage namespace with no (or an empty) namespace_id. The LocalStorage +// version of the StorageNamespace lives in the StorageController. +// InspectorDOMStorageAgents that are registered on this object are notified +// through |DidDispatchStorageEvent|. +// +// With the kOnionSoupDOMStorage flag off: +// The StorageNamespace basically delegates calls to GetWebStorageArea to the +// internal WebStorageNamespace. |GetWebStorageArea| is used to get the storage +// area for an origin. +// +// With the kOnionSoupDOMStorage flag on: +// The StorageNamespace for SessioStorage supplement the Page. |GetCachedArea| +// is used to get the storage area for an origin. +class MODULES_EXPORT StorageNamespace final + : public GarbageCollectedFinalized<StorageNamespace>, + public Supplement<Page>, + public CachedStorageArea::InspectorEventListener { + USING_GARBAGE_COLLECTED_MIXIN(StorageNamespace); public: - explicit StorageNamespace(std::unique_ptr<WebStorageNamespace>); - ~StorageNamespace(); + static const char kSupplementName[]; + + static void ProvideSessionStorageNamespaceTo(Page&, WebViewClient*); + static StorageNamespace* From(Page* page) { + return Supplement<Page>::From<StorageNamespace>(page); + } + + // Constructor for an onion-souped LocalStorage namespace. + StorageNamespace(StorageController*); + // Constructor for an onion-souped SessionStorage namespace. + StorageNamespace(StorageController*, const String& namespace_id); + // Pre-onion-soup constructor. WebStorageNamespace must not be null. + StorageNamespace(std::unique_ptr<WebStorageNamespace>); + + ~StorageNamespace() override; + + // TODO(dmurph): Remove this once Onion Soupified. + const String& namespace_id() { return namespace_id_; } + // TODO(dmurph): Remove this once Onion Soupified. + std::unique_ptr<WebStorageArea> GetWebStorageArea(const SecurityOrigin*); + + scoped_refptr<CachedStorageArea> GetCachedArea(const SecurityOrigin* origin); - static std::unique_ptr<WebStorageArea> LocalStorageArea( - const SecurityOrigin*); - std::unique_ptr<WebStorageArea> GetStorageArea(const SecurityOrigin*); + // Only valid to call this if |this| and |target| are session storage + // namespaces. + void CloneTo(const String& target); - bool IsSameNamespace(const WebStorageNamespace& session_namespace) const; + size_t TotalCacheSize() const; + + // Removes any CachedStorageAreas that aren't referenced by any source. + void CleanUpUnusedAreas(); + + bool IsSessionStorage() const { return !namespace_id_.IsEmpty(); } + + void AddInspectorStorageAgent(InspectorDOMStorageAgent* agent); + void RemoveInspectorStorageAgent(InspectorDOMStorageAgent* agent); + + void Trace(Visitor* visitor) override; + + // Iterates all of the inspector agents and calls + // |DidDispatchDOMStorageEvent|. + void DidDispatchStorageEvent(const SecurityOrigin* origin, + const String& key, + const String& old_value, + const String& new_value) override; private: + void EnsureConnected(); + + HeapHashSet<WeakMember<InspectorDOMStorageAgent>> inspector_agents_; + + // Onion-souped storage wiring, not turned on yet. + // Lives globally. + StorageController* controller_; + String namespace_id_; + mojom::blink::SessionStorageNamespacePtr namespace_; + HashMap<scoped_refptr<const SecurityOrigin>, + scoped_refptr<CachedStorageArea>, + SecurityOriginHash> + cached_areas_; + + // Pre-onion-soup storage wiring, currently active. std::unique_ptr<WebStorageNamespace> web_storage_namespace_; }; diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_namespace_controller.cc b/chromium/third_party/blink/renderer/modules/storage/storage_namespace_controller.cc deleted file mode 100644 index 9ee5d2880ba..00000000000 --- a/chromium/third_party/blink/renderer/modules/storage/storage_namespace_controller.cc +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2015 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/storage/storage_namespace_controller.h" - -#include <memory> - -#include "third_party/blink/public/platform/platform.h" -#include "third_party/blink/public/platform/web_storage_namespace.h" -#include "third_party/blink/public/web/web_view_client.h" -#include "third_party/blink/renderer/core/frame/content_settings_client.h" -#include "third_party/blink/renderer/modules/storage/inspector_dom_storage_agent.h" -#include "third_party/blink/renderer/modules/storage/storage_namespace.h" - -namespace blink { - -#define STATIC_ASSERT_MATCHING_ENUM(enum_name1, enum_name2) \ - static_assert(static_cast<int>(enum_name1) == static_cast<int>(enum_name2), \ - "mismatching enums: " #enum_name1) -STATIC_ASSERT_MATCHING_ENUM(StorageArea::StorageType::kLocalStorage, - ContentSettingsClient::StorageType::kLocal); -STATIC_ASSERT_MATCHING_ENUM(StorageArea::StorageType::kSessionStorage, - ContentSettingsClient::StorageType::kSession); - -const char StorageNamespaceController::kSupplementName[] = - "StorageNamespaceController"; - -StorageNamespaceController::StorageNamespaceController(WebViewClient* client) - : inspector_agent_(nullptr), web_view_client_(client) {} - -StorageNamespaceController::~StorageNamespaceController() = default; - -void StorageNamespaceController::Trace(blink::Visitor* visitor) { - Supplement<Page>::Trace(visitor); - visitor->Trace(inspector_agent_); -} - -StorageNamespace* StorageNamespaceController::SessionStorage( - bool optional_create) { - if (!session_storage_ && optional_create) - session_storage_ = CreateSessionStorageNamespace(); - return session_storage_.get(); -} - -void StorageNamespaceController::ProvideStorageNamespaceTo( - Page& page, - WebViewClient* client) { - ProvideTo(page, new StorageNamespaceController(client)); -} - -std::unique_ptr<StorageNamespace> -StorageNamespaceController::CreateSessionStorageNamespace() { - if (!web_view_client_) - return nullptr; - - return std::make_unique<StorageNamespace>( - Platform::Current()->CreateSessionStorageNamespace( - web_view_client_->GetSessionStorageNamespaceId())); -} - -bool StorageNamespaceController::CanAccessStorageArea( - LocalFrame* frame, - StorageArea::StorageType type) const { - DCHECK(frame->GetContentSettingsClient()); - return frame->GetContentSettingsClient()->AllowStorage( - static_cast<ContentSettingsClient::StorageType>(type)); -} - -} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_namespace_controller.h b/chromium/third_party/blink/renderer/modules/storage/storage_namespace_controller.h deleted file mode 100644 index b53f45859fd..00000000000 --- a/chromium/third_party/blink/renderer/modules/storage/storage_namespace_controller.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2015 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_STORAGE_STORAGE_NAMESPACE_CONTROLLER_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_STORAGE_NAMESPACE_CONTROLLER_H_ - -#include <memory> - -#include "third_party/blink/renderer/core/page/page.h" -#include "third_party/blink/renderer/modules/modules_export.h" -#include "third_party/blink/renderer/modules/storage/storage_area.h" -#include "third_party/blink/renderer/platform/supplementable.h" - -namespace blink { - -class InspectorDOMStorageAgent; -class StorageNamespace; -class WebViewClient; - -class MODULES_EXPORT StorageNamespaceController final - : public GarbageCollectedFinalized<StorageNamespaceController>, - public Supplement<Page> { - USING_GARBAGE_COLLECTED_MIXIN(StorageNamespaceController); - - public: - static const char kSupplementName[]; - - StorageNamespace* SessionStorage(bool optional_create = true); - ~StorageNamespaceController(); - - bool CanAccessStorageArea(LocalFrame*, StorageArea::StorageType) const; - - static void ProvideStorageNamespaceTo(Page&, WebViewClient*); - static StorageNamespaceController* From(Page* page) { - return Supplement<Page>::From<StorageNamespaceController>(page); - } - - void Trace(blink::Visitor*) override; - - InspectorDOMStorageAgent* InspectorAgent() { return inspector_agent_; } - void SetInspectorAgent(InspectorDOMStorageAgent* agent) { - inspector_agent_ = agent; - } - - private: - explicit StorageNamespaceController(WebViewClient*); - - std::unique_ptr<StorageNamespace> CreateSessionStorageNamespace(); - - std::unique_ptr<StorageNamespace> session_storage_; - Member<InspectorDOMStorageAgent> inspector_agent_; - WebViewClient* web_view_client_; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_STORAGE_NAMESPACE_CONTROLLER_H_ diff --git a/chromium/third_party/blink/renderer/modules/storage/storage_namespace_test.cc b/chromium/third_party/blink/renderer/modules/storage/storage_namespace_test.cc new file mode 100644 index 00000000000..ca24c518276 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/storage/storage_namespace_test.cc @@ -0,0 +1,96 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/storage/storage_namespace.h" +#include <third_party/blink/renderer/modules/storage/storage_controller.h> + +#include "base/task/post_task.h" +#include "base/test/scoped_feature_list.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/platform/scheduler/test/fake_renderer_scheduler.h" +#include "third_party/blink/renderer/modules/storage/testing/fake_area_source.h" +#include "third_party/blink/renderer/platform/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/uuid.h" +#include "third_party/blink/renderer/platform/web_task_runner.h" + +namespace blink { +namespace { +class NoopStoragePartitionService + : public mojom::blink::StoragePartitionService { + public: + void OpenLocalStorage(const scoped_refptr<const SecurityOrigin>& origin, + mojom::blink::StorageAreaRequest request) override {} + + void OpenSessionStorage( + const String& namespace_id, + mojom::blink::SessionStorageNamespaceRequest request) override {} +}; + +} // namespace + +class StorageNamespaceTest : public testing::Test { + public: + const size_t kTestCacheLimit = 100; + + StorageNamespaceTest() { + features_.InitAndEnableFeature(features::kOnionSoupDOMStorage); + } + ~StorageNamespaceTest() override {} + + base::test::ScopedFeatureList features_; +}; + +TEST_F(StorageNamespaceTest, BasicStorageAreas) { + const auto kOrigin = SecurityOrigin::CreateFromString("http://dom_storage1/"); + const auto kOrigin2 = + SecurityOrigin::CreateFromString("http://dom_storage2/"); + const auto kOrigin3 = + SecurityOrigin::CreateFromString("http://dom_storage3/"); + const String kKey("key"); + const String kValue("value"); + const String kSessionStorageNamespace("abcd"); + const KURL kPageUrl("http://dom_storage/page"); + Persistent<FakeAreaSource> source_area = new FakeAreaSource(kPageUrl); + + blink::scheduler::FakeRendererScheduler renderer_scheduler; + + mojom::blink::StoragePartitionServicePtr storage_partition_service_ptr; + PostCrossThreadTask( + *base::CreateSequencedTaskRunnerWithTraits({}), FROM_HERE, + CrossThreadBind( + [](mojom::blink::StoragePartitionServiceRequest request) { + mojo::MakeStrongBinding( + std::make_unique<NoopStoragePartitionService>(), + std::move(request)); + }, + WTF::Passed(MakeRequest(&storage_partition_service_ptr)))); + + StorageController controller(renderer_scheduler.IPCTaskRunner(), + std::move(storage_partition_service_ptr), + kTestCacheLimit); + StorageNamespace* localStorage = new StorageNamespace(&controller); + StorageNamespace* sessionStorage = + new StorageNamespace(&controller, kSessionStorageNamespace); + + EXPECT_FALSE(localStorage->IsSessionStorage()); + EXPECT_TRUE(sessionStorage->IsSessionStorage()); + + auto cached_area1 = localStorage->GetCachedArea(kOrigin.get()); + cached_area1->RegisterSource(source_area); + cached_area1->SetItem(kKey, kValue, source_area); + auto cached_area2 = localStorage->GetCachedArea(kOrigin2.get()); + cached_area2->RegisterSource(source_area); + cached_area2->SetItem(kKey, kValue, source_area); + auto cached_area3 = sessionStorage->GetCachedArea(kOrigin3.get()); + cached_area3->RegisterSource(source_area); + cached_area3->SetItem(kKey, kValue, source_area); + + EXPECT_EQ(cached_area1->GetItem(kKey), kValue); + EXPECT_EQ(cached_area2->GetItem(kKey), kValue); + EXPECT_EQ(cached_area3->GetItem(kKey), kValue); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/storage/testing/fake_area_source.h b/chromium/third_party/blink/renderer/modules/storage/testing/fake_area_source.h index 92e1cf497e4..cbb2886c6dc 100644 --- a/chromium/third_party/blink/renderer/modules/storage/testing/fake_area_source.h +++ b/chromium/third_party/blink/renderer/modules/storage/testing/fake_area_source.h @@ -19,11 +19,12 @@ class FakeAreaSource : public GarbageCollectedFinalized<FakeAreaSource>, explicit FakeAreaSource(const KURL& page_url) : page_url_(page_url) {} KURL GetPageUrl() const override { return page_url_; } - void EnqueueStorageEvent(const String& key, + bool EnqueueStorageEvent(const String& key, const String& old_value, const String& new_value, const String& url) override { events.push_back(Event{key, old_value, new_value, url}); + return true; } blink::WebScopedVirtualTimePauser CreateWebScopedVirtualTimePauser( diff --git a/chromium/third_party/blink/renderer/modules/time_zone_monitor/time_zone_monitor_client.cc b/chromium/third_party/blink/renderer/modules/time_zone_monitor/time_zone_monitor_client.cc index 4d8a9721a4c..e17c7d029ef 100644 --- a/chromium/third_party/blink/renderer/modules/time_zone_monitor/time_zone_monitor_client.cc +++ b/chromium/third_party/blink/renderer/modules/time_zone_monitor/time_zone_monitor_client.cc @@ -65,21 +65,7 @@ void TimeZoneMonitorClient::OnTimeZoneChange(const String& time_zone_info) { } NotifyTimezoneChangeToV8(V8PerIsolateData::MainThreadIsolate()); - - HashSet<WorkerThread*>& threads = WorkerThread::WorkerThreads(); - HashSet<WorkerBackingThread*> posted; - for (WorkerThread* thread : threads) { - // Ensure every WorkerBackingThread(holding one platform thread) only get - // the task posted once, because one WorkerBackingThread could be shared - // among multiple WorkerThreads. - if (posted.Contains(&thread->GetWorkerBackingThread())) - continue; - PostCrossThreadTask(*thread->GetTaskRunner(TaskType::kInternalDefault), - FROM_HERE, - CrossThreadBind(&NotifyTimezoneChangeOnWorkerThread, - WTF::CrossThreadUnretained(thread))); - posted.insert(&thread->GetWorkerBackingThread()); - } + WorkerThread::CallOnAllWorkerThreads(&NotifyTimezoneChangeOnWorkerThread); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/vibration/navigator_vibration.cc b/chromium/third_party/blink/renderer/modules/vibration/navigator_vibration.cc index 3381c6414ac..181bac4a60b 100644 --- a/chromium/third_party/blink/renderer/modules/vibration/navigator_vibration.cc +++ b/chromium/third_party/blink/renderer/modules/vibration/navigator_vibration.cc @@ -19,7 +19,6 @@ #include "third_party/blink/renderer/modules/vibration/navigator_vibration.h" -#include "third_party/blink/public/platform/site_engagement.mojom-blink.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/user_gesture_indicator.h" #include "third_party/blink/renderer/core/frame/deprecation.h" @@ -32,7 +31,6 @@ #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/modules/vibration/vibration_controller.h" -#include "third_party/blink/renderer/platform/feature_policy/feature_policy.h" #include "third_party/blink/renderer/platform/histogram.h" namespace blink { @@ -129,27 +127,6 @@ void NavigatorVibration::CollectHistogramMetrics(const LocalFrame& frame) { DEFINE_STATIC_LOCAL(EnumerationHistogram, navigator_vibrate_histogram, ("Vibration.Context", NavigatorVibrationType::kEnumMax)); navigator_vibrate_histogram.Count(type); - - switch (frame.GetDocument()->GetEngagementLevel()) { - case mojom::blink::EngagementLevel::NONE: - UseCounter::Count(&frame, WebFeature::kNavigatorVibrateEngagementNone); - break; - case mojom::blink::EngagementLevel::MINIMAL: - UseCounter::Count(&frame, WebFeature::kNavigatorVibrateEngagementMinimal); - break; - case mojom::blink::EngagementLevel::LOW: - UseCounter::Count(&frame, WebFeature::kNavigatorVibrateEngagementLow); - break; - case mojom::blink::EngagementLevel::MEDIUM: - UseCounter::Count(&frame, WebFeature::kNavigatorVibrateEngagementMedium); - break; - case mojom::blink::EngagementLevel::HIGH: - UseCounter::Count(&frame, WebFeature::kNavigatorVibrateEngagementHigh); - break; - case mojom::blink::EngagementLevel::MAX: - UseCounter::Count(&frame, WebFeature::kNavigatorVibrateEngagementMax); - break; - } } VibrationController* NavigatorVibration::Controller(LocalFrame& frame) { diff --git a/chromium/third_party/blink/renderer/modules/vr/navigator_vr.cc b/chromium/third_party/blink/renderer/modules/vr/navigator_vr.cc index ad15980a428..25c1178ad50 100644 --- a/chromium/third_party/blink/renderer/modules/vr/navigator_vr.cc +++ b/chromium/third_party/blink/renderer/modules/vr/navigator_vr.cc @@ -5,6 +5,7 @@ #include "third_party/blink/renderer/modules/vr/navigator_vr.h" #include "services/metrics/public/cpp/ukm_builders.h" +#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_security_origin.h" #include "third_party/blink/public/web/web_frame.h" @@ -23,7 +24,6 @@ #include "third_party/blink/renderer/modules/vr/vr_get_devices_callback.h" #include "third_party/blink/renderer/modules/vr/vr_pose.h" #include "third_party/blink/renderer/modules/xr/xr.h" -#include "third_party/blink/renderer/platform/feature_policy/feature_policy.h" namespace blink { @@ -144,7 +144,8 @@ ScriptPromise NavigatorVR::getVRDisplays(ScriptState* script_state) { script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError, kNotAssociatedWithDocumentMessage)); } - if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr)) { + if (!GetDocument()->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr, + ReportOptions::kReportOnFailure)) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kSecurityError, kFeaturePolicyBlockedMessage)); diff --git a/chromium/third_party/blink/renderer/modules/vr/vr_display.cc b/chromium/third_party/blink/renderer/modules/vr/vr_display.cc index 3a73e9a0f16..17ab044676d 100644 --- a/chromium/third_party/blink/renderer/modules/vr/vr_display.cc +++ b/chromium/third_party/blink/renderer/modules/vr/vr_display.cc @@ -398,7 +398,8 @@ ScriptPromise VRDisplay::requestPresent(ScriptState* script_state, // allowed outside a user gesture so that the presented content may be // updated. if (first_present) { - if (!Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr)) { + if (!LocalFrame::HasTransientUserActivation(doc ? doc->GetFrame() + : nullptr)) { DOMException* exception = DOMException::Create(DOMExceptionCode::kInvalidStateError, "API can only be initiated by a user gesture."); @@ -683,10 +684,11 @@ void VRDisplay::BeginPresent() { // For GVR, we shut down normal vsync processing during VR presentation. // Run window.rAF once manually so that applications get a chance to // schedule a VRDisplay.rAF in case they do so only while presenting. - if (!pending_vrdisplay_raf_ && !capabilities_->hasExternalDisplay()) { + if (doc && !pending_vrdisplay_raf_ && !capabilities_->hasExternalDisplay()) { TimeTicks timestamp = WTF::CurrentTimeTicks(); - Platform::Current()->CurrentThread()->GetTaskRunner()->PostTask( - FROM_HERE, WTF::Bind(&VRDisplay::ProcessScheduledWindowAnimations, + doc->GetTaskRunner(blink::TaskType::kInternalMedia) + ->PostTask(FROM_HERE, + WTF::Bind(&VRDisplay::ProcessScheduledWindowAnimations, WrapWeakPersistent(this), timestamp)); } } @@ -933,7 +935,7 @@ void VRDisplay::OnActivate(device::mojom::blink::VRDisplayEventReason reason, std::unique_ptr<UserGestureIndicator> gesture_indicator; if (reason == device::mojom::blink::VRDisplayEventReason::MOUNTED) - gesture_indicator = Frame::NotifyUserActivation(doc->GetFrame()); + gesture_indicator = LocalFrame::NotifyUserActivation(doc->GetFrame()); base::AutoReset<bool> in_activate(&in_display_activate_, true); @@ -1051,6 +1053,10 @@ void VRDisplay::OnPresentingVSync( NOTIMPLEMENTED(); } + Document* doc = GetDocument(); + if (!doc) + return; + // Post a task to handle scheduled animations after the current // execution context finishes, so that we yield to non-mojo tasks in // between frames. Executing mojo tasks back to back within the same @@ -1059,10 +1065,13 @@ void VRDisplay::OnPresentingVSync( // this is due to WaitForIncomingMethodCall receiving the OnVSync // but queueing it for immediate execution since it doesn't match // the interface being waited on. - Platform::Current()->CurrentThread()->GetTaskRunner()->PostTask( - FROM_HERE, WTF::Bind(&VRDisplay::ProcessScheduledAnimations, - WrapWeakPersistent(this), - TimeTicks() + frame_data->time_delta)); + // + // Used kInternalMedia since 1) this is not spec-ed and 2) this is media + // related then tasks should not be throttled or frozen in background tabs. + doc->GetTaskRunner(blink::TaskType::kInternalMedia) + ->PostTask(FROM_HERE, WTF::Bind(&VRDisplay::ProcessScheduledAnimations, + WrapWeakPersistent(this), + TimeTicks() + frame_data->time_delta)); } void VRDisplay::OnNonImmersiveVSync(TimeTicks timestamp) { diff --git a/chromium/third_party/blink/renderer/modules/vr/vr_display.h b/chromium/third_party/blink/renderer/modules/vr/vr_display.h index de85257ee3c..429ac4e6f69 100644 --- a/chromium/third_party/blink/renderer/modules/vr/vr_display.h +++ b/chromium/third_party/blink/renderer/modules/vr/vr_display.h @@ -265,21 +265,28 @@ class VRDisplay final : public EventTargetWithInlineData, using VRDisplayVector = HeapVector<Member<VRDisplay>>; +// When adding values, insert them before Max and add them to +// VRPresentationResult in enums.xml. Do not reuse values. +// Also, remove kPlaceholderForPreviousHighValue. +// When values become obsolete, comment them out here and mark them deprecated +// in enums.xml. enum class PresentationResult { kRequested = 0, kSuccess = 1, kSuccessAlreadyPresenting = 2, kVRDisplayCannotPresent = 3, kPresentationNotSupportedByDisplay = 4, - kVRDisplayNotFound = 5, + // kVRDisplayNotFound = 5, kNotInitiatedByUserGesture = 6, kInvalidNumberOfLayers = 7, kInvalidLayerSource = 8, kLayerSourceMissingWebGLContext = 9, kInvalidLayerBounds = 10, - kServiceInactive = 11, - kRequestDenied = 12, - kFullscreenNotEnabled = 13, + // kServiceInactive = 11, + // kRequestDenied = 12, + // kFullscreenNotEnabled = 13, + // TODO(ddorwin): Remove this placeholder when adding a new value. + kPlaceholderForPreviousHighValue = 13, kPresentationResultMax, // Must be last member of enum. }; diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/DEPS b/chromium/third_party/blink/renderer/modules/wake_lock/DEPS index 23424fb8031..5f009fc2d9a 100644 --- a/chromium/third_party/blink/renderer/modules/wake_lock/DEPS +++ b/chromium/third_party/blink/renderer/modules/wake_lock/DEPS @@ -3,5 +3,6 @@ include_rules = [ "+services/device/public/mojom", "+services/device/public/interfaces/constants.mojom-blink.h", "+services/device/public/mojom/wake_lock.mojom-blink.h", + "+services/device/public/mojom/wake_lock_provider.mojom-blink.h", "+third_party/blink/renderer/modules/event_target_modules.h", ] diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.cc b/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.cc index 43671330e6c..58ea962fae5 100644 --- a/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.cc +++ b/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.cc @@ -27,11 +27,14 @@ ScriptPromise NavigatorWakeLock::getWakeLock(ScriptState* script_state, ScriptPromise NavigatorWakeLock::getWakeLock(ScriptState* script_state, String lock_type) { - // TODO(crbug.com/873030): Handle 'system' Wake Lock if (lock_type == "screen") { if (!wake_lock_screen_) wake_lock_screen_ = WakeLock::CreateScreenWakeLock(script_state); return wake_lock_screen_->GetPromise(script_state); + } else if (lock_type == "system") { + if (!wake_lock_system_) + wake_lock_system_ = WakeLock::CreateSystemWakeLock(script_state); + return wake_lock_system_->GetPromise(script_state); } return ScriptPromise::RejectWithDOMException( @@ -51,6 +54,7 @@ NavigatorWakeLock& NavigatorWakeLock::From(Navigator& navigator) { void NavigatorWakeLock::Trace(blink::Visitor* visitor) { visitor->Trace(wake_lock_screen_); + visitor->Trace(wake_lock_system_); Supplement<Navigator>::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.h b/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.h index 1ffe09eee67..f6d0c183b9a 100644 --- a/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.h +++ b/chromium/third_party/blink/renderer/modules/wake_lock/navigator_wake_lock.h @@ -33,6 +33,7 @@ class NavigatorWakeLock final : public GarbageCollected<NavigatorWakeLock>, explicit NavigatorWakeLock(Navigator&); Member<WakeLock> wake_lock_screen_; + Member<WakeLock> wake_lock_system_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.cc b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.cc index 109ce866f9f..f1947ebc4b5 100644 --- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.cc +++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.cc @@ -5,12 +5,15 @@ #include "third_party/blink/renderer/modules/wake_lock/wake_lock.h" #include "services/device/public/mojom/constants.mojom-blink.h" +#include "services/device/public/mojom/wake_lock_provider.mojom-blink.h" +#include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/modules/wake_lock/wake_lock_request.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" @@ -20,14 +23,17 @@ WakeLock* WakeLock::CreateScreenWakeLock(ScriptState* script_state) { return new WakeLock(script_state, LockType::kScreen); } +WakeLock* WakeLock::CreateSystemWakeLock(ScriptState* script_state) { + return new WakeLock(script_state, LockType::kSystem); +} + WakeLock::~WakeLock() = default; WakeLock::WakeLock(ScriptState* script_state, LockType type) : ContextLifecycleObserver(blink::ExecutionContext::From(script_state)), PageVisibilityObserver( - ToDocument(blink::ExecutionContext::From(script_state))->GetPage()), + To<Document>(blink::ExecutionContext::From(script_state))->GetPage()), type_(type) { - DCHECK(type == LockType::kScreen); } ScriptPromise WakeLock::GetPromise(ScriptState* script_state) { @@ -78,9 +84,23 @@ void WakeLock::BindToServiceIfNeeded() { if (wake_lock_service_) return; - LocalFrame* frame = ToDocument(GetExecutionContext())->GetFrame(); - frame->GetInterfaceProvider().GetInterface( + device::mojom::blink::WakeLockType type; + switch (type_) { + case LockType::kSystem: + type = device::mojom::blink::WakeLockType::kPreventAppSuspension; + break; + case LockType::kScreen: + type = device::mojom::blink::WakeLockType::kPreventDisplaySleep; + break; + } + + device::mojom::blink::WakeLockProviderPtr provider; + Platform::Current()->GetConnector()->BindInterface( + device::mojom::blink::kServiceName, mojo::MakeRequest(&provider)); + provider->GetWakeLockWithoutContext( + type, device::mojom::blink::WakeLockReason::kOther, "Blink Wake Lock", mojo::MakeRequest(&wake_lock_service_)); + wake_lock_service_.set_connection_error_handler( WTF::Bind(&WakeLock::OnConnectionError, WrapWeakPersistent(this))); } diff --git a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.h b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.h index 40112dc4acc..a8896f249de 100644 --- a/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.h +++ b/chromium/third_party/blink/renderer/modules/wake_lock/wake_lock.h @@ -36,6 +36,8 @@ class WakeLock final : public EventTargetWithInlineData, // Called by NavigatorWakeLock to create Screen Wake Lock static WakeLock* CreateScreenWakeLock(ScriptState*); + // Called by NavigatorWakeLock to create System Wake Lock + static WakeLock* CreateSystemWakeLock(ScriptState*); // Resolves and returns same promise of that particular WakeLockType each time ScriptPromise GetPromise(ScriptState*); diff --git a/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc index 6a2819e3f18..39ee21aae4b 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/analyser_node.cc @@ -35,7 +35,7 @@ namespace blink { AnalyserHandler::AnalyserHandler(AudioNode& node, float sample_rate) : AudioBasicInspectorHandler(kNodeTypeAnalyser, node, sample_rate, 1) { - channel_count_ = 1; + channel_count_ = 2; Initialize(); } diff --git a/chromium/third_party/blink/renderer/modules/webaudio/async_audio_decoder.cc b/chromium/third_party/blink/renderer/modules/webaudio/async_audio_decoder.cc index d5287d2b31a..aae1753fe87 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/async_audio_decoder.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/async_audio_decoder.cc @@ -27,7 +27,6 @@ #include "base/location.h" #include "third_party/blink/public/platform/platform.h" -#include "third_party/blink/public/platform/web_thread.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h" #include "third_party/blink/renderer/modules/webaudio/base_audio_context.h" @@ -35,6 +34,7 @@ #include "third_party/blink/renderer/platform/audio/audio_file_reader.h" #include "third_party/blink/renderer/platform/cross_thread_functional.h" #include "third_party/blink/renderer/platform/scheduler/public/background_scheduler.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/blink/renderer/platform/web_task_runner.h" namespace blink { @@ -51,6 +51,10 @@ void AsyncAudioDecoder::DecodeAsync( if (!audio_data) return; + scoped_refptr<base::SingleThreadTaskRunner> task_runner = + context->GetExecutionContext()->GetTaskRunner( + blink::TaskType::kInternalMedia); + BackgroundScheduler::PostOnBackgroundThread( FROM_HERE, CrossThreadBind(&AsyncAudioDecoder::DecodeOnBackgroundThread, @@ -58,7 +62,8 @@ void AsyncAudioDecoder::DecodeAsync( WrapCrossThreadPersistent(success_callback), WrapCrossThreadPersistent(error_callback), WrapCrossThreadPersistent(resolver), - WrapCrossThreadPersistent(context))); + WrapCrossThreadPersistent(context), + std::move(task_runner))); } void AsyncAudioDecoder::DecodeOnBackgroundThread( @@ -67,7 +72,8 @@ void AsyncAudioDecoder::DecodeOnBackgroundThread( V8PersistentCallbackFunction<V8DecodeSuccessCallback>* success_callback, V8PersistentCallbackFunction<V8DecodeErrorCallback>* error_callback, ScriptPromiseResolver* resolver, - BaseAudioContext* context) { + BaseAudioContext* context, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { DCHECK(!IsMainThread()); scoped_refptr<AudioBus> bus = CreateBusFromInMemoryAudioFile( audio_data->Data(), audio_data->ByteLength(), false, sample_rate); @@ -80,7 +86,7 @@ void AsyncAudioDecoder::DecodeOnBackgroundThread( // exist any more. if (context) { PostCrossThreadTask( - *Platform::Current()->MainThread()->GetTaskRunner(), FROM_HERE, + *task_runner, FROM_HERE, CrossThreadBind(&AsyncAudioDecoder::NotifyComplete, WrapCrossThreadPersistent(audio_data), WrapCrossThreadPersistent(success_callback), diff --git a/chromium/third_party/blink/renderer/modules/webaudio/async_audio_decoder.h b/chromium/third_party/blink/renderer/modules/webaudio/async_audio_decoder.h index 372849be732..5783e16946f 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/async_audio_decoder.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/async_audio_decoder.h @@ -32,6 +32,10 @@ #include "third_party/blink/renderer/bindings/modules/v8/v8_decode_error_callback.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_decode_success_callback.h" +namespace base { +class SingleThreadTaskRunner; +} + namespace blink { class AudioBuffer; @@ -71,7 +75,8 @@ class AsyncAudioDecoder { V8PersistentCallbackFunction<V8DecodeSuccessCallback>*, V8PersistentCallbackFunction<V8DecodeErrorCallback>*, ScriptPromiseResolver*, - BaseAudioContext*); + BaseAudioContext*, + scoped_refptr<base::SingleThreadTaskRunner>); static void NotifyComplete( DOMArrayBuffer* audio_data, V8PersistentCallbackFunction<V8DecodeSuccessCallback>*, diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc index 7e5d2d715cd..74ce5c17336 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.cc @@ -349,12 +349,20 @@ bool AudioBufferSourceHandler::RenderFromBuffer( for (unsigned i = 0; i < number_of_channels; ++i) { float* destination = destination_channels[i]; const float* source = source_channels[i]; - - double sample1 = source[read_index]; - double sample2 = source[read_index2]; - double sample = (1.0 - interpolation_factor) * sample1 + - interpolation_factor * sample2; - + double sample; + + if (read_index == read_index2 && read_index >= 1) { + // We're at the end of the buffer, so just linearly extrapolate from + // the last two samples. + double sample1 = source[read_index - 1]; + double sample2 = source[read_index]; + sample = sample2 + (sample2 - sample1) * interpolation_factor; + } else { + double sample1 = source[read_index]; + double sample2 = source[read_index2]; + sample = (1.0 - interpolation_factor) * sample1 + + interpolation_factor * sample2; + } destination[write_index] = clampTo<float>(sample); } write_index++; diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc index 272bb914556..9669d35a3f2 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_context.cc @@ -14,13 +14,18 @@ #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/use_counter.h" +#include "third_party/blink/renderer/core/html/media/html_media_element.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/core/timing/dom_window_performance.h" #include "third_party/blink/renderer/core/timing/window_performance.h" +#include "third_party/blink/renderer/modules/mediastream/media_stream.h" #include "third_party/blink/renderer/modules/webaudio/audio_context_options.h" #include "third_party/blink/renderer/modules/webaudio/audio_timestamp.h" #include "third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h" +#include "third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.h" +#include "third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.h" +#include "third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.h" #include "third_party/blink/renderer/platform/audio/audio_utilities.h" #include "third_party/blink/renderer/platform/bindings/exception_messages.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" @@ -327,6 +332,32 @@ double AudioContext::baseLatency() const { static_cast<double>(sampleRate()); } +MediaElementAudioSourceNode* AudioContext::createMediaElementSource( + HTMLMediaElement* media_element, + ExceptionState& exception_state) { + DCHECK(IsMainThread()); + + return MediaElementAudioSourceNode::Create(*this, *media_element, + exception_state); +} + +MediaStreamAudioSourceNode* AudioContext::createMediaStreamSource( + MediaStream* media_stream, + ExceptionState& exception_state) { + DCHECK(IsMainThread()); + + return MediaStreamAudioSourceNode::Create(*this, *media_stream, + exception_state); +} + +MediaStreamAudioDestinationNode* AudioContext::createMediaStreamDestination( + ExceptionState& exception_state) { + DCHECK(IsMainThread()); + + // Set number of output channels to stereo by default. + return MediaStreamAudioDestinationNode::Create(*this, 2, exception_state); +} + void AudioContext::NotifySourceNodeStart() { source_node_started_ = true; if (!user_gesture_required_) @@ -361,13 +392,14 @@ AutoplayPolicy::Type AudioContext::GetAutoplayPolicy() const { } bool AudioContext::AreAutoplayRequirementsFulfilled() const { + DCHECK(GetDocument()); + switch (GetAutoplayPolicy()) { case AutoplayPolicy::Type::kNoUserGestureRequired: return true; case AutoplayPolicy::Type::kUserGestureRequired: case AutoplayPolicy::Type::kUserGestureRequiredForCrossOrigin: - return Frame::HasTransientUserActivation( - GetDocument() ? GetDocument()->GetFrame() : nullptr); + return LocalFrame::HasTransientUserActivation(GetDocument()->GetFrame()); case AutoplayPolicy::Type::kDocumentUserActivationRequired: return AutoplayPolicy::IsDocumentAllowedToPlay(*GetDocument()); } @@ -394,7 +426,7 @@ bool AudioContext::IsAllowedToStart() const { if (!user_gesture_required_) return true; - Document* document = ToDocument(GetExecutionContext()); + Document* document = To<Document>(GetExecutionContext()); DCHECK(document); switch (GetAutoplayPolicy()) { @@ -422,7 +454,7 @@ bool AudioContext::IsAllowedToStart() const { } void AudioContext::RecordAutoplayMetrics() { - if (!autoplay_status_.has_value()) + if (!autoplay_status_.has_value() || !GetDocument()) return; ukm::UkmRecorder* ukm_recorder = GetDocument()->UkmRecorder(); @@ -494,7 +526,11 @@ void AudioContext::NotifyAudibleAudioStopped() { DCHECK(IsMainThread()); DCHECK(audio_context_manager_); - audio_context_manager_->AudioContextAudiblePlaybackStopped(context_id_); + // If we don't have a document, we don't need to notify anyone that we've + // stopped. + if (GetDocument()) { + audio_context_manager_->AudioContextAudiblePlaybackStopped(context_id_); + } } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_context.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_context.h index d93934e4e0c..7a3db4c0c1b 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_context.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_context.h @@ -19,6 +19,11 @@ class AudioContextOptions; class AudioTimestamp; class Document; class ExceptionState; +class HTMLMediaElement; +class MediaElementAudioSourceNode; +class MediaStream; +class MediaStreamAudioDestinationNode; +class MediaStreamAudioSourceNode; class ScriptState; class WebAudioLatencyHint; @@ -41,14 +46,21 @@ class MODULES_EXPORT AudioContext : public BaseAudioContext { ScriptPromise closeContext(ScriptState*); bool IsContextClosed() const final; - ScriptPromise suspendContext(ScriptState*) final; - ScriptPromise resumeContext(ScriptState*) final; + ScriptPromise suspendContext(ScriptState*); + ScriptPromise resumeContext(ScriptState*); bool HasRealtimeConstraint() final { return true; } void getOutputTimestamp(ScriptState*, AudioTimestamp&); double baseLatency() const; + MediaElementAudioSourceNode* createMediaElementSource(HTMLMediaElement*, + ExceptionState&); + MediaStreamAudioSourceNode* createMediaStreamSource(MediaStream*, + ExceptionState&); + MediaStreamAudioDestinationNode* createMediaStreamDestination( + ExceptionState&); + // Called by handlers of AudioScheduledSourceNode and AudioBufferSourceNode to // notify their associated AudioContext when start() is called. It may resume // the AudioContext if it is now allowed to start. diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_context.idl b/chromium/third_party/blink/renderer/modules/webaudio/audio_context.idl index 2983635f315..e386af9d511 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_context.idl +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_context.idl @@ -40,6 +40,7 @@ enum AudioContextLatencyCategory { ] interface AudioContext : BaseAudioContext { [MeasureAs=AudioContextSuspend, CallWith=ScriptState, ImplementedAs=suspendContext] Promise<void> suspend(); [MeasureAs=AudioContextClose, CallWith=ScriptState, ImplementedAs=closeContext] Promise<void> close(); + [MeasureAs=AudioContextResume, CallWith=ScriptState, ImplementedAs=resumeContext] Promise<void> resume(); // Output timestamp [MeasureAs=AudioContextGetOutputTimestamp, CallWith=ScriptState] AudioTimestamp getOutputTimestamp(); @@ -48,10 +49,8 @@ enum AudioContextLatencyCategory { // passing the audio from the AudioDestinationNode to the audio subsystem readonly attribute double baseLatency; - // Sources - // TODO(rtoy): The following methods should be here instead of in BaseAudioContext: - // - // createMediaElementSource(HTMLMediaElement mediaElement) - // createMediaStreamSource(MediaStream mediaStream) - // createMediaStreamDestination() + [RaisesException, MeasureAs=AudioContextCreateMediaElementSource] MediaElementAudioSourceNode createMediaElementSource(HTMLMediaElement mediaElement); + [RaisesException, MeasureAs=AudioContextCreateMediaStreamSource] MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream); + [RaisesException, MeasureAs=AudioContextCreateMediaStreamDestination] MediaStreamAudioDestinationNode createMediaStreamDestination(); + }; diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc index 93af83128ff..b9b40ca63c7 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc @@ -84,11 +84,6 @@ class AudioContextAutoplayTestPlatform : public TestingPlatformSupport { AudioHardwareSampleRate(), AudioHardwareBufferSize()); } - std::unique_ptr<WebThread> CreateThread( - const WebThreadCreationParams& params) override { - return old_platform_->CreateThread(params); - } - double AudioHardwareSampleRate() override { return 44100; } size_t AudioHardwareBufferSize() override { return 128; } }; @@ -264,8 +259,8 @@ TEST_P(AudioContextAutoplayTest, AutoplayMetrics_CallResumeNoGesture_Main) { // Creates an AudioContext with a user gesture inside a x-origin child frame. TEST_P(AudioContextAutoplayTest, AutoplayMetrics_CreateGesture_Child) { std::unique_ptr<UserGestureIndicator> user_gesture_scope = - Frame::NotifyUserActivation(ChildDocument().GetFrame(), - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(ChildDocument().GetFrame(), + UserGestureToken::kNewGesture); AudioContext* audio_context = AudioContext::Create( ChildDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION); @@ -293,8 +288,8 @@ TEST_P(AudioContextAutoplayTest, AutoplayMetrics_CreateGesture_Child) { // Creates an AudioContext with a user gesture inside a main frame. TEST_P(AudioContextAutoplayTest, AutoplayMetrics_CreateGesture_Main) { std::unique_ptr<UserGestureIndicator> user_gesture_scope = - Frame::NotifyUserActivation(GetDocument().GetFrame(), - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame(), + UserGestureToken::kNewGesture); AudioContext* audio_context = AudioContext::Create( GetDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION); @@ -325,8 +320,8 @@ TEST_P(AudioContextAutoplayTest, AutoplayMetrics_CallResumeGesture_Child) { ChildDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION); std::unique_ptr<UserGestureIndicator> user_gesture_scope = - Frame::NotifyUserActivation(ChildDocument().GetFrame(), - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(ChildDocument().GetFrame(), + UserGestureToken::kNewGesture); audio_context->resumeContext(GetScriptStateFrom(ChildDocument())); RejectPendingResolvers(audio_context); @@ -360,8 +355,8 @@ TEST_P(AudioContextAutoplayTest, AutoplayMetrics_CallResumeGesture_Main) { GetDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION); std::unique_ptr<UserGestureIndicator> user_gesture_scope = - Frame::NotifyUserActivation(GetDocument().GetFrame(), - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame(), + UserGestureToken::kNewGesture); audio_context->resumeContext(GetScriptStateFrom(GetDocument())); RejectPendingResolvers(audio_context); @@ -440,8 +435,8 @@ TEST_P(AudioContextAutoplayTest, AutoplayMetrics_NodeStartGesture_Child) { ChildDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION); std::unique_ptr<UserGestureIndicator> user_gesture_scope = - Frame::NotifyUserActivation(ChildDocument().GetFrame(), - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(ChildDocument().GetFrame(), + UserGestureToken::kNewGesture); audio_context->NotifySourceNodeStart(); RecordAutoplayStatus(audio_context); @@ -471,8 +466,8 @@ TEST_P(AudioContextAutoplayTest, AutoplayMetrics_NodeStartGesture_Main) { GetDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION); std::unique_ptr<UserGestureIndicator> user_gesture_scope = - Frame::NotifyUserActivation(GetDocument().GetFrame(), - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame(), + UserGestureToken::kNewGesture); audio_context->NotifySourceNodeStart(); RecordAutoplayStatus(audio_context); @@ -503,8 +498,8 @@ TEST_P(AudioContextAutoplayTest, audio_context->NotifySourceNodeStart(); std::unique_ptr<UserGestureIndicator> user_gesture_scope = - Frame::NotifyUserActivation(ChildDocument().GetFrame(), - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(ChildDocument().GetFrame(), + UserGestureToken::kNewGesture); audio_context->resumeContext(GetScriptStateFrom(ChildDocument())); RejectPendingResolvers(audio_context); RecordAutoplayStatus(audio_context); @@ -539,8 +534,8 @@ TEST_P(AudioContextAutoplayTest, audio_context->NotifySourceNodeStart(); std::unique_ptr<UserGestureIndicator> user_gesture_scope = - Frame::NotifyUserActivation(GetDocument().GetFrame(), - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame(), + UserGestureToken::kNewGesture); audio_context->resumeContext(GetScriptStateFrom(GetDocument())); RejectPendingResolvers(audio_context); RecordAutoplayStatus(audio_context); @@ -571,8 +566,8 @@ TEST_P(AudioContextAutoplayTest, ChildDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION); std::unique_ptr<UserGestureIndicator> user_gesture_scope = - Frame::NotifyUserActivation(ChildDocument().GetFrame(), - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(ChildDocument().GetFrame(), + UserGestureToken::kNewGesture); audio_context->NotifySourceNodeStart(); audio_context->resumeContext(GetScriptStateFrom(ChildDocument())); RejectPendingResolvers(audio_context); @@ -607,8 +602,8 @@ TEST_P(AudioContextAutoplayTest, GetDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION); std::unique_ptr<UserGestureIndicator> user_gesture_scope = - Frame::NotifyUserActivation(GetDocument().GetFrame(), - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(GetDocument().GetFrame(), + UserGestureToken::kNewGesture); audio_context->NotifySourceNodeStart(); audio_context->resumeContext(GetScriptStateFrom(GetDocument())); RejectPendingResolvers(audio_context); @@ -634,8 +629,8 @@ TEST_P(AudioContextAutoplayTest, // document previous received a user gesture. TEST_P(AudioContextAutoplayTest, AutoplayMetrics_DocumentReceivedGesture_Child) { - Frame::NotifyUserActivation(ChildDocument().GetFrame(), - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(ChildDocument().GetFrame(), + UserGestureToken::kNewGesture); AudioContext* audio_context = AudioContext::Create( ChildDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION); @@ -671,8 +666,8 @@ TEST_P(AudioContextAutoplayTest, // document previous received a user gesture. TEST_P(AudioContextAutoplayTest, AutoplayMetrics_DocumentReceivedGesture_Main) { - Frame::NotifyUserActivation(ChildDocument().GetFrame(), - UserGestureToken::kNewGesture); + LocalFrame::NotifyUserActivation(ChildDocument().GetFrame(), + UserGestureToken::kNewGesture); AudioContext* audio_context = AudioContext::Create( GetDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION); diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_context_test.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_context_test.cc index 6f994307305..2923f69a21f 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_context_test.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_context_test.cc @@ -9,9 +9,9 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/web_audio_device.h" #include "third_party/blink/public/platform/web_audio_latency_hint.h" -#include "third_party/blink/public/platform/web_thread.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/blink/renderer/platform/testing/testing_platform_support.h" namespace blink { @@ -72,11 +72,6 @@ class AudioContextTestPlatform : public TestingPlatformSupport { AudioHardwareSampleRate(), buffer_size); } - std::unique_ptr<WebThread> CreateThread( - const WebThreadCreationParams& params) override { - return old_platform_->CreateThread(params); - } - double AudioHardwareSampleRate() override { return 44100; } size_t AudioHardwareBufferSize() override { return 128; } }; diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc index 936f36d5465..f3f1d0d78c2 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_node.cc @@ -416,7 +416,7 @@ void AudioHandler::EnableOutputsIfNecessary() { #if DEBUG_AUDIONODE_REFERENCES > 1 fprintf(stderr, "[%16p]: %16p: %2d: EnableOutputsIfNecessary: is_disabled %d count " - "%d output size %zu\n", + "%d output size %u\n", Context(), this, GetNodeType(), is_disabled_, connection_ref_count_, outputs_.size()); #endif diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc index eb6008313aa..24f4820c89b 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc @@ -52,7 +52,9 @@ AudioParamHandler::AudioParamHandler(BaseAudioContext& context, automation_rate_(rate), rate_mode_(rate_mode), min_value_(min_value), - max_value_(max_value) { + max_value_(max_value), + summing_bus_( + AudioBus::Create(1, AudioUtilities::kRenderQuantumFrames, false)) { // The destination MUST exist because we need the destination handler for the // AudioParam. CHECK(context.destination()); @@ -258,23 +260,25 @@ void AudioParamHandler::CalculateFinalValues(float* values, SetIntrinsicValue(value); } - // Now sum all of the audio-rate connections together (unity-gain summing - // junction). Note that connections would normally be mono, but we mix down - // to mono if necessary. - scoped_refptr<AudioBus> summing_bus = - AudioBus::Create(1, number_of_values, false); - summing_bus->SetChannelMemory(0, values, number_of_values); + // If there are any connections, sum all of the audio-rate connections + // together (unity-gain summing junction). Note that connections would + // normally be mono, but we mix down to mono if necessary. + if (NumberOfRenderingConnections() > 0) { + DCHECK_LE(number_of_values, AudioUtilities::kRenderQuantumFrames); - for (unsigned i = 0; i < NumberOfRenderingConnections(); ++i) { - AudioNodeOutput* output = RenderingOutput(i); - DCHECK(output); + summing_bus_->SetChannelMemory(0, values, number_of_values); - // Render audio from this output. - AudioBus* connection_bus = - output->Pull(nullptr, AudioUtilities::kRenderQuantumFrames); + for (unsigned i = 0; i < NumberOfRenderingConnections(); ++i) { + AudioNodeOutput* output = RenderingOutput(i); + DCHECK(output); - // Sum, with unity-gain. - summing_bus->SumFrom(*connection_bus); + // Render audio from this output. + AudioBus* connection_bus = + output->Pull(nullptr, AudioUtilities::kRenderQuantumFrames); + + // Sum, with unity-gain. + summing_bus_->SumFrom(*connection_bus); + } } } diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_param.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_param.h index 1dfb251c0a2..eca5b5875bd 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_param.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_param.h @@ -248,6 +248,9 @@ class AudioParamHandler final : public ThreadSafeRefCounted<AudioParamHandler>, // The destination node used to get necessary information like the smaple rate // and context time. scoped_refptr<AudioDestinationHandler> destination_handler_; + + // Audio bus to sum in any connections to the AudioParam. + scoped_refptr<AudioBus> summing_bus_; }; // AudioParam class represents web-exposed AudioParam interface. diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc index a7db4bac113..139b8c50bc2 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc @@ -33,6 +33,7 @@ #include "third_party/blink/renderer/core/frame/deprecation.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/platform/audio/audio_utilities.h" +#include "third_party/blink/renderer/platform/audio/vector_math.h" #include "third_party/blink/renderer/platform/bindings/exception_messages.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/wtf/cpu.h" @@ -551,12 +552,43 @@ void AudioParamTimeline::InsertEvent(std::unique_ptr<ParamEvent> event, // Events of type |kSetValueCurveEnd| or |kCancelValues| never // conflict. if (!(test_type == ParamEvent::kSetValueCurveEnd || - test_type == ParamEvent::kCancelValues) && - events_[i]->Time() > event->Time() && events_[i]->Time() < end_time) { - exception_state.ThrowDOMException( - DOMExceptionCode::kNotSupportedError, - EventToString(*event) + " overlaps " + EventToString(*events_[i])); - return; + test_type == ParamEvent::kCancelValues)) { + if (test_type == ParamEvent::kSetValueCurve) { + // A SetValueCurve overlapping an existing SetValueCurve requires + // special care. + double test_end_time = events_[i]->Time() + events_[i]->Duration(); + // Test if old event starts somewhere in the middle of the new event. + bool overlap = (events_[i]->Time() >= event->Time() && + events_[i]->Time() < end_time); + // Test if old event ends somewhere in the middle of the new event. + overlap = overlap || + (test_end_time > event->Time() && test_end_time < end_time); + // Test if new event starts somewhere in the middle of the old event. + overlap = overlap || (event->Time() >= events_[i]->Time() && + event->Time() < test_end_time); + // Test if new event ends somewhere in the middle of the old event. + overlap = overlap || (end_time >= events_[i]->Time() && + end_time < test_end_time); + if (overlap) { + // If the start time of the event overlaps the start/end of an + // existing event or if the existing event end overlaps the + // start/end of the event, it's an error. + exception_state.ThrowDOMException( + DOMExceptionCode::kNotSupportedError, + EventToString(*event) + " overlaps " + + EventToString(*events_[i])); + return; + } + } else { + if (events_[i]->Time() > event->Time() && + events_[i]->Time() < end_time) { + exception_state.ThrowDOMException( + DOMExceptionCode::kNotSupportedError, + EventToString(*event) + " overlaps " + + EventToString(*events_[i])); + return; + } + } } } else { // Otherwise, make sure this event doesn't overlap any existing @@ -822,8 +854,8 @@ float AudioParamTimeline::ValuesForFrameRange(size_t start_frame, number_of_values, sample_rate, control_rate); // Clamp the values now to the nominal range - for (unsigned k = 0; k < number_of_values; ++k) - values[k] = clampTo(values[k], min_value, max_value); + VectorMath::Vclip(values, 1, &min_value, &max_value, values, 1, + number_of_values); return last_value; } diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc index a6fba8c4a19..761113d9ecd 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet.cc @@ -21,7 +21,8 @@ AudioWorklet* AudioWorklet::Create(BaseAudioContext* context) { } AudioWorklet::AudioWorklet(BaseAudioContext* context) - : Worklet(ToDocument(context->GetExecutionContext())), context_(context) {} + : Worklet(To<Document>(context->GetExecutionContext())), + context_(context) {} void AudioWorklet::CreateProcessor( scoped_refptr<AudioWorkletHandler> handler, diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc index 9dc2b84f96d..718ef75dbb8 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc @@ -20,6 +20,7 @@ #include "third_party/blink/renderer/core/messaging/message_port.h" #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" +#include "third_party/blink/renderer/core/workers/worker_thread.h" #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h" #include "third_party/blink/renderer/modules/webaudio/audio_param_descriptor.h" #include "third_party/blink/renderer/modules/webaudio/audio_worklet_processor.h" @@ -36,24 +37,23 @@ namespace blink { AudioWorkletGlobalScope* AudioWorkletGlobalScope::Create( std::unique_ptr<GlobalScopeCreationParams> creation_params, - v8::Isolate* isolate, WorkerThread* thread) { - return new AudioWorkletGlobalScope(std::move(creation_params), isolate, - thread); + return new AudioWorkletGlobalScope(std::move(creation_params), thread); } AudioWorkletGlobalScope::AudioWorkletGlobalScope( std::unique_ptr<GlobalScopeCreationParams> creation_params, - v8::Isolate* isolate, WorkerThread* thread) - : ThreadedWorkletGlobalScope(std::move(creation_params), isolate, thread) {} + : WorkletGlobalScope(std::move(creation_params), + thread->GetWorkerReportingProxy(), + thread) {} AudioWorkletGlobalScope::~AudioWorkletGlobalScope() = default; void AudioWorkletGlobalScope::Dispose() { DCHECK(IsContextThread()); is_closing_ = true; - ThreadedWorkletGlobalScope::Dispose(); + WorkletGlobalScope::Dispose(); } void AudioWorkletGlobalScope::registerProcessor( @@ -401,7 +401,7 @@ double AudioWorkletGlobalScope::currentTime() const { void AudioWorkletGlobalScope::Trace(blink::Visitor* visitor) { visitor->Trace(processor_definition_map_); visitor->Trace(processor_instances_); - ThreadedWorkletGlobalScope::Trace(visitor); + WorkletGlobalScope::Trace(visitor); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h index d92c0055a41..ce29470c280 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h @@ -7,7 +7,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" -#include "third_party/blink/renderer/core/workers/threaded_worklet_global_scope.h" +#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/webaudio/audio_param_descriptor.h" #include "third_party/blink/renderer/platform/audio/audio_array.h" @@ -46,14 +46,12 @@ class MODULES_EXPORT ProcessorCreationParams final { // This is constructed and destroyed on a worker thread, and all methods also // must be called on the worker thread. -class MODULES_EXPORT AudioWorkletGlobalScope final - : public ThreadedWorkletGlobalScope { +class MODULES_EXPORT AudioWorkletGlobalScope final : public WorkletGlobalScope { DEFINE_WRAPPERTYPEINFO(); public: static AudioWorkletGlobalScope* Create( std::unique_ptr<GlobalScopeCreationParams>, - v8::Isolate*, WorkerThread*); ~AudioWorkletGlobalScope() override; bool IsAudioWorkletGlobalScope() const final { return true; } @@ -106,7 +104,6 @@ class MODULES_EXPORT AudioWorkletGlobalScope final private: AudioWorkletGlobalScope(std::unique_ptr<GlobalScopeCreationParams>, - v8::Isolate*, WorkerThread*); bool is_closing_ = false; diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc index d2130f08b8a..80b166f42dd 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc @@ -55,7 +55,7 @@ static const size_t kRenderQuantumFrames = 128; class AudioWorkletGlobalScopeTest : public PageTestBase { public: void SetUp() override { - AudioWorkletThread::CreateSharedBackingThreadForTest(); + AudioWorkletThread::EnsureSharedBackingThread(); PageTestBase::SetUp(IntSize()); Document* document = &GetDocument(); document->SetURL(KURL("https://example.com/")); diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc index d74292811d0..cee79bc7253 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc @@ -47,12 +47,15 @@ AudioWorkletHandler::AudioWorkletHandler( AddInput(); } - // If |options.outputChannelCount| unspecified, all outputs are mono. + if (options.hasOutputChannelCount()) { + is_output_channel_count_given_ = true; + } + for (unsigned i = 0; i < options.numberOfOutputs(); ++i) { - unsigned long channel_count = options.hasOutputChannelCount() + // If |options.outputChannelCount| unspecified, all outputs are mono. + AddOutput(is_output_channel_count_given_ ? options.outputChannelCount()[i] - : 1; - AddOutput(channel_count); + : 1); } if (Context()->GetExecutionContext()) { @@ -132,9 +135,11 @@ void AudioWorkletHandler::CheckNumberOfChannelsForInput(AudioNodeInput* input) { Context()->AssertGraphOwner(); DCHECK(input); - // Dynamic channel count only works when the node has 1 input and 1 output. - // Otherwise the channel count(s) should not be dynamically changed. - if (NumberOfInputs() == 1 && NumberOfOutputs() == 1) { + // Dynamic channel count only works when the node has 1 input, 1 output and + // |outputChannelCount| is not given. Otherwise the channel count(s) should + // not be dynamically changed. + if (NumberOfInputs() == 1 && NumberOfOutputs() == 1 && + !is_output_channel_count_given_) { DCHECK_EQ(input, &this->Input(0)); unsigned number_of_input_channels = Input(0).NumberOfChannels(); if (number_of_input_channels != Output(0).NumberOfChannels()) { diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.h index be38e866031..058202c2392 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_node.h @@ -85,6 +85,9 @@ class AudioWorkletHandler final : public AudioHandler { bool RequiresTailProcessing() const override { return true; } scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; + + // Used only if number of inputs and outputs are 1. + bool is_output_channel_count_given_ = false; }; class AudioWorkletNode final : public AudioNode, diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.cc index bf6104358df..2778e171275 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.cc @@ -52,28 +52,10 @@ WorkerBackingThread& AudioWorkletThread::GetWorkerBackingThread() { return *WorkletThreadHolder<AudioWorkletThread>::GetInstance()->GetThread(); } -void CollectAllGarbageOnAudioWorkletThread(WaitableEvent* done_event) { - blink::ThreadState::Current()->CollectAllGarbage(); - done_event->Signal(); -} - -void AudioWorkletThread::CollectAllGarbage() { - DCHECK(IsMainThread()); - WaitableEvent done_event; - WorkletThreadHolder<AudioWorkletThread>* worklet_thread_holder = - WorkletThreadHolder<AudioWorkletThread>::GetInstance(); - if (!worklet_thread_holder) - return; - worklet_thread_holder->GetThread()->BackingThread().PostTask( - FROM_HERE, CrossThreadBind(&CollectAllGarbageOnAudioWorkletThread, - CrossThreadUnretained(&done_event))); - done_event.Wait(); -} - void AudioWorkletThread::EnsureSharedBackingThread() { DCHECK(IsMainThread()); WorkletThreadHolder<AudioWorkletThread>::EnsureInstance( - WebThreadCreationParams(blink::WebThreadType::kWebAudioThread)); + ThreadCreationParams(WebThreadType::kWebAudioThread)); } void AudioWorkletThread::ClearSharedBackingThread() { @@ -82,24 +64,11 @@ void AudioWorkletThread::ClearSharedBackingThread() { WorkletThreadHolder<AudioWorkletThread>::ClearInstance(); } -WebThread* AudioWorkletThread::GetSharedBackingThread() { - DCHECK(IsMainThread()); - WorkletThreadHolder<AudioWorkletThread>* instance = - WorkletThreadHolder<AudioWorkletThread>::GetInstance(); - return &(instance->GetThread()->BackingThread().PlatformThread()); -} - -void AudioWorkletThread::CreateSharedBackingThreadForTest() { - WorkletThreadHolder<AudioWorkletThread>::CreateForTest( - WebThreadCreationParams(blink::WebThreadType::kWebAudioThread)); -} - WorkerOrWorkletGlobalScope* AudioWorkletThread::CreateWorkerGlobalScope( std::unique_ptr<GlobalScopeCreationParams> creation_params) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"), "AudioWorkletThread::createWorkerGlobalScope"); - return AudioWorkletGlobalScope::Create(std::move(creation_params), - GetIsolate(), this); + return AudioWorkletGlobalScope::Create(std::move(creation_params), this); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.h b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.h index 3181902f9c7..d3bf941fe3b 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.h @@ -28,19 +28,9 @@ class MODULES_EXPORT AudioWorkletThread final : public WorkerThread { // The backing thread is cleared by clearSharedBackingThread(). void ClearWorkerBackingThread() override {} - // This may block the main thread. - static void CollectAllGarbage(); - static void EnsureSharedBackingThread(); static void ClearSharedBackingThread(); - static void CreateSharedBackingThreadForTest(); - - // This only can be called after EnsureSharedBackingThread() is performed. - // Currently AudioWorkletThread owns only one thread and it is shared by all - // the customers. - static WebThread* GetSharedBackingThread(); - private: explicit AudioWorkletThread(WorkerReportingProxy&); diff --git a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc index 8c54cadf397..076dbbfff1b 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc @@ -39,7 +39,7 @@ namespace blink { class AudioWorkletThreadTest : public PageTestBase { public: void SetUp() override { - AudioWorkletThread::CreateSharedBackingThreadForTest(); + AudioWorkletThread::EnsureSharedBackingThread(); PageTestBase::SetUp(IntSize()); Document* document = &GetDocument(); document->SetURL(KURL("https://example.com/")); diff --git a/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.cc b/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.cc index 27cf8f0e928..64d9b51b82e 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.cc @@ -33,10 +33,10 @@ #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/frame/settings.h" +#include "third_party/blink/renderer/core/html/media/autoplay_policy.h" #include "third_party/blink/renderer/core/html/media/html_media_element.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/inspector/console_types.h" -#include "third_party/blink/renderer/modules/mediastream/media_stream.h" #include "third_party/blink/renderer/modules/webaudio/analyser_node.h" #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h" #include "third_party/blink/renderer/modules/webaudio/audio_buffer_source_node.h" @@ -56,9 +56,6 @@ #include "third_party/blink/renderer/modules/webaudio/dynamics_compressor_node.h" #include "third_party/blink/renderer/modules/webaudio/gain_node.h" #include "third_party/blink/renderer/modules/webaudio/iir_filter_node.h" -#include "third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.h" -#include "third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.h" -#include "third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.h" #include "third_party/blink/renderer/modules/webaudio/offline_audio_completion_event.h" #include "third_party/blink/renderer/modules/webaudio/offline_audio_context.h" #include "third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h" @@ -96,13 +93,15 @@ BaseAudioContext::BaseAudioContext(Document* document, is_cleared_(false), is_resolving_resume_promises_(false), has_posted_cleanup_task_(false), - deferred_task_handler_(DeferredTaskHandler::Create()), + deferred_task_handler_(DeferredTaskHandler::Create( + document->GetTaskRunner(TaskType::kInternalMedia))), context_state_(kSuspended), periodic_wave_sine_(nullptr), periodic_wave_square_(nullptr), periodic_wave_sawtooth_(nullptr), periodic_wave_triangle_(nullptr), - output_position_() {} + output_position_(), + task_runner_(document->GetTaskRunner(TaskType::kInternalMedia)) {} BaseAudioContext::~BaseAudioContext() { { @@ -113,9 +112,6 @@ BaseAudioContext::~BaseAudioContext() { } GetDeferredTaskHandler().ContextWillBeDestroyed(); - DCHECK(!active_source_nodes_.size()); - DCHECK(!is_resolving_resume_promises_); - DCHECK(!resume_resolvers_.size()); } void BaseAudioContext::Initialize() { @@ -173,6 +169,10 @@ void BaseAudioContext::Uninitialize() { listener_->WaitForHRTFDatabaseLoaderThreadCompletion(); Clear(); + + DCHECK(!is_resolving_resume_promises_); + DCHECK_EQ(resume_resolvers_.size(), 0u); + DCHECK_EQ(active_source_nodes_.size(), 0u); } void BaseAudioContext::ContextDestroyed(ExecutionContext*) { @@ -361,32 +361,6 @@ ConstantSourceNode* BaseAudioContext::createConstantSource( return ConstantSourceNode::Create(*this, exception_state); } -MediaElementAudioSourceNode* BaseAudioContext::createMediaElementSource( - HTMLMediaElement* media_element, - ExceptionState& exception_state) { - DCHECK(IsMainThread()); - - return MediaElementAudioSourceNode::Create(*this, *media_element, - exception_state); -} - -MediaStreamAudioSourceNode* BaseAudioContext::createMediaStreamSource( - MediaStream* media_stream, - ExceptionState& exception_state) { - DCHECK(IsMainThread()); - - return MediaStreamAudioSourceNode::Create(*this, *media_stream, - exception_state); -} - -MediaStreamAudioDestinationNode* BaseAudioContext::createMediaStreamDestination( - ExceptionState& exception_state) { - DCHECK(IsMainThread()); - - // Set number of output channels to stereo by default. - return MediaStreamAudioDestinationNode::Create(*this, 2, exception_state); -} - ScriptProcessorNode* BaseAudioContext::createScriptProcessor( ExceptionState& exception_state) { DCHECK(IsMainThread()); @@ -632,7 +606,7 @@ void BaseAudioContext::SetContextState(AudioContextState new_state) { if (was_audible_ && context_state_ != kRunning) { was_audible_ = false; PostCrossThreadTask( - *Platform::Current()->MainThread()->GetTaskRunner(), FROM_HERE, + *task_runner_, FROM_HERE, CrossThreadBind(&BaseAudioContext::NotifyAudibleAudioStopped, WrapCrossThreadPersistent(this))); } @@ -660,7 +634,7 @@ void BaseAudioContext::NotifySourceNodeFinishedProcessing( } Document* BaseAudioContext::GetDocument() const { - return ToDocument(GetExecutionContext()); + return To<Document>(GetExecutionContext()); } void BaseAudioContext::NotifySourceNodeStartedProcessing(AudioNode* node) { @@ -762,12 +736,12 @@ void BaseAudioContext::HandlePostRenderTasks(const AudioBus* destination_bus) { was_audible_ = is_audible; if (is_audible) { PostCrossThreadTask( - *Platform::Current()->MainThread()->GetTaskRunner(), FROM_HERE, + *task_runner_, FROM_HERE, CrossThreadBind(&BaseAudioContext::NotifyAudibleAudioStarted, WrapCrossThreadPersistent(this))); } else { PostCrossThreadTask( - *Platform::Current()->MainThread()->GetTaskRunner(), FROM_HERE, + *task_runner_, FROM_HERE, CrossThreadBind(&BaseAudioContext::NotifyAudibleAudioStopped, WrapCrossThreadPersistent(this))); } @@ -849,7 +823,7 @@ void BaseAudioContext::ScheduleMainThreadCleanup() { if (has_posted_cleanup_task_) return; PostCrossThreadTask( - *Platform::Current()->MainThread()->GetTaskRunner(), FROM_HERE, + *task_runner_, FROM_HERE, CrossThreadBind(&BaseAudioContext::PerformCleanupOnMainThread, WrapCrossThreadPersistent(this))); has_posted_cleanup_task_ = true; @@ -985,21 +959,4 @@ void BaseAudioContext::UpdateWorkletGlobalScopeOnRenderingThread() { } } -bool BaseAudioContext::WouldTaintOrigin(const KURL& url) const { - // Data URLs don't taint the origin. - if (url.ProtocolIsData()) { - return false; - } - - Document* document = GetDocument(); - if (document && document->GetSecurityOrigin()) { - // The origin is tainted if and only if we cannot read content from the URL. - return !document->GetSecurityOrigin()->CanRequest(url); - } - - // Be conservative and assume it's tainted if it's not a data url and if we - // can't get the security origin of the document. - return true; -} - } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.h b/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.h index fadb4834357..ae933f20167 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.h @@ -49,6 +49,10 @@ #include "third_party/blink/renderer/platform/wtf/threading.h" #include "third_party/blink/renderer/platform/wtf/vector.h" +namespace base { +class SingleThreadTaskRunner; +} + namespace blink { class AnalyserNode; @@ -67,12 +71,7 @@ class Document; class DynamicsCompressorNode; class ExceptionState; class GainNode; -class HTMLMediaElement; class IIRFilterNode; -class MediaElementAudioSourceNode; -class MediaStream; -class MediaStreamAudioDestinationNode; -class MediaStreamAudioSourceNode; class OscillatorNode; class PannerNode; class PeriodicWave; @@ -175,12 +174,6 @@ class MODULES_EXPORT BaseAudioContext // JavaScript). AudioBufferSourceNode* createBufferSource(ExceptionState&); ConstantSourceNode* createConstantSource(ExceptionState&); - MediaElementAudioSourceNode* createMediaElementSource(HTMLMediaElement*, - ExceptionState&); - MediaStreamAudioSourceNode* createMediaStreamSource(MediaStream*, - ExceptionState&); - MediaStreamAudioDestinationNode* createMediaStreamDestination( - ExceptionState&); GainNode* createGain(ExceptionState&); BiquadFilterNode* createBiquadFilter(ExceptionState&); WaveShaperNode* createWaveShaper(ExceptionState&); @@ -216,12 +209,6 @@ class MODULES_EXPORT BaseAudioContext const PeriodicWaveConstraints&, ExceptionState&); - // Suspend - virtual ScriptPromise suspendContext(ScriptState*) = 0; - - // Resume - virtual ScriptPromise resumeContext(ScriptState*) = 0; - // IIRFilter IIRFilterNode* createIIRFilter(Vector<double> feedforward_coef, Vector<double> feedback_coef, @@ -309,13 +296,6 @@ class MODULES_EXPORT BaseAudioContext // Does nothing when the worklet global scope does not exist. void UpdateWorkletGlobalScopeOnRenderingThread(); - // Returns true if the URL would taint the origin so that we shouldn't be - // allowing media to played through webaudio. - // TODO(crbug.com/845913): This should really be on an AudioContext. Move - // this when we move the media stuff from BaseAudioContext to AudioContext, as - // requried by the spec. - bool WouldTaintOrigin(const KURL& url) const; - protected: enum ContextType { kRealtimeContext, kOfflineContext }; @@ -349,6 +329,16 @@ class MODULES_EXPORT BaseAudioContext const String& Uuid() const { return uuid_; } + // The audio thread relies on the main thread to perform some operations + // over the objects that it owns and controls; |ScheduleMainThreadCleanup()| + // posts the task to initiate those. + void ScheduleMainThreadCleanup(); + + // Handles promise resolving, stopping and finishing up of audio source nodes + // etc. Actions that should happen, but can happen asynchronously to the + // audio thread making rendering progress. + void PerformCleanupOnMainThread(); + private: friend class AudioContextAutoplayTest; @@ -388,18 +378,6 @@ class MODULES_EXPORT BaseAudioContext // these Promises. void ResolvePromisesForUnpause(); - // The audio thread relies on the main thread to perform some operations - // over the objects that it owns and controls; |ScheduleMainThreadCleanup()| - // posts the task to initiate those. - // - // That is, we combine all those sub-tasks into one task action for - // convenience and performance, |PerformCleanupOnMainThread()|. It handles - // promise resolving, stopping and finishing up of audio source nodes etc. - // Actions that should happen, but can happen asynchronously to the - // audio thread making rendering progress. - void ScheduleMainThreadCleanup(); - void PerformCleanupOnMainThread(); - // When the context is going away, reject any pending script promise // resolvers. virtual void RejectPendingResolvers(); @@ -466,6 +444,8 @@ class MODULES_EXPORT BaseAudioContext // determine audibility on render quantum boundaries, so counting quanta is // all that's needed. size_t total_audible_renders_ = 0; + + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.idl b/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.idl index 6bed5699721..a1d7cd614fb 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.idl +++ b/chromium/third_party/blink/renderer/modules/webaudio/base_audio_context.idl @@ -61,15 +61,6 @@ callback DecodeSuccessCallback = void (AudioBuffer decodedData); [RaisesException, MeasureAs=AudioContextCreateChannelSplitter] ChannelSplitterNode createChannelSplitter(optional unsigned long numberOfOutputs); [RaisesException, MeasureAs=AudioContextCreateChannelMerger] ChannelMergerNode createChannelMerger(optional unsigned long numberOfInputs); - // Pause/resume - [MeasureAs=AudioContextResume, CallWith=ScriptState, ImplementedAs=resumeContext] Promise<void> resume(); - - // TODO(rtoy): These really belong to the AudioContext, but we need them - // here so we can use an offline audio context to test these. - [RaisesException, MeasureAs=AudioContextCreateMediaElementSource] MediaElementAudioSourceNode createMediaElementSource(HTMLMediaElement mediaElement); - [RaisesException, MeasureAs=AudioContextCreateMediaStreamSource] MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream); - [RaisesException, MeasureAs=AudioContextCreateMediaStreamDestination] MediaStreamAudioDestinationNode createMediaStreamDestination(); - [SecureContext] readonly attribute AudioWorklet audioWorklet; attribute EventHandler onstatechange; diff --git a/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc index 372008bc98a..3e6b0b4f240 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.cc @@ -44,9 +44,7 @@ const size_t MaxFFTSize = 32768; namespace blink { ConvolverHandler::ConvolverHandler(AudioNode& node, float sample_rate) - : AudioHandler(kNodeTypeConvolver, node, sample_rate), - normalize_(true), - buffer_has_been_set_(false) { + : AudioHandler(kNodeTypeConvolver, node, sample_rate), normalize_(true) { AddInput(); AddOutput(1); @@ -102,15 +100,6 @@ void ConvolverHandler::SetBuffer(AudioBuffer* buffer, return; } - if (buffer && buffer_has_been_set_) { - exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, - "Cannot set buffer to non-null after it " - "has been already been set to a non-null " - "buffer"); - return; - } - - buffer_has_been_set_ = true; if (buffer->sampleRate() != Context()->sampleRate()) { exception_state.ThrowDOMException( DOMExceptionCode::kNotSupportedError, diff --git a/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.h b/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.h index 16e71832ef9..fc11d61ce49 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/convolver_node.h @@ -31,6 +31,7 @@ #include "base/memory/scoped_refptr.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/webaudio/audio_node.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/threading_primitives.h" namespace blink { @@ -85,10 +86,6 @@ class MODULES_EXPORT ConvolverHandler final : public AudioHandler { // Normalize the impulse response or not. Must default to true. bool normalize_; - // True if the |buffer| attribute has ever been set to a non-null - // value. Defaults to false. - bool buffer_has_been_set_; - FRIEND_TEST_ALL_PREFIXES(ConvolverNodeTest, ReverbLifetime); }; diff --git a/chromium/third_party/blink/renderer/modules/webaudio/cross_thread_audio_worklet_processor_info.h b/chromium/third_party/blink/renderer/modules/webaudio/cross_thread_audio_worklet_processor_info.h index 01f6c0d9eee..64cf12545be 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/cross_thread_audio_worklet_processor_info.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/cross_thread_audio_worklet_processor_info.h @@ -14,7 +14,7 @@ namespace blink { // when requested when the synchronization between AudioWorkletMessagingProxy // and AudioWorkletGlobalScope. class CrossThreadAudioParamInfo { - DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + DISALLOW_NEW(); public: explicit CrossThreadAudioParamInfo(const AudioParamDescriptor* descriptor) @@ -39,7 +39,7 @@ class CrossThreadAudioParamInfo { // created only when requested when the synchronization between // AudioWorkletMessagingProxy and AudioWorkletGlobalScope. class CrossThreadAudioWorkletProcessorInfo { - DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + DISALLOW_NEW(); public: explicit CrossThreadAudioWorkletProcessorInfo( diff --git a/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.cc index 0e5675e2bd1..964e68ea31a 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.cc @@ -68,21 +68,20 @@ void DefaultAudioDestinationHandler::Dispose() { void DefaultAudioDestinationHandler::Initialize() { DCHECK(IsMainThread()); - if (IsInitialized()) - return; - CreateDestination(); + CreatePlatformDestination(); AudioHandler::Initialize(); } void DefaultAudioDestinationHandler::Uninitialize() { DCHECK(IsMainThread()); - if (!IsInitialized()) - return; - if (destination_->IsPlaying()) - StopDestination(); + // It is possible that the handler is already uninitialized. + if (!IsInitialized()) { + return; + } + StopPlatformDestination(); AudioHandler::Uninitialize(); } @@ -94,7 +93,7 @@ void DefaultAudioDestinationHandler::SetChannelCount( // The channelCount for the input to this node controls the actual number of // channels we send to the audio hardware. It can only be set if the number // is less than the number of hardware channels. - if (!MaxChannelCount() || channel_count > MaxChannelCount()) { + if (channel_count > MaxChannelCount()) { exception_state.ThrowDOMException( DOMExceptionCode::kIndexSizeError, ExceptionMessages::IndexOutsideRange<unsigned>( @@ -108,33 +107,29 @@ void DefaultAudioDestinationHandler::SetChannelCount( AudioHandler::SetChannelCount(channel_count, exception_state); // Stop, re-create and start the destination to apply the new channel count. - if (!exception_state.HadException() && - this->ChannelCount() != old_channel_count && IsInitialized()) { - StopDestination(); - CreateDestination(); - StartDestination(); + if (this->ChannelCount() != old_channel_count && + !exception_state.HadException()) { + StopPlatformDestination(); + CreatePlatformDestination(); + StartPlatformDestination(); } } void DefaultAudioDestinationHandler::StartRendering() { - DCHECK(IsInitialized()); - // Context might try to start rendering again while the destination is - // running. Ignore it when that happens. - if (IsInitialized() && !destination_->IsPlaying()) { - StartDestination(); - } + DCHECK(IsMainThread()); + + StartPlatformDestination(); } void DefaultAudioDestinationHandler::StopRendering() { - DCHECK(IsInitialized()); - // Context might try to stop rendering again while the destination is stopped. - // Ignore it when that happens. - if (IsInitialized() && destination_->IsPlaying()) { - StopDestination(); - } + DCHECK(IsMainThread()); + + StopPlatformDestination(); } void DefaultAudioDestinationHandler::RestartRendering() { + DCHECK(IsMainThread()); + StopRendering(); StartRendering(); } @@ -144,7 +139,10 @@ unsigned long DefaultAudioDestinationHandler::MaxChannelCount() const { } double DefaultAudioDestinationHandler::SampleRate() const { - return destination_ ? destination_->SampleRate() : 0; + // This can be accessed from both threads (main and audio), so it is + // possible that |platform_destination_| is not fully functional when it + // is accssed by the audio thread. + return platform_destination_ ? platform_destination_->SampleRate() : 0; } void DefaultAudioDestinationHandler::Render( @@ -161,8 +159,9 @@ void DefaultAudioDestinationHandler::Render( // safe execution of the subsequence operations because the hanlder holds // the context as |UntracedMember| and it can go away anytime. DCHECK(Context()); - if (!Context()) + if (!Context()) { return; + } Context()->GetDeferredTaskHandler().SetAudioThreadToCurrentThread(); @@ -176,24 +175,23 @@ void DefaultAudioDestinationHandler::Render( Context()->HandlePreRenderTasks(output_position); - DCHECK_GE(NumberOfInputs(), 1u); - if (NumberOfInputs() < 1) { - destination_bus->Zero(); - return; - } - // Renders the graph by pulling all the input(s) to this node. This will in // turn pull on their input(s), all the way backwards through the graph. AudioBus* rendered_bus = Input(0).Pull(destination_bus, number_of_frames); + DCHECK(rendered_bus); if (!rendered_bus) { + // AudioNodeInput might be in the middle of destruction. Then the internal + // summing bus will return as nullptr. Then zero out the output. destination_bus->Zero(); } else if (rendered_bus != destination_bus) { - // in-place processing was not possible - so copy + // In-place processing was not possible. Copy the rendererd result to the + // given |destination_bus| buffer. destination_bus->CopyFrom(*rendered_bus); } - // Processes "automatic" nodes that are not connected to anything. + // Processes "automatic" nodes that are not connected to anything. This can + // be done after copying because it does not affect the rendered result. Context()->GetDeferredTaskHandler().ProcessAutomaticPullNodes( number_of_frames); @@ -207,37 +205,46 @@ void DefaultAudioDestinationHandler::Render( } size_t DefaultAudioDestinationHandler::GetCallbackBufferSize() const { - return destination_->CallbackBufferSize(); + DCHECK(IsMainThread()); + DCHECK(IsInitialized()); + + return platform_destination_->CallbackBufferSize(); } int DefaultAudioDestinationHandler::GetFramesPerBuffer() const { - return destination_ ? destination_->FramesPerBuffer() : 0; + DCHECK(IsMainThread()); + DCHECK(IsInitialized()); + + return platform_destination_ ? platform_destination_->FramesPerBuffer() : 0; } -void DefaultAudioDestinationHandler::CreateDestination() { - destination_ = AudioDestination::Create(*this, ChannelCount(), latency_hint_); +void DefaultAudioDestinationHandler::CreatePlatformDestination() { + platform_destination_ = + AudioDestination::Create(*this, ChannelCount(), latency_hint_); } -void DefaultAudioDestinationHandler::StartDestination() { - DCHECK(!destination_->IsPlaying()); +void DefaultAudioDestinationHandler::StartPlatformDestination() { + if (platform_destination_->IsPlaying()) { + return; + } AudioWorklet* audio_worklet = Context()->audioWorklet(); if (audio_worklet && audio_worklet->IsReady()) { // This task runner is only used to fire the audio render callback, so it // MUST not be throttled to avoid potential audio glitch. - destination_->StartWithWorkletTaskRunner( + platform_destination_->StartWithWorkletTaskRunner( audio_worklet->GetMessagingProxy() ->GetBackingWorkerThread() ->GetTaskRunner(TaskType::kInternalMedia)); } else { - destination_->Start(); + platform_destination_->Start(); } } -void DefaultAudioDestinationHandler::StopDestination() { - DCHECK(destination_->IsPlaying()); - - destination_->Stop(); +void DefaultAudioDestinationHandler::StopPlatformDestination() { + if (platform_destination_->IsPlaying()) { + platform_destination_->Stop(); + } } // ----------------------------------------------------------------------------- diff --git a/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h b/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h index 65268abf8b7..0507a5a85ff 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h @@ -79,12 +79,14 @@ class DefaultAudioDestinationHandler final : public AudioDestinationHandler, explicit DefaultAudioDestinationHandler(AudioNode&, const WebAudioLatencyHint&); - void CreateDestination(); - void StartDestination(); - void StopDestination(); + void CreatePlatformDestination(); + void StartPlatformDestination(); + void StopPlatformDestination(); const WebAudioLatencyHint latency_hint_; - scoped_refptr<AudioDestination> destination_; + + // Holds the audio device thread that runs the real time audio context. + scoped_refptr<AudioDestination> platform_destination_; }; // ----------------------------------------------------------------------------- diff --git a/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc b/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc index 70131fea333..073fbc01c0f 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc @@ -26,11 +26,11 @@ #include "third_party/blink/renderer/modules/webaudio/deferred_task_handler.h" #include "third_party/blink/public/platform/platform.h" -#include "third_party/blink/public/platform/web_thread.h" #include "third_party/blink/renderer/modules/webaudio/audio_node.h" #include "third_party/blink/renderer/modules/webaudio/audio_node_output.h" #include "third_party/blink/renderer/modules/webaudio/offline_audio_context.h" #include "third_party/blink/renderer/platform/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/blink/renderer/platform/web_task_runner.h" namespace blink { @@ -127,38 +127,42 @@ void DeferredTaskHandler::HandleDirtyAudioNodeOutputs() { output->UpdateRenderingState(); } -void DeferredTaskHandler::AddAutomaticPullNode(AudioHandler* node) { +void DeferredTaskHandler::AddAutomaticPullNode( + scoped_refptr<AudioHandler> node) { AssertGraphOwner(); - if (!automatic_pull_nodes_.Contains(node)) { - automatic_pull_nodes_.insert(node); - automatic_pull_nodes_need_updating_ = true; + if (!automatic_pull_handlers_.Contains(node)) { + automatic_pull_handlers_.insert(node); + automatic_pull_handlers_need_updating_ = true; } } -void DeferredTaskHandler::RemoveAutomaticPullNode(AudioHandler* node) { +void DeferredTaskHandler::RemoveAutomaticPullNode( + scoped_refptr<AudioHandler> node) { AssertGraphOwner(); - if (automatic_pull_nodes_.Contains(node)) { - automatic_pull_nodes_.erase(node); - automatic_pull_nodes_need_updating_ = true; + if (automatic_pull_handlers_.Contains(node)) { + automatic_pull_handlers_.erase(node); + automatic_pull_handlers_need_updating_ = true; } } void DeferredTaskHandler::UpdateAutomaticPullNodes() { AssertGraphOwner(); - if (automatic_pull_nodes_need_updating_) { - CopyToVector(automatic_pull_nodes_, rendering_automatic_pull_nodes_); - automatic_pull_nodes_need_updating_ = false; + if (automatic_pull_handlers_need_updating_) { + CopyToVector(automatic_pull_handlers_, rendering_automatic_pull_handlers_); + automatic_pull_handlers_need_updating_ = false; } } void DeferredTaskHandler::ProcessAutomaticPullNodes(size_t frames_to_process) { DCHECK(IsAudioThread()); - for (unsigned i = 0; i < rendering_automatic_pull_nodes_.size(); ++i) - rendering_automatic_pull_nodes_[i]->ProcessIfNecessary(frames_to_process); + for (unsigned i = 0; i < rendering_automatic_pull_handlers_.size(); ++i) { + rendering_automatic_pull_handlers_[i]->ProcessIfNecessary( + frames_to_process); + } } void DeferredTaskHandler::AddTailProcessingHandler( @@ -261,19 +265,18 @@ void DeferredTaskHandler::UpdateChangedChannelInterpretation() { deferred_channel_interpretation_change_.clear(); } -DeferredTaskHandler::DeferredTaskHandler() - : automatic_pull_nodes_need_updating_(false), audio_thread_(0) {} +DeferredTaskHandler::DeferredTaskHandler( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : automatic_pull_handlers_need_updating_(false), + task_runner_(std::move(task_runner)), + audio_thread_(0) {} -scoped_refptr<DeferredTaskHandler> DeferredTaskHandler::Create() { - return base::AdoptRef(new DeferredTaskHandler()); +scoped_refptr<DeferredTaskHandler> DeferredTaskHandler::Create( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + return base::AdoptRef(new DeferredTaskHandler(std::move(task_runner))); } -DeferredTaskHandler::~DeferredTaskHandler() { - DCHECK(!automatic_pull_nodes_.size()); - if (automatic_pull_nodes_need_updating_) - rendering_automatic_pull_nodes_.resize(automatic_pull_nodes_.size()); - DCHECK(!rendering_automatic_pull_nodes_.size()); -} +DeferredTaskHandler::~DeferredTaskHandler() = default; void DeferredTaskHandler::HandleDeferredTasks() { UpdateChangedChannelCountMode(); @@ -319,7 +322,7 @@ void DeferredTaskHandler::RequestToDeleteHandlersOnMainThread() { deletable_orphan_handlers_.AppendVector(rendering_orphan_handlers_); rendering_orphan_handlers_.clear(); PostCrossThreadTask( - *Platform::Current()->MainThread()->GetTaskRunner(), FROM_HERE, + *task_runner_, FROM_HERE, CrossThreadBind(&DeferredTaskHandler::DeleteHandlersOnMainThread, scoped_refptr<DeferredTaskHandler>(this))); } @@ -337,6 +340,8 @@ void DeferredTaskHandler::ClearHandlersToBeDeleted() { tail_processing_handlers_.clear(); rendering_orphan_handlers_.clear(); deletable_orphan_handlers_.clear(); + automatic_pull_handlers_.clear(); + rendering_automatic_pull_handlers_.clear(); } void DeferredTaskHandler::SetAudioThreadToCurrentThread() { diff --git a/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.h b/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.h index f83258f9793..aa1752797db 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/deferred_task_handler.h @@ -35,6 +35,10 @@ #include "third_party/blink/renderer/platform/wtf/threading_primitives.h" #include "third_party/blink/renderer/platform/wtf/vector.h" +namespace base { +class SingleThreadTaskRunner; +} + namespace blink { class BaseAudioContext; @@ -59,7 +63,8 @@ class AudioSummingJunction; class MODULES_EXPORT DeferredTaskHandler final : public ThreadSafeRefCounted<DeferredTaskHandler> { public: - static scoped_refptr<DeferredTaskHandler> Create(); + static scoped_refptr<DeferredTaskHandler> Create( + scoped_refptr<base::SingleThreadTaskRunner> task_runner); ~DeferredTaskHandler(); void HandleDeferredTasks(); @@ -69,8 +74,9 @@ class MODULES_EXPORT DeferredTaskHandler final // when they are not connected to any downstream nodes. These two methods are // called by the nodes who want to add/remove themselves into/from the // automatic pull lists. - void AddAutomaticPullNode(AudioHandler*); - void RemoveAutomaticPullNode(AudioHandler*); + void AddAutomaticPullNode(scoped_refptr<AudioHandler>); + void RemoveAutomaticPullNode(scoped_refptr<AudioHandler>); + // Called right before handlePostRenderTasks() to handle nodes which need to // be pulled even when they are not connected to anything. void ProcessAutomaticPullNodes(size_t frames_to_process); @@ -180,7 +186,7 @@ class MODULES_EXPORT DeferredTaskHandler final }; private: - DeferredTaskHandler(); + explicit DeferredTaskHandler(scoped_refptr<base::SingleThreadTaskRunner>); void UpdateAutomaticPullNodes(); void UpdateChangedChannelCountMode(); void UpdateChangedChannelInterpretation(); @@ -192,15 +198,16 @@ class MODULES_EXPORT DeferredTaskHandler final // has been processed. void UpdateTailProcessingHandlers(); - // For the sake of thread safety, we maintain a seperate Vector of automatic - // pull nodes for rendering in m_renderingAutomaticPullNodes. It will be - // copied from m_automaticPullNodes by updateAutomaticPullNodes() at the - // very start or end of the rendering quantum. - HashSet<AudioHandler*> automatic_pull_nodes_; - Vector<AudioHandler*> rendering_automatic_pull_nodes_; - // m_automaticPullNodesNeedUpdating keeps track if m_automaticPullNodes is - // modified. - bool automatic_pull_nodes_need_updating_; + // For the sake of thread safety, we maintain a seperate Vector of + // AudioHandlers for "automatic-pull nodes": + // |rendering_automatic_pull_handlers|. This storage will be copied from + // |automatic_pull_handlers| by |UpdateAutomaticPullNodes()| at the beginning + // or end of the render quantum. + HashSet<scoped_refptr<AudioHandler>> automatic_pull_handlers_; + Vector<scoped_refptr<AudioHandler>> rendering_automatic_pull_handlers_; + + // Keeps track if the |automatic_pull_handlers| storage is touched. + bool automatic_pull_handlers_need_updating_; // Collection of nodes where the channel count mode has changed. We want the // channel count mode to change in the pre- or post-rendering phase so as @@ -227,6 +234,8 @@ class MODULES_EXPORT DeferredTaskHandler final // main thread will disable the outputs. Vector<scoped_refptr<AudioHandler>> finished_tail_processing_handlers_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + // Graph locking. RecursiveMutex context_graph_mutex_; volatile ThreadIdentifier audio_thread_; diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.cc index 9c24f3a4ff5..d7b07b5fea7 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.cc @@ -29,8 +29,8 @@ #include "third_party/blink/renderer/core/frame/deprecation.h" #include "third_party/blink/renderer/core/html/media/html_media_element.h" #include "third_party/blink/renderer/core/inspector/console_message.h" +#include "third_party/blink/renderer/modules/webaudio/audio_context.h" #include "third_party/blink/renderer/modules/webaudio/audio_node_output.h" -#include "third_party/blink/renderer/modules/webaudio/base_audio_context.h" #include "third_party/blink/renderer/modules/webaudio/media_element_audio_source_options.h" #include "third_party/blink/renderer/platform/audio/audio_utilities.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" @@ -136,19 +136,7 @@ void MediaElementAudioSourceHandler::SetFormat(size_t number_of_channels, } bool MediaElementAudioSourceHandler::WouldTaintOrigin() { - // If we're cross-origin and allowed access vie CORS, we're not tainted. - if (MediaElement()->GetWebMediaPlayer()->DidPassCORSAccessCheck()) { - return false; - } - - // Handles the case where the url is a redirect to another site that we're not - // allowed to access. - if (!MediaElement()->HasSingleSecurityOrigin()) { - return true; - } - - // Test to see if the current media URL taint the origin of the audio context? - return Context()->WouldTaintOrigin(MediaElement()->currentSrc()); + return MediaElement()->GetWebMediaPlayer()->WouldTaintOrigin(); } void MediaElementAudioSourceHandler::PrintCORSMessage(const String& message) { @@ -217,14 +205,14 @@ void MediaElementAudioSourceHandler::unlock() { // ---------------------------------------------------------------- MediaElementAudioSourceNode::MediaElementAudioSourceNode( - BaseAudioContext& context, + AudioContext& context, HTMLMediaElement& media_element) : AudioNode(context) { SetHandler(MediaElementAudioSourceHandler::Create(*this, media_element)); } MediaElementAudioSourceNode* MediaElementAudioSourceNode::Create( - BaseAudioContext& context, + AudioContext& context, HTMLMediaElement& media_element, ExceptionState& exception_state) { DCHECK(IsMainThread()); @@ -261,7 +249,7 @@ MediaElementAudioSourceNode* MediaElementAudioSourceNode::Create( } MediaElementAudioSourceNode* MediaElementAudioSourceNode::Create( - BaseAudioContext* context, + AudioContext* context, const MediaElementAudioSourceOptions& options, ExceptionState& exception_state) { return Create(*context, *options.mediaElement(), exception_state); diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.h b/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.h index 311d563cebb..9fbb8127720 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.h @@ -33,11 +33,12 @@ #include "third_party/blink/renderer/modules/webaudio/audio_node.h" #include "third_party/blink/renderer/platform/audio/audio_source_provider_client.h" #include "third_party/blink/renderer/platform/audio/multi_channel_resampler.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/threading_primitives.h" namespace blink { -class BaseAudioContext; +class AudioContext; class HTMLMediaElement; class MediaElementAudioSourceOptions; @@ -114,13 +115,11 @@ class MediaElementAudioSourceNode final : public AudioNode, USING_GARBAGE_COLLECTED_MIXIN(MediaElementAudioSourceNode); public: - static MediaElementAudioSourceNode* Create(BaseAudioContext&, + static MediaElementAudioSourceNode* Create(AudioContext&, HTMLMediaElement&, ExceptionState&); - static MediaElementAudioSourceNode* Create( - BaseAudioContext*, - const MediaElementAudioSourceOptions&, - ExceptionState&); + static MediaElementAudioSourceNode* + Create(AudioContext*, const MediaElementAudioSourceOptions&, ExceptionState&); void Trace(blink::Visitor*) override; MediaElementAudioSourceHandler& GetMediaElementAudioSourceHandler() const; @@ -135,7 +134,7 @@ class MediaElementAudioSourceNode final : public AudioNode, UNLOCK_FUNCTION(GetMediaElementAudioSourceHandler().GetProcessLock()); private: - MediaElementAudioSourceNode(BaseAudioContext&, HTMLMediaElement&); + MediaElementAudioSourceNode(AudioContext&, HTMLMediaElement&); }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.idl b/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.idl index 8a1df10e151..991626190db 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.idl +++ b/chromium/third_party/blink/renderer/modules/webaudio/media_element_audio_source_node.idl @@ -25,8 +25,7 @@ // See https://webaudio.github.io/web-audio-api/#mediaelementaudiosourcenode [ - // TODO(rtoy): This should be AudioContext, not BaseAudioContext. - Constructor(BaseAudioContext context, MediaElementAudioSourceOptions options), + Constructor(AudioContext context, MediaElementAudioSourceOptions options), RaisesException=Constructor, Measure ] diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc index d9f697bf68a..31f983cea2b 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc @@ -26,7 +26,7 @@ #include "third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.h" #include "third_party/blink/public/platform/web_rtc_peer_connection_handler.h" -#include "third_party/blink/renderer/core/frame/deprecation.h" +#include "third_party/blink/renderer/modules/webaudio/audio_context.h" #include "third_party/blink/renderer/modules/webaudio/audio_node_input.h" #include "third_party/blink/renderer/modules/webaudio/audio_node_options.h" #include "third_party/blink/renderer/modules/webaudio/base_audio_context.h" @@ -142,7 +142,7 @@ unsigned long MediaStreamAudioDestinationHandler::MaxChannelCount() const { // ---------------------------------------------------------------- MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode( - BaseAudioContext& context, + AudioContext& context, size_t number_of_channels) : AudioBasicInspectorNode(context) { SetHandler( @@ -150,7 +150,7 @@ MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode( } MediaStreamAudioDestinationNode* MediaStreamAudioDestinationNode::Create( - BaseAudioContext& context, + AudioContext& context, size_t number_of_channels, ExceptionState& exception_state) { DCHECK(IsMainThread()); @@ -164,7 +164,7 @@ MediaStreamAudioDestinationNode* MediaStreamAudioDestinationNode::Create( } MediaStreamAudioDestinationNode* MediaStreamAudioDestinationNode::Create( - BaseAudioContext* context, + AudioContext* context, const AudioNodeOptions& options, ExceptionState& exception_state) { DCHECK(IsMainThread()); @@ -182,12 +182,6 @@ MediaStreamAudioDestinationNode* MediaStreamAudioDestinationNode::Create( node->HandleChannelOptions(options, exception_state); - if (!context->HasRealtimeConstraint()) { - Deprecation::CountDeprecation( - node->GetExecutionContext(), - WebFeature::kMediaStreamDestinationOnOfflineContext); - } - return node; } diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.h b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.h index b4a5710cbc5..427d924d5d4 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.h @@ -33,7 +33,7 @@ namespace blink { -class BaseAudioContext; +class AudioContext; class MediaStreamAudioDestinationHandler final : public AudioBasicInspectorHandler { @@ -78,17 +78,17 @@ class MediaStreamAudioDestinationNode final : public AudioBasicInspectorNode { DEFINE_WRAPPERTYPEINFO(); public: - static MediaStreamAudioDestinationNode* Create(BaseAudioContext&, + static MediaStreamAudioDestinationNode* Create(AudioContext&, size_t number_of_channels, ExceptionState&); - static MediaStreamAudioDestinationNode* Create(BaseAudioContext*, + static MediaStreamAudioDestinationNode* Create(AudioContext*, const AudioNodeOptions&, ExceptionState&); MediaStream* stream() const; private: - MediaStreamAudioDestinationNode(BaseAudioContext&, size_t number_of_channels); + MediaStreamAudioDestinationNode(AudioContext&, size_t number_of_channels); }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.idl b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.idl index 7cc91d87cc3..d4bc924b9a1 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.idl +++ b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.idl @@ -25,7 +25,7 @@ // See https://webaudio.github.io/web-audio-api/#mediastreamaudiodestinationnode [ - Constructor(BaseAudioContext context, optional AudioNodeOptions options), + Constructor(AudioContext context, optional AudioNodeOptions options), RaisesException=Constructor, Measure ] diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc index 59c845c491f..488a5380262 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc @@ -26,9 +26,8 @@ #include "third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.h" #include <memory> -#include "third_party/blink/renderer/core/frame/deprecation.h" +#include "third_party/blink/renderer/modules/webaudio/audio_context.h" #include "third_party/blink/renderer/modules/webaudio/audio_node_output.h" -#include "third_party/blink/renderer/modules/webaudio/base_audio_context.h" #include "third_party/blink/renderer/modules/webaudio/media_stream_audio_source_options.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/wtf/locker.h" @@ -120,7 +119,7 @@ void MediaStreamAudioSourceHandler::Process(size_t number_of_frames) { // ---------------------------------------------------------------- MediaStreamAudioSourceNode::MediaStreamAudioSourceNode( - BaseAudioContext& context, + AudioContext& context, MediaStream& media_stream, MediaStreamTrack* audio_track, std::unique_ptr<AudioSourceProvider> audio_source_provider) @@ -132,7 +131,7 @@ MediaStreamAudioSourceNode::MediaStreamAudioSourceNode( } MediaStreamAudioSourceNode* MediaStreamAudioSourceNode::Create( - BaseAudioContext& context, + AudioContext& context, MediaStream& media_stream, ExceptionState& exception_state) { DCHECK(IsMainThread()); @@ -166,17 +165,11 @@ MediaStreamAudioSourceNode* MediaStreamAudioSourceNode::Create( // context keeps reference until node is disconnected context.NotifySourceNodeStartedProcessing(node); - if (!context.HasRealtimeConstraint()) { - Deprecation::CountDeprecation( - node->GetExecutionContext(), - WebFeature::kMediaStreamSourceOnOfflineContext); - } - return node; } MediaStreamAudioSourceNode* MediaStreamAudioSourceNode::Create( - BaseAudioContext* context, + AudioContext* context, const MediaStreamAudioSourceOptions& options, ExceptionState& exception_state) { return Create(*context, *options.mediaStream(), exception_state); diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.h b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.h index f903710cba2..21bd3e48818 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.h @@ -36,7 +36,7 @@ namespace blink { -class BaseAudioContext; +class AudioContext; class MediaStreamAudioSourceOptions; class MediaStreamAudioSourceHandler final : public AudioHandler { @@ -83,13 +83,11 @@ class MediaStreamAudioSourceNode final : public AudioNode, USING_GARBAGE_COLLECTED_MIXIN(MediaStreamAudioSourceNode); public: - static MediaStreamAudioSourceNode* Create(BaseAudioContext&, + static MediaStreamAudioSourceNode* Create(AudioContext&, MediaStream&, ExceptionState&); - static MediaStreamAudioSourceNode* Create( - BaseAudioContext*, - const MediaStreamAudioSourceOptions&, - ExceptionState&); + static MediaStreamAudioSourceNode* + Create(AudioContext*, const MediaStreamAudioSourceOptions&, ExceptionState&); void Trace(blink::Visitor*) override; @@ -99,7 +97,7 @@ class MediaStreamAudioSourceNode final : public AudioNode, void SetFormat(size_t number_of_channels, float sample_rate) override; private: - MediaStreamAudioSourceNode(BaseAudioContext&, + MediaStreamAudioSourceNode(AudioContext&, MediaStream&, MediaStreamTrack*, std::unique_ptr<AudioSourceProvider>); diff --git a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.idl b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.idl index 1e8713dd726..e3c8a6c05be 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.idl +++ b/chromium/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.idl @@ -25,7 +25,7 @@ // See https://webaudio.github.io/web-audio-api/#mediastreamaudiosourcenode [ - Constructor(BaseAudioContext context, MediaStreamAudioSourceOptions options), + Constructor(AudioContext context, MediaStreamAudioSourceOptions options), RaisesException=Constructor, Measure ] diff --git a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc index fa3c1d6dc0b..ba5601767ff 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc @@ -50,14 +50,13 @@ OfflineAudioContext* OfflineAudioContext::Create( float sample_rate, ExceptionState& exception_state) { // FIXME: add support for workers. - if (!context || !context->IsDocument()) { + auto* document = DynamicTo<Document>(context); + if (!document) { exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, "Workers are not supported."); return nullptr; } - Document* document = ToDocument(context); - if (!number_of_frames) { exception_state.ThrowDOMException( DOMExceptionCode::kNotSupportedError, @@ -222,12 +221,6 @@ ScriptPromise OfflineAudioContext::startOfflineRendering( return complete_resolver_->Promise(); } -ScriptPromise OfflineAudioContext::suspendContext(ScriptState* script_state) { - LOG(FATAL) << "This CANNOT be called on OfflineAudioContext; this is only to " - "implement the pure virtual interface from BaseAudioContext."; - return ScriptPromise(); -} - ScriptPromise OfflineAudioContext::suspendContext(ScriptState* script_state, double when) { DCHECK(IsMainThread()); @@ -379,6 +372,8 @@ void OfflineAudioContext::FireCompletionEvent() { } is_rendering_started_ = false; + + PerformCleanupOnMainThread(); } bool OfflineAudioContext::HandlePreOfflineRenderTasks() { diff --git a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.h b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.h index dc9e3bddb19..17e47893dc1 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.h @@ -59,11 +59,7 @@ class MODULES_EXPORT OfflineAudioContext final : public BaseAudioContext { ScriptPromise startOfflineRendering(ScriptState*); ScriptPromise suspendContext(ScriptState*, double); - ScriptPromise resumeContext(ScriptState*) final; - - // This is to implement the pure virtual method from BaseAudioContext. - // CANNOT be called from an OfflineAudioContext. - ScriptPromise suspendContext(ScriptState*) final; + ScriptPromise resumeContext(ScriptState*); void RejectPendingResolvers() override; diff --git a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.idl b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.idl index 92d713de756..3c57739a7da 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.idl +++ b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_context.idl @@ -36,4 +36,5 @@ readonly attribute unsigned long length; [CallWith=ScriptState, ImplementedAs=startOfflineRendering, MeasureAs=OfflineAudioContextStartRendering] Promise<AudioBuffer> startRendering(); [CallWith=ScriptState, ImplementedAs=suspendContext, MeasureAs=OfflineAudioContextSuspend] Promise<void> suspend(double suspendTime); + [MeasureAs=OfflineAudioContextResume, CallWith=ScriptState, ImplementedAs=resumeContext] Promise<void> resume(); }; diff --git a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc index 673121b3094..fd5e12d5934 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc @@ -373,7 +373,7 @@ void OfflineAudioDestinationHandler::PrepareTaskRunnerForRendering() { if (!render_thread_) { // The context started from the non-AudioWorklet mode. render_thread_ = Platform::Current()->CreateThread( - WebThreadCreationParams(WebThreadType::kOfflineAudioRenderThread)); + ThreadCreationParams(WebThreadType::kOfflineAudioRenderThread)); render_thread_task_runner_ = render_thread_->GetTaskRunner(); } } diff --git a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h index db4a535ab41..dc658d2a2f7 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h @@ -28,10 +28,10 @@ #include <memory> #include "base/memory/scoped_refptr.h" -#include "third_party/blink/public/platform/web_thread.h" #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h" #include "third_party/blink/renderer/modules/webaudio/audio_destination_node.h" #include "third_party/blink/renderer/modules/webaudio/offline_audio_context.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" namespace blink { @@ -145,7 +145,7 @@ class OfflineAudioDestinationHandler final : public AudioDestinationHandler { // The rendering thread for the non-AudioWorklet mode. For the AudioWorklet // node, AudioWorkletThread will drive the rendering. - std::unique_ptr<WebThread> render_thread_; + std::unique_ptr<Thread> render_thread_; scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; diff --git a/chromium/third_party/blink/renderer/modules/webaudio/oscillator_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/oscillator_node.cc index 6292f04046f..c1f07b9f888 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/oscillator_node.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/oscillator_node.cc @@ -154,6 +154,28 @@ bool OscillatorHandler::SetType(unsigned type) { return true; } +// Convert the detune value (in cents) to a frequency scale multiplier: +// 2^(d/1200) +static float DetuneToFrequencyMultiplier(float detune_value) { + return std::exp2(detune_value / 1200); +} + +// Clamp the frequency value to lie with Nyquist frequency. For NaN, arbitrarily +// clamp to +Nyquist. +static void ClampFrequency(float* frequency, + int frames_to_process, + float nyquist) { + for (int k = 0; k < frames_to_process; ++k) { + float f = frequency[k]; + + if (std::isnan(f)) { + frequency[k] = nyquist; + } else { + frequency[k] = clampTo(f, -nyquist, nyquist); + } + } +} + bool OscillatorHandler::CalculateSampleAccuratePhaseIncrements( size_t frames_to_process) { bool is_good = frames_to_process <= phase_increments_.size() && @@ -199,9 +221,9 @@ bool OscillatorHandler::CalculateSampleAccuratePhaseIncrements( // Convert from cents to rate scalar. float k = 1.0 / 1200; Vsmul(detune_values, 1, &k, detune_values, 1, frames_to_process); - for (unsigned i = 0; i < frames_to_process; ++i) - detune_values[i] = powf( - 2, detune_values[i]); // FIXME: converting to expf() will be faster. + for (unsigned i = 0; i < frames_to_process; ++i) { + detune_values[i] = std::exp2(detune_values[i]); + } if (has_frequency_changes) { // Multiply frequencies by detune scalings. @@ -212,11 +234,13 @@ bool OscillatorHandler::CalculateSampleAccuratePhaseIncrements( // Handle ordinary parameter changes if there are no scheduled // changes. float detune = detune_->Value(); - float detune_scale = powf(2, detune / 1200); + float detune_scale = DetuneToFrequencyMultiplier(detune); final_scale *= detune_scale; } if (has_sample_accurate_values) { + ClampFrequency(phase_increments, frames_to_process, + Context()->sampleRate() / 2); // Convert from frequency to wavetable increment. Vsmul(phase_increments, 1, &final_scale, phase_increments, 1, frames_to_process); @@ -232,6 +256,7 @@ static float DoInterpolation(double virtual_read_index, const float* lower_wave_data, const float* higher_wave_data) { DCHECK_GE(incr, 0); + DCHECK(std::isfinite(virtual_read_index)); double sample_lower = 0; double sample_higher = 0; @@ -392,8 +417,9 @@ void OscillatorHandler::Process(size_t frames_to_process) { if (!has_sample_accurate_values) { frequency = frequency_->Value(); float detune = detune_->Value(); - float detune_scale = powf(2, detune / 1200); + float detune_scale = DetuneToFrequencyMultiplier(detune); frequency *= detune_scale; + ClampFrequency(&frequency, 1, Context()->sampleRate() / 2); periodic_wave_->WaveDataForFundamentalFrequency(frequency, lower_wave_data, higher_wave_data, table_interpolation_factor); @@ -479,12 +505,14 @@ OscillatorNode::OscillatorNode(BaseAudioContext& context, -context.sampleRate() / 2, context.sampleRate() / 2)), // Default to no detuning. - detune_(AudioParam::Create( - context, - kParamTypeOscillatorDetune, - 0, - AudioParamHandler::AutomationRate::kAudio, - AudioParamHandler::AutomationRateMode::kVariable)) { + detune_( + AudioParam::Create(context, + kParamTypeOscillatorDetune, + 0, + AudioParamHandler::AutomationRate::kAudio, + AudioParamHandler::AutomationRateMode::kVariable, + -1200 * log2f(std::numeric_limits<float>::max()), + 1200 * log2f(std::numeric_limits<float>::max()))) { SetHandler(OscillatorHandler::Create( *this, context.sampleRate(), oscillator_type, wave_table, frequency_->Handler(), detune_->Handler())); diff --git a/chromium/third_party/blink/renderer/modules/webaudio/panner_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/panner_node.cc index 51821b017fa..fac20df4477 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/panner_node.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/panner_node.cc @@ -740,10 +740,10 @@ PannerNode* PannerNode::Create(BaseAudioContext* context, node->setRefDistance(options.refDistance(), exception_state); node->setMaxDistance(options.maxDistance(), exception_state); - node->setRolloffFactor(options.rolloffFactor()); + node->setRolloffFactor(options.rolloffFactor(), exception_state); node->setConeInnerAngle(options.coneInnerAngle()); node->setConeOuterAngle(options.coneOuterAngle()); - node->setConeOuterGain(options.coneOuterGain()); + node->setConeOuterGain(options.coneOuterGain(), exception_state); return node; } @@ -818,7 +818,15 @@ double PannerNode::rolloffFactor() const { return GetPannerHandler().RolloffFactor(); } -void PannerNode::setRolloffFactor(double factor) { +void PannerNode::setRolloffFactor(double factor, + ExceptionState& exception_state) { + if (factor < 0) { + exception_state.ThrowRangeError( + ExceptionMessages::IndexExceedsMinimumBound<double>("rolloffFactor", + factor, 0)); + return; + } + GetPannerHandler().SetRolloffFactor(factor); } @@ -842,7 +850,17 @@ double PannerNode::coneOuterGain() const { return GetPannerHandler().ConeOuterGain(); } -void PannerNode::setConeOuterGain(double gain) { +void PannerNode::setConeOuterGain(double gain, + ExceptionState& exception_state) { + if (gain < 0 || gain > 1) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + ExceptionMessages::IndexOutsideRange<double>( + "coneOuterGain", gain, 0, ExceptionMessages::kInclusiveBound, 1, + ExceptionMessages::kInclusiveBound)); + return; + } + GetPannerHandler().SetConeOuterGain(gain); } diff --git a/chromium/third_party/blink/renderer/modules/webaudio/panner_node.h b/chromium/third_party/blink/renderer/modules/webaudio/panner_node.h index b1f2896d3f9..2e4851c6c7a 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/panner_node.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/panner_node.h @@ -236,13 +236,13 @@ class PannerNode final : public AudioNode { double maxDistance() const; void setMaxDistance(double, ExceptionState&); double rolloffFactor() const; - void setRolloffFactor(double); + void setRolloffFactor(double, ExceptionState&); double coneInnerAngle() const; void setConeInnerAngle(double); double coneOuterAngle() const; void setConeOuterAngle(double); double coneOuterGain() const; - void setConeOuterGain(double); + void setConeOuterGain(double, ExceptionState&); private: PannerNode(BaseAudioContext&); diff --git a/chromium/third_party/blink/renderer/modules/webaudio/panner_node.idl b/chromium/third_party/blink/renderer/modules/webaudio/panner_node.idl index 3acde7e5519..25a19fcb790 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/panner_node.idl +++ b/chromium/third_party/blink/renderer/modules/webaudio/panner_node.idl @@ -61,10 +61,10 @@ enum DistanceModelType { [RaisesException=Setter] attribute double refDistance; [RaisesException=Setter] attribute double maxDistance; - attribute double rolloffFactor; + [RaisesException=Setter] attribute double rolloffFactor; // Directional sound cone attribute double coneInnerAngle; attribute double coneOuterAngle; - attribute double coneOuterGain; + [RaisesException=Setter] attribute double coneOuterGain; }; diff --git a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc index d6da662107b..7d6bce137ea 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc @@ -51,6 +51,8 @@ ScriptProcessorHandler::ScriptProcessorHandler( unsigned number_of_output_channels) : AudioHandler(kNodeTypeScriptProcessor, node, sample_rate), double_buffer_index_(0), + input_buffers_(new HeapVector<Member<AudioBuffer>>()), + output_buffers_(new HeapVector<Member<AudioBuffer>>()), buffer_size_(buffer_size), buffer_read_write_index_(0), number_of_input_channels_(number_of_input_channels), @@ -115,8 +117,8 @@ void ScriptProcessorHandler::Initialize() { sample_rate) : nullptr; - input_buffers_.push_back(input_buffer); - output_buffers_.push_back(output_buffer); + input_buffers_->push_back(input_buffer); + output_buffers_->push_back(output_buffer); } AudioHandler::Initialize(); @@ -139,14 +141,14 @@ void ScriptProcessorHandler::Process(size_t frames_to_process) { // sides. unsigned double_buffer_index = this->DoubleBufferIndex(); bool is_double_buffer_index_good = - double_buffer_index < 2 && double_buffer_index < input_buffers_.size() && - double_buffer_index < output_buffers_.size(); + double_buffer_index < 2 && double_buffer_index < input_buffers_->size() && + double_buffer_index < output_buffers_->size(); DCHECK(is_double_buffer_index_good); if (!is_double_buffer_index_good) return; - AudioBuffer* input_buffer = input_buffers_[double_buffer_index].Get(); - AudioBuffer* output_buffer = output_buffers_[double_buffer_index].Get(); + AudioBuffer* input_buffer = input_buffers_->at(double_buffer_index).Get(); + AudioBuffer* output_buffer = output_buffers_->at(double_buffer_index).Get(); // Check the consistency of input and output buffers. unsigned number_of_input_channels = internal_input_bus_->NumberOfChannels(); @@ -260,8 +262,8 @@ void ScriptProcessorHandler::FireProcessEvent(unsigned double_buffer_index) { if (double_buffer_index > 1) return; - AudioBuffer* input_buffer = input_buffers_[double_buffer_index].Get(); - AudioBuffer* output_buffer = output_buffers_[double_buffer_index].Get(); + AudioBuffer* input_buffer = input_buffers_->at(double_buffer_index).Get(); + AudioBuffer* output_buffer = output_buffers_->at(double_buffer_index).Get(); DCHECK(output_buffer); if (!output_buffer) return; @@ -298,8 +300,8 @@ void ScriptProcessorHandler::FireProcessEventForOfflineAudioContext( return; } - AudioBuffer* input_buffer = input_buffers_[double_buffer_index].Get(); - AudioBuffer* output_buffer = output_buffers_[double_buffer_index].Get(); + AudioBuffer* input_buffer = input_buffers_->at(double_buffer_index).Get(); + AudioBuffer* output_buffer = output_buffers_->at(double_buffer_index).Get(); DCHECK(output_buffer); if (!output_buffer) { waitable_event->Signal(); diff --git a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h index fa04c857c96..9e658ef1453 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h +++ b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h @@ -31,6 +31,7 @@ #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" #include "third_party/blink/renderer/modules/webaudio/audio_node.h" #include "third_party/blink/renderer/platform/audio/audio_bus.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/vector.h" @@ -91,8 +92,8 @@ class ScriptProcessorHandler final : public AudioHandler { // These Persistent don't make reference cycles including the owner // ScriptProcessorNode. - PersistentHeapVector<Member<AudioBuffer>> input_buffers_; - PersistentHeapVector<Member<AudioBuffer>> output_buffers_; + CrossThreadPersistent<HeapVector<Member<AudioBuffer>>> input_buffers_; + CrossThreadPersistent<HeapVector<Member<AudioBuffer>>> output_buffers_; size_t buffer_size_; unsigned buffer_read_write_index_; diff --git a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node_test.cc b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node_test.cc index 4a086fd0545..010730403a6 100644 --- a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node_test.cc +++ b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node_test.cc @@ -18,14 +18,14 @@ TEST(ScriptProcessorNodeTest, BufferLifetime) { context->createScriptProcessor(ASSERT_NO_EXCEPTION); ScriptProcessorHandler& handler = static_cast<ScriptProcessorHandler&>(node->Handler()); - EXPECT_EQ(2u, handler.input_buffers_.size()); - EXPECT_EQ(2u, handler.output_buffers_.size()); + EXPECT_EQ(2u, handler.input_buffers_->size()); + EXPECT_EQ(2u, handler.output_buffers_->size()); BaseAudioContext::GraphAutoLocker locker(context); handler.Dispose(); // Buffers should live after dispose() because an audio thread is using // them. - EXPECT_EQ(2u, handler.input_buffers_.size()); - EXPECT_EQ(2u, handler.output_buffers_.size()); + EXPECT_EQ(2u, handler.input_buffers_->size()); + EXPECT_EQ(2u, handler.output_buffers_->size()); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database_authorizer.cc b/chromium/third_party/blink/renderer/modules/webdatabase/database_authorizer.cc index d67ac4e3af8..c1a4560c2f8 100644 --- a/chromium/third_party/blink/renderer/modules/webdatabase/database_authorizer.cc +++ b/chromium/third_party/blink/renderer/modules/webdatabase/database_authorizer.cc @@ -72,7 +72,7 @@ const FunctionNameList& WhitelistedFunctions() { ({ // SQLite functions used to help implement some operations // ALTER TABLE helpers - "sqlite_rename_table", "sqlite_rename_trigger", + "sqlite_rename_column", "sqlite_rename_table", "sqlite_rename_test", // GLOB helpers "glob", // SQLite core functions diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database_client.cc b/chromium/third_party/blink/renderer/modules/webdatabase/database_client.cc index f92d64c6f79..5c936399e32 100644 --- a/chromium/third_party/blink/renderer/modules/webdatabase/database_client.cc +++ b/chromium/third_party/blink/renderer/modules/webdatabase/database_client.cc @@ -51,7 +51,7 @@ DatabaseClient* DatabaseClient::FromPage(Page* page) { } DatabaseClient* DatabaseClient::From(ExecutionContext* context) { - return DatabaseClient::FromPage(ToDocument(context)->GetPage()); + return DatabaseClient::FromPage(To<Document>(context)->GetPage()); } const char DatabaseClient::kSupplementName[] = "DatabaseClient"; @@ -61,7 +61,7 @@ bool DatabaseClient::AllowDatabase(ExecutionContext* context, const String& display_name, unsigned estimated_size) { DCHECK(context->IsContextThread()); - Document* document = ToDocument(context); + Document* document = To<Document>(context); DCHECK(document->GetFrame()); if (document->GetFrame()->GetContentSettingsClient()) { return document->GetFrame()->GetContentSettingsClient()->AllowDatabase( diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database_context.cc b/chromium/third_party/blink/renderer/modules/webdatabase/database_context.cc index 1f0e3ed891c..1eb9b79abff 100644 --- a/chromium/third_party/blink/renderer/modules/webdatabase/database_context.cc +++ b/chromium/third_party/blink/renderer/modules/webdatabase/database_context.cc @@ -175,7 +175,7 @@ void DatabaseContext::StopDatabases() { } bool DatabaseContext::AllowDatabaseAccess() const { - return ToDocument(GetExecutionContext())->IsActive(); + return To<Document>(GetExecutionContext())->IsActive(); } const SecurityOrigin* DatabaseContext::GetSecurityOrigin() const { diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database_manager.cc b/chromium/third_party/blink/renderer/modules/webdatabase/database_manager.cc index b0e4bc74089..919a6e193d9 100644 --- a/chromium/third_party/blink/renderer/modules/webdatabase/database_manager.cc +++ b/chromium/third_party/blink/renderer/modules/webdatabase/database_manager.cc @@ -49,7 +49,7 @@ DatabaseManager& DatabaseManager::Manager() { return *g_database_manager; } -DatabaseManager::DatabaseManager() = default; +DatabaseManager::DatabaseManager() : context_map_(new ContextMap) {} DatabaseManager::~DatabaseManager() = default; @@ -61,7 +61,7 @@ DatabaseContext* DatabaseManager::ExistingDatabaseContextFor( DCHECK_LE(database_context_registered_count_, database_context_instance_count_); #endif - return context_map_.at(context); + return context_map_->at(context); } DatabaseContext* DatabaseManager::DatabaseContextFor( @@ -74,7 +74,7 @@ DatabaseContext* DatabaseManager::DatabaseContextFor( void DatabaseManager::RegisterDatabaseContext( DatabaseContext* database_context) { ExecutionContext* context = database_context->GetExecutionContext(); - context_map_.Set(context, database_context); + context_map_->Set(context, database_context); #if DCHECK_IS_ON() database_context_registered_count_++; #endif @@ -83,11 +83,11 @@ void DatabaseManager::RegisterDatabaseContext( void DatabaseManager::UnregisterDatabaseContext( DatabaseContext* database_context) { ExecutionContext* context = database_context->GetExecutionContext(); - DCHECK(context_map_.at(context)); + DCHECK(context_map_->at(context)); #if DCHECK_IS_ON() database_context_registered_count_--; #endif - context_map_.erase(context); + context_map_->erase(context); } #if DCHECK_IS_ON() diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database_manager.h b/chromium/third_party/blink/renderer/modules/webdatabase/database_manager.h index 9c5f2390855..3b2a79080e2 100644 --- a/chromium/third_party/blink/renderer/modules/webdatabase/database_manager.h +++ b/chromium/third_party/blink/renderer/modules/webdatabase/database_manager.h @@ -28,7 +28,7 @@ #include "third_party/blink/renderer/modules/webdatabase/database_context.h" #include "third_party/blink/renderer/modules/webdatabase/database_error.h" -#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" #include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" @@ -102,13 +102,12 @@ class DatabaseManager { static void LogErrorMessage(ExecutionContext*, const String& message); - // m_contextMap can have two or more entries even though we don't support + // context_map_ can have two or more entries even though we don't support // Web SQL on workers because single Blink process can have multiple main // contexts. - typedef PersistentHeapHashMap<Member<ExecutionContext>, - Member<DatabaseContext>> + typedef HeapHashMap<Member<ExecutionContext>, Member<DatabaseContext>> ContextMap; - ContextMap context_map_; + Persistent<ContextMap> context_map_; #if DCHECK_IS_ON() int database_context_registered_count_ = 0; int database_context_instance_count_ = 0; diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database_thread.cc b/chromium/third_party/blink/renderer/modules/webdatabase/database_thread.cc index ae8cb7d3adb..554d5418f73 100644 --- a/chromium/third_party/blink/renderer/modules/webdatabase/database_thread.cc +++ b/chromium/third_party/blink/renderer/modules/webdatabase/database_thread.cc @@ -60,7 +60,7 @@ void DatabaseThread::Start() { if (thread_) return; thread_ = WebThreadSupportingGC::Create( - WebThreadCreationParams(WebThreadType::kDatabaseThread)); + ThreadCreationParams(WebThreadType::kDatabaseThread)); thread_->PostTask(FROM_HERE, CrossThreadBind(&DatabaseThread::SetupDatabaseThread, WrapCrossThreadPersistent(this))); @@ -86,7 +86,7 @@ void DatabaseThread::Terminate() { WrapCrossThreadPersistent(this))); } sync.Wait(); - // The WebThread destructor blocks until all the tasks of the database + // The Thread destructor blocks until all the tasks of the database // thread are processed. However, it shouldn't block at all because // the database thread has already finished processing the cleanup task. thread_.reset(); @@ -171,7 +171,7 @@ void DatabaseThread::ScheduleTask(std::unique_ptr<DatabaseTask> task) { DCHECK(!termination_requested_); } #endif - // WebThread takes ownership of the task. + // Thread takes ownership of the task. thread_->PostTask(FROM_HERE, CrossThreadBind(&DatabaseTask::Run, std::move(task))); } diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database_tracker.cc b/chromium/third_party/blink/renderer/modules/webdatabase/database_tracker.cc index b632e5f8a91..a6d1208c289 100644 --- a/chromium/third_party/blink/renderer/modules/webdatabase/database_tracker.cc +++ b/chromium/third_party/blink/renderer/modules/webdatabase/database_tracker.cc @@ -46,7 +46,6 @@ #include "third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_file_system.h" #include "third_party/blink/renderer/platform/cross_thread_functional.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" -#include "third_party/blink/renderer/platform/weborigin/security_origin_hash.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" @@ -215,8 +214,7 @@ void DatabaseTracker::ForEachOpenDatabaseInPage(Page* page, for (auto& name_database_set : *origin_map.value) { for (Database* database : *name_database_set.value) { ExecutionContext* context = database->GetExecutionContext(); - DCHECK(context->IsDocument()); - if (ToDocument(context)->GetFrame()->GetPage() == page) + if (To<Document>(context)->GetPage() == page) callback.Run(database); } } diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/database_tracker.h b/chromium/third_party/blink/renderer/modules/webdatabase/database_tracker.h index 9470898324a..36ed498a1ef 100644 --- a/chromium/third_party/blink/renderer/modules/webdatabase/database_tracker.h +++ b/chromium/third_party/blink/renderer/modules/webdatabase/database_tracker.h @@ -35,7 +35,7 @@ #include "base/macros.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/webdatabase/database_error.h" -#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/text/string_hash.h" diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction_coordinator.h b/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction_coordinator.h index dfb205b6933..35e5be3d4f7 100644 --- a/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction_coordinator.h +++ b/chromium/third_party/blink/renderer/modules/webdatabase/sql_transaction_coordinator.h @@ -34,6 +34,7 @@ #include "base/macros.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/deque.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" @@ -55,7 +56,7 @@ class SQLTransactionCoordinator private: typedef Deque<CrossThreadPersistent<SQLTransactionBackend>> TransactionsQueue; struct CoordinationInfo { - DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + DISALLOW_NEW(); public: TransactionsQueue pending_transactions; diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sql_value.h b/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sql_value.h index b66442eeaec..06e25731bab 100644 --- a/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sql_value.h +++ b/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sql_value.h @@ -35,7 +35,7 @@ namespace blink { class SQLValue { - DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + DISALLOW_NEW(); public: enum Type { kNullValue, kNumberValue, kStringValue }; diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h b/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h index 7ea6e18b515..16717405c82 100644 --- a/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h +++ b/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h @@ -29,7 +29,7 @@ #include "base/macros.h" #include "build/build_config.h" -#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/text/cstring.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/threading.h" diff --git a/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_file_system.cc b/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_file_system.cc index 987281c913b..ed1d1ab3cea 100644 --- a/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_file_system.cc +++ b/chromium/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_file_system.cc @@ -62,9 +62,10 @@ int SQLiteFileSystem::OpenDatabase(const String& filename, sqlite3** database) { << "InitializeSQLite() must be called before " << __func__; #endif // DCHECK_IS_ON() - return sqlite3_open_v2(filename.Utf8().data(), database, - SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, - "chromium_vfs"); + return sqlite3_open_v2( + filename.Utf8().data(), database, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_PRIVATECACHE, + "chromium_vfs"); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn b/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn index b8b35ff312c..db785e23255 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/webgl/BUILD.gn @@ -27,6 +27,8 @@ blink_modules_sources("webgl") { "ext_texture_filter_anisotropic.cc", "ext_texture_filter_anisotropic.h", "gl_string_query.h", + "khr_parallel_shader_compile.cc", + "khr_parallel_shader_compile.h", "oes_element_index_uint.cc", "oes_element_index_uint.h", "oes_standard_derivatives.cc", diff --git a/chromium/third_party/blink/renderer/modules/webgl/OWNERS b/chromium/third_party/blink/renderer/modules/webgl/OWNERS index 7429f36593d..5eeccc4842c 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/OWNERS +++ b/chromium/third_party/blink/renderer/modules/webgl/OWNERS @@ -1,4 +1,5 @@ bajones@chromium.org +kainino@chromium.org kbr@chromium.org zmo@chromium.org diff --git a/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.cc b/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.cc new file mode 100644 index 00000000000..649ee4bee7f --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.cc @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.h" + +#include "gpu/command_buffer/client/gles2_interface.h" + +namespace blink { + +KHRParallelShaderCompile::KHRParallelShaderCompile( + WebGLRenderingContextBase* context) + : WebGLExtension(context) { + context->ExtensionsUtil()->EnsureExtensionEnabled( + "GL_KHR_parallel_shader_compile"); + // Use 2 background threads per WebGL context by default. + context->ContextGL()->MaxShaderCompilerThreadsKHR(2); +} + +WebGLExtensionName KHRParallelShaderCompile::GetName() const { + return kKHRParallelShaderCompileName; +} + +KHRParallelShaderCompile* KHRParallelShaderCompile::Create( + WebGLRenderingContextBase* context) { + return new KHRParallelShaderCompile(context); +} + +void KHRParallelShaderCompile::maxShaderCompilerThreadsKHR(GLuint count) { + WebGLExtensionScopedContext scoped(this); + if (scoped.IsLost()) + return; + // For WebGL contexts, we don't want applications to be able to spin up huge + // numbers of shader compliation threads. Enforce a maximum of 2 here. + scoped.Context()->ContextGL()->MaxShaderCompilerThreadsKHR( + std::min(2u, count)); +} + +bool KHRParallelShaderCompile::Supported(WebGLRenderingContextBase* context) { + return context->ExtensionsUtil()->SupportsExtension( + "GL_KHR_parallel_shader_compile"); +} + +const char* KHRParallelShaderCompile::ExtensionName() { + return "KHR_parallel_shader_compile"; +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.h b/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.h new file mode 100644 index 00000000000..e777123fa9c --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_KHR_PARALLEL_SHADER_COMPILE_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_KHR_PARALLEL_SHADER_COMPILE_H_ + +#include "third_party/blink/renderer/modules/webgl/webgl_extension.h" + +namespace blink { + +class KHRParallelShaderCompile final : public WebGLExtension { + DEFINE_WRAPPERTYPEINFO(); + + public: + static KHRParallelShaderCompile* Create(WebGLRenderingContextBase*); + static bool Supported(WebGLRenderingContextBase*); + static const char* ExtensionName(); + + WebGLExtensionName GetName() const override; + + void maxShaderCompilerThreadsKHR(GLuint count); + + private: + explicit KHRParallelShaderCompile(WebGLRenderingContextBase*); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_KHR_PARALLEL_SHADER_COMPILE_H_ diff --git a/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.idl b/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.idl new file mode 100644 index 00000000000..a8512340d50 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.idl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/ + +[ + NoInterfaceObject, + DoNotCheckConstants +] interface KHRParallelShaderCompile { + const GLenum MAX_SHADER_COMPILER_THREADS_KHR = 0x91B0; + const GLenum COMPLETION_STATUS_KHR = 0x91B1; + + void maxShaderCompilerThreadsKHR(GLuint count); +}; diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.cc index 53d9de343c9..4e7e0c12447 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.cc +++ b/chromium/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.cc @@ -5,6 +5,8 @@ #include "third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.h" #include "third_party/blink/public/platform/web_graphics_context_3d_provider.h" +#include "third_party/blink/renderer/bindings/modules/v8/webgl_any.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { @@ -55,6 +57,30 @@ void WebGL2ComputeRenderingContextBase::memoryBarrierByRegion( ContextGL()->MemoryBarrierByRegion(barriers); } +ScriptValue WebGL2ComputeRenderingContextBase::getParameter( + ScriptState* script_state, + GLenum pname) { + if (isContextLost()) + return ScriptValue::CreateNull(script_state); + switch (pname) { + case GL_SHADING_LANGUAGE_VERSION: { + return WebGLAny( + script_state, + "WebGL GLSL ES 3.10 (" + + String(ContextGL()->GetString(GL_SHADING_LANGUAGE_VERSION)) + + ")"); + } + case GL_VERSION: { + return WebGLAny(script_state, + "WebGL 2.0 Compute (" + + String(ContextGL()->GetString(GL_VERSION)) + ")"); + } + + default: + return WebGL2RenderingContextBase::getParameter(script_state, pname); + } +} + void WebGL2ComputeRenderingContextBase::Trace(blink::Visitor* visitor) { WebGL2RenderingContextBase::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.h b/chromium/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.h index 3339f9cb79b..39fe21eb8e8 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.h +++ b/chromium/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.h @@ -35,6 +35,7 @@ class WebGL2ComputeRenderingContextBase : public WebGL2RenderingContextBase { /* WebGLRenderingContextBase overrides */ void InitializeNewContext() override; + ScriptValue getParameter(ScriptState*, GLenum pname) override; void Trace(blink::Visitor*) override; diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc index c0c85e3fb14..5c3ae9ea8ae 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc +++ b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc @@ -17,6 +17,7 @@ #include "third_party/blink/renderer/modules/webgl/ext_color_buffer_float.h" #include "third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.h" #include "third_party/blink/renderer/modules/webgl/ext_texture_filter_anisotropic.h" +#include "third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.h" #include "third_party/blink/renderer/modules/webgl/oes_texture_float_linear.h" #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.h" #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc.h" @@ -122,6 +123,8 @@ void WebGL2RenderingContext::RegisterContextExtensions() { ext_disjoint_timer_query_web_gl2_); RegisterExtension<EXTTextureFilterAnisotropic>( ext_texture_filter_anisotropic_); + RegisterExtension<KHRParallelShaderCompile>(khr_parallel_shader_compile_, + kDraftExtension); RegisterExtension<OESTextureFloatLinear>(oes_texture_float_linear_); RegisterExtension<WebGLCompressedTextureASTC>(webgl_compressed_texture_astc_); RegisterExtension<WebGLCompressedTextureETC>(webgl_compressed_texture_etc_); @@ -141,6 +144,7 @@ void WebGL2RenderingContext::Trace(blink::Visitor* visitor) { visitor->Trace(ext_color_buffer_float_); visitor->Trace(ext_disjoint_timer_query_web_gl2_); visitor->Trace(ext_texture_filter_anisotropic_); + visitor->Trace(khr_parallel_shader_compile_); visitor->Trace(oes_texture_float_linear_); visitor->Trace(webgl_compressed_texture_astc_); visitor->Trace(webgl_compressed_texture_etc_); diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h index 1db2acea31e..4b6f24ea49a 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h +++ b/chromium/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h @@ -18,6 +18,7 @@ class OESTextureFloatLinear; class WebGLDebugRendererInfo; class WebGLLoseContext; class WebGLMultiview; +class KHRParallelShaderCompile; class WebGL2RenderingContext : public WebGL2RenderingContextBase { DEFINE_WRAPPERTYPEINFO(); @@ -60,6 +61,7 @@ class WebGL2RenderingContext : public WebGL2RenderingContextBase { Member<EXTColorBufferFloat> ext_color_buffer_float_; Member<EXTDisjointTimerQueryWebGL2> ext_disjoint_timer_query_web_gl2_; Member<EXTTextureFilterAnisotropic> ext_texture_filter_anisotropic_; + Member<KHRParallelShaderCompile> khr_parallel_shader_compile_; Member<OESTextureFloatLinear> oes_texture_float_linear_; Member<WebGLCompressedTextureASTC> webgl_compressed_texture_astc_; Member<WebGLCompressedTextureETC> webgl_compressed_texture_etc_; diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc index 3846b2a179d..26b4610c87c 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc +++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc @@ -22,6 +22,7 @@ WebGLContextAttributes ToWebGLContextAttributes( attrs.fail_if_major_performance_caveat); result.setCompatibleXRDevice( static_cast<XRDevice*>(attrs.compatible_xr_device.Get())); + result.setLowLatency(attrs.low_latency); return result; } diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attributes.idl b/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attributes.idl index 38ca0f6b6a0..39092f2acab 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attributes.idl +++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_context_attributes.idl @@ -35,4 +35,6 @@ dictionary WebGLContextAttributes { boolean preserveDrawingBuffer = false; boolean failIfMajorPerformanceCaveat = false; [OriginTrialEnabled=WebXR] XRDevice compatibleXRDevice = null; + // TODO(crbug.com/788439): remove OriginTrialEnabled. + [OriginTrialEnabled=LowLatencyCanvas] boolean lowLatency = false; }; diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h index f3e544031f2..786b9e1230b 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h +++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_extension_name.h @@ -18,6 +18,7 @@ enum WebGLExtensionName { kEXTFragDepthName, kEXTShaderTextureLODName, kEXTsRGBName, + kKHRParallelShaderCompileName, kEXTTextureFilterAnisotropicName, kOESElementIndexUintName, kOESStandardDerivativesName, diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_program.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_program.cc index 4c6e51707f4..dc72854384c 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/webgl_program.cc +++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_program.cc @@ -74,6 +74,14 @@ bool WebGLProgram::LinkStatus(WebGLRenderingContextBase* context) { return link_status_; } +bool WebGLProgram::CompletionStatus(WebGLRenderingContextBase* context) { + GLint completed = 0; + gpu::gles2::GLES2Interface* gl = context->ContextGL(); + gl->GetProgramiv(object_, GL_COMPLETION_STATUS_KHR, &completed); + + return completed; +} + void WebGLProgram::IncreaseLinkCount() { ++link_count_; info_valid_ = false; diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_program.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_program.h index 40f0042022e..d70c358163b 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/webgl_program.h +++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_program.h @@ -43,6 +43,8 @@ class WebGLProgram final : public WebGLSharedPlatform3DObject { bool LinkStatus(WebGLRenderingContextBase*); + bool CompletionStatus(WebGLRenderingContextBase*); + unsigned LinkCount() const { return link_count_; } // This is to be called everytime after the program is successfully linked. diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc index c5d482bba1d..059b718a360 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc +++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc @@ -44,6 +44,7 @@ #include "third_party/blink/renderer/modules/webgl/ext_shader_texture_lod.h" #include "third_party/blink/renderer/modules/webgl/ext_srgb.h" #include "third_party/blink/renderer/modules/webgl/ext_texture_filter_anisotropic.h" +#include "third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.h" #include "third_party/blink/renderer/modules/webgl/oes_element_index_uint.h" #include "third_party/blink/renderer/modules/webgl/oes_standard_derivatives.h" #include "third_party/blink/renderer/modules/webgl/oes_texture_float.h" @@ -158,6 +159,8 @@ void WebGLRenderingContext::RegisterContextExtensions() { RegisterExtension<EXTTextureFilterAnisotropic>( ext_texture_filter_anisotropic_, kApprovedExtension, kBothPrefixes); RegisterExtension<EXTsRGB>(exts_rgb_); + RegisterExtension<KHRParallelShaderCompile>(khr_parallel_shader_compile_, + kDraftExtension); RegisterExtension<OESElementIndexUint>(oes_element_index_uint_); RegisterExtension<OESStandardDerivatives>(oes_standard_derivatives_); RegisterExtension<OESTextureFloat>(oes_texture_float_); @@ -194,6 +197,7 @@ void WebGLRenderingContext::Trace(blink::Visitor* visitor) { visitor->Trace(ext_shader_texture_lod_); visitor->Trace(ext_texture_filter_anisotropic_); visitor->Trace(exts_rgb_); + visitor->Trace(khr_parallel_shader_compile_); visitor->Trace(oes_element_index_uint_); visitor->Trace(oes_standard_derivatives_); visitor->Trace(oes_texture_float_); diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h index 5d13ec8aed7..46b21b8d8af 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h +++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h @@ -40,6 +40,7 @@ class EXTFragDepth; class EXTShaderTextureLOD; class EXTsRGB; class EXTTextureFilterAnisotropic; +class KHRParallelShaderCompile; class OESElementIndexUint; class OESStandardDerivatives; class OESTextureFloat; @@ -98,6 +99,7 @@ class WebGLRenderingContext final : public WebGLRenderingContextBase { Member<EXTShaderTextureLOD> ext_shader_texture_lod_; Member<EXTTextureFilterAnisotropic> ext_texture_filter_anisotropic_; Member<EXTsRGB> exts_rgb_; + Member<KHRParallelShaderCompile> khr_parallel_shader_compile_; Member<OESElementIndexUint> oes_element_index_uint_; Member<OESStandardDerivatives> oes_standard_derivatives_; Member<OESTextureFloat> oes_texture_float_; diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc index 051cb2897f0..2d312c67b97 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc @@ -1119,7 +1119,7 @@ void WebGLRenderingContextBase::InitializeNewContext() { // into account here? marked_canvas_dirty_ = false; - animation_frame_in_progress_ = false; + must_paint_to_canvas_ = false; active_texture_unit_ = 0; pack_alignment_ = 4; unpack_alignment_ = 4; @@ -1348,6 +1348,11 @@ void WebGLRenderingContextBase::MarkContextChanged( return; } + // Regardless of whether dirty propagations are optimized away, the back + // buffer is now out of sync with respect to the canvas's internal backing + // store -- which is only used for certain purposes, like printing. + must_paint_to_canvas_ = true; + if (!GetDrawingBuffer()->MarkContentsChanged() && marked_canvas_dirty_) { return; } @@ -1361,10 +1366,8 @@ void WebGLRenderingContextBase::MarkContextChanged( if (!canvas()) return; - marked_canvas_dirty_ = true; - - if (!animation_frame_in_progress_) { - animation_frame_in_progress_ = true; + if (!marked_canvas_dirty_) { + marked_canvas_dirty_ = true; LayoutBox* layout_box = canvas()->GetLayoutBox(); if (layout_box && layout_box->HasAcceleratedCompositing()) { layout_box->ContentChanged(change_type); @@ -1397,7 +1400,7 @@ void WebGLRenderingContextBase::PushFrame() { } void WebGLRenderingContextBase::FinalizeFrame() { - animation_frame_in_progress_ = false; + marked_canvas_dirty_ = false; } void WebGLRenderingContextBase::OnErrorMessage(const char* message, @@ -1545,10 +1548,10 @@ bool WebGLRenderingContextBase::PaintRenderingResultsToCanvas( return false; bool must_clear_now = ClearIfComposited() != kSkipped; - if (!marked_canvas_dirty_ && !must_clear_now) + if (!must_paint_to_canvas_ && !must_clear_now) return false; - marked_canvas_dirty_ = false; + must_paint_to_canvas_ = false; if (Host()->ResourceProvider() && Host()->ResourceProvider()->Size() != GetDrawingBuffer()->Size()) { @@ -1602,8 +1605,9 @@ bool WebGLRenderingContextBase::CopyRenderingResultsFromDrawingBuffer( // CopyToPlatformTexture is done correctly. See crbug.com/794706. gl->Flush(); + bool flip_y = is_origin_top_left_ && !canvas()->LowLatencyEnabled(); return drawing_buffer_->CopyToPlatformTexture( - gl, GL_TEXTURE_2D, texture_id, true, is_origin_top_left_, + gl, GL_TEXTURE_2D, texture_id, true, flip_y, IntPoint(0, 0), IntRect(IntPoint(0, 0), drawing_buffer_->Size()), source_buffer); } @@ -1614,8 +1618,10 @@ bool WebGLRenderingContextBase::CopyRenderingResultsFromDrawingBuffer( scoped_refptr<StaticBitmapImage> image = GetImage(kPreferAcceleration); if (!image) return false; + cc::PaintFlags paint_flags; + paint_flags.setBlendMode(SkBlendMode::kSrc); resource_provider->Canvas()->drawImage(image->PaintImageForCurrentFrame(), 0, - 0, nullptr); + 0, &paint_flags); return true; } @@ -3342,6 +3348,13 @@ ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* script_state, SynthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_multiview not enabled"); return ScriptValue::CreateNull(script_state); + case GL_MAX_SHADER_COMPILER_THREADS_KHR: + if (ExtensionEnabled(kKHRParallelShaderCompileName)) + return GetUnsignedIntParameter(script_state, pname); + SynthesizeGLError( + GL_INVALID_ENUM, "getParameter", + "invalid parameter name, KHR_parallel_shader_compile not enabled"); + return ScriptValue::CreateNull(script_state); default: if ((ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2OrHigher()) && pname >= GL_DRAW_BUFFER0_EXT && @@ -3375,6 +3388,14 @@ ScriptValue WebGLRenderingContextBase::getProgramParameter( return WebGLAny(script_state, static_cast<bool>(value)); case GL_LINK_STATUS: return WebGLAny(script_state, program->LinkStatus(this)); + case GL_COMPLETION_STATUS_KHR: + if (!ExtensionEnabled(kKHRParallelShaderCompileName)) { + SynthesizeGLError(GL_INVALID_ENUM, "getProgramParameter", + "invalid parameter name"); + return ScriptValue::CreateNull(script_state); + } + + return WebGLAny(script_state, program->CompletionStatus(this)); case GL_ACTIVE_UNIFORM_BLOCKS: case GL_TRANSFORM_FEEDBACK_VARYINGS: if (!IsWebGL2OrHigher()) { @@ -3468,6 +3489,14 @@ ScriptValue WebGLRenderingContextBase::getShaderParameter( case GL_COMPILE_STATUS: ContextGL()->GetShaderiv(ObjectOrZero(shader), pname, &value); return WebGLAny(script_state, static_cast<bool>(value)); + case GL_COMPLETION_STATUS_KHR: + if (!ExtensionEnabled(kKHRParallelShaderCompileName)) { + SynthesizeGLError(GL_INVALID_ENUM, "getShaderParameter", + "invalid parameter name"); + return ScriptValue::CreateNull(script_state); + } + ContextGL()->GetShaderiv(ObjectOrZero(shader), pname, &value); + return WebGLAny(script_state, static_cast<bool>(value)); case GL_SHADER_TYPE: ContextGL()->GetShaderiv(ObjectOrZero(shader), pname, &value); return WebGLAny(script_state, static_cast<unsigned>(value)); @@ -5175,7 +5204,7 @@ void WebGLRenderingContextBase::TexImageViaGPU( IntPoint(xoffset, yoffset), source_sub_rectangle); } else { WebGLRenderingContextBase* gl = source_canvas_webgl_context; - if (gl->is_origin_top_left_) + if (gl->is_origin_top_left_ && !canvas()->LowLatencyEnabled()) flip_y = !flip_y; ScopedTexture2DRestorer restorer(gl); if (!gl->GetDrawingBuffer()->CopyToPlatformTexture( @@ -5409,6 +5438,9 @@ void WebGLRenderingContextBase::TexImageHelperHTMLVideoElement( yoffset, zoffset)) return; + GLint adjusted_internalformat = + ConvertTexInternalFormat(internalformat, type); + // For WebGL last-uploaded-frame-metadata API. https://crbug.com/639174 WebMediaPlayer::VideoFrameUploadMetadata frame_metadata = {}; int already_uploaded_id = -1; @@ -5447,8 +5479,8 @@ void WebGLRenderingContextBase::TexImageHelperHTMLVideoElement( // SW path. if (video->CopyVideoTextureToPlatformTexture( - ContextGL(), target, texture->Object(), internalformat, format, - type, level, unpack_premultiply_alpha_, unpack_flip_y_, + ContextGL(), target, texture->Object(), adjusted_internalformat, + format, type, level, unpack_premultiply_alpha_, unpack_flip_y_, already_uploaded_id, frame_metadata_ptr)) { texture->UpdateLastUploadedFrame(frame_metadata); return; @@ -5458,8 +5490,8 @@ void WebGLRenderingContextBase::TexImageHelperHTMLVideoElement( // (e.g. video camera frames): upload them to the GPU, do a GPU decode, and // then copy into the target texture. if (video->CopyVideoYUVDataToPlatformTexture( - ContextGL(), target, texture->Object(), internalformat, format, - type, level, unpack_premultiply_alpha_, unpack_flip_y_, + ContextGL(), target, texture->Object(), adjusted_internalformat, + format, type, level, unpack_premultiply_alpha_, unpack_flip_y_, already_uploaded_id, frame_metadata_ptr)) { texture->UpdateLastUploadedFrame(frame_metadata); return; @@ -5474,8 +5506,8 @@ void WebGLRenderingContextBase::TexImageHelperHTMLVideoElement( if (video->TexImageImpl( static_cast<WebMediaPlayer::TexImageFunctionID>(function_id), target, ContextGL(), texture->Object(), level, - ConvertTexInternalFormat(internalformat, type), format, type, - xoffset, yoffset, zoffset, unpack_flip_y_, + adjusted_internalformat, format, type, xoffset, yoffset, zoffset, + unpack_flip_y_, unpack_premultiply_alpha_ && unpack_colorspace_conversion_ == GL_NONE)) { texture->ClearLastUploadedFrame(); @@ -5487,8 +5519,8 @@ void WebGLRenderingContextBase::TexImageHelperHTMLVideoElement( VideoFrameToImage(video, already_uploaded_id, frame_metadata_ptr); if (!image) return; - TexImageImpl(function_id, target, level, internalformat, xoffset, yoffset, - zoffset, format, type, image.get(), + TexImageImpl(function_id, target, level, adjusted_internalformat, xoffset, + yoffset, zoffset, format, type, image.get(), WebGLImageConversion::kHtmlDomVideo, unpack_flip_y_, unpack_premultiply_alpha_, source_image_rect, depth, unpack_image_height); diff --git a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h index 424f8bcf4f6..96c15706bcf 100644 --- a/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h +++ b/chromium/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h @@ -580,7 +580,7 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext, DrawingBuffer* GetDrawingBuffer() const; class TextureUnitState { - DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + DISALLOW_NEW(); public: TraceWrapperMember<WebGLTexture> texture2d_binding_; @@ -730,7 +730,10 @@ class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext, bool destruction_in_progress_ = false; bool marked_canvas_dirty_; - bool animation_frame_in_progress_; + // For performance reasons we must separately track whether we've + // copied WebGL's drawing buffer to the canvas's backing store, for + // example for printing. + bool must_paint_to_canvas_; // List of bound VBO's. Used to maintain info about sizes for ARRAY_BUFFER and // stored values for ELEMENT_ARRAY_BUFFER diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_access.cc b/chromium/third_party/blink/renderer/modules/webmidi/midi_access.cc index 884e88aa912..1d64eac6069 100644 --- a/chromium/third_party/blink/renderer/modules/webmidi/midi_access.cc +++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_access.cc @@ -69,8 +69,7 @@ MIDIAccess::MIDIAccess( sysex_enabled_(sysex_enabled), has_pending_activity_(false) { accessor_->SetClient(this); - for (size_t i = 0; i < ports.size(); ++i) { - const MIDIAccessInitializer::PortDescriptor& port = ports[i]; + for (const auto& port : ports) { if (port.type == MIDIPort::kTypeInput) { inputs_.push_back(MIDIInput::Create(this, port.id, port.manufacturer, port.name, port.version, @@ -106,8 +105,7 @@ bool MIDIAccess::HasPendingActivity() const { MIDIInputMap* MIDIAccess::inputs() const { HeapVector<Member<MIDIInput>> inputs; HashSet<String> ids; - for (size_t i = 0; i < inputs_.size(); ++i) { - MIDIInput* input = inputs_[i]; + for (MIDIInput* input : inputs_) { if (input->GetState() != PortState::DISCONNECTED) { inputs.push_back(input); ids.insert(input->id()); @@ -123,8 +121,7 @@ MIDIInputMap* MIDIAccess::inputs() const { MIDIOutputMap* MIDIAccess::outputs() const { HeapVector<Member<MIDIOutput>> outputs; HashSet<String> ids; - for (size_t i = 0; i < outputs_.size(); ++i) { - MIDIOutput* output = outputs_[i]; + for (MIDIOutput* output : outputs_) { if (output->GetState() != PortState::DISCONNECTED) { outputs.push_back(output); ids.insert(output->id()); diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc b/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc index 33a8b5b3175..5db5ab3f029 100644 --- a/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc +++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc @@ -43,10 +43,10 @@ ScriptPromise MIDIAccessInitializer::Start() { ConnectToPermissionService(GetExecutionContext(), mojo::MakeRequest(&permission_service_)); - Document* doc = ToDocumentOrNull(GetExecutionContext()); + Document& doc = To<Document>(*GetExecutionContext()); permission_service_->RequestPermission( CreateMidiPermissionDescriptor(options_.hasSysex() && options_.sysex()), - Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr), + LocalFrame::HasTransientUserActivation(doc.GetFrame()), WTF::Bind(&MIDIAccessInitializer::OnPermissionsUpdated, WrapPersistent(this))); diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h b/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h index 2a2da55db34..ef1e7d4d84b 100644 --- a/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h +++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h @@ -26,7 +26,7 @@ class MODULES_EXPORT MIDIAccessInitializer : public ScriptPromiseResolver, public MIDIAccessorClient { public: struct PortDescriptor { - DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); + DISALLOW_NEW(); String id; String manufacturer; String name; diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_input.cc b/chromium/third_party/blink/renderer/modules/webmidi/midi_input.cc index 0992d957d1d..65395387832 100644 --- a/chromium/third_party/blink/renderer/modules/webmidi/midi_input.cc +++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_input.cc @@ -101,7 +101,7 @@ void MIDIInput::DidReceiveMIDIData(unsigned port_index, DOMUint8Array* array = DOMUint8Array::Create(data, length); DispatchEvent(*MIDIMessageEvent::Create(time_stamp, array)); - UseCounter::Count(*ToDocument(GetExecutionContext()), + UseCounter::Count(*To<Document>(GetExecutionContext()), WebFeature::kMIDIMessageEvent); } diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_output.cc b/chromium/third_party/blink/renderer/modules/webmidi/midi_output.cc index 2c712d16ac9..9c087cbbad3 100644 --- a/chromium/third_party/blink/renderer/modules/webmidi/midi_output.cc +++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_output.cc @@ -53,7 +53,7 @@ DOMUint8Array* ConvertUnsignedDataToUint8Array( ExceptionState& exception_state) { DOMUint8Array* array = DOMUint8Array::Create(unsigned_data.size()); DOMUint8Array::ValueType* array_data = array->Data(); - for (size_t i = 0; i < unsigned_data.size(); ++i) { + for (wtf_size_t i = 0; i < unsigned_data.size(); ++i) { if (unsigned_data[i] > 0xff) { exception_state.ThrowTypeError("The value at index " + String::Number(i) + " (" + String::Number(unsigned_data[i]) + diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_port.cc b/chromium/third_party/blink/renderer/modules/webmidi/midi_port.cc index da3e04f5abc..776eaa6d9fe 100644 --- a/chromium/third_party/blink/renderer/modules/webmidi/midi_port.cc +++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_port.cc @@ -198,7 +198,7 @@ void MIDIPort::OpenAsynchronously(ScriptPromiseResolver* resolver) { if (!GetExecutionContext()) return; - UseCounter::Count(*ToDocument(GetExecutionContext()), + UseCounter::Count(*To<Document>(GetExecutionContext()), WebFeature::kMIDIPortOpen); DCHECK_NE(0u, running_open_count_); running_open_count_--; diff --git a/chromium/third_party/blink/renderer/modules/webmidi/midi_port_map.h b/chromium/third_party/blink/renderer/modules/webmidi/midi_port_map.h index 5961c6b1f8a..51db70ef437 100644 --- a/chromium/third_party/blink/renderer/modules/webmidi/midi_port_map.h +++ b/chromium/third_party/blink/renderer/modules/webmidi/midi_port_map.h @@ -21,7 +21,7 @@ class MIDIPortMap : public ScriptWrappable, public Maplike<String, T*> { : entries_(entries) {} // IDL attributes / methods - size_t size() const { return entries_.size(); } + uint32_t size() const { return entries_.size(); } void Trace(blink::Visitor* visitor) override { visitor->Trace(entries_); diff --git a/chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc b/chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc index 4d08522cff1..aa7c5fbf746 100644 --- a/chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc +++ b/chromium/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc @@ -89,7 +89,7 @@ ScriptPromise NavigatorWebMIDI::requestMIDIAccess(ScriptState* script_state, "The frame is not working.")); } - Document& document = *ToDocument(ExecutionContext::From(script_state)); + Document& document = *To<Document>(ExecutionContext::From(script_state)); if (options.hasSysex() && options.sysex()) { UseCounter::Count( document, @@ -102,9 +102,8 @@ ScriptPromise NavigatorWebMIDI::requestMIDIAccess(ScriptState* script_state, UseCounter::CountCrossOriginIframe( document, WebFeature::kRequestMIDIAccessIframe_ObscuredByFootprinting); - if (!document.GetFrame()->IsFeatureEnabled( - mojom::FeaturePolicyFeature::kMidiFeature, - ReportOptions::kReportOnFailure)) { + if (!document.IsFeatureEnabled(mojom::FeaturePolicyFeature::kMidiFeature, + ReportOptions::kReportOnFailure)) { UseCounter::Count(document, WebFeature::kMidiDisabledByFeaturePolicy); document.AddConsoleMessage(ConsoleMessage::Create( kJSMessageSource, kWarningMessageLevel, kFeaturePolicyConsoleWarning)); diff --git a/chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc b/chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc index dca964a2ab1..a1495b090ca 100644 --- a/chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc +++ b/chromium/third_party/blink/renderer/modules/webshare/navigator_share.cc @@ -102,8 +102,7 @@ const char NavigatorShare::kSupplementName[] = "NavigatorShare"; ScriptPromise NavigatorShare::share(ScriptState* script_state, const ShareData& share_data) { - Document* doc = ToDocument(ExecutionContext::From(script_state)); - DCHECK(doc); + Document* doc = To<Document>(ExecutionContext::From(script_state)); if (!share_data.hasTitle() && !share_data.hasText() && !share_data.hasURL()) { v8::Local<v8::Value> error = V8ThrowException::CreateTypeError( @@ -120,7 +119,7 @@ ScriptPromise NavigatorShare::share(ScriptState* script_state, return ScriptPromise::Reject(script_state, error); } - if (!Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr)) { + if (!LocalFrame::HasTransientUserActivation(doc->GetFrame())) { DOMException* error = DOMException::Create( DOMExceptionCode::kNotAllowedError, "Must be handling a user gesture to perform a share request."); diff --git a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc index 5e643649ae6..8d10617e9f6 100644 --- a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc +++ b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.cc @@ -30,7 +30,9 @@ #include "third_party/blink/renderer/modules/websockets/dom_websocket.h" +#include "base/feature_list.h" #include "base/location.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/public/platform/web_insecure_request_policy.h" @@ -47,6 +49,7 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/use_counter.h" #include "third_party/blink/renderer/core/inspector/console_message.h" +#include "third_party/blink/renderer/core/loader/mixed_content_checker.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h" #include "third_party/blink/renderer/modules/websockets/close_event.h" @@ -54,6 +57,7 @@ #include "third_party/blink/renderer/platform/blob/blob_data.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/histogram.h" +#include "third_party/blink/renderer/platform/loader/mixed_content_autoupgrade_status.h" #include "third_party/blink/renderer/platform/network/network_log.h" #include "third_party/blink/renderer/platform/weborigin/known_ports.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" @@ -63,11 +67,20 @@ #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/blink/renderer/platform/wtf/text/cstring.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" +#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h" static const size_t kMaxByteSizeForHistogram = 100 * 1000 * 1000; static const int32_t kBucketCountForMessageSizeHistogram = 50; static const char kWebSocketSubprotocolSeparator[] = ", "; +namespace { +void LogMixedAutoupgradeStatus(blink::MixedContentAutoupgradeStatus status) { + // For websockets we use the response received element to log successful + // connections. + UMA_HISTOGRAM_ENUMERATION("MixedAutoupgrade.Websocket.Status", status); +} +} // namespace + namespace blink { DOMWebSocket::EventQueue::EventQueue(EventTarget* target) @@ -185,7 +198,7 @@ static inline bool IsValidSubprotocolCharacter(UChar character) { bool DOMWebSocket::IsValidSubprotocolString(const String& protocol) { if (protocol.IsEmpty()) return false; - for (size_t i = 0; i < protocol.length(); ++i) { + for (wtf_size_t i = 0; i < protocol.length(); ++i) { if (!IsValidSubprotocolCharacter(protocol[i])) return false; } @@ -194,7 +207,7 @@ bool DOMWebSocket::IsValidSubprotocolString(const String& protocol) { static String EncodeSubprotocolString(const String& protocol) { StringBuilder builder; - for (size_t i = 0; i < protocol.length(); i++) { + for (wtf_size_t i = 0; i < protocol.length(); i++) { if (protocol[i] < 0x20 || protocol[i] > 0x7E) builder.Append(String::Format("\\u%04X", protocol[i])); else if (protocol[i] == 0x5c) @@ -208,7 +221,7 @@ static String EncodeSubprotocolString(const String& protocol) { static String JoinStrings(const Vector<String>& strings, const char* separator) { StringBuilder builder; - for (size_t i = 0; i < strings.size(); ++i) { + for (wtf_size_t i = 0; i < strings.size(); ++i) { if (i) builder.Append(separator); builder.Append(strings[i]); @@ -231,7 +244,8 @@ DOMWebSocket::DOMWebSocket(ExecutionContext* context) subprotocol_(""), extensions_(""), event_queue_(EventQueue::Create(this)), - buffered_amount_update_task_pending_(false) {} + buffered_amount_update_task_pending_(false), + was_autoupgraded_to_wss_(false) {} DOMWebSocket::~DOMWebSocket() { DCHECK(!channel_); @@ -291,10 +305,20 @@ void DOMWebSocket::Connect(const String& url, NETWORK_DVLOG(1) << "WebSocket " << this << " connect() url=" << url; url_ = KURL(NullURL(), url); - if (GetExecutionContext()->GetSecurityContext().GetInsecureRequestPolicy() & - kUpgradeInsecureRequests && + bool upgrade_insecure_requests_set = + GetExecutionContext()->GetSecurityContext().GetInsecureRequestPolicy() & + kUpgradeInsecureRequests; + + if ((upgrade_insecure_requests_set || + MixedContentChecker::ShouldAutoupgrade( + GetExecutionContext()->Url(), + WebMixedContentContextType::kBlockable)) && url_.Protocol() == "ws" && !SecurityOrigin::Create(url_)->IsPotentiallyTrustworthy()) { + if (!upgrade_insecure_requests_set) { + was_autoupgraded_to_wss_ = true; + LogMixedAutoupgradeStatus(MixedContentAutoupgradeStatus::kStarted); + } UseCounter::Count(GetExecutionContext(), WebFeature::kUpgradeInsecureRequestsUpgradedRequest); url_.SetProtocol("wss"); @@ -349,26 +373,26 @@ void DOMWebSocket::Connect(const String& url, } // Fail if not all elements in |protocols| are valid. - for (size_t i = 0; i < protocols.size(); ++i) { - if (!IsValidSubprotocolString(protocols[i])) { + for (const String& protocol : protocols) { + if (!IsValidSubprotocolString(protocol)) { state_ = kClosed; - exception_state.ThrowDOMException( - DOMExceptionCode::kSyntaxError, - "The subprotocol '" + EncodeSubprotocolString(protocols[i]) + - "' is invalid."); + exception_state.ThrowDOMException(DOMExceptionCode::kSyntaxError, + "The subprotocol '" + + EncodeSubprotocolString(protocol) + + "' is invalid."); return; } } // Fail if there're duplicated elements in |protocols|. HashSet<String> visited; - for (size_t i = 0; i < protocols.size(); ++i) { - if (!visited.insert(protocols[i]).is_new_entry) { + for (const String& protocol : protocols) { + if (!visited.insert(protocol).is_new_entry) { state_ = kClosed; - exception_state.ThrowDOMException( - DOMExceptionCode::kSyntaxError, - "The subprotocol '" + EncodeSubprotocolString(protocols[i]) + - "' is duplicated."); + exception_state.ThrowDOMException(DOMExceptionCode::kSyntaxError, + "The subprotocol '" + + EncodeSubprotocolString(protocol) + + "' is duplicated."); return; } } @@ -678,6 +702,8 @@ void DOMWebSocket::Unpause() { void DOMWebSocket::DidConnect(const String& subprotocol, const String& extensions) { NETWORK_DVLOG(1) << "WebSocket " << this << " DidConnect()"; + if (was_autoupgraded_to_wss_) + LogMixedAutoupgradeStatus(MixedContentAutoupgradeStatus::kResponseReceived); if (state_ != kConnecting) return; state_ = kOpen; @@ -739,6 +765,8 @@ void DOMWebSocket::DidReceiveBinaryMessage( void DOMWebSocket::DidError() { NETWORK_DVLOG(1) << "WebSocket " << this << " DidError()"; + if (state_ == kConnecting && was_autoupgraded_to_wss_) + LogMixedAutoupgradeStatus(MixedContentAutoupgradeStatus::kFailed); ReflectBufferedAmountConsumption(); state_ = kClosed; event_queue_->Dispatch(Event::Create(EventTypeNames::error)); diff --git a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.h b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.h index 4278acea08c..5511d12644a 100644 --- a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.h +++ b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket.h @@ -266,6 +266,8 @@ class MODULES_EXPORT DOMWebSocket : public EventTargetWithInlineData, Member<EventQueue> event_queue_; bool buffered_amount_update_task_pending_; + + bool was_autoupgraded_to_wss_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc index f46924e609f..784928d791f 100644 --- a/chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc +++ b/chromium/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc @@ -6,8 +6,10 @@ #include <memory> +#include "base/test/scoped_feature_list.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/web_insecure_request_policy.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" @@ -267,6 +269,27 @@ TEST(DOMWebSocketTest, insecureRequestsDoNotUpgrade) { EXPECT_EQ(KURL("ws://example.com/endpoint"), websocket_scope.Socket().url()); } +TEST(DOMWebSocketTest, mixedContentAutoUpgrade) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(features::kMixedContentAutoupgrade); + V8TestingScope scope; + DOMWebSocketTestScope websocket_scope(scope.GetExecutionContext()); + { + InSequence s; + EXPECT_CALL(websocket_scope.Channel(), + Connect(KURL("wss://example.com/endpoint"), String())) + .WillOnce(Return(true)); + } + scope.GetDocument().SetURL(KURL("https://example.com")); + scope.GetDocument().SetInsecureRequestPolicy(kLeaveInsecureRequestsAlone); + websocket_scope.Socket().Connect("ws://example.com/endpoint", + Vector<String>(), scope.GetExceptionState()); + + EXPECT_FALSE(scope.GetExceptionState().HadException()); + EXPECT_EQ(DOMWebSocket::kConnecting, websocket_scope.Socket().readyState()); + EXPECT_EQ(KURL("wss://example.com/endpoint"), websocket_scope.Socket().url()); +} + TEST(DOMWebSocketTest, channelConnectSuccess) { V8TestingScope scope; DOMWebSocketTestScope websocket_scope(scope.GetExecutionContext()); diff --git a/chromium/third_party/blink/renderer/modules/websockets/inspector_websocket_events.cc b/chromium/third_party/blink/renderer/modules/websockets/inspector_websocket_events.cc index ea3e2460d7d..f94cb8d91ea 100644 --- a/chromium/third_party/blink/renderer/modules/websockets/inspector_websocket_events.cc +++ b/chromium/third_party/blink/renderer/modules/websockets/inspector_websocket_events.cc @@ -22,11 +22,11 @@ std::unique_ptr<TracedValue> InspectorWebSocketCreateEvent::Data( const String& protocol) { DCHECK(execution_context->IsContextThread()); std::unique_ptr<TracedValue> value = TracedValue::Create(); - value->SetInteger("identifier", identifier); + value->SetInteger("identifier", static_cast<int>(identifier)); value->SetString("url", url.GetString()); - if (execution_context->IsDocument()) { - value->SetString("frame", IdentifiersFactory::FrameId( - ToDocument(execution_context)->GetFrame())); + if (auto* document = DynamicTo<Document>(execution_context)) { + value->SetString("frame", + IdentifiersFactory::FrameId(document->GetFrame())); } else if (execution_context->IsWorkerGlobalScope()) { value->SetString("workerId", IdentifiersFactory::IdFromToken( ToWorkerGlobalScope(execution_context) @@ -47,10 +47,10 @@ std::unique_ptr<TracedValue> InspectorWebSocketEvent::Data( unsigned long identifier) { DCHECK(execution_context->IsContextThread()); std::unique_ptr<TracedValue> value = TracedValue::Create(); - value->SetInteger("identifier", identifier); - if (execution_context->IsDocument()) { - value->SetString("frame", IdentifiersFactory::FrameId( - ToDocument(execution_context)->GetFrame())); + value->SetInteger("identifier", static_cast<int>(identifier)); + if (auto* document = DynamicTo<Document>(execution_context)) { + value->SetString("frame", + IdentifiersFactory::FrameId(document->GetFrame())); } else if (execution_context->IsWorkerGlobalScope()) { value->SetString("workerId", IdentifiersFactory::IdFromToken( ToWorkerGlobalScope(execution_context) diff --git a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc index c7755b7977e..f08c1c4b9fe 100644 --- a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc +++ b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc @@ -62,6 +62,7 @@ #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/functional.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" namespace blink { @@ -428,16 +429,16 @@ WebSocketChannelImpl::Message::Message(unsigned short code, void WebSocketChannelImpl::SendInternal( WebSocketHandle::MessageType message_type, const char* data, - size_t total_size, + wtf_size_t total_size, uint64_t* consumed_buffered_amount) { WebSocketHandle::MessageType frame_type = sent_size_of_top_message_ ? WebSocketHandle::kMessageTypeContinuation : message_type; DCHECK_GE(total_size, sent_size_of_top_message_); // The first cast is safe since the result of min() never exceeds - // the range of size_t. The second cast is necessary to compile + // the range of wtf_size_t. The second cast is necessary to compile // min() on ILP32. - size_t size = static_cast<size_t>( + wtf_size_t size = static_cast<wtf_size_t>( std::min(sending_quota_, static_cast<uint64_t>(total_size - sent_size_of_top_message_))); bool final = (sent_size_of_top_message_ + size == total_size); @@ -650,7 +651,7 @@ void WebSocketChannelImpl::DidReceiveData(WebSocketHandle* handle, break; } - receiving_message_data_.Append(data, size); + receiving_message_data_.Append(data, SafeCast<uint32_t>(size)); received_data_size_for_flow_control_ += size; FlowControlIfNecessary(); if (!fin) { diff --git a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h index dfb664c18db..121dca5eccc 100644 --- a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h +++ b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h @@ -51,6 +51,7 @@ #include "third_party/blink/renderer/platform/wtf/text/cstring.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/vector.h" +#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h" namespace blink { @@ -133,7 +134,7 @@ class MODULES_EXPORT WebSocketChannelImpl final void SendInternal(WebSocketHandle::MessageType, const char* data, - size_t total_size, + wtf_size_t total_size, uint64_t* consumed_buffered_amount); void ProcessSendQueue(); void FlowControlIfNecessary(); @@ -200,7 +201,7 @@ class MODULES_EXPORT WebSocketChannelImpl final bool receiving_message_type_is_text_; uint64_t sending_quota_; uint64_t received_data_size_for_flow_control_; - size_t sent_size_of_top_message_; + wtf_size_t sent_size_of_top_message_; std::unique_ptr<FrameScheduler::ActiveConnectionHandle> connection_handle_for_scheduler_; diff --git a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc index ccc4d0521a7..c13eb980d9f 100644 --- a/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc +++ b/chromium/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc @@ -25,6 +25,7 @@ #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/vector.h" +#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h" using testing::_; using testing::InSequence; @@ -96,8 +97,9 @@ class MockWebSocketHandle : public WebSocketHandle { const KURL&, const String&, WebSocketHandleClient*)); - MOCK_METHOD4(Send, - void(bool, WebSocketHandle::MessageType, const char*, size_t)); + MOCK_METHOD4( + Send, + void(bool, WebSocketHandle::MessageType, const char*, wtf_size_t)); MOCK_METHOD1(FlowControl, void(int64_t)); MOCK_METHOD2(Close, void(unsigned short, const String&)); }; diff --git a/chromium/third_party/blink/renderer/modules/websockets/websocket_handle.h b/chromium/third_party/blink/renderer/modules/websockets/websocket_handle.h index 464adb305fa..4a7c0402c76 100644 --- a/chromium/third_party/blink/renderer/modules/websockets/websocket_handle.h +++ b/chromium/third_party/blink/renderer/modules/websockets/websocket_handle.h @@ -36,6 +36,7 @@ #include "services/network/public/mojom/websocket.mojom-blink.h" #include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/vector.h" +#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h" namespace blink { @@ -67,7 +68,7 @@ class WebSocketHandle { const String& user_agent_override, WebSocketHandleClient*, base::SingleThreadTaskRunner*) = 0; - virtual void Send(bool fin, MessageType, const char* data, size_t) = 0; + virtual void Send(bool fin, MessageType, const char* data, wtf_size_t) = 0; virtual void FlowControl(int64_t quota) = 0; virtual void Close(unsigned short code, const String& reason) = 0; }; diff --git a/chromium/third_party/blink/renderer/modules/websockets/websocket_handle_impl.cc b/chromium/third_party/blink/renderer/modules/websockets/websocket_handle_impl.cc index 079a508ddff..2d052f9b2d3 100644 --- a/chromium/third_party/blink/renderer/modules/websockets/websocket_handle_impl.cc +++ b/chromium/third_party/blink/renderer/modules/websockets/websocket_handle_impl.cc @@ -67,7 +67,7 @@ void WebSocketHandleImpl::Connect(network::mojom::blink::WebSocketPtr websocket, void WebSocketHandleImpl::Send(bool fin, WebSocketHandle::MessageType type, const char* data, - size_t size) { + wtf_size_t size) { DCHECK(websocket_); network::mojom::blink::WebSocketMessageType type_to_pass; diff --git a/chromium/third_party/blink/renderer/modules/websockets/websocket_handle_impl.h b/chromium/third_party/blink/renderer/modules/websockets/websocket_handle_impl.h index 0e16a3ed8e7..9f89fd6cc5b 100644 --- a/chromium/third_party/blink/renderer/modules/websockets/websocket_handle_impl.h +++ b/chromium/third_party/blink/renderer/modules/websockets/websocket_handle_impl.h @@ -34,6 +34,7 @@ #include "mojo/public/cpp/bindings/binding.h" #include "services/network/public/mojom/websocket.mojom-blink.h" #include "third_party/blink/renderer/modules/websockets/websocket_handle.h" +#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h" namespace blink { @@ -50,7 +51,7 @@ class WebSocketHandleImpl : public WebSocketHandle, const String& user_agent_override, WebSocketHandleClient*, base::SingleThreadTaskRunner*) override; - void Send(bool fin, MessageType, const char* data, size_t) override; + void Send(bool fin, MessageType, const char* data, wtf_size_t) override; void FlowControl(int64_t quota) override; void Close(unsigned short code, const String& reason) override; diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb.cc b/chromium/third_party/blink/renderer/modules/webusb/usb.cc index 6f96c1ae804..5da4060b792 100644 --- a/chromium/third_party/blink/renderer/modules/webusb/usb.cc +++ b/chromium/third_party/blink/renderer/modules/webusb/usb.cc @@ -8,6 +8,7 @@ #include "device/usb/public/mojom/device.mojom-blink.h" #include "services/service_manager/public/cpp/interface_provider.h" +#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/dom/document.h" @@ -19,7 +20,6 @@ #include "third_party/blink/renderer/modules/webusb/usb_device.h" #include "third_party/blink/renderer/modules/webusb/usb_device_filter.h" #include "third_party/blink/renderer/modules/webusb/usb_device_request_options.h" -#include "third_party/blink/renderer/platform/feature_policy/feature_policy.h" #include "third_party/blink/renderer/platform/mojo/mojo_helper.h" #include "third_party/blink/renderer/platform/wtf/functional.h" @@ -34,23 +34,53 @@ const char kFeaturePolicyBlocked[] = "Access to the feature \"usb\" is disallowed by feature policy."; const char kNoDeviceSelected[] = "No device selected."; -UsbDeviceFilterPtr ConvertDeviceFilter(const USBDeviceFilter& filter) { +void RejectWithTypeError(const String& error_details, + ScriptPromiseResolver* resolver) { + ScriptState::Scope scope(resolver->GetScriptState()); + v8::Isolate* isolate = resolver->GetScriptState()->GetIsolate(); + resolver->Reject(V8ThrowException::CreateTypeError(isolate, error_details)); +} + +UsbDeviceFilterPtr ConvertDeviceFilter(const USBDeviceFilter& filter, + ScriptPromiseResolver* resolver) { auto mojo_filter = device::mojom::blink::UsbDeviceFilter::New(); mojo_filter->has_vendor_id = filter.hasVendorId(); if (mojo_filter->has_vendor_id) mojo_filter->vendor_id = filter.vendorId(); mojo_filter->has_product_id = filter.hasProductId(); - if (mojo_filter->has_product_id) + if (mojo_filter->has_product_id) { + if (!mojo_filter->has_vendor_id) { + RejectWithTypeError( + "A filter containing a productId must also contain a vendorId.", + resolver); + return nullptr; + } mojo_filter->product_id = filter.productId(); + } mojo_filter->has_class_code = filter.hasClassCode(); if (mojo_filter->has_class_code) mojo_filter->class_code = filter.classCode(); mojo_filter->has_subclass_code = filter.hasSubclassCode(); - if (mojo_filter->has_subclass_code) + if (mojo_filter->has_subclass_code) { + if (!mojo_filter->has_class_code) { + RejectWithTypeError( + "A filter containing a subclassCode must also contain a classCode.", + resolver); + return nullptr; + } mojo_filter->subclass_code = filter.subclassCode(); + } mojo_filter->has_protocol_code = filter.hasProtocolCode(); - if (mojo_filter->has_protocol_code) + if (mojo_filter->has_protocol_code) { + if (!mojo_filter->has_subclass_code) { + RejectWithTypeError( + "A filter containing a protocolCode must also contain a " + "subclassCode.", + resolver); + return nullptr; + } mojo_filter->protocol_code = filter.protocolCode(); + } if (filter.hasSerialNumber()) mojo_filter->serial_number = filter.serialNumber(); return mojo_filter; @@ -82,10 +112,8 @@ ScriptPromise USB::getDevices(ScriptState* script_state) { } if (!IsFeatureEnabled()) { ExecutionContext* execution_context = ExecutionContext::From(script_state); - if (execution_context && execution_context->IsDocument()) { - ToDocument(execution_context) - ->GetFrame() - ->ReportFeaturePolicyViolation(mojom::FeaturePolicyFeature::kUsb); + if (auto* document = DynamicTo<Document>(execution_context)) { + document->ReportFeaturePolicyViolation(mojom::FeaturePolicyFeature::kUsb); } return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kSecurityError, @@ -103,14 +131,14 @@ ScriptPromise USB::getDevices(ScriptState* script_state) { ScriptPromise USB::requestDevice(ScriptState* script_state, const USBDeviceRequestOptions& options) { LocalFrame* frame = GetFrame(); - if (!frame) { + if (!frame || !frame->GetDocument()) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError)); } - if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kUsb, - ReportOptions::kReportOnFailure)) { + if (!frame->GetDocument()->IsFeatureEnabled( + mojom::FeaturePolicyFeature::kUsb, ReportOptions::kReportOnFailure)) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kSecurityError, kFeaturePolicyBlocked)); @@ -118,7 +146,7 @@ ScriptPromise USB::requestDevice(ScriptState* script_state, EnsureServiceConnection(); - if (!Frame::HasTransientUserActivation(frame)) { + if (!LocalFrame::HasTransientUserActivation(frame)) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create( @@ -126,19 +154,26 @@ ScriptPromise USB::requestDevice(ScriptState* script_state, "Must be handling a user gesture to show a permission request.")); } + ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); + ScriptPromise promise = resolver->Promise(); Vector<UsbDeviceFilterPtr> filters; if (options.hasFilters()) { filters.ReserveCapacity(options.filters().size()); - for (const auto& filter : options.filters()) - filters.push_back(ConvertDeviceFilter(filter)); + for (const auto& filter : options.filters()) { + UsbDeviceFilterPtr converted_filter = + ConvertDeviceFilter(filter, resolver); + if (!converted_filter) + return promise; + filters.push_back(std::move(converted_filter)); + } } - ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); + DCHECK(options.filters().size() == filters.size()); get_permission_requests_.insert(resolver); service_->GetPermission(std::move(filters), WTF::Bind(&USB::OnGetPermission, WrapPersistent(this), WrapPersistent(resolver))); - return resolver->Promise(); + return promise; } ExecutionContext* USB::GetExecutionContext() const { @@ -255,7 +290,7 @@ void USB::EnsureServiceConnection() { DCHECK(!client_binding_.is_bound()); - device::mojom::blink::UsbDeviceManagerClientPtr client; + device::mojom::blink::UsbDeviceManagerClientAssociatedPtrInfo client; client_binding_.Bind(mojo::MakeRequest(&client)); service_->SetClient(std::move(client)); } @@ -277,9 +312,8 @@ bool USB::IsContextSupported() const { } bool USB::IsFeatureEnabled() const { - ExecutionContext* context = GetExecutionContext(); - FeaturePolicy* policy = context->GetSecurityContext().GetFeaturePolicy(); - return policy->IsFeatureEnabled(mojom::FeaturePolicyFeature::kUsb); + return GetExecutionContext()->GetSecurityContext().IsFeatureEnabled( + mojom::FeaturePolicyFeature::kUsb); } void USB::Trace(blink::Visitor* visitor) { diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb.h b/chromium/third_party/blink/renderer/modules/webusb/usb.h index 9c871d920fd..768227ec3bd 100644 --- a/chromium/third_party/blink/renderer/modules/webusb/usb.h +++ b/chromium/third_party/blink/renderer/modules/webusb/usb.h @@ -6,7 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBUSB_USB_H_ #include "device/usb/public/mojom/device_manager.mojom-blink.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/associated_binding.h" #include "third_party/blink/public/mojom/usb/web_usb_service.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" @@ -84,7 +84,8 @@ class USB final : public EventTargetWithInlineData, mojom::blink::WebUsbServicePtr service_; HeapHashSet<Member<ScriptPromiseResolver>> get_devices_requests_; HeapHashSet<Member<ScriptPromiseResolver>> get_permission_requests_; - mojo::Binding<device::mojom::blink::UsbDeviceManagerClient> client_binding_; + mojo::AssociatedBinding<device::mojom::blink::UsbDeviceManagerClient> + client_binding_; HeapHashMap<String, WeakMember<USBDevice>> device_cache_; }; diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_alternate_interface.cc b/chromium/third_party/blink/renderer/modules/webusb/usb_alternate_interface.cc index ebcddcca82e..fb2799d19b7 100644 --- a/chromium/third_party/blink/renderer/modules/webusb/usb_alternate_interface.cc +++ b/chromium/third_party/blink/renderer/modules/webusb/usb_alternate_interface.cc @@ -12,16 +12,16 @@ namespace blink { USBAlternateInterface* USBAlternateInterface::Create( const USBInterface* interface, - size_t alternate_index) { + wtf_size_t alternate_index) { return new USBAlternateInterface(interface, alternate_index); } USBAlternateInterface* USBAlternateInterface::Create( const USBInterface* interface, - size_t alternate_setting, + uint8_t alternate_setting, ExceptionState& exception_state) { const auto& alternates = interface->Info().alternates; - for (size_t i = 0; i < alternates.size(); ++i) { + for (wtf_size_t i = 0; i < alternates.size(); ++i) { if (alternates[i]->alternate_setting == alternate_setting) return USBAlternateInterface::Create(interface, i); } @@ -30,7 +30,7 @@ USBAlternateInterface* USBAlternateInterface::Create( } USBAlternateInterface::USBAlternateInterface(const USBInterface* interface, - size_t alternate_index) + wtf_size_t alternate_index) : interface_(interface), alternate_index_(alternate_index) { DCHECK(interface_); DCHECK_LT(alternate_index_, interface_->Info().alternates.size()); @@ -46,7 +46,7 @@ USBAlternateInterface::Info() const { HeapVector<Member<USBEndpoint>> USBAlternateInterface::endpoints() const { HeapVector<Member<USBEndpoint>> endpoints; - for (size_t i = 0; i < Info().endpoints.size(); ++i) + for (wtf_size_t i = 0; i < Info().endpoints.size(); ++i) endpoints.push_back(USBEndpoint::Create(this, i)); return endpoints; } diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_alternate_interface.h b/chromium/third_party/blink/renderer/modules/webusb/usb_alternate_interface.h index cb020d544a6..da8d3182551 100644 --- a/chromium/third_party/blink/renderer/modules/webusb/usb_alternate_interface.h +++ b/chromium/third_party/blink/renderer/modules/webusb/usb_alternate_interface.h @@ -20,12 +20,12 @@ class USBAlternateInterface : public ScriptWrappable { public: static USBAlternateInterface* Create(const USBInterface*, - size_t alternate_index); + wtf_size_t alternate_index); static USBAlternateInterface* Create(const USBInterface*, - size_t alternate_setting, + uint8_t alternate_setting, ExceptionState&); - USBAlternateInterface(const USBInterface*, size_t alternate_index); + USBAlternateInterface(const USBInterface*, wtf_size_t alternate_index); const device::mojom::blink::UsbAlternateInterfaceInfo& Info() const; @@ -40,7 +40,7 @@ class USBAlternateInterface : public ScriptWrappable { private: Member<const USBInterface> interface_; - const size_t alternate_index_; + const wtf_size_t alternate_index_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_configuration.cc b/chromium/third_party/blink/renderer/modules/webusb/usb_configuration.cc index 582ffe46995..cc21bf0ffd5 100644 --- a/chromium/third_party/blink/renderer/modules/webusb/usb_configuration.cc +++ b/chromium/third_party/blink/renderer/modules/webusb/usb_configuration.cc @@ -12,15 +12,15 @@ namespace blink { USBConfiguration* USBConfiguration::Create(const USBDevice* device, - size_t configuration_index) { + wtf_size_t configuration_index) { return new USBConfiguration(device, configuration_index); } USBConfiguration* USBConfiguration::Create(const USBDevice* device, - size_t configuration_value, + uint8_t configuration_value, ExceptionState& exception_state) { const auto& configurations = device->Info().configurations; - for (size_t i = 0; i < configurations.size(); ++i) { + for (wtf_size_t i = 0; i < configurations.size(); ++i) { if (configurations[i]->configuration_value == configuration_value) return new USBConfiguration(device, i); } @@ -29,7 +29,7 @@ USBConfiguration* USBConfiguration::Create(const USBDevice* device, } USBConfiguration::USBConfiguration(const USBDevice* device, - size_t configuration_index) + wtf_size_t configuration_index) : device_(device), configuration_index_(configuration_index) { DCHECK(device_); DCHECK_LT(configuration_index_, device_->Info().configurations.size()); @@ -39,7 +39,7 @@ const USBDevice* USBConfiguration::Device() const { return device_; } -size_t USBConfiguration::Index() const { +wtf_size_t USBConfiguration::Index() const { return configuration_index_; } @@ -50,7 +50,7 @@ const device::mojom::blink::UsbConfigurationInfo& USBConfiguration::Info() HeapVector<Member<USBInterface>> USBConfiguration::interfaces() const { HeapVector<Member<USBInterface>> interfaces; - for (size_t i = 0; i < Info().interfaces.size(); ++i) + for (wtf_size_t i = 0; i < Info().interfaces.size(); ++i) interfaces.push_back(USBInterface::Create(this, i)); return interfaces; } diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_configuration.h b/chromium/third_party/blink/renderer/modules/webusb/usb_configuration.h index c71bfea9f8c..c8ed6bc7063 100644 --- a/chromium/third_party/blink/renderer/modules/webusb/usb_configuration.h +++ b/chromium/third_party/blink/renderer/modules/webusb/usb_configuration.h @@ -19,15 +19,16 @@ class USBConfiguration : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: - static USBConfiguration* Create(const USBDevice*, size_t configuration_index); static USBConfiguration* Create(const USBDevice*, - size_t configuration_value, + wtf_size_t configuration_index); + static USBConfiguration* Create(const USBDevice*, + uint8_t configuration_value, ExceptionState&); - USBConfiguration(const USBDevice*, size_t configuration_index); + USBConfiguration(const USBDevice*, wtf_size_t configuration_index); const USBDevice* Device() const; - size_t Index() const; + wtf_size_t Index() const; const device::mojom::blink::UsbConfigurationInfo& Info() const; uint8_t configurationValue() const { return Info().configuration_value; } @@ -38,7 +39,7 @@ class USBConfiguration : public ScriptWrappable { private: Member<const USBDevice> device_; - const size_t configuration_index_; + const wtf_size_t configuration_index_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_device.cc b/chromium/third_party/blink/renderer/modules/webusb/usb_device.cc index f74584f3323..d46935c3fd0 100644 --- a/chromium/third_party/blink/renderer/modules/webusb/usb_device.cc +++ b/chromium/third_party/blink/renderer/modules/webusb/usb_device.cc @@ -116,13 +116,14 @@ USBDevice::USBDevice(UsbDeviceInfoPtr device_info, device_(std::move(device)), opened_(false), device_state_change_in_progress_(false), - configuration_index_(-1) { + configuration_index_(kNotFound) { if (device_) { device_.set_connection_error_handler( WTF::Bind(&USBDevice::OnConnectionError, WrapWeakPersistent(this))); } - int configuration_index = FindConfigurationIndex(Info().active_configuration); - if (configuration_index != -1) + wtf_size_t configuration_index = + FindConfigurationIndex(Info().active_configuration); + if (configuration_index != kNotFound) OnConfigurationSelected(true /* success */, configuration_index); } @@ -132,27 +133,28 @@ USBDevice::~USBDevice() { DCHECK(device_requests_.IsEmpty()); } -bool USBDevice::IsInterfaceClaimed(size_t configuration_index, - size_t interface_index) const { - return configuration_index_ != -1 && - static_cast<size_t>(configuration_index_) == configuration_index && +bool USBDevice::IsInterfaceClaimed(wtf_size_t configuration_index, + wtf_size_t interface_index) const { + return configuration_index_ != kNotFound && + configuration_index_ == configuration_index && claimed_interfaces_.Get(interface_index); } -size_t USBDevice::SelectedAlternateInterface(size_t interface_index) const { +wtf_size_t USBDevice::SelectedAlternateInterface( + wtf_size_t interface_index) const { return selected_alternates_[interface_index]; } USBConfiguration* USBDevice::configuration() const { - if (configuration_index_ != -1) + if (configuration_index_ != kNotFound) return USBConfiguration::Create(this, configuration_index_); return nullptr; } HeapVector<Member<USBConfiguration>> USBDevice::configurations() const { - size_t num_configurations = Info().configurations.size(); + wtf_size_t num_configurations = Info().configurations.size(); HeapVector<Member<USBConfiguration>> configurations(num_configurations); - for (size_t i = 0; i < num_configurations; ++i) + for (wtf_size_t i = 0; i < num_configurations; ++i) configurations[i] = USBConfiguration::Create(this, i); return configurations; } @@ -198,8 +200,9 @@ ScriptPromise USBDevice::selectConfiguration(ScriptState* script_state, resolver->Reject(DOMException::Create( DOMExceptionCode::kInvalidStateError, kOpenRequired)); } else { - int configuration_index = FindConfigurationIndex(configuration_value); - if (configuration_index == -1) { + wtf_size_t configuration_index = + FindConfigurationIndex(configuration_value); + if (configuration_index == kNotFound) { resolver->Reject(DOMException::Create(DOMExceptionCode::kNotFoundError, "The configuration value " "provided is not supported by " @@ -225,8 +228,8 @@ ScriptPromise USBDevice::claimInterface(ScriptState* script_state, ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); if (EnsureDeviceConfigured(resolver)) { - int interface_index = FindInterfaceIndex(interface_number); - if (interface_index == -1) { + wtf_size_t interface_index = FindInterfaceIndex(interface_number); + if (interface_index == kNotFound) { resolver->Reject(DOMException::Create(DOMExceptionCode::kNotFoundError, kInterfaceNotFound)); } else if (interface_state_change_in_progress_.Get(interface_index)) { @@ -261,8 +264,8 @@ ScriptPromise USBDevice::releaseInterface(ScriptState* script_state, ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); if (EnsureDeviceConfigured(resolver)) { - int interface_index = FindInterfaceIndex(interface_number); - if (interface_index == -1) { + wtf_size_t interface_index = FindInterfaceIndex(interface_number); + if (interface_index == kNotFound) { resolver->Reject(DOMException::Create(DOMExceptionCode::kNotFoundError, "The interface number provided is " "not supported by the device in " @@ -295,11 +298,11 @@ ScriptPromise USBDevice::selectAlternateInterface(ScriptState* script_state, ScriptPromise promise = resolver->Promise(); if (EnsureInterfaceClaimed(interface_number, resolver)) { // TODO(reillyg): This is duplicated work. - int interface_index = FindInterfaceIndex(interface_number); - DCHECK_NE(interface_index, -1); - int alternate_index = + wtf_size_t interface_index = FindInterfaceIndex(interface_number); + DCHECK_NE(interface_index, kNotFound); + wtf_size_t alternate_index = FindAlternateIndex(interface_index, alternate_setting); - if (alternate_index == -1) { + if (alternate_index == kNotFound) { resolver->Reject(DOMException::Create(DOMExceptionCode::kNotFoundError, "The alternate setting provided is " "not supported by the device in " @@ -484,43 +487,44 @@ void USBDevice::Trace(blink::Visitor* visitor) { ContextLifecycleObserver::Trace(visitor); } -int USBDevice::FindConfigurationIndex(uint8_t configuration_value) const { +wtf_size_t USBDevice::FindConfigurationIndex( + uint8_t configuration_value) const { const auto& configurations = Info().configurations; - for (size_t i = 0; i < configurations.size(); ++i) { + for (wtf_size_t i = 0; i < configurations.size(); ++i) { if (configurations[i]->configuration_value == configuration_value) return i; } - return -1; + return kNotFound; } -int USBDevice::FindInterfaceIndex(uint8_t interface_number) const { - DCHECK_NE(configuration_index_, -1); +wtf_size_t USBDevice::FindInterfaceIndex(uint8_t interface_number) const { + DCHECK_NE(configuration_index_, kNotFound); const auto& interfaces = Info().configurations[configuration_index_]->interfaces; - for (size_t i = 0; i < interfaces.size(); ++i) { + for (wtf_size_t i = 0; i < interfaces.size(); ++i) { if (interfaces[i]->interface_number == interface_number) return i; } - return -1; + return kNotFound; } -int USBDevice::FindAlternateIndex(size_t interface_index, - uint8_t alternate_setting) const { - DCHECK_NE(configuration_index_, -1); +wtf_size_t USBDevice::FindAlternateIndex(uint32_t interface_index, + uint8_t alternate_setting) const { + DCHECK_NE(configuration_index_, kNotFound); const auto& alternates = Info() .configurations[configuration_index_] ->interfaces[interface_index] ->alternates; - for (size_t i = 0; i < alternates.size(); ++i) { + for (wtf_size_t i = 0; i < alternates.size(); ++i) { if (alternates[i]->alternate_setting == alternate_setting) return i; } - return -1; + return kNotFound; } -bool USBDevice::IsProtectedInterfaceClass(int interface_index) const { - DCHECK_NE(configuration_index_, -1); - DCHECK_NE(interface_index, -1); +bool USBDevice::IsProtectedInterfaceClass(wtf_size_t interface_index) const { + DCHECK_NE(configuration_index_, kNotFound); + DCHECK_NE(interface_index, kNotFound); // USB Class Codes are defined by the USB-IF: // http://www.usb.org/developers/defined_class @@ -578,7 +582,7 @@ bool USBDevice::EnsureDeviceConfigured(ScriptPromiseResolver* resolver) const { } else if (!opened_) { resolver->Reject(DOMException::Create(DOMExceptionCode::kInvalidStateError, kOpenRequired)); - } else if (configuration_index_ == -1) { + } else if (configuration_index_ == kNotFound) { resolver->Reject( DOMException::Create(DOMExceptionCode::kInvalidStateError, "The device must have a configuration selected.")); @@ -592,8 +596,8 @@ bool USBDevice::EnsureInterfaceClaimed(uint8_t interface_number, ScriptPromiseResolver* resolver) const { if (!EnsureDeviceConfigured(resolver)) return false; - int interface_index = FindInterfaceIndex(interface_number); - if (interface_index == -1) { + wtf_size_t interface_index = FindInterfaceIndex(interface_number); + if (interface_index == kNotFound) { resolver->Reject(DOMException::Create(DOMExceptionCode::kNotFoundError, kInterfaceNotFound)); } else if (interface_state_change_in_progress_.Get(interface_index)) { @@ -632,7 +636,7 @@ bool USBDevice::EnsureEndpointAvailable(bool in_transfer, } bool USBDevice::AnyInterfaceChangeInProgress() const { - for (size_t i = 0; i < interface_state_change_in_progress_.size(); ++i) { + for (wtf_size_t i = 0; i < interface_state_change_in_progress_.size(); ++i) { if (interface_state_change_in_progress_.QuickGet(i)) return true; } @@ -660,13 +664,13 @@ UsbControlTransferParamsPtr USBDevice::ConvertControlTransferParameters( if (parameters.recipient() == "device") { mojo_parameters->recipient = UsbControlTransferRecipient::DEVICE; } else if (parameters.recipient() == "interface") { - size_t interface_number = parameters.index() & 0xff; + uint8_t interface_number = parameters.index() & 0xff; if (!EnsureInterfaceClaimed(interface_number, resolver)) return nullptr; mojo_parameters->recipient = UsbControlTransferRecipient::INTERFACE; } else if (parameters.recipient() == "endpoint") { bool in_transfer = parameters.index() & 0x80; - size_t endpoint_number = parameters.index() & 0x0f; + uint8_t endpoint_number = parameters.index() & 0x0f; if (!EnsureEndpointAvailable(in_transfer, endpoint_number, resolver)) return nullptr; mojo_parameters->recipient = UsbControlTransferRecipient::ENDPOINT; @@ -685,7 +689,7 @@ UsbControlTransferParamsPtr USBDevice::ConvertControlTransferParameters( return mojo_parameters; } -void USBDevice::SetEndpointsForInterface(size_t interface_index, bool set) { +void USBDevice::SetEndpointsForInterface(wtf_size_t interface_index, bool set) { const auto& configuration = *Info().configurations[configuration_index_]; const auto& interface = *configuration.interfaces[interface_index]; const auto& alternate = @@ -744,7 +748,7 @@ void USBDevice::OnDeviceOpenedOrClosed(bool opened) { device_state_change_in_progress_ = false; } -void USBDevice::AsyncSelectConfiguration(size_t configuration_index, +void USBDevice::AsyncSelectConfiguration(wtf_size_t configuration_index, ScriptPromiseResolver* resolver, bool success) { if (!MarkRequestComplete(resolver)) @@ -761,10 +765,10 @@ void USBDevice::AsyncSelectConfiguration(size_t configuration_index, } void USBDevice::OnConfigurationSelected(bool success, - size_t configuration_index) { + wtf_size_t configuration_index) { if (success) { configuration_index_ = configuration_index; - size_t num_interfaces = + wtf_size_t num_interfaces = Info().configurations[configuration_index_]->interfaces.size(); claimed_interfaces_.ClearAll(); claimed_interfaces_.Resize(num_interfaces); @@ -778,7 +782,7 @@ void USBDevice::OnConfigurationSelected(bool success, device_state_change_in_progress_ = false; } -void USBDevice::AsyncClaimInterface(size_t interface_index, +void USBDevice::AsyncClaimInterface(wtf_size_t interface_index, ScriptPromiseResolver* resolver, bool success) { if (!MarkRequestComplete(resolver)) @@ -793,7 +797,7 @@ void USBDevice::AsyncClaimInterface(size_t interface_index, } } -void USBDevice::AsyncReleaseInterface(size_t interface_index, +void USBDevice::AsyncReleaseInterface(wtf_size_t interface_index, ScriptPromiseResolver* resolver, bool success) { if (!MarkRequestComplete(resolver)) @@ -809,7 +813,7 @@ void USBDevice::AsyncReleaseInterface(size_t interface_index, } void USBDevice::OnInterfaceClaimedOrUnclaimed(bool claimed, - size_t interface_index) { + wtf_size_t interface_index) { if (claimed) { claimed_interfaces_.Set(interface_index); } else { @@ -820,8 +824,8 @@ void USBDevice::OnInterfaceClaimedOrUnclaimed(bool claimed, interface_state_change_in_progress_.Clear(interface_index); } -void USBDevice::AsyncSelectAlternateInterface(size_t interface_index, - size_t alternate_index, +void USBDevice::AsyncSelectAlternateInterface(wtf_size_t interface_index, + wtf_size_t alternate_index, ScriptPromiseResolver* resolver, bool success) { if (!MarkRequestComplete(resolver)) diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_device.h b/chromium/third_party/blink/renderer/modules/webusb/usb_device.h index 41b611655fc..c106b4b8b86 100644 --- a/chromium/third_party/blink/renderer/modules/webusb/usb_device.h +++ b/chromium/third_party/blink/renderer/modules/webusb/usb_device.h @@ -40,9 +40,9 @@ class USBDevice : public ScriptWrappable, public ContextLifecycleObserver { const device::mojom::blink::UsbDeviceInfo& Info() const { return *device_info_; } - bool IsInterfaceClaimed(size_t configuration_index, - size_t interface_index) const; - size_t SelectedAlternateInterface(size_t interface_index) const; + bool IsInterfaceClaimed(wtf_size_t configuration_index, + wtf_size_t interface_index) const; + wtf_size_t SelectedAlternateInterface(wtf_size_t interface_index) const; // USBDevice.idl uint8_t usbVersionMajor() const { return Info().usb_version_major; } @@ -105,11 +105,11 @@ class USBDevice : public ScriptWrappable, public ContextLifecycleObserver { void Trace(blink::Visitor*) override; private: - int FindConfigurationIndex(uint8_t configuration_value) const; - int FindInterfaceIndex(uint8_t interface_number) const; - int FindAlternateIndex(size_t interface_index, - uint8_t alternate_setting) const; - bool IsProtectedInterfaceClass(int interface_index) const; + wtf_size_t FindConfigurationIndex(uint8_t configuration_value) const; + wtf_size_t FindInterfaceIndex(uint8_t interface_number) const; + wtf_size_t FindAlternateIndex(wtf_size_t interface_index, + uint8_t alternate_setting) const; + bool IsProtectedInterfaceClass(wtf_size_t interface_index) const; bool EnsureNoDeviceOrInterfaceChangeInProgress(ScriptPromiseResolver*) const; bool EnsureDeviceConfigured(ScriptPromiseResolver*) const; bool EnsureInterfaceClaimed(uint8_t interface_number, @@ -121,25 +121,25 @@ class USBDevice : public ScriptWrappable, public ContextLifecycleObserver { device::mojom::blink::UsbControlTransferParamsPtr ConvertControlTransferParameters(const USBControlTransferParameters&, ScriptPromiseResolver*) const; - void SetEndpointsForInterface(size_t interface_index, bool set); + void SetEndpointsForInterface(wtf_size_t interface_index, bool set); void AsyncOpen(ScriptPromiseResolver*, device::mojom::blink::UsbOpenDeviceError); void AsyncClose(ScriptPromiseResolver*); void OnDeviceOpenedOrClosed(bool); - void AsyncSelectConfiguration(size_t configuration_index, + void AsyncSelectConfiguration(wtf_size_t configuration_index, ScriptPromiseResolver*, bool success); - void OnConfigurationSelected(bool success, size_t configuration_index); - void AsyncClaimInterface(size_t interface_index, + void OnConfigurationSelected(bool success, wtf_size_t configuration_index); + void AsyncClaimInterface(wtf_size_t interface_index, ScriptPromiseResolver*, bool success); - void AsyncReleaseInterface(size_t interface_index, + void AsyncReleaseInterface(wtf_size_t interface_index, ScriptPromiseResolver*, bool success); - void OnInterfaceClaimedOrUnclaimed(bool claimed, size_t interface_index); - void AsyncSelectAlternateInterface(size_t interface_index, - size_t alternate_index, + void OnInterfaceClaimedOrUnclaimed(bool claimed, wtf_size_t interface_index); + void AsyncSelectAlternateInterface(wtf_size_t interface_index, + wtf_size_t alternate_index, ScriptPromiseResolver*, bool success); void AsyncControlTransferIn(ScriptPromiseResolver*, @@ -172,10 +172,10 @@ class USBDevice : public ScriptWrappable, public ContextLifecycleObserver { HeapHashSet<Member<ScriptPromiseResolver>> device_requests_; bool opened_; bool device_state_change_in_progress_; - int configuration_index_; + wtf_size_t configuration_index_; WTF::BitVector claimed_interfaces_; WTF::BitVector interface_state_change_in_progress_; - WTF::Vector<size_t> selected_alternates_; + WTF::Vector<wtf_size_t> selected_alternates_; WTF::BitVector in_endpoints_; WTF::BitVector out_endpoints_; }; diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_endpoint.cc b/chromium/third_party/blink/renderer/modules/webusb/usb_endpoint.cc index 0152b9a70d9..5a0043c1734 100644 --- a/chromium/third_party/blink/renderer/modules/webusb/usb_endpoint.cc +++ b/chromium/third_party/blink/renderer/modules/webusb/usb_endpoint.cc @@ -45,19 +45,19 @@ String ConvertTypeToEnum(const UsbTransferType& type) { } // namespace USBEndpoint* USBEndpoint::Create(const USBAlternateInterface* alternate, - size_t endpoint_index) { + wtf_size_t endpoint_index) { return new USBEndpoint(alternate, endpoint_index); } USBEndpoint* USBEndpoint::Create(const USBAlternateInterface* alternate, - size_t endpoint_number, + uint8_t endpoint_number, const String& direction, ExceptionState& exception_state) { UsbTransferDirection mojo_direction = direction == "in" ? UsbTransferDirection::INBOUND : UsbTransferDirection::OUTBOUND; const auto& endpoints = alternate->Info().endpoints; - for (size_t i = 0; i < endpoints.size(); ++i) { + for (wtf_size_t i = 0; i < endpoints.size(); ++i) { const auto& endpoint = endpoints[i]; if (endpoint->endpoint_number == endpoint_number && endpoint->direction == mojo_direction) @@ -69,7 +69,7 @@ USBEndpoint* USBEndpoint::Create(const USBAlternateInterface* alternate, } USBEndpoint::USBEndpoint(const USBAlternateInterface* alternate, - size_t endpoint_index) + wtf_size_t endpoint_index) : alternate_(alternate), endpoint_index_(endpoint_index) { DCHECK(alternate_); DCHECK_LT(endpoint_index_, alternate_->Info().endpoints.size()); diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_endpoint.h b/chromium/third_party/blink/renderer/modules/webusb/usb_endpoint.h index 7a4759047bb..663a1d4006f 100644 --- a/chromium/third_party/blink/renderer/modules/webusb/usb_endpoint.h +++ b/chromium/third_party/blink/renderer/modules/webusb/usb_endpoint.h @@ -19,13 +19,13 @@ class USBEndpoint : public ScriptWrappable { public: static USBEndpoint* Create(const USBAlternateInterface*, - size_t endpoint_index); + wtf_size_t endpoint_index); static USBEndpoint* Create(const USBAlternateInterface*, - size_t endpoint_number, + uint8_t endpoint_number, const String& direction, ExceptionState&); - USBEndpoint(const USBAlternateInterface*, size_t endpoint_index); + USBEndpoint(const USBAlternateInterface*, wtf_size_t endpoint_index); const device::mojom::blink::UsbEndpointInfo& Info() const; @@ -38,7 +38,7 @@ class USBEndpoint : public ScriptWrappable { private: Member<const USBAlternateInterface> alternate_; - const size_t endpoint_index_; + const wtf_size_t endpoint_index_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_interface.cc b/chromium/third_party/blink/renderer/modules/webusb/usb_interface.cc index 4091c9a38f9..4193de72179 100644 --- a/chromium/third_party/blink/renderer/modules/webusb/usb_interface.cc +++ b/chromium/third_party/blink/renderer/modules/webusb/usb_interface.cc @@ -13,16 +13,16 @@ namespace blink { USBInterface* USBInterface::Create(const USBConfiguration* configuration, - size_t interface_index) { + wtf_size_t interface_index) { return new USBInterface(configuration->Device(), configuration->Index(), interface_index); } USBInterface* USBInterface::Create(const USBConfiguration* configuration, - size_t interface_number, + uint8_t interface_number, ExceptionState& exception_state) { const auto& interfaces = configuration->Info().interfaces; - for (size_t i = 0; i < interfaces.size(); ++i) { + for (wtf_size_t i = 0; i < interfaces.size(); ++i) { if (interfaces[i]->interface_number == interface_number) return new USBInterface(configuration->Device(), configuration->Index(), i); @@ -32,8 +32,8 @@ USBInterface* USBInterface::Create(const USBConfiguration* configuration, } USBInterface::USBInterface(const USBDevice* device, - size_t configuration_index, - size_t interface_index) + wtf_size_t configuration_index, + wtf_size_t interface_index) : device_(device), configuration_index_(configuration_index), interface_index_(interface_index) { @@ -58,7 +58,7 @@ USBAlternateInterface* USBInterface::alternate() const { HeapVector<Member<USBAlternateInterface>> USBInterface::alternates() const { HeapVector<Member<USBAlternateInterface>> alternates; - for (size_t i = 0; i < Info().alternates.size(); ++i) + for (wtf_size_t i = 0; i < Info().alternates.size(); ++i) alternates.push_back(USBAlternateInterface::Create(this, i)); return alternates; } diff --git a/chromium/third_party/blink/renderer/modules/webusb/usb_interface.h b/chromium/third_party/blink/renderer/modules/webusb/usb_interface.h index 2bcb1ba7ee1..a8639a6cf41 100644 --- a/chromium/third_party/blink/renderer/modules/webusb/usb_interface.h +++ b/chromium/third_party/blink/renderer/modules/webusb/usb_interface.h @@ -20,14 +20,15 @@ class USBInterface : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: - static USBInterface* Create(const USBConfiguration*, size_t interface_index); static USBInterface* Create(const USBConfiguration*, - size_t interface_number, + wtf_size_t interface_index); + static USBInterface* Create(const USBConfiguration*, + uint8_t interface_number, ExceptionState&); USBInterface(const USBDevice*, - size_t configuration_index, - size_t interface_index); + wtf_size_t configuration_index, + wtf_size_t interface_index); const device::mojom::blink::UsbInterfaceInfo& Info() const; @@ -40,8 +41,8 @@ class USBInterface : public ScriptWrappable { private: Member<const USBDevice> device_; - const size_t configuration_index_; - const size_t interface_index_; + const wtf_size_t configuration_index_; + const wtf_size_t interface_index_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr.cc b/chromium/third_party/blink/renderer/modules/xr/xr.cc index 94d75fb3781..6115eafb100 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr.cc @@ -6,6 +6,7 @@ #include "services/metrics/public/cpp/ukm_builders.h" #include "services/service_manager/public/cpp/interface_provider.h" +#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h" #include "third_party/blink/public/platform/interface_provider.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/dom/document.h" @@ -14,7 +15,6 @@ #include "third_party/blink/renderer/modules/event_modules.h" #include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/modules/xr/xr_device.h" -#include "third_party/blink/renderer/platform/feature_policy/feature_policy.h" namespace blink { namespace { @@ -73,8 +73,10 @@ ScriptPromise XR::requestDevice(ScriptState* script_state) { did_log_requestDevice_ = true; } - if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr)) { - // Only allow the call to be made if the appropraite feature policy is in + if (!frame->GetDocument()->IsFeatureEnabled( + mojom::FeaturePolicyFeature::kWebVr, + ReportOptions::kReportOnFailure)) { + // Only allow the call to be made if the appropriate feature policy is in // place. return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kSecurityError, diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.cc b/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.cc index 0d4bd264f26..b00c970e42b 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.cc @@ -4,6 +4,7 @@ #include "third_party/blink/renderer/modules/xr/xr_coordinate_system.h" +#include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" namespace blink { @@ -29,9 +30,18 @@ DOMFloat32Array* XRCoordinateSystem::getTransformTo( return nullptr; } +ExecutionContext* XRCoordinateSystem::GetExecutionContext() const { + return session()->GetExecutionContext(); +} + +const AtomicString& XRCoordinateSystem::InterfaceName() const { + return EventTargetNames::XRCoordinateSystem; +} + void XRCoordinateSystem::Trace(blink::Visitor* visitor) { visitor->Trace(session_); ScriptWrappable::Trace(visitor); + EventTargetWithInlineData::Trace(visitor); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.h b/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.h index 265f4c61e5b..9ba5d6ece16 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.h @@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_COORDINATE_SYSTEM_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_COORDINATE_SYSTEM_H_ +#include "third_party/blink/renderer/core/dom/events/event_target.h" #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/heap/handle.h" @@ -15,7 +16,7 @@ namespace blink { class TransformationMatrix; class XRSession; -class XRCoordinateSystem : public ScriptWrappable { +class XRCoordinateSystem : public EventTargetWithInlineData { DEFINE_WRAPPERTYPEINFO(); public: @@ -24,7 +25,11 @@ class XRCoordinateSystem : public ScriptWrappable { DOMFloat32Array* getTransformTo(XRCoordinateSystem*) const; - XRSession* session() { return session_; } + XRSession* session() const { return session_; } + + // EventTarget overrides. + ExecutionContext* GetExecutionContext() const override; + const AtomicString& InterfaceName() const override; virtual std::unique_ptr<TransformationMatrix> TransformBasePose( const TransformationMatrix& base_pose) = 0; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl b/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl index 42e5a9b1029..668360f27a0 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl +++ b/chromium/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl @@ -7,6 +7,6 @@ SecureContext, Exposed=Window, OriginTrialEnabled=WebXR -] interface XRCoordinateSystem { +] interface XRCoordinateSystem : EventTarget { Float32Array? getTransformTo(XRCoordinateSystem other); }; diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_device.cc b/chromium/third_party/blink/renderer/modules/xr/xr_device.cc index 92cd3cb2d44..a2a9d57ffcf 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_device.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_device.cc @@ -97,7 +97,7 @@ int64_t XRDevice::GetSourceId() const { ScriptPromise XRDevice::requestSession( ScriptState* script_state, const XRSessionCreationOptions& options) { - Document* doc = ToDocumentOrNull(ExecutionContext::From(script_state)); + Document* doc = To<Document>(ExecutionContext::From(script_state)); if (options.immersive() && !did_log_request_immersive_session_ && doc) { ukm::builders::XR_WebXR(GetSourceId()) @@ -117,7 +117,7 @@ ScriptPromise XRDevice::requestSession( // TODO(ijamardo): Should we just exit if there is not document? bool has_user_activation = - Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr); + LocalFrame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr); // Check if the current page state prevents the requested session from being // created. diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc b/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc index b985bd429f0..fa26356ef1c 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_frame_provider.cc @@ -12,6 +12,7 @@ #include "third_party/blink/renderer/core/dom/frame_request_callback_collection.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h" +#include "third_party/blink/renderer/core/loader/document_loader.h" #include "third_party/blink/renderer/modules/xr/xr.h" #include "third_party/blink/renderer/modules/xr/xr_device.h" #include "third_party/blink/renderer/modules/xr/xr_presentation_context.h" @@ -286,8 +287,12 @@ void XRFrameProvider::OnImmersiveFrameData( // between frames. Executing mojo tasks back to back within the same // execution context caused extreme input delay due to processing // multiple frames without yielding, see crbug.com/701444. - Platform::Current()->CurrentThread()->GetTaskRunner()->PostTask( - FROM_HERE, WTF::Bind(&XRFrameProvider::ProcessScheduledFrame, + // + // Used kInternalMedia since 1) this is not spec-ed and 2) this is media + // related then tasks should not be throttled or frozen in background tabs. + frame->GetTaskRunner(blink::TaskType::kInternalMedia) + ->PostTask(FROM_HERE, + WTF::Bind(&XRFrameProvider::ProcessScheduledFrame, WrapWeakPersistent(this), nullptr, high_res_now_ms)); } @@ -301,8 +306,13 @@ void XRFrameProvider::OnNonImmersiveVSync(double high_res_now_ms) { if (immersive_session_) return; - Platform::Current()->CurrentThread()->GetTaskRunner()->PostTask( - FROM_HERE, WTF::Bind(&XRFrameProvider::ProcessScheduledFrame, + LocalFrame* frame = device_->xr()->GetFrame(); + if (!frame) + return; + + frame->GetTaskRunner(blink::TaskType::kInternalMedia) + ->PostTask(FROM_HERE, + WTF::Bind(&XRFrameProvider::ProcessScheduledFrame, WrapWeakPersistent(this), nullptr, high_res_now_ms)); } @@ -340,8 +350,9 @@ void XRFrameProvider::OnNonImmersiveFrameData( .InMillisecondsF(); if (HasARSession()) { - Platform::Current()->CurrentThread()->GetTaskRunner()->PostTask( - FROM_HERE, WTF::Bind(&XRFrameProvider::ProcessScheduledFrame, + frame->GetTaskRunner(blink::TaskType::kInternalMedia) + ->PostTask(FROM_HERE, + WTF::Bind(&XRFrameProvider::ProcessScheduledFrame, WrapWeakPersistent(this), std::move(frame_data), high_res_now_ms)); } diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_layer.cc b/chromium/third_party/blink/renderer/modules/xr/xr_layer.cc index 6dd1aeaa952..84a957914b0 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_layer.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_layer.cc @@ -15,6 +15,8 @@ XRLayer::XRLayer(XRSession* session, XRLayerType layer_type) void XRLayer::OnFrameStart(const base::Optional<gpu::MailboxHolder>&) {} void XRLayer::OnFrameEnd() {} void XRLayer::OnResize() {} +void XRLayer::HandleBackgroundImage(const gpu::MailboxHolder&, const IntSize&) { +} void XRLayer::Trace(blink::Visitor* visitor) { visitor->Trace(session_); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_layer.h b/chromium/third_party/blink/renderer/modules/xr/xr_layer.h index 4150d74ef51..708ecb758d2 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_layer.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_layer.h @@ -29,6 +29,10 @@ class XRLayer : public ScriptWrappable { virtual void OnFrameEnd(); virtual void OnResize(); + // Called from XRSession::OnFrame handler. Params are background texture + // mailbox holder and its size respectively. + virtual void HandleBackgroundImage(const gpu::MailboxHolder&, const IntSize&); + void Trace(blink::Visitor*) override; private: diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_session.cc b/chromium/third_party/blink/renderer/modules/xr/xr_session.cc index 08fdc3abdb5..d2e7b43e2b2 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_session.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_session.cc @@ -249,7 +249,7 @@ void XRSession::cancelAnimationFrame(int id) { } HeapVector<Member<XRInputSource>> XRSession::getInputSources() const { - Document* doc = ToDocumentOrNull(GetExecutionContext()); + Document* doc = To<Document>(GetExecutionContext()); if (!did_log_getInputSources_ && doc) { ukm::builders::XR_WebXR(device_->GetSourceId()) .SetDidGetXRInputSources(1) @@ -492,10 +492,8 @@ void XRSession::OnFrame( // If using a background image, the caller must provide its pixel size // also. The source size can differ from the current drawing buffer size. DCHECK(background_size); - // TODO(https://crbug.com/837509): Remove this static_cast. - XRWebGLLayer* webgl_layer = static_cast<XRWebGLLayer*>(frame_base_layer); - webgl_layer->OverwriteColorBufferFromMailboxTexture( - background_mailbox_holder.value(), background_size.value()); + frame_base_layer->HandleBackgroundImage(background_mailbox_holder.value(), + background_size.value()); } // Resolve the queued requestAnimationFrame callbacks. All XR rendering will @@ -512,7 +510,7 @@ void XRSession::OnFrame( } void XRSession::LogGetPose() const { - Document* doc = ToDocumentOrNull(GetExecutionContext()); + Document* doc = To<Document>(GetExecutionContext()); if (!did_log_getDevicePose_ && doc) { did_log_getDevicePose_ = true; @@ -633,7 +631,7 @@ void XRSession::OnSelectEnd(XRInputSource* input_source) { return; std::unique_ptr<UserGestureIndicator> gesture_indicator = - Frame::NotifyUserActivation(frame); + LocalFrame::NotifyUserActivation(frame); XRInputSourceEvent* event = CreateInputSourceEvent(EventTypeNames::selectend, input_source); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc index be53fae2a05..99f98b4a820 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc +++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc @@ -311,6 +311,12 @@ void XRWebGLLayer::OnResize() { viewports_dirty_ = true; } +void XRWebGLLayer::HandleBackgroundImage( + const gpu::MailboxHolder& mailbox_holder, + const IntSize& size) { + OverwriteColorBufferFromMailboxTexture(mailbox_holder, size); +} + scoped_refptr<StaticBitmapImage> XRWebGLLayer::TransferToStaticBitmapImage( std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback) { return drawing_buffer_->TransferToStaticBitmapImage(out_release_callback); diff --git a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h index 7616c7ce1ae..6368b919df4 100644 --- a/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h +++ b/chromium/third_party/blink/renderer/modules/xr/xr_webgl_layer.h @@ -44,10 +44,8 @@ class XRWebGLLayer final : public XRLayer, WebGLRenderingContextOrWebGL2RenderingContext&) const; WebGLFramebuffer* framebuffer() const { return framebuffer_; } - unsigned long framebufferWidth() const { - return drawing_buffer_->size().Width(); - } - unsigned long framebufferHeight() const { + uint32_t framebufferWidth() const { return drawing_buffer_->size().Width(); } + uint32_t framebufferHeight() const { return drawing_buffer_->size().Height(); } @@ -69,6 +67,8 @@ class XRWebGLLayer final : public XRLayer, void OnFrameStart(const base::Optional<gpu::MailboxHolder>&) override; void OnFrameEnd() override; void OnResize() override; + void HandleBackgroundImage(const gpu::MailboxHolder&, + const IntSize&) override; void OverwriteColorBufferFromMailboxTexture(const gpu::MailboxHolder&, const IntSize& size); |