From 086c044dc34dfc0f74fbe41f4ecb402b2cd34884 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:13:33 +0200 Subject: Merging upstream version 125.0.1. Signed-off-by: Daniel Baumann --- dom/animation/DocumentTimeline.cpp | 16 +- dom/animation/EffectCompositor.h | 4 +- dom/base/BodyUtil.cpp | 4 +- dom/base/CharacterData.cpp | 27 +- dom/base/CharacterData.h | 2 +- dom/base/ChromeUtils.cpp | 108 +-- dom/base/ChromeUtils.h | 3 +- dom/base/ContentProcessMessageManager.cpp | 3 +- dom/base/DOMParser.cpp | 10 +- dom/base/DOMRequest.cpp | 256 ------ dom/base/DOMRequest.h | 103 --- dom/base/DOMRequestHelper.sys.mjs | 335 -------- dom/base/DirectionalityUtils.cpp | 745 ++++------------ dom/base/DirectionalityUtils.h | 5 +- dom/base/Document.cpp | 149 +++- dom/base/Document.h | 38 +- dom/base/DocumentFragment.h | 2 +- dom/base/Element.cpp | 135 ++- dom/base/Element.h | 44 +- dom/base/EventSource.cpp | 3 +- dom/base/FlushType.h | 2 +- dom/base/FragmentOrElement.cpp | 48 +- dom/base/IDTracker.cpp | 25 +- dom/base/InProcessBrowserChildMessageManager.cpp | 24 +- dom/base/InProcessBrowserChildMessageManager.h | 3 - dom/base/IndexedDBHelper.sys.mjs | 6 +- dom/base/MimeType.cpp | 14 +- dom/base/MimeType.h | 9 +- dom/base/Navigator.cpp | 3 + dom/base/Navigator.h | 1 - dom/base/RadioGroupContainer.cpp | 11 + dom/base/RadioGroupContainer.h | 1 + dom/base/ResizeObserver.cpp | 121 +-- dom/base/ResizeObserver.h | 31 +- dom/base/Selection.cpp | 59 +- dom/base/ShadowRoot.cpp | 9 +- dom/base/StructuredCloneHolder.cpp | 121 +++ dom/base/StructuredCloneHolder.h | 14 + dom/base/StructuredCloneTags.h | 4 + dom/base/UnbindContext.h | 35 + dom/base/UseCounters.conf | 1 - dom/base/crashtests/crashtests.list | 4 +- dom/base/moz.build | 6 +- dom/base/nsAttrValue.cpp | 4 +- dom/base/nsContentCID.h | 195 ----- dom/base/nsContentUtils.cpp | 41 +- dom/base/nsContentUtils.h | 129 ++- dom/base/nsCopySupport.cpp | 42 +- dom/base/nsDOMNavigationTiming.cpp | 3 +- dom/base/nsDOMWindowUtils.cpp | 1 + dom/base/nsFocusManager.cpp | 107 ++- dom/base/nsFocusManager.h | 30 +- dom/base/nsFrameLoader.cpp | 146 +--- dom/base/nsFrameLoader.h | 9 - dom/base/nsGlobalWindowInner.cpp | 33 +- dom/base/nsGlobalWindowInner.h | 13 + dom/base/nsGlobalWindowOuter.cpp | 1 - dom/base/nsIContent.h | 11 +- dom/base/nsIDOMRequestService.idl | 21 - dom/base/nsINode.cpp | 27 +- dom/base/nsINode.h | 42 +- dom/base/nsIScriptableContentIterator.idl | 8 - dom/base/nsImageLoadingContent.cpp | 14 +- dom/base/nsImageLoadingContent.h | 5 +- dom/base/nsJSEnvironment.cpp | 15 + dom/base/nsObjectLoadingContent.cpp | 8 +- dom/base/nsObjectLoadingContent.h | 2 +- dom/base/nsTextNode.cpp | 19 +- dom/base/nsTextNode.h | 2 +- dom/base/nsWindowRoot.cpp | 2 - dom/base/test/browser.toml | 10 + dom/base/test/browser_object_attachment.js | 168 ++++ dom/base/test/chrome.toml | 3 - dom/base/test/chrome/bug418986-1.js | 3 + dom/base/test/chrome/chrome.toml | 4 - dom/base/test/chrome/file_bug549682.xhtml | 10 +- dom/base/test/chrome/file_bug616841.xhtml | 2 +- dom/base/test/chrome/test_bug1339722.html | 4 +- dom/base/test/chrome/test_bug339494.xhtml | 2 +- dom/base/test/chrome/test_bug429785.xhtml | 2 +- dom/base/test/chrome/test_bug430050.xhtml | 2 +- .../test/chrome/test_chromeOuterWindowID.xhtml | 2 +- dom/base/test/chrome/test_swapFrameLoaders.xhtml | 25 - dom/base/test/chrome/title_window.xhtml | 4 +- .../test/chrome/window_nsITextInputProcessor.xhtml | 4 +- dom/base/test/chrome/window_swapFrameLoaders.xhtml | 223 ----- dom/base/test/common_postMessages.js | 2 + dom/base/test/file_bug1008126_worker.js | 2 + dom/base/test/file_bug945152_worker.js | 1 + dom/base/test/file_focus_shadow_dom.html | 24 +- dom/base/test/file_img_attachment.jpg | Bin 0 -> 2711 bytes dom/base/test/file_img_attachment.jpg^headers^ | 1 + dom/base/test/file_img_object_attachment.html | 6 + dom/base/test/file_pdf_attachment.pdf | Bin 0 -> 1568 bytes dom/base/test/file_pdf_attachment.pdf^headers^ | 2 + dom/base/test/file_pdf_object_attachment.html | 6 + .../test/fullscreen/MozDomFullscreen_chrome.xhtml | 2 +- .../browser_fullscreen-navigation-history-race.js | 2 +- .../browser_fullscreen-tab-close-race.js | 2 +- dom/base/test/fullscreen/file_fullscreen-api.html | 22 +- .../fullscreen/file_fullscreen-bug-1798219-2.html | 2 +- .../fullscreen/file_fullscreen-bug-1798219.html | 2 +- .../test/fullscreen/file_fullscreen-denied.html | 2 +- .../fullscreen/file_fullscreen-esc-exit-inner.html | 2 +- .../test/fullscreen/file_fullscreen-esc-exit.html | 4 +- .../test/fullscreen/file_fullscreen-shadowdom.html | 2 +- .../fullscreen/file_fullscreen-svg-element.html | 2 +- dom/base/test/fullscreen/fullscreen.xhtml | 2 +- dom/base/test/fullscreen/fullscreen_helpers.js | 4 +- dom/base/test/fullscreen/test_fullscreen-api.html | 2 +- .../test/fullscreen/test_fullscreen_modal.html | 11 +- dom/base/test/gtest/TestMimeType.cpp | 142 ++- dom/base/test/meta_viewport/viewport_helpers.js | 1 + dom/base/test/mochitest.toml | 5 +- dom/base/test/test_domrequest.html | 233 ----- dom/base/test/test_domrequesthelper.xhtml | 549 ------------ dom/base/test/test_focus_radio.html | 90 ++ dom/base/test/unit/test_error_codes.js | 2 +- .../test/useractivation/file_clipboard_common.js | 8 +- .../test_popup_blocker_async_callback.html | 2 +- .../test_useractivation_scrollbar.html | 2 +- dom/base/use_counter_metrics.yaml | 34 + dom/bindings/BindingDeclarations.h | 12 +- dom/bindings/BindingIPCUtils.h | 9 + dom/bindings/BindingUtils.h | 48 +- dom/bindings/Bindings.conf | 21 + dom/bindings/Codegen.py | 171 ++-- dom/bindings/Configuration.py | 27 +- dom/bindings/mozwebidlcodegen/__init__.py | 18 +- dom/bindings/parser/WebIDL.py | 134 +-- dom/bindings/parser/tests/test_builtin_filename.py | 2 +- .../parser/tests/test_distinguishability.py | 97 ++- .../tests/test_legacyTreatNonObjectAsNull.py | 11 + .../parser/tests/test_union_callback_dict.py | 132 +++ dom/bindings/test/TestBindingHeader.h | 14 + dom/bindings/test/TestCodeGen.webidl | 13 + dom/bindings/test/TestInterfaceJS.sys.mjs | 8 +- dom/bindings/test/test_async_iterable.html | 2 +- .../test_bug1123516_maplikesetlikechrome.xhtml | 4 +- dom/bindings/test/test_observablearray.html | 16 +- dom/bindings/test/test_observablearray_helper.html | 14 +- .../test/test_observablearray_proxyhandler.html | 10 +- ...test_promise_rejections_from_jsimplemented.html | 2 +- dom/bindings/test/test_sequence_wrapping.html | 2 +- .../tests/browser_private_browsing.js | 8 +- dom/broadcastchannel/tests/file_mozbrowser.html | 20 - dom/broadcastchannel/tests/file_mozbrowser2.html | 21 - dom/broadcastchannel/tests/iframe_mozbrowser.html | 15 - dom/broadcastchannel/tests/iframe_mozbrowser2.html | 15 - dom/broadcastchannel/tests/mochitest.toml | 4 - dom/broadcastchannel/tests/test_bfcache.html | 2 +- .../tests/test_event_listener_leaks.html | 2 +- .../tests/test_message_after_close.html | 2 +- dom/browser-element/BrowserElementChild.js | 42 - dom/browser-element/BrowserElementChildPreload.js | 290 ------- dom/browser-element/BrowserElementParent.jsm | 276 ------ .../BrowserElementPromptService.jsm | 720 ---------------- dom/browser-element/components.conf | 14 - dom/browser-element/moz.build | 37 - dom/browser-element/nsIBrowserElementAPI.idl | 44 - dom/cache/Cache.cpp | 5 +- dom/cache/CacheStorage.cpp | 5 +- dom/cache/Connection.cpp | 5 + dom/cache/DBAction.cpp | 3 +- dom/cache/DBSchema.cpp | 14 +- dom/cache/Manager.cpp | 36 + dom/cache/test/browser/browser_cache_pb_window.js | 26 +- dom/cache/test/mochitest/driver.js | 8 +- dom/cache/test/mochitest/test_cache.js | 2 +- .../test/mochitest/test_cache_match_request.js | 2 +- .../test/mochitest/test_cache_orphaned_body.html | 12 +- .../test/mochitest/test_cache_orphaned_cache.html | 8 +- dom/cache/test/mochitest/test_cache_padding.html | 6 +- dom/cache/test/mochitest/test_cache_restart.html | 6 +- dom/cache/test/mochitest/test_cache_shrink.html | 8 +- .../test/mochitest/test_cache_tons_of_fd.html | 2 +- .../test/mochitest/test_cache_updateUsage.html | 6 +- dom/cache/test/mochitest/test_caches.js | 2 +- dom/cache/test/xpcshell/test_empty_directories.js | 2 +- dom/canvas/CacheInvalidator.h | 19 +- dom/canvas/CanvasRenderingContext2D.cpp | 271 +++--- dom/canvas/CanvasRenderingContext2D.h | 32 +- dom/canvas/ClientWebGLContext.cpp | 139 ++- dom/canvas/ClientWebGLContext.h | 12 +- dom/canvas/DmdStdContainers.h | 100 +++ dom/canvas/DrawTargetWebgl.cpp | 41 +- dom/canvas/DrawTargetWebgl.h | 3 +- dom/canvas/HostWebGLContext.h | 34 +- dom/canvas/ImageBitmap.cpp | 27 +- dom/canvas/ImageUtils.cpp | 40 +- dom/canvas/ImageUtils.h | 5 +- dom/canvas/OffscreenCanvasDisplayHelper.cpp | 164 ++-- dom/canvas/QueueParamTraits.h | 12 +- dom/canvas/TexUnpackBlob.cpp | 87 +- dom/canvas/TexUnpackBlob.h | 2 +- dom/canvas/WebGL2Context.h | 4 +- dom/canvas/WebGL2ContextFramebuffers.cpp | 14 +- dom/canvas/WebGLChild.cpp | 33 +- dom/canvas/WebGLContext.cpp | 33 +- dom/canvas/WebGLContext.h | 11 +- dom/canvas/WebGLContextGL.cpp | 16 +- dom/canvas/WebGLIpdl.h | 139 ++- dom/canvas/WebGLMemoryTracker.cpp | 15 +- dom/canvas/WebGLQueueParamTraits.h | 18 +- dom/canvas/WebGLShaderValidator.h | 2 +- dom/canvas/WebGLTexture.h | 8 + dom/canvas/WebGLTextureUpload.cpp | 22 +- dom/canvas/WebGLTypes.h | 143 +-- dom/canvas/crashtests/crashtests.list | 6 +- dom/canvas/moz.build | 1 + dom/canvas/nsICanvasRenderingContextInternal.cpp | 24 + dom/canvas/nsICanvasRenderingContextInternal.h | 4 + dom/canvas/test/mochitest.toml | 4 + .../test/reftest/colors/_generated_reftest.list | 176 ++++ dom/canvas/test/reftest/colors/color_canvas.html | 461 ++++++++++ .../colors/generate_color_canvas_reftests.py | 427 +++++++++ dom/canvas/test/reftest/filters/reftest.list | 4 +- dom/canvas/test/reftest/reftest.list | 12 +- .../test/test_accelerated_canvas_context_loss.html | 121 +++ .../test/webgl-conf/generated-mochitest.toml | 9 +- dom/canvas/test/webgl-conf/mochitest-errata.toml | 10 +- dom/canvas/test/webgl-mochitest/mochitest.toml | 53 +- dom/chrome-webidl/ChromeUtils.webidl | 18 +- dom/chrome-webidl/ConsoleInstance.webidl | 179 ++++ dom/chrome-webidl/FrameLoader.webidl | 7 - dom/chrome-webidl/IOUtils.webidl | 2 +- dom/chrome-webidl/InspectorUtils.webidl | 36 +- dom/chrome-webidl/JSProcessActor.webidl | 3 + dom/chrome-webidl/JSWindowActor.webidl | 3 + dom/chrome-webidl/moz.build | 1 + dom/clients/manager/ClientIPCUtils.h | 14 +- dom/clients/manager/ClientManagerParent.cpp | 7 +- dom/clients/manager/ClientSourceParent.cpp | 67 +- dom/clients/manager/ClientSourceParent.h | 4 +- dom/console/Console.h | 1 + dom/console/ConsoleAPIStorage.sys.mjs | 2 +- dom/console/ConsoleInstance.cpp | 10 +- dom/console/ConsoleUtils.cpp | 1 + .../tests/mochitest/test_accounts_error.html | 4 +- .../tests/mochitest/test_accounts_redirect.html | 4 +- .../tests/mochitest/test_delay_reject.html | 4 +- .../tests/mochitest/test_empty_provider_list.html | 4 +- .../mochitest/test_get_without_providers.html | 4 +- .../tests/mochitest/test_idtoken_error.html | 4 +- .../tests/mochitest/test_idtoken_redirect.html | 4 +- .../identity/tests/mochitest/test_no_accounts.html | 4 +- .../identity/tests/mochitest/test_simple.html | 2 +- .../tests/mochitest/test_two_accounts.html | 2 +- .../tests/mochitest/test_two_providers.html | 2 +- .../mochitest/test_wrong_provider_in_manifest.html | 4 +- dom/crypto/test/test-array.js | 2 +- dom/crypto/test/test-worker.js | 2 +- dom/crypto/test/test_WebCrypto.html | 4 +- dom/crypto/test/test_WebCrypto_ECDH.html | 2 +- dom/crypto/test/test_WebCrypto_JWK.html | 2 +- dom/docs/webIdlBindings/index.md | 36 +- dom/encoding/test/reftest/reftest.list | 4 +- dom/encoding/test/test_TextDecoder.js | 2 +- dom/events/Clipboard.cpp | 84 +- dom/events/Clipboard.h | 7 +- dom/events/DataTransfer.cpp | 114 ++- dom/events/DataTransfer.h | 25 +- dom/events/EventListenerService.cpp | 63 -- dom/events/EventNameList.h | 3 + dom/events/PointerEventHandler.cpp | 51 +- dom/events/PointerEventHandler.h | 38 +- dom/events/TouchEvent.cpp | 2 +- dom/events/nsIEventListenerService.idl | 30 - ..._navigator_clipboard_contextmenu_suppression.js | 163 +++- dom/events/test/mochitest.toml | 3 + .../pointerevents/mochitest_support_external.js | 2 + dom/events/test/pointerevents/test_bug1315862.html | 4 +- dom/events/test/test_accesskey.html | 2 +- dom/events/test/test_bug226361.xhtml | 9 +- dom/events/test/test_bug238987.html | 2 +- dom/events/test/test_bug336682.js | 2 + dom/events/test/test_bug448602.html | 21 - .../test/test_mouse_events_after_touchend.html | 232 +++++ ...lit_keypress_event_model_on_old_Confluence.html | 2 +- ...ss_event_model_on_old_Office_Online_Server.html | 2 +- dom/fetch/FetchDriver.cpp | 46 +- dom/fetch/FetchIPCTypes.h | 34 +- dom/fetch/InternalRequest.cpp | 9 +- dom/fetch/InternalRequest.h | 8 + dom/fetch/Request.cpp | 71 +- dom/fetch/Request.h | 2 + dom/file/ipc/tests/script_file.js | 4 +- dom/file/tests/common_blob.js | 2 + dom/file/tests/worker_blob_reading.js | 2 + dom/file/tests/worker_fileReader.js | 2 + dom/file/uri/BlobURLInputStream.cpp | 7 +- dom/file/uri/BlobURLProtocolHandler.cpp | 7 +- dom/filesystem/compat/tests/script_entries.js | 4 +- dom/filesystem/compat/tests/test_basic.html | 18 +- dom/filesystem/tests/script_fileList.js | 4 +- dom/filesystem/tests/script_promptHandler.js | 6 +- dom/filesystem/tests/test_basic.html | 2 +- dom/filesystem/tests/test_webkitdirectory.html | 10 +- dom/fs/api/FileSystemDirectoryHandle.cpp | 4 +- dom/fs/api/FileSystemFileHandle.cpp | 2 +- dom/fs/api/FileSystemHandle.cpp | 2 +- dom/fs/child/FileSystemWritableFileStreamChild.h | 1 - dom/gamepad/fallback/FallbackGamepad.cpp | 1 + dom/gamepad/ipc/GamepadMessageUtils.h | 18 +- dom/html/ElementInternals.cpp | 44 + dom/html/ElementInternals.h | 28 + dom/html/FetchPriority.h | 11 + dom/html/HTMLAnchorElement.cpp | 4 +- dom/html/HTMLAnchorElement.h | 2 +- dom/html/HTMLAreaElement.cpp | 4 +- dom/html/HTMLAreaElement.h | 2 +- dom/html/HTMLButtonElement.cpp | 4 +- dom/html/HTMLButtonElement.h | 2 +- dom/html/HTMLDetailsElement.cpp | 5 +- dom/html/HTMLDialogElement.cpp | 4 +- dom/html/HTMLDialogElement.h | 2 +- dom/html/HTMLElement.cpp | 4 +- dom/html/HTMLElement.h | 2 +- dom/html/HTMLEmbedElement.cpp | 6 +- dom/html/HTMLEmbedElement.h | 2 +- dom/html/HTMLFormElement.cpp | 31 +- dom/html/HTMLFormElement.h | 8 +- dom/html/HTMLIFrameElement.h | 5 - dom/html/HTMLImageElement.cpp | 21 +- dom/html/HTMLImageElement.h | 4 +- dom/html/HTMLInputElement.cpp | 29 +- dom/html/HTMLInputElement.h | 2 +- dom/html/HTMLLegendElement.cpp | 4 +- dom/html/HTMLLegendElement.h | 2 +- dom/html/HTMLLinkElement.cpp | 20 +- dom/html/HTMLLinkElement.h | 3 +- dom/html/HTMLMarqueeElement.cpp | 4 +- dom/html/HTMLMarqueeElement.h | 2 +- dom/html/HTMLMediaElement.cpp | 5 +- dom/html/HTMLMediaElement.h | 2 +- dom/html/HTMLMetaElement.cpp | 4 +- dom/html/HTMLMetaElement.h | 2 +- dom/html/HTMLObjectElement.cpp | 6 +- dom/html/HTMLObjectElement.h | 2 +- dom/html/HTMLOptionElement.cpp | 4 +- dom/html/HTMLOptionElement.h | 2 +- dom/html/HTMLScriptElement.cpp | 16 + dom/html/HTMLScriptElement.h | 1 + dom/html/HTMLSelectElement.cpp | 4 +- dom/html/HTMLSelectElement.h | 2 +- dom/html/HTMLSharedElement.cpp | 4 +- dom/html/HTMLSharedElement.h | 2 +- dom/html/HTMLSlotElement.cpp | 4 +- dom/html/HTMLSlotElement.h | 2 +- dom/html/HTMLSourceElement.cpp | 4 +- dom/html/HTMLSourceElement.h | 2 +- dom/html/HTMLStyleElement.cpp | 27 +- dom/html/HTMLStyleElement.h | 7 +- dom/html/HTMLTableElement.cpp | 4 +- dom/html/HTMLTableElement.h | 2 +- dom/html/HTMLTemplateElement.h | 14 +- dom/html/HTMLTextAreaElement.cpp | 5 +- dom/html/HTMLTextAreaElement.h | 2 +- dom/html/HTMLTitleElement.cpp | 4 +- dom/html/HTMLTitleElement.h | 2 +- dom/html/HTMLTrackElement.cpp | 10 +- dom/html/HTMLTrackElement.h | 2 +- dom/html/HTMLVideoElement.cpp | 5 +- dom/html/HTMLVideoElement.h | 2 +- dom/html/TextControlState.cpp | 1 - dom/html/moz.build | 2 - dom/html/nsBrowserElement.cpp | 57 -- dom/html/nsBrowserElement.h | 57 -- dom/html/nsGenericHTMLElement.cpp | 45 +- dom/html/nsGenericHTMLElement.h | 8 +- dom/html/nsGenericHTMLFrameElement.cpp | 51 +- dom/html/nsGenericHTMLFrameElement.h | 25 +- dom/html/nsHTMLContentSink.cpp | 2 - dom/html/test/formData_test.js | 2 + dom/html/test/forms/test_change_event.html | 2 +- dom/html/test/forms/test_input_event.html | 2 +- dom/html/test/forms/test_input_file_picker.html | 2 +- dom/html/test/mochitest.toml | 30 +- dom/html/test/test_bug389797.html | 4 +- dom/html/test/test_bug500885.html | 2 +- dom/html/test/test_bug556645.html | 10 +- dom/html/test/test_bug592802.html | 2 +- .../test/test_filepicker_default_directory.html | 2 +- dom/html/test/test_input_file_cancel_event.html | 2 +- dom/html/test/test_input_files_not_nsIFile.html | 2 +- dom/html/test/test_multipleFilePicker.html | 2 +- dom/indexedDB/ActorsParent.cpp | 441 +++++----- dom/indexedDB/ActorsParent.h | 5 +- dom/indexedDB/ActorsParentCommon.cpp | 2 +- dom/indexedDB/IDBFactory.cpp | 35 +- dom/indexedDB/IndexedDatabaseManager.cpp | 45 +- dom/indexedDB/IndexedDatabaseManager.h | 3 + dom/indexedDB/SchemaUpgrades.cpp | 6 +- dom/indexedDB/SerializationHelpers.h | 7 +- dom/indexedDB/test/abort_on_reload.html | 6 +- dom/indexedDB/test/bfcache_page1.html | 2 +- dom/indexedDB/test/blob_worker_crash_iframe.html | 2 +- dom/indexedDB/test/browser_private_idb.js | 4 +- dom/indexedDB/test/bug839193.js | 2 +- .../error_events_abort_transactions_iframe.html | 6 +- dom/indexedDB/test/event_propagation_iframe.html | 4 +- .../test/exceptions_in_events_iframe.html | 4 +- dom/indexedDB/test/head.js | 2 +- dom/indexedDB/test/helpers.js | 4 +- dom/indexedDB/test/leaving_page_iframe.html | 2 +- dom/indexedDB/test/mochitest-common.toml | 6 +- dom/indexedDB/test/test_abort_on_reload.html | 2 +- dom/indexedDB/test/test_event_listener_leaks.html | 2 +- dom/indexedDB/test/test_open_for_principal.html | 1 + dom/indexedDB/test/third_party_window.html | 2 +- dom/indexedDB/test/unit/test_blocked_order.js | 8 +- .../test/unit/test_cleanup_transaction.js | 4 +- dom/indexedDB/test/unit/test_clear.js | 2 +- .../test/unit/test_connection_idle_maintenance.js | 97 +++ .../unit/test_connection_idle_maintenance_stop.js | 204 +++++ dom/indexedDB/test/unit/test_cursor_cycle.js | 2 +- dom/indexedDB/test/unit/test_cursor_mutation.js | 4 +- dom/indexedDB/test/unit/test_cursors.js | 4 +- dom/indexedDB/test/unit/test_database_onclose.js | 4 +- dom/indexedDB/test/unit/test_getAll.js | 2 +- .../test/unit/test_index_object_cursors.js | 4 +- .../test/unit/test_index_update_delete.js | 4 +- dom/indexedDB/test/unit/test_indexes_bad_values.js | 2 +- dom/indexedDB/test/unit/test_invalid_version.js | 1 + .../test/unit/test_quotaExceeded_recovery.js | 4 +- dom/indexedDB/test/unit/test_remove_objectStore.js | 2 +- dom/indexedDB/test/unit/test_setVersion_throw.js | 4 +- dom/indexedDB/test/unit/test_table_locks.js | 4 +- dom/indexedDB/test/unit/test_transaction_abort.js | 17 +- .../test/unit/test_transaction_abort_hang.js | 4 +- .../test/unit/xpcshell-head-parent-process.js | 14 +- .../test/unit/xpcshell-parent-process.toml | 4 + dom/interfaces/base/nsITextInputProcessor.idl | 8 - dom/interfaces/html/moz.build | 15 - dom/interfaces/html/nsIDOMMozBrowserFrame.idl | 27 - dom/interfaces/html/nsIMozBrowserFrame.idl | 34 - .../payments/nsIPaymentActionResponse.idl | 34 - dom/interfaces/payments/nsIPaymentAddress.idl | 7 - .../payments/nsIPaymentRequestService.idl | 2 - dom/interfaces/payments/nsIPaymentUIService.idl | 2 - dom/interfaces/push/nsIPushNotifier.idl | 3 - dom/ipc/BrowserChild.cpp | 11 +- dom/ipc/BrowserParent.cpp | 16 +- dom/ipc/BrowserParent.h | 3 +- dom/ipc/ContentChild.cpp | 82 +- dom/ipc/ContentChild.h | 3 - dom/ipc/ContentParent.cpp | 136 ++- dom/ipc/ContentParent.h | 11 +- dom/ipc/FilePickerParent.cpp | 16 +- dom/ipc/FilePickerParent.h | 10 +- dom/ipc/JSValidatorChild.cpp | 10 +- dom/ipc/PBrowser.ipdl | 2 +- dom/ipc/PContent.ipdl | 25 +- dom/ipc/ProcessHangMonitor.cpp | 30 +- dom/ipc/ProcessPriorityManager.cpp | 37 +- dom/ipc/ProcessPriorityManager.h | 2 - dom/ipc/jar.mn | 7 - dom/ipc/jsactor/JSActorManager.cpp | 14 +- dom/ipc/jsactor/JSActorService.cpp | 8 +- dom/ipc/moz.build | 2 - dom/ipc/tests/JSWindowActor/browser.toml | 5 +- .../tests/JSWindowActor/browser_crash_report.js | 2 +- .../JSWindowActor/browser_destroy_callbacks.js | 4 +- .../tests/JSWindowActor/browser_getActor_filter.js | 4 +- .../tests/browser_child_clipboard_restricted.js | 2 +- dom/ipc/tests/browser_gc_schedule.js | 4 +- dom/ipc/tests/browser_wpi_base.js | 4 +- .../tests/file_broadcast_currenturi_onload.html | 2 +- dom/ipc/tests/file_endless_js.html | 2 +- dom/ipc/tests/process_error.xhtml | 2 +- dom/ipc/tests/test_bug1086684.js | 2 +- dom/ipc/tests/test_temporaryfile_stream.html | 2 +- dom/ipc/tests/test_window_open_discarded_bc.html | 2 +- .../dom_localization/test_l10n_mutations.html | 2 +- dom/locales/en-US/chrome/security/csp.properties | 107 ++- .../en-US/chrome/security/security.properties | 2 +- dom/localstorage/LSSnapshot.cpp | 2 +- .../test/unit/databaseShadowing-shared.js | 2 + dom/locks/test/test_strongworker.html | 2 +- dom/manifest/ImageObjectProcessor.sys.mjs | 2 +- dom/manifest/Manifest.sys.mjs | 2 +- dom/manifest/ManifestIcons.sys.mjs | 2 +- .../test/test_ManifestProcessor_warnings.html | 2 +- dom/mathml/MathMLElement.cpp | 4 +- dom/mathml/MathMLElement.h | 2 +- dom/mathml/moz.build | 2 - dom/mathml/tests/mochitest/mochitest.toml | 3 - .../tests/mochitest/test_math_tabindex_focus.html | 47 - dom/media/ADTSDemuxer.cpp | 247 +----- dom/media/ADTSDemuxer.h | 16 +- dom/media/AudibilityMonitor.h | 2 +- dom/media/AudioSampleFormat.h | 234 +++-- dom/media/AudioSegment.h | 10 +- dom/media/CallbackThreadRegistry.cpp | 1 + dom/media/ChannelMediaDecoder.cpp | 8 +- dom/media/ExternalEngineStateMachine.cpp | 126 ++- dom/media/ExternalEngineStateMachine.h | 15 +- dom/media/IdpSandbox.sys.mjs | 2 +- dom/media/ImageToI420.cpp | 8 +- dom/media/MediaData.h | 14 +- dom/media/MediaDecoder.cpp | 18 +- dom/media/MediaDecoder.h | 25 + dom/media/MediaDecoderStateMachineBase.cpp | 4 +- dom/media/MediaDecoderStateMachineBase.h | 4 +- dom/media/MediaDevices.cpp | 6 +- dom/media/MediaInfo.h | 14 +- dom/media/MediaManager.cpp | 75 +- dom/media/MediaQueue.h | 86 +- dom/media/MediaStreamTrack.cpp | 2 +- dom/media/MediaTrackGraph.cpp | 6 + dom/media/PeerConnection.sys.mjs | 139 +-- dom/media/VideoFrameConverter.h | 21 +- dom/media/VideoUtils.cpp | 3 - .../test/browser/browser_autoplay_videoDocument.js | 4 +- dom/media/autoplay/test/browser/head.js | 8 +- .../file_autoplay_policy_eventdown_activation.html | 4 +- .../file_autoplay_policy_key_blacklist.html | 2 +- ...autoplay_policy_play_before_loadedmetadata.html | 2 +- .../file_autoplay_policy_unmute_pauses.html | 4 +- .../test/browser/browser_doctor_notification.js | 14 +- dom/media/eme/EMEUtils.cpp | 39 +- dom/media/eme/EMEUtils.h | 3 + dom/media/eme/KeySystemConfig.cpp | 37 +- dom/media/eme/KeySystemConfig.h | 7 + dom/media/eme/MediaKeySession.cpp | 23 +- dom/media/eme/MediaKeySession.h | 7 +- dom/media/eme/MediaKeySystemAccess.cpp | 85 +- dom/media/eme/MediaKeySystemAccess.h | 3 +- dom/media/eme/MediaKeySystemAccessManager.cpp | 3 +- dom/media/eme/MediaKeys.cpp | 17 +- .../eme/mediadrm/MediaDrmCDMCallbackProxy.cpp | 1 - dom/media/eme/mediafoundation/WMFCDMImpl.cpp | 107 +-- dom/media/eme/mediafoundation/WMFCDMImpl.h | 4 +- dom/media/eme/mediafoundation/WMFCDMProxy.cpp | 3 +- dom/media/flac/FlacDecoder.cpp | 8 +- dom/media/gmp/ChromiumCDMProxy.cpp | 3 +- dom/media/gmp/GMPChild.cpp | 47 +- dom/media/gmp/GMPDiskStorage.cpp | 1 - dom/media/gmp/GMPLoader.cpp | 2 +- dom/media/gmp/GMPParent.cpp | 16 +- dom/media/gmp/moz.build | 2 +- dom/media/gmp/rlz/moz.build | 6 +- dom/media/gtest/TestAudioSampleFormat.cpp | 116 +++ dom/media/gtest/TestAudioSegment.cpp | 16 +- dom/media/gtest/TestAudioTrackGraph.cpp | 2 +- dom/media/gtest/TestMediaDataDecoder.cpp | 3 +- dom/media/gtest/TestMediaDataEncoder.cpp | 9 +- dom/media/gtest/TestMediaQueue.cpp | 16 + dom/media/gtest/TestMediaUtils.cpp | 2 +- dom/media/gtest/moz.build | 1 + dom/media/ipc/MFCDMSerializers.h | 16 +- dom/media/ipc/MFMediaEngineParent.cpp | 4 +- dom/media/ipc/RDDProcessHost.cpp | 4 - dom/media/ipc/RDDProcessManager.cpp | 8 +- dom/media/ipc/RemoteDecoderManagerChild.cpp | 32 +- dom/media/mediacapabilities/MediaCapabilities.cpp | 25 +- dom/media/mediacontrol/ContentMediaController.cpp | 4 +- dom/media/mediacontrol/ContentMediaController.h | 2 +- .../mediacontrol/ContentPlaybackController.cpp | 9 +- dom/media/mediacontrol/MediaControlKeyManager.cpp | 14 +- dom/media/mediacontrol/MediaControlKeyManager.h | 2 +- dom/media/mediacontrol/MediaControlKeySource.cpp | 6 +- dom/media/mediacontrol/MediaControlKeySource.h | 8 +- dom/media/mediacontrol/MediaControlService.cpp | 10 +- dom/media/mediacontrol/MediaControlUtils.h | 13 +- dom/media/mediacontrol/MediaController.cpp | 20 +- dom/media/mediacontrol/MediaController.h | 2 +- dom/media/mediacontrol/MediaStatusManager.cpp | 27 +- dom/media/mediacontrol/MediaStatusManager.h | 13 +- .../browser_media_control_before_media_starts.js | 2 +- .../tests/gtest/MediaKeyListenerTest.h | 2 +- dom/media/mediacontrol/tests/gtest/moz.build | 2 +- dom/media/mediasession/MediaSession.cpp | 30 +- dom/media/mediasession/MediaSession.h | 22 +- dom/media/mediasession/MediaSessionIPCUtils.h | 17 +- dom/media/mediasession/moz.build | 4 + .../mediasession/test/gtest/TestPositionState.cpp | 127 +++ dom/media/mediasession/test/gtest/moz.build | 15 + dom/media/mediasource/MediaSourceDecoder.cpp | 33 +- dom/media/mediasource/MediaSourceDecoder.h | 5 + dom/media/mediasource/test/mochitest.toml | 2 + .../test/test_BufferedSeekCanPlayThrough.html | 46 + dom/media/mediasource/test/test_EndOfStream.html | 2 +- .../mediasource/test/test_EndOfStream_mp4.html | 2 +- .../mediasource/test/test_ExperimentalAsync.html | 4 +- dom/media/mediasource/test/test_SetModeThrows.html | 2 +- dom/media/metrics.yaml | 44 + dom/media/nsIMediaManager.idl | 5 - dom/media/platforms/PDMFactory.cpp | 41 +- dom/media/platforms/PEMFactory.cpp | 10 +- dom/media/platforms/agnostic/bytestreams/Adts.cpp | 234 ++++- dom/media/platforms/agnostic/bytestreams/Adts.h | 117 ++- .../platforms/agnostic/bytestreams/AnnexB.cpp | 12 +- .../agnostic/eme/ChromiumCDMVideoDecoder.cpp | 39 +- .../platforms/agnostic/eme/EMEDecoderModule.cpp | 18 +- .../platforms/agnostic/gmp/GMPDecoderModule.cpp | 10 + dom/media/platforms/apple/AppleATDecoder.cpp | 90 +- dom/media/platforms/apple/AppleATDecoder.h | 5 +- dom/media/platforms/apple/AppleDecoderModule.cpp | 7 +- dom/media/platforms/apple/AppleVTDecoder.cpp | 10 +- dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp | 12 +- dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp | 7 +- dom/media/platforms/ffmpeg/FFmpegLibWrapper.h | 11 +- dom/media/platforms/ffmpeg/FFmpegRDFTTypes.h | 34 - dom/media/platforms/ffmpeg/FFmpegVideoEncoder.cpp | 255 +++--- dom/media/platforms/ffmpeg/FFmpegVideoEncoder.h | 13 + .../platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp | 14 +- .../platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.h | 8 +- dom/media/platforms/moz.build | 18 +- dom/media/platforms/wmf/MFCDMSession.cpp | 3 +- .../platforms/wmf/MFMediaEngineAudioStream.cpp | 2 +- .../platforms/wmf/MFMediaEngineDecoderModule.cpp | 16 +- .../platforms/wmf/MFMediaEngineDecoderModule.h | 2 + dom/media/platforms/wmf/MFMediaEngineStream.cpp | 33 +- dom/media/platforms/wmf/MFMediaEngineStream.h | 8 +- .../platforms/wmf/MFMediaEngineVideoStream.cpp | 108 ++- dom/media/platforms/wmf/MFMediaEngineVideoStream.h | 27 +- dom/media/platforms/wmf/MFMediaSource.h | 2 - dom/media/platforms/wmf/WMFAudioMFTManager.cpp | 25 +- dom/media/platforms/wmf/WMFAudioMFTManager.h | 1 + dom/media/platforms/wmf/WMFMediaDataEncoder.h | 5 +- dom/media/platforms/wmf/WMFUtils.cpp | 34 +- .../webrtc/videoengine/VideoCaptureAndroid.java | 35 +- .../android_video_capture/video_capture_android.cc | 12 +- .../video_capture_avfoundation.mm | 5 +- dom/media/test/background_video.js | 2 +- dom/media/test/bipbop-clearkey-video-av1.mp4 | Bin 0 -> 52054 bytes .../test/bipbop-clearkey-video-av1.mp4^headers^ | 1 + dom/media/test/bipbop-clearkey-video-av1.webm | Bin 0 -> 50186 bytes .../test/bipbop-clearkey-video-av1.webm^headers^ | 1 + dom/media/test/browser/browser.toml | 4 + .../browser_encrypted_play_time_telemetry.js | 70 -- .../browser_glean_first_frame_loaded_time.js | 81 ++ .../browser_tab_visibility_and_play_time.js | 2 +- dom/media/test/browser/head.js | 119 +++ dom/media/test/browser/wmfme/browser.toml | 8 +- .../browser_wmfme_glean_first_frame_loaded_time.js | 98 +++ dom/media/test/can_play_type_ogg.js | 2 +- dom/media/test/crashtests/crashtests.list | 10 +- dom/media/test/eme.js | 4 +- dom/media/test/manifest.js | 46 +- dom/media/test/mochitest.toml | 5 + dom/media/test/mochitest_background_video.toml | 4 + dom/media/test/mochitest_bugs.toml | 17 +- dom/media/test/mochitest_compat.toml | 13 +- dom/media/test/mochitest_eme.toml | 4 + dom/media/test/mochitest_media_recorder.toml | 4 + dom/media/test/mochitest_seek.toml | 4 + dom/media/test/mochitest_stream.toml | 4 + dom/media/test/reftest/color_quads/reftest.list | 26 +- dom/media/test/reftest/reftest.list | 14 +- dom/media/test/test_arraybuffer.html | 4 +- dom/media/test/test_aspectratio_mp4.html | 2 +- ...und_video_resume_after_end_show_last_frame.html | 2 +- dom/media/test/test_buffered.html | 2 +- .../test/test_bug1431810_opus_downmix_to_mono.html | 8 +- dom/media/test/test_cueless_webm_seek-1.html | 2 +- dom/media/test/test_cueless_webm_seek-2.html | 2 +- dom/media/test/test_cueless_webm_seek-3.html | 2 +- dom/media/test/test_decode_error_crossorigin.html | 2 +- dom/media/test/test_delay_load.html | 2 +- dom/media/test/test_eme_detach_media_keys.html | 2 +- ...ch_reattach_same_mediakeys_during_playback.html | 4 +- dom/media/test/test_eme_getstatusforpolicy.html | 2 +- dom/media/test/test_eme_initDataTypes.html | 4 +- .../test/test_eme_mfcdm_generate_request.html | 6 +- .../test/test_eme_mfcdm_getstatusforpolicy.html | 2 +- dom/media/test/test_eme_missing_pssh.html | 2 +- dom/media/test/test_eme_non_mse_fails.html | 2 +- dom/media/test/test_eme_playback.html | 4 +- dom/media/test/test_eme_protection_query.html | 2 +- dom/media/test/test_eme_pssh_in_moof.html | 2 +- .../test/test_eme_requestKeySystemAccess.html | 4 +- dom/media/test/test_eme_request_notifications.html | 4 +- .../test/test_eme_sample_groups_playback.html | 4 +- .../test_eme_stream_capture_blocked_case1.html | 2 +- .../test_eme_stream_capture_blocked_case2.html | 2 +- .../test_eme_stream_capture_blocked_case3.html | 2 +- .../test/test_eme_unsetMediaKeys_then_capture.html | 4 +- .../test/test_eme_wideinve_l1_installation.html | 4 +- dom/media/test/test_eme_wv_privacy.html | 2 +- dom/media/test/test_hls_player_independency.html | 4 +- dom/media/test/test_hw_video_decoding.html | 5 +- dom/media/test/test_invalid_reject.html | 4 +- dom/media/test/test_invalid_reject_play.html | 4 +- dom/media/test/test_load.html | 8 +- dom/media/test/test_load_source.html | 4 +- dom/media/test/test_media_selection.html | 4 +- ..._mediarecorder_record_canvas_captureStream.html | 2 +- ...arecorder_record_changing_video_resolution.html | 2 +- ...t_mediarecorder_record_downsize_resolution.html | 2 +- ...t_mediarecorder_record_gum_video_timeslice.html | 2 +- .../test/test_mediarecorder_record_session.html | 2 +- .../test_mediarecorder_record_startstopstart.html | 4 +- .../test/test_mediarecorder_record_timeslice.html | 2 +- ...est_mediarecorder_record_upsize_resolution.html | 2 +- .../test_mediatrack_consuming_mediaresource.html | 12 +- .../test_mediatrack_consuming_mediastream.html | 8 +- .../test/test_mediatrack_replay_from_end.html | 8 +- .../test/test_midflight_redirect_blocked.html | 2 +- dom/media/test/test_mixed_principals.html | 2 +- dom/media/test/test_new_audio.html | 2 +- dom/media/test/test_periodic_timeupdate.html | 2 +- dom/media/test/test_play_twice.html | 2 +- dom/media/test/test_playback.html | 2 +- dom/media/test/test_playback_errors.html | 2 +- dom/media/test/test_playback_hls.html | 2 +- dom/media/test/test_preload_actions.html | 54 +- dom/media/test/test_preload_suspend.html | 2 +- dom/media/test/test_reset_events_async.html | 6 +- dom/media/test/test_seek-10.html | 2 +- dom/media/test/test_seekToNextFrame.html | 2 +- .../test/test_temporary_file_blob_video_plays.html | 2 +- dom/media/test/test_video_dimensions.html | 2 +- dom/media/test/test_video_low_power_telemetry.html | 2 +- dom/media/utils/TelemetryProbesReporter.cpp | 46 + dom/media/utils/TelemetryProbesReporter.h | 2 + dom/media/webaudio/FFTBlock.cpp | 14 +- dom/media/webaudio/FFTBlock.h | 290 ++----- dom/media/webaudio/OscillatorNode.cpp | 6 +- dom/media/webaudio/blink/FFTConvolver.cpp | 2 +- dom/media/webaudio/blink/HRTFKernel.cpp | 2 +- dom/media/webaudio/blink/PeriodicWave.cpp | 2 +- dom/media/webaudio/moz.build | 2 - .../test/audioBufferSourceNodeDetached_worker.js | 2 +- .../webaudio/test/test_OfflineAudioContext.html | 4 +- .../test/test_WebAudioMemoryReporting.html | 2 +- .../test/test_audioBufferSourceNodeOffset.html | 2 +- .../test/test_audioContextSuspendResumeClose.html | 8 +- dom/media/webaudio/test/test_bug1056032.html | 2 +- dom/media/webaudio/test/test_bug867174.html | 2 +- .../test/test_convolverNodeNormalization.html | 2 +- .../test/test_decodeAudioDataOnDetachedBuffer.html | 2 +- .../webaudio/test/test_decodeAudioDataPromise.html | 2 +- dom/media/webaudio/test/test_decodeAudioError.html | 4 +- .../webaudio/test/test_dynamicsCompressorNode.html | 2 +- .../webaudio/test/test_event_listener_leaks.html | 2 +- .../test/test_mediaStreamAudioSourceNodeNoGC.html | 2 +- dom/media/webaudio/test/test_pannerNodeTail.html | 2 +- .../test/test_scriptProcessorNodeNotConnected.html | 2 +- dom/media/webaudio/test/webaudio.js | 2 +- dom/media/webcodecs/AudioData.cpp | 731 ++++++++++++++++ dom/media/webcodecs/AudioData.h | 176 ++++ dom/media/webcodecs/AudioDecoder.cpp | 481 +++++++++++ dom/media/webcodecs/AudioDecoder.h | 83 ++ dom/media/webcodecs/DecoderAgent.cpp | 2 - dom/media/webcodecs/DecoderTemplate.cpp | 15 +- dom/media/webcodecs/DecoderTypes.h | 64 +- dom/media/webcodecs/EncodedAudioChunk.cpp | 260 ++++++ dom/media/webcodecs/EncodedAudioChunk.h | 117 +++ dom/media/webcodecs/VideoDecoder.cpp | 97 +-- dom/media/webcodecs/VideoEncoder.cpp | 103 +-- dom/media/webcodecs/VideoFrame.cpp | 41 +- dom/media/webcodecs/WebCodecsUtils.cpp | 109 ++- dom/media/webcodecs/WebCodecsUtils.h | 9 +- dom/media/webcodecs/moz.build | 6 + dom/media/webrtc/MediaEngineFake.cpp | 6 +- dom/media/webrtc/MediaEngineRemoteVideoSource.cpp | 3 +- dom/media/webrtc/MediaEngineWebRTCAudio.cpp | 6 +- dom/media/webrtc/MediaTrackConstraints.h | 11 - dom/media/webrtc/MediaTransportChild.h | 6 +- dom/media/webrtc/PMediaTransport.ipdl | 4 +- dom/media/webrtc/WebrtcGlobal.h | 33 +- dom/media/webrtc/WebrtcIPCTraits.h | 11 +- dom/media/webrtc/jsapi/MediaTransportHandler.cpp | 62 +- dom/media/webrtc/jsapi/MediaTransportHandler.h | 15 +- .../webrtc/jsapi/MediaTransportHandlerIPC.cpp | 10 +- dom/media/webrtc/jsapi/MediaTransportParent.cpp | 14 +- dom/media/webrtc/jsapi/PeerConnectionImpl.cpp | 562 ++++++++---- dom/media/webrtc/jsapi/PeerConnectionImpl.h | 42 +- dom/media/webrtc/jsapi/RTCDtlsTransport.cpp | 7 +- dom/media/webrtc/jsapi/RTCDtlsTransport.h | 3 + dom/media/webrtc/jsapi/RTCIceTransport.cpp | 60 ++ dom/media/webrtc/jsapi/RTCIceTransport.h | 53 ++ dom/media/webrtc/jsapi/RTCRtpReceiver.cpp | 4 +- dom/media/webrtc/jsapi/RTCRtpSender.cpp | 1 - dom/media/webrtc/jsapi/RTCRtpTransceiver.cpp | 33 +- dom/media/webrtc/jsapi/RTCRtpTransceiver.h | 3 +- dom/media/webrtc/jsapi/moz.build | 2 + dom/media/webrtc/jsep/JsepSessionImpl.cpp | 12 +- dom/media/webrtc/jsep/JsepTrack.cpp | 4 +- dom/media/webrtc/jsep/JsepTrack.h | 10 +- dom/media/webrtc/metrics.yaml | 80 +- dom/media/webrtc/tests/mochitests/head.js | 1 + dom/media/webrtc/tests/mochitests/iceTestUtils.js | 126 +++ dom/media/webrtc/tests/mochitests/pc.js | 21 +- .../test_peerConnection_RTCIceTransport.html | 197 +++++ .../test_peerConnection_basicAudioNATRelay.html | 2 + .../test_peerConnection_basicAudioNATRelayTCP.html | 2 + .../test_peerConnection_basicAudioNATRelayTLS.html | 2 + .../test_peerConnection_basicAudioNATSrflx.html | 2 + ...est_peerConnection_basicAudioNoisyUDPBlock.html | 2 + .../test_peerConnection_basicAudioRelayPolicy.html | 5 +- .../mochitests/test_peerConnection_bug825703.html | 79 +- .../mochitests/test_peerConnection_callbacks.html | 29 +- .../test_peerConnection_localRollback.html | 2 +- .../test_peerConnection_portRestrictions.html | 4 + .../mochitests/test_peerConnection_restartIce.html | 12 +- ...onnection_restartIceLocalAndRemoteRollback.html | 10 - ...est_peerConnection_restartIceLocalRollback.html | 9 - .../test_peerConnection_restartIceNoBundle.html | 12 +- ...peerConnection_restartIceNoBundleNoRtcpMux.html | 12 +- .../test_peerConnection_restartIceNoRtcpMux.html | 13 +- .../test_peerConnection_sillyCodecPriorities.html | 12 +- .../test_peerConnection_stats_relayProtocol.html | 2 + ...t_peerConnection_threeUnbundledConnections.html | 4 +- .../test_peerConnection_throwInCallbacks.html | 7 +- .../test_peerConnection_verifyDescriptions.html | 89 +- .../webrtc/third_party_build/default_config_env | 20 +- .../webrtc/third_party_build/filter_git_changes.py | 2 +- dom/media/webrtc/third_party_build/prep_repo.sh | 8 +- .../webrtc/third_party_build/save_patch_stack.py | 2 +- .../webrtc/third_party_build/verify_vendoring.sh | 16 +- dom/media/webrtc/transport/nricectx.cpp | 180 ++-- dom/media/webrtc/transport/nricectx.h | 39 +- dom/media/webrtc/transport/nricemediastream.cpp | 55 ++ dom/media/webrtc/transport/nricemediastream.h | 14 + dom/media/webrtc/transport/test/ice_unittest.cpp | 134 ++- .../transport/test/test_nr_socket_ice_unittest.cpp | 3 +- .../webrtc/transport/test/transport_unittests.cpp | 16 +- .../transport/third_party/nICEr/src/ice/ice_ctx.c | 38 +- .../transport/third_party/nICEr/src/ice/ice_ctx.h | 21 +- .../third_party/nICEr/src/ice/ice_handler.h | 6 + .../third_party/nICEr/src/ice/ice_media_stream.c | 38 + .../third_party/nICEr/src/ice/ice_media_stream.h | 1 + .../third_party/nICEr/src/ice/ice_peer_ctx.c | 6 + .../webrtc/transportbridge/MediaPipelineFilter.cpp | 34 +- .../webrtc/transportbridge/MediaPipelineFilter.h | 4 +- .../webspeech/recognition/SpeechRecognition.cpp | 13 +- .../webspeech/synth/nsISynthVoiceRegistry.idl | 12 - dom/media/webvtt/WebVTTListener.cpp | 2 +- dom/media/webvtt/test/mochitest/manifest.js | 2 +- dom/media/webvtt/test/mochitest/mochitest.toml | 12 +- dom/media/webvtt/update-webvtt.js | 4 +- dom/messagechannel/MessagePort.cpp | 36 +- dom/messagechannel/MessagePort.h | 6 +- dom/messagechannel/tests/mm_messageChannel.js | 2 +- .../tests/mm_messageChannelParent.js | 8 +- .../tests/test_event_listener_leaks.html | 2 +- dom/messagechannel/tests/test_messageChannel.xhtml | 2 +- .../tests/test_messageChannel_start.html | 34 +- dom/messagechannel/tests/test_removedWindow.html | 6 +- dom/midi/MIDIPort.cpp | 4 +- dom/midi/tests/MIDITestUtils.js | 2 +- dom/midi/tests/browser_midi_permission_gated.js | 2 +- dom/midi/tests/browser_refresh_port_list.js | 12 +- dom/midi/tests/test_midi_device_enumeration.html | 2 +- .../test_midi_device_explicit_open_close.html | 8 +- dom/midi/tests/test_midi_device_pending.html | 4 +- dom/moz.build | 2 - .../test_tcpsocket_client_and_server_basics.js | 8 +- dom/network/tests/test_udpsocket.html | 18 +- dom/notification/Notification.cpp | 13 +- dom/notification/Notification.h | 3 +- dom/notification/NotificationStorage.sys.mjs | 2 +- dom/notification/new/NotificationDB.sys.mjs | 25 +- dom/notification/old/NotificationDB.sys.mjs | 32 +- .../test_notification_system_principal.xhtml | 5 +- .../test/mochitest/NotificationTest.js | 2 +- .../test/mochitest/test_notification_basics.html | 2 +- .../test/mochitest/test_notification_tag.html | 7 +- dom/notification/test/unit/test_notificationdb.js | 2 +- dom/origin-trials/tests/mochitest/common.js | 2 +- dom/payments/PaymentRequestManager.cpp | 6 +- dom/performance/LargestContentfulPaint.h | 10 - dom/performance/Performance.cpp | 60 +- dom/performance/PerformanceTiming.cpp | 4 +- dom/permission/PermissionUtils.cpp | 2 +- dom/promise/Promise.cpp | 53 -- dom/promise/Promise.h | 7 - dom/promise/tests/promise_uncatchable_exception.js | 4 +- dom/promise/tests/test_bug883683.html | 4 +- .../tests/test_on_promise_settled_duplicates.html | 2 +- dom/promise/tests/test_promise.html | 92 +- .../tests/test_promise_uncatchable_exception.html | 2 +- dom/promise/tests/test_promise_utils.html | 12 +- dom/promise/tests/test_promise_xrays.html | 26 +- dom/promise/tests/test_resolve.html | 2 +- dom/promise/tests/test_webassembly_compile.html | 2 +- dom/promise/tests/unit/test_monitor_uncaught.js | 8 +- .../tests/unit/test_promise_job_across_sandbox.js | 5 +- dom/push/Push.sys.mjs | 161 ++-- dom/push/PushComponents.sys.mjs | 12 +- dom/push/PushCrypto.sys.mjs | 4 +- dom/push/PushDB.sys.mjs | 4 +- dom/push/PushService.sys.mjs | 22 +- dom/push/PushServiceHttp2.sys.mjs | 14 +- dom/push/PushServiceWebSocket.sys.mjs | 8 +- dom/push/test/lifetime_worker.js | 4 +- dom/push/test/mockpushserviceparent.js | 2 +- dom/push/test/test_data.html | 2 +- dom/push/test/test_has_permissions.html | 2 +- dom/push/test/test_multiple_register.html | 18 +- .../test_multiple_register_different_scope.html | 2 +- ...ultiple_register_during_service_activation.html | 2 +- dom/push/test/test_permissions.html | 2 +- dom/push/test/test_register.html | 2 +- dom/push/test/test_register_key.html | 2 +- dom/push/test/test_serviceworker_lifetime.html | 22 +- .../test_try_registering_offline_disabled.html | 10 +- dom/push/test/test_utils.js | 8 +- dom/push/test/worker.js | 4 +- dom/push/test/xpcshell/broadcast_handler.sys.mjs | 2 +- dom/push/test/xpcshell/head.js | 8 +- dom/push/test/xpcshell/test_broadcast_success.js | 4 +- dom/push/test/xpcshell/test_clearAll_successful.js | 4 +- .../test/xpcshell/test_clear_forgetAboutSite.js | 2 +- dom/push/test/xpcshell/test_clear_origin_data.js | 5 - dom/push/test/xpcshell/test_drop_expired.js | 2 +- .../test/xpcshell/test_notification_duplicate.js | 2 +- dom/push/test/xpcshell/test_notification_error.js | 2 +- .../test/xpcshell/test_notification_incomplete.js | 4 +- .../xpcshell/test_notification_version_string.js | 2 +- dom/push/test/xpcshell/test_permissions.js | 4 +- dom/push/test/xpcshell/test_quota_exceeded.js | 6 +- dom/push/test/xpcshell/test_quota_observer.js | 4 +- .../test/xpcshell/test_quota_with_notification.js | 12 +- dom/push/test/xpcshell/test_reconnect_retry.js | 2 +- dom/push/test/xpcshell/test_register_case.js | 2 +- dom/push/test/xpcshell/test_register_flush.js | 2 +- .../test/xpcshell/test_register_invalid_channel.js | 4 +- .../xpcshell/test_register_invalid_endpoint.js | 4 +- .../test/xpcshell/test_register_invalid_json.js | 2 +- dom/push/test/xpcshell/test_register_no_id.js | 2 +- .../test/xpcshell/test_register_request_queue.js | 2 +- dom/push/test/xpcshell/test_register_rollback.js | 2 +- dom/push/test/xpcshell/test_register_wrong_id.js | 2 +- dom/push/test/xpcshell/test_register_wrong_type.js | 4 +- dom/push/test/xpcshell/test_registration_error.js | 2 +- dom/push/test/xpcshell/test_retry_ws.js | 4 +- dom/push/test/xpcshell/test_service_child.js | 4 +- .../test/xpcshell/test_unregister_empty_scope.js | 2 +- dom/push/test/xpcshell/test_unregister_error.js | 2 +- .../test/xpcshell/test_unregister_invalid_json.js | 4 +- .../test/xpcshell/test_unregister_not_found.js | 2 +- dom/push/test/xpcshell/test_unregister_success.js | 2 +- dom/quota/ActorsParent.cpp | 39 +- dom/quota/CachingDatabaseConnection.cpp | 12 +- dom/quota/CachingDatabaseConnection.h | 12 +- dom/quota/Config.h | 10 - dom/quota/OriginParser.cpp | 6 +- dom/quota/OriginParser.h | 2 - dom/quota/QuotaCommon.cpp | 98 ++- dom/quota/QuotaCommon.h | 4 +- dom/quota/QuotaManager.h | 3 +- dom/quota/ScopedLogExtraInfo.cpp | 37 +- dom/quota/ScopedLogExtraInfo.h | 21 +- dom/quota/SerializationHelpers.h | 2 - dom/quota/StorageOriginAttributes.cpp | 50 +- dom/quota/StorageOriginAttributes.h | 22 +- dom/quota/test/gtest/TestScopedLogExtraInfo.cpp | 31 +- .../test/gtest/TestStorageOriginAttributes.cpp | 75 ++ .../test/modules/system/worker/ModuleLoader.js | 2 +- .../test/xpcshell/telemetry/test_dom_quota_try.js | 180 ++++ dom/quota/test/xpcshell/telemetry/xpcshell.toml | 3 + dom/reporting/tests/browser_cleanup.js | 8 +- dom/reporting/tests/common_deprecated.js | 10 +- dom/reporting/tests/iframe_delivering.html | 2 +- dom/reporting/tests/worker_delivering.js | 2 +- dom/reporting/tests/worker_deprecated.js | 1 + dom/script/ScriptLoader.cpp | 140 ++- dom/script/moz.build | 7 +- dom/script/nsIScriptLoaderObserver.h | 70 ++ dom/script/nsIScriptLoaderObserver.idl | 48 -- dom/security/ReferrerInfo.cpp | 36 +- dom/security/ReferrerInfo.h | 7 - .../featurepolicy/test/mochitest/mochitest.toml | 2 + .../test/mochitest/test_initial_aboutblank.html | 26 + dom/security/metrics.yaml | 153 ++++ dom/security/moz.build | 2 +- dom/security/nsCSPContext.cpp | 225 +++-- dom/security/nsCSPContext.h | 13 +- dom/security/nsCSPUtils.cpp | 51 +- dom/security/nsCSPUtils.h | 12 +- dom/security/nsContentSecurityUtils.cpp | 53 +- dom/security/nsHTTPSOnlyUtils.cpp | 63 +- dom/security/nsHTTPSOnlyUtils.h | 9 +- dom/security/test/csp/file_csp_error_messages.html | 33 + dom/security/test/csp/mochitest.toml | 3 + dom/security/test/csp/test_csp_error_messages.html | 75 ++ dom/security/test/general/browser.toml | 10 + .../browser_restrict_privileged_about_script.js | 2 +- .../test/general/browser_test_data_download.js | 4 +- .../test/general/browser_test_data_text_csv.js | 4 +- .../test/general/browser_test_http_download.js | 275 ++++++ .../test/general/browser_test_report_blocking.js | 2 +- .../browser_test_toplevel_data_navigations.js | 2 +- .../browser_test_view_image_data_navigation.js | 4 +- dom/security/test/general/http_download_page.html | 23 + dom/security/test/general/http_download_server.sjs | 20 + .../test/general/test_block_script_wrong_mime.html | 6 +- .../test_block_toplevel_data_navigation.html | 2 +- dom/security/test/general/test_bug1277803.xhtml | 2 +- ...est_contentpolicytype_targeted_link_iframe.html | 2 +- dom/security/test/general/test_meta_referrer.html | 2 +- .../general/test_same_site_cookies_subrequest.html | 2 +- .../test_same_site_cookies_toplevel_nav.html | 2 +- .../test/https-first/browser_download_attribute.js | 2 +- .../test/https-first/browser_httpsfirst.js | 35 + .../https-first/browser_mixed_content_download.js | 2 +- .../test/https-first/browser_schemeless.js | 28 + dom/security/test/https-first/file_data_uri.html | 2 +- .../test/https-first/test_resource_upgrade.html | 2 +- dom/security/test/https-only/browser_hsts_host.js | 2 +- dom/security/test/https-only/browser_save_as.js | 14 +- .../test/https-only/browser_user_gesture.js | 2 +- .../test/https-only/file_upgrade_insecure.html | 2 +- .../file_websocket_exceptions_iframe.html | 6 +- .../test/https-only/test_redirect_upgrade.html | 4 +- .../test/https-only/test_resource_upgrade.html | 2 +- .../browser_test_mixed_content_download.js | 2 +- dom/security/test/referrer-policy/browser.toml | 4 +- .../referrer-policy/browser_fragment_navigation.js | 42 - .../referrer-policy/browser_session_history.js | 57 ++ .../referrer-policy/file_fragment_navigation.sjs | 21 - .../test/referrer-policy/file_session_history.sjs | 27 + .../test/referrer-policy/referrer_helper.js | 4 +- .../test/referrer-policy/test_img_referrer.html | 4 +- .../test/sec-fetch/browser_external_loads.js | 4 +- dom/security/test/sec-fetch/browser_navigation.js | 2 +- .../test_iframe_history_manipulation.html | 2 +- .../sec-fetch/test_iframe_src_metaRedirect.html | 2 +- .../sec-fetch/test_iframe_srcdoc_metaRedirect.html | 2 +- .../test_iframe_window_open_metaRedirect.html | 2 +- .../test/sec-fetch/test_trustworthy_loopback.html | 2 +- dom/security/test/sec-fetch/test_websocket.html | 6 +- dom/security/test/unit/test_csp_reports.js | 2 +- .../test_csp_upgrade_insecure_request_header.js | 8 +- .../test_https_only_https_first_default_port.js | 8 +- .../test/unit/test_https_only_https_first_prefs.js | 6 +- dom/security/trusted-types/TrustedHTML.cpp | 13 + dom/security/trusted-types/TrustedHTML.h | 19 + dom/security/trusted-types/TrustedScript.cpp | 13 + dom/security/trusted-types/TrustedScript.h | 19 + dom/security/trusted-types/TrustedScriptURL.cpp | 14 + dom/security/trusted-types/TrustedScriptURL.h | 18 + dom/security/trusted-types/TrustedTypePolicy.cpp | 43 + dom/security/trusted-types/TrustedTypePolicy.h | 72 ++ .../trusted-types/TrustedTypePolicyFactory.cpp | 50 ++ .../trusted-types/TrustedTypePolicyFactory.h | 105 +++ dom/security/trusted-types/TrustedTypeUtils.h | 35 + dom/security/trusted-types/moz.build | 27 + dom/serializers/nsDOMSerializer.cpp | 1 - dom/serviceworkers/ServiceWorkerEvents.cpp | 3 +- dom/serviceworkers/ServiceWorkerIPCUtils.h | 13 +- dom/serviceworkers/ServiceWorkerInfo.cpp | 4 +- dom/serviceworkers/ServiceWorkerManager.cpp | 4 +- dom/serviceworkers/ServiceWorkerManagerParent.cpp | 6 +- dom/serviceworkers/ServiceWorkerOp.cpp | 3 +- dom/serviceworkers/test/browser_download.js | 2 +- dom/serviceworkers/test/close_test.js | 2 + .../eventsource_cors_response_intercept_worker.js | 2 + ...mixed_content_cors_response_intercept_worker.js | 2 + ...eventsource_opaque_response_intercept_worker.js | 2 + ...ntsource_synthetic_response_intercept_worker.js | 2 + dom/serviceworkers/test/gtest/TestReadWrite.cpp | 109 +-- .../test/test_serviceworker_interfaces.js | 4 +- dom/smil/SMILAnimationController.cpp | 4 +- dom/storage/SessionStorageManager.cpp | 3 +- dom/storage/StorageDBUpdater.cpp | 5 +- dom/storage/StorageUtils.cpp | 9 +- dom/streams/test/xpcshell/bug-1387503-1.js | 4 +- dom/streams/test/xpcshell/bug-1773237.js | 2 +- .../test/xpcshell/dom_stream_prototype_test.js | 2 +- dom/streams/test/xpcshell/response.js | 8 +- dom/streams/test/xpcshell/subclassing.js | 2 +- dom/svg/SVGAElement.cpp | 4 +- dom/svg/SVGAElement.h | 2 +- dom/svg/SVGAnimationElement.cpp | 4 +- dom/svg/SVGAnimationElement.h | 2 +- dom/svg/SVGFEImageElement.cpp | 6 +- dom/svg/SVGFEImageElement.h | 2 +- dom/svg/SVGImageElement.cpp | 6 +- dom/svg/SVGImageElement.h | 2 +- dom/svg/SVGMPathElement.cpp | 4 +- dom/svg/SVGMPathElement.h | 2 +- dom/svg/SVGSVGElement.cpp | 4 +- dom/svg/SVGSVGElement.h | 2 +- dom/svg/SVGStyleElement.cpp | 4 +- dom/svg/SVGStyleElement.h | 2 +- dom/svg/SVGTitleElement.cpp | 4 +- dom/svg/SVGTitleElement.h | 2 +- dom/svg/SVGUseElement.cpp | 17 +- dom/svg/SVGUseElement.h | 2 +- dom/svg/test/test_SVGTransformListAddition.xhtml | 2 +- dom/svg/test/test_bounds.html | 6 +- dom/svg/test/test_bug1426594.html | 8 +- dom/svg/test/test_fragments.html | 3 +- dom/svg/test/test_selectSubString.xhtml | 2 +- dom/svg/test/test_text_selection.html | 2 +- dom/system/IOUtils.cpp | 956 ++++++++++++--------- dom/system/IOUtils.h | 52 +- dom/system/NetworkGeolocationProvider.sys.mjs | 2 +- dom/system/PathUtils.h | 3 +- dom/system/tests/ioutils/file_ioutils_worker.js | 2 +- .../tests/ioutils/test_ioutils_copy_move.html | 18 +- .../tests/ioutils/test_ioutils_dir_iteration.html | 4 +- .../tests/ioutils/test_ioutils_mac_xattr.html | 6 +- dom/system/tests/ioutils/test_ioutils_mkdir.html | 8 +- .../tests/ioutils/test_ioutils_read_write.html | 34 +- .../ioutils/test_ioutils_read_write_json.html | 4 +- .../ioutils/test_ioutils_read_write_utf8.html | 18 +- dom/system/tests/ioutils/test_ioutils_remove.html | 4 +- .../test_ioutils_stat_set_modification_time.html | 6 +- .../test_ioutils_windows_file_attributes.html | 2 +- .../browser/browser_ConsoleStorageAPITests.js | 4 +- .../browser_ConsoleStoragePBTest_perwindowpb.js | 2 +- dom/tests/browser/browser_bug1004814.js | 2 +- dom/tests/browser/browser_bug1236512.js | 4 +- dom/tests/browser/browser_bug1238427.js | 2 +- dom/tests/browser/browser_bug1563629.js | 2 +- ...ser_form_associated_custom_elements_validity.js | 47 + .../browser_localStorage_privatestorageevent.js | 20 +- dom/tests/browser/browser_persist_cookies.js | 2 +- .../browser/browser_persist_cross_origin_iframe.js | 8 +- dom/tests/browser/browser_persist_image_accept.js | 4 +- .../browser/browser_persist_mixed_content_image.js | 2 +- .../browser/browser_sessionStorage_navigation.js | 2 +- .../browser_test_focus_after_modal_state.js | 4 +- .../browser/browser_windowProxy_transplant.js | 2 +- .../browser/create_webrtc_peer_connection.html | 2 +- dom/tests/browser/file_postMessage_parent.html | 2 +- dom/tests/browser/geo_leak_test.html | 2 +- dom/tests/browser/test-console-api.html | 2 +- dom/tests/browser/worker_bug1004814.js | 2 +- dom/tests/mochitest/chrome/child_focus_frame.html | 2 +- dom/tests/mochitest/chrome/file_bug800817.xhtml | 11 +- dom/tests/mochitest/chrome/test_bug800817.xhtml | 10 +- dom/tests/mochitest/chrome/window_focus.xhtml | 57 +- dom/tests/mochitest/general/mochitest.toml | 8 +- .../general/test_focus_scrollchildframe.html | 12 +- dom/tests/mochitest/general/test_interfaces.js | 40 +- dom/tests/mochitest/webcomponents/mochitest.toml | 2 - .../webcomponents/test_event_stopping.html | 174 ---- dom/tests/unit/test_Fetch.js | 6 +- dom/tests/unit/test_PromiseDebugging.js | 2 +- dom/tests/unit/test_geolocation_monitor.js | 2 +- dom/tests/unit/test_geolocation_provider.js | 4 +- dom/url/tests/browser_download_after_revoke.js | 2 +- dom/url/tests/protocol_worker.js | 2 + dom/url/tests/urlSearchParams_commons.js | 4 + dom/url/tests/url_exceptions_worker.js | 2 +- dom/vr/XRSystem.cpp | 54 +- dom/vr/XRSystem.h | 2 +- dom/vr/test/reftest/reftest.list | 6 +- dom/webauthn/MacOSWebAuthnService.mm | 21 + dom/webauthn/moz.build | 2 +- .../WebBrowserPersistLocalDocument.cpp | 1 - dom/webgpu/Adapter.cpp | 13 +- dom/webgpu/CanvasContext.h | 2 + dom/webgpu/CommandBuffer.cpp | 17 +- dom/webgpu/CommandBuffer.h | 4 +- dom/webgpu/CommandEncoder.cpp | 37 +- dom/webgpu/CommandEncoder.h | 10 +- dom/webgpu/ComputePassEncoder.cpp | 26 +- dom/webgpu/ComputePassEncoder.h | 7 +- dom/webgpu/Device.cpp | 52 +- dom/webgpu/Queue.cpp | 34 +- dom/webgpu/RenderPassEncoder.cpp | 66 +- dom/webgpu/RenderPassEncoder.h | 6 +- dom/webgpu/SupportedFeatures.cpp | 3 +- dom/webgpu/Utility.cpp | 2 - dom/webgpu/ipc/PWebGPU.ipdl | 2 + dom/webgpu/ipc/WebGPUChild.cpp | 4 +- dom/webgpu/ipc/WebGPUParent.cpp | 82 +- dom/webgpu/ipc/WebGPUParent.h | 6 +- dom/webgpu/ipc/WebGPUSerialize.h | 5 +- dom/webidl/ARIAMixin.webidl | 148 ++++ dom/webidl/AbortController.webidl | 2 +- dom/webidl/AccessibilityRole.webidl | 16 - dom/webidl/AddonManager.webidl | 4 +- dom/webidl/AriaAttributes.webidl | 136 --- dom/webidl/AudioData.webidl | 63 ++ dom/webidl/AudioDecoder.webidl | 53 ++ dom/webidl/CSSStyleDeclaration.webidl | 3 + dom/webidl/CanvasRenderingContext2D.webidl | 1 + dom/webidl/Console.webidl | 172 +--- dom/webidl/DOMRequest.webidl | 32 - dom/webidl/Element.webidl | 3 +- dom/webidl/ElementInternals.webidl | 3 +- dom/webidl/EncodedAudioChunk.webidl | 38 + dom/webidl/EventHandler.webidl | 2 + dom/webidl/Gamepad.webidl | 6 +- dom/webidl/GamepadAxisMoveEvent.webidl | 2 +- dom/webidl/GamepadButtonEvent.webidl | 3 +- dom/webidl/GamepadEvent.webidl | 3 +- dom/webidl/GamepadHapticActuator.webidl | 3 +- dom/webidl/GamepadLightIndicator.webidl | 2 +- dom/webidl/GamepadPose.webidl | 3 +- dom/webidl/GamepadTouch.webidl | 2 +- dom/webidl/GleanMetrics.webidl | 33 + dom/webidl/HTMLImageElement.webidl | 2 + dom/webidl/HTMLTemplateElement.webidl | 4 +- dom/webidl/Navigator.webidl | 2 +- dom/webidl/RTCDtlsTransport.webidl | 1 + dom/webidl/RTCIceTransport.webidl | 43 + dom/webidl/RTCPeerConnection.webidl | 57 +- dom/webidl/RTCSessionDescription.webidl | 9 +- dom/webidl/Request.webidl | 3 + dom/webidl/SVGAElement.webidl | 2 +- dom/webidl/SecurityPolicyViolationEvent.webidl | 18 +- dom/webidl/TrustedTypes.webidl | 64 ++ dom/webidl/VideoDecoder.webidl | 2 +- dom/webidl/WebGPU.webidl | 4 +- dom/webidl/WebXR.webidl | 4 +- dom/webidl/WindowOrWorkerGlobalScope.webidl | 7 + dom/webidl/moz.build | 14 +- dom/webscheduling/WebTaskScheduler.cpp | 5 +- dom/webtransport/parent/WebTransportParent.cpp | 5 +- dom/workers/RuntimeService.cpp | 17 +- dom/workers/WorkerIPCUtils.h | 6 +- dom/workers/WorkerPrivate.cpp | 7 +- dom/workers/WorkerScope.cpp | 10 + dom/workers/WorkerScope.h | 4 + dom/workers/remoteworkers/RemoteWorkerChild.cpp | 7 +- .../test/WorkerDebugger.console_debugger.js | 2 + dom/workers/test/bug1014466_worker.js | 2 + dom/workers/test/notification_permission_worker.js | 2 + dom/workers/test/notification_worker.js | 2 + .../test/notification_worker_child-child.js | 2 + dom/workers/test/onLine_worker_child.js | 5 +- dom/workers/test/onLine_worker_head.js | 2 + dom/workers/test/promise_worker.js | 2 + dom/workers/test/test_worker_interfaces.js | 10 +- dom/xhr/XMLHttpRequest.h | 85 +- dom/xhr/XMLHttpRequestMainThread.cpp | 80 +- dom/xhr/XMLHttpRequestMainThread.h | 11 +- dom/xhr/XMLHttpRequestWorker.cpp | 3 +- dom/xhr/tests/file_XHRResponseURL.js | 12 +- .../file_sync_xhr_document_write_with_iframe.html | 2 +- dom/xhr/tests/relativeLoad_worker.js | 2 +- dom/xhr/tests/temporaryFileBlob.sjs | 4 +- dom/xhr/tests/terminateSyncXHR_worker.js | 2 +- dom/xhr/tests/test_XHR.js | 3 + dom/xhr/tests/test_XHRDocURI.html | 40 +- dom/xhr/tests/test_XHR_timeout.js | 2 + dom/xhr/tests/test_bug1752863_worker.js | 2 +- dom/xhr/tests/test_worker_xhr_responseURL.html | 2 +- dom/xhr/tests/test_worker_xhr_system.js | 4 +- dom/xhr/tests/test_xhr_progressevents.html | 2 +- dom/xhr/tests/worker_temporaryFileBlob.js | 3 + dom/xhr/tests/worker_terminateSyncXHR_frame.html | 2 +- dom/xhr/tests/xhrAbort_worker.js | 4 +- dom/xhr/tests/xhr_worker.js | 18 +- dom/xml/XMLDocument.cpp | 1 - dom/xml/XMLStylesheetProcessingInstruction.cpp | 5 +- dom/xml/XMLStylesheetProcessingInstruction.h | 2 +- dom/xml/nsXMLElement.cpp | 4 +- dom/xml/nsXMLElement.h | 2 +- dom/xslt/tests/mochitest/mochitest.toml | 2 + .../tests/mochitest/test_parameter_conversion.html | 49 ++ dom/xslt/xpath/XPathEvaluator.cpp | 1 - dom/xslt/xslt/txEXSLTFunctions.cpp | 5 +- dom/xslt/xslt/txMozillaTextOutput.cpp | 1 - dom/xslt/xslt/txMozillaXMLOutput.cpp | 1 - dom/xslt/xslt/txMozillaXSLTProcessor.cpp | 1 - dom/xul/XULButtonElement.cpp | 4 +- dom/xul/XULButtonElement.h | 2 +- dom/xul/XULFrameElement.cpp | 4 +- dom/xul/XULFrameElement.h | 2 +- dom/xul/XULMenuBarElement.cpp | 4 +- dom/xul/XULMenuBarElement.h | 2 +- dom/xul/XULTreeElement.cpp | 4 +- dom/xul/XULTreeElement.h | 2 +- dom/xul/nsXULContentSink.cpp | 1 - dom/xul/nsXULContentUtils.cpp | 1 - dom/xul/nsXULElement.cpp | 13 +- dom/xul/nsXULElement.h | 2 +- dom/xul/nsXULPopupListener.cpp | 1 - dom/xul/test/test_bug468176.xhtml | 2 +- 1270 files changed, 18629 insertions(+), 12761 deletions(-) delete mode 100644 dom/base/DOMRequest.cpp delete mode 100644 dom/base/DOMRequest.h delete mode 100644 dom/base/DOMRequestHelper.sys.mjs create mode 100644 dom/base/UnbindContext.h delete mode 100644 dom/base/nsContentCID.h delete mode 100644 dom/base/nsIDOMRequestService.idl create mode 100644 dom/base/test/browser_object_attachment.js delete mode 100644 dom/base/test/chrome/test_swapFrameLoaders.xhtml delete mode 100644 dom/base/test/chrome/window_swapFrameLoaders.xhtml create mode 100644 dom/base/test/file_img_attachment.jpg create mode 100644 dom/base/test/file_img_attachment.jpg^headers^ create mode 100644 dom/base/test/file_img_object_attachment.html create mode 100644 dom/base/test/file_pdf_attachment.pdf create mode 100644 dom/base/test/file_pdf_attachment.pdf^headers^ create mode 100644 dom/base/test/file_pdf_object_attachment.html delete mode 100644 dom/base/test/test_domrequest.html delete mode 100644 dom/base/test/test_domrequesthelper.xhtml create mode 100644 dom/base/test/test_focus_radio.html create mode 100644 dom/bindings/parser/tests/test_legacyTreatNonObjectAsNull.py create mode 100644 dom/bindings/parser/tests/test_union_callback_dict.py delete mode 100644 dom/broadcastchannel/tests/file_mozbrowser.html delete mode 100644 dom/broadcastchannel/tests/file_mozbrowser2.html delete mode 100644 dom/broadcastchannel/tests/iframe_mozbrowser.html delete mode 100644 dom/broadcastchannel/tests/iframe_mozbrowser2.html delete mode 100644 dom/browser-element/BrowserElementChild.js delete mode 100644 dom/browser-element/BrowserElementChildPreload.js delete mode 100644 dom/browser-element/BrowserElementParent.jsm delete mode 100644 dom/browser-element/BrowserElementPromptService.jsm delete mode 100644 dom/browser-element/components.conf delete mode 100644 dom/browser-element/moz.build delete mode 100644 dom/browser-element/nsIBrowserElementAPI.idl create mode 100644 dom/canvas/DmdStdContainers.h create mode 100644 dom/canvas/test/reftest/colors/_generated_reftest.list create mode 100644 dom/canvas/test/reftest/colors/color_canvas.html create mode 100644 dom/canvas/test/reftest/colors/generate_color_canvas_reftests.py create mode 100644 dom/canvas/test/test_accelerated_canvas_context_loss.html create mode 100644 dom/chrome-webidl/ConsoleInstance.webidl create mode 100644 dom/events/test/test_mouse_events_after_touchend.html delete mode 100644 dom/html/nsBrowserElement.cpp delete mode 100644 dom/html/nsBrowserElement.h create mode 100644 dom/indexedDB/test/unit/test_connection_idle_maintenance.js create mode 100644 dom/indexedDB/test/unit/test_connection_idle_maintenance_stop.js delete mode 100644 dom/interfaces/html/moz.build delete mode 100644 dom/interfaces/html/nsIDOMMozBrowserFrame.idl delete mode 100644 dom/interfaces/html/nsIMozBrowserFrame.idl delete mode 100644 dom/ipc/jar.mn delete mode 100644 dom/mathml/tests/mochitest/mochitest.toml delete mode 100644 dom/mathml/tests/mochitest/test_math_tabindex_focus.html create mode 100644 dom/media/gtest/TestAudioSampleFormat.cpp create mode 100644 dom/media/mediasession/test/gtest/TestPositionState.cpp create mode 100644 dom/media/mediasession/test/gtest/moz.build create mode 100644 dom/media/mediasource/test/test_BufferedSeekCanPlayThrough.html delete mode 100644 dom/media/platforms/ffmpeg/FFmpegRDFTTypes.h create mode 100644 dom/media/test/bipbop-clearkey-video-av1.mp4 create mode 100644 dom/media/test/bipbop-clearkey-video-av1.mp4^headers^ create mode 100644 dom/media/test/bipbop-clearkey-video-av1.webm create mode 100644 dom/media/test/bipbop-clearkey-video-av1.webm^headers^ create mode 100644 dom/media/test/browser/browser_glean_first_frame_loaded_time.js create mode 100644 dom/media/test/browser/head.js create mode 100644 dom/media/test/browser/wmfme/browser_wmfme_glean_first_frame_loaded_time.js create mode 100644 dom/media/webcodecs/AudioData.cpp create mode 100644 dom/media/webcodecs/AudioData.h create mode 100644 dom/media/webcodecs/AudioDecoder.cpp create mode 100644 dom/media/webcodecs/AudioDecoder.h create mode 100644 dom/media/webcodecs/EncodedAudioChunk.cpp create mode 100644 dom/media/webcodecs/EncodedAudioChunk.h create mode 100644 dom/media/webrtc/jsapi/RTCIceTransport.cpp create mode 100644 dom/media/webrtc/jsapi/RTCIceTransport.h create mode 100644 dom/media/webrtc/tests/mochitests/test_peerConnection_RTCIceTransport.html create mode 100644 dom/quota/test/xpcshell/telemetry/test_dom_quota_try.js create mode 100644 dom/script/nsIScriptLoaderObserver.h delete mode 100644 dom/script/nsIScriptLoaderObserver.idl create mode 100644 dom/security/featurepolicy/test/mochitest/test_initial_aboutblank.html create mode 100644 dom/security/metrics.yaml create mode 100644 dom/security/test/csp/file_csp_error_messages.html create mode 100644 dom/security/test/csp/test_csp_error_messages.html create mode 100644 dom/security/test/general/browser_test_http_download.js create mode 100644 dom/security/test/general/http_download_page.html create mode 100644 dom/security/test/general/http_download_server.sjs delete mode 100644 dom/security/test/referrer-policy/browser_fragment_navigation.js create mode 100644 dom/security/test/referrer-policy/browser_session_history.js delete mode 100644 dom/security/test/referrer-policy/file_fragment_navigation.sjs create mode 100644 dom/security/test/referrer-policy/file_session_history.sjs create mode 100644 dom/security/trusted-types/TrustedHTML.cpp create mode 100644 dom/security/trusted-types/TrustedHTML.h create mode 100644 dom/security/trusted-types/TrustedScript.cpp create mode 100644 dom/security/trusted-types/TrustedScript.h create mode 100644 dom/security/trusted-types/TrustedScriptURL.cpp create mode 100644 dom/security/trusted-types/TrustedScriptURL.h create mode 100644 dom/security/trusted-types/TrustedTypePolicy.cpp create mode 100644 dom/security/trusted-types/TrustedTypePolicy.h create mode 100644 dom/security/trusted-types/TrustedTypePolicyFactory.cpp create mode 100644 dom/security/trusted-types/TrustedTypePolicyFactory.h create mode 100644 dom/security/trusted-types/TrustedTypeUtils.h create mode 100644 dom/security/trusted-types/moz.build delete mode 100644 dom/tests/mochitest/webcomponents/test_event_stopping.html create mode 100644 dom/webidl/ARIAMixin.webidl delete mode 100644 dom/webidl/AccessibilityRole.webidl delete mode 100644 dom/webidl/AriaAttributes.webidl create mode 100644 dom/webidl/AudioData.webidl create mode 100644 dom/webidl/AudioDecoder.webidl delete mode 100644 dom/webidl/DOMRequest.webidl create mode 100644 dom/webidl/EncodedAudioChunk.webidl create mode 100644 dom/webidl/RTCIceTransport.webidl create mode 100644 dom/webidl/TrustedTypes.webidl create mode 100644 dom/xslt/tests/mochitest/test_parameter_conversion.html (limited to 'dom') diff --git a/dom/animation/DocumentTimeline.cpp b/dom/animation/DocumentTimeline.cpp index 85e08ca8b0..804ae66160 100644 --- a/dom/animation/DocumentTimeline.cpp +++ b/dom/animation/DocumentTimeline.cpp @@ -55,9 +55,9 @@ DocumentTimeline::DocumentTimeline(Document* aDocument, } DocumentTimeline::~DocumentTimeline() { - MOZ_ASSERT(!mIsObservingRefreshDriver, - "Timeline should have disassociated" - " from the refresh driver before being destroyed"); + MOZ_RELEASE_ASSERT(!mIsObservingRefreshDriver, + "Timeline should have disassociated" + " from the refresh driver before being destroyed"); if (isInList()) { remove(); } @@ -206,7 +206,8 @@ void DocumentTimeline::NotifyTimerAdjusted(TimeStamp aTime) { } void DocumentTimeline::ObserveRefreshDriver(nsRefreshDriver* aDriver) { - MOZ_ASSERT(!mIsObservingRefreshDriver); + MOZ_RELEASE_ASSERT(!mIsObservingRefreshDriver, + "shouldn't register as an observer more than once"); // Set the mIsObservingRefreshDriver flag before calling AddRefreshObserver // since it might end up calling NotifyTimerAdjusted which calls // MostRecentRefreshTimeUpdated which has an assertion for @@ -218,9 +219,10 @@ void DocumentTimeline::ObserveRefreshDriver(nsRefreshDriver* aDriver) { } void DocumentTimeline::NotifyRefreshDriverCreated(nsRefreshDriver* aDriver) { - MOZ_ASSERT(!mIsObservingRefreshDriver, - "Timeline should not be observing the refresh driver before" - " it is created"); + MOZ_RELEASE_ASSERT( + !mIsObservingRefreshDriver, + "Timeline should not be observing the refresh driver before" + " it is created"); if (!mAnimationOrder.isEmpty()) { MOZ_ASSERT(isInList(), diff --git a/dom/animation/EffectCompositor.h b/dom/animation/EffectCompositor.h index 34c2688486..78ec63f595 100644 --- a/dom/animation/EffectCompositor.h +++ b/dom/animation/EffectCompositor.h @@ -244,8 +244,8 @@ class EffectCompositor { // animations that can be throttled, we will add an entry to the hashtable to // indicate that the style rule on the element is out of date but without // posting a restyle to update it. - EnumeratedArray> + EnumeratedArray, + kCascadeLevelCount> mElementsToRestyle; bool mIsInPreTraverse = false; diff --git a/dom/base/BodyUtil.cpp b/dom/base/BodyUtil.cpp index e5d86a3c36..e8de3d18ec 100644 --- a/dom/base/BodyUtil.cpp +++ b/dom/base/BodyUtil.cpp @@ -267,7 +267,7 @@ class MOZ_STACK_CLASS FormDataParser { } // Determine boundary from mimetype. - UniquePtr parsed = CMimeType::Parse(mMixedCaseMimeType); + RefPtr parsed = CMimeType::Parse(mMixedCaseMimeType); if (!parsed) { return false; } @@ -422,7 +422,7 @@ already_AddRefed BodyUtil::ConsumeFormData( if (isValidUrlEncodedMimeType) { RefPtr fd = new FormData(aParent); DebugOnly status = URLParams::Parse( - aStr, [&fd](const nsAString& aName, const nsAString& aValue) { + aStr, true, [&fd](const nsAString& aName, const nsAString& aValue) { ErrorResult rv; fd->Append(aName, aValue, rv); MOZ_ASSERT(!rv.Failed()); diff --git a/dom/base/CharacterData.cpp b/dom/base/CharacterData.cpp index b4809a0293..eccf9fe4d9 100644 --- a/dom/base/CharacterData.cpp +++ b/dom/base/CharacterData.cpp @@ -11,32 +11,22 @@ #include "mozilla/dom/CharacterData.h" -#include "mozilla/DebugOnly.h" - #include "mozilla/AsyncEventDispatcher.h" -#include "mozilla/MemoryReporting.h" #include "mozilla/dom/BindContext.h" #include "mozilla/dom/Element.h" -#include "mozilla/dom/HTMLSlotElement.h" #include "mozilla/dom/MutationObservers.h" #include "mozilla/dom/ShadowRoot.h" #include "mozilla/dom/Document.h" +#include "mozilla/dom/UnbindContext.h" #include "nsReadableUtils.h" #include "mozilla/InternalMutationEvent.h" -#include "nsCOMPtr.h" -#include "nsDOMString.h" -#include "nsChangeHint.h" -#include "nsCOMArray.h" #include "mozilla/dom/DirectionalityUtils.h" -#include "nsCCUncollectableMarker.h" #include "mozAutoDocUpdate.h" #include "nsIContentInlines.h" #include "nsTextNode.h" #include "nsBidiUtils.h" -#include "PLDHashTable.h" #include "mozilla/Sprintf.h" #include "nsWindowSizes.h" -#include "nsWrapperCacheInlines.h" #if defined(ACCESSIBILITY) && defined(DEBUG) # include "nsAccessibilityService.h" @@ -478,13 +468,14 @@ nsresult CharacterData::BindToTree(BindContext& aContext, nsINode& aParent) { return NS_OK; } -void CharacterData::UnbindFromTree(bool aNullParent) { +void CharacterData::UnbindFromTree(UnbindContext& aContext) { // Unset frame flags; if we need them again later, they'll get set again. UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE | NS_REFRAME_IF_WHITESPACE); - HandleShadowDOMRelatedRemovalSteps(aNullParent); + const bool nullParent = aContext.IsUnbindRoot(this); + HandleShadowDOMRelatedRemovalSteps(nullParent); - if (aNullParent) { + if (nullParent) { if (GetParent()) { NS_RELEASE(mParent); } else { @@ -495,15 +486,13 @@ void CharacterData::UnbindFromTree(bool aNullParent) { ClearInDocument(); SetIsConnected(false); - if (aNullParent || !mParent->IsInShadowTree()) { + if (nullParent || !mParent->IsInShadowTree()) { UnsetFlags(NODE_IS_IN_SHADOW_TREE); // Begin keeping track of our subtree root. - SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot()); - } + SetSubtreeRootPointer(nullParent ? this : mParent->SubtreeRoot()); - if (nsExtendedContentSlots* slots = GetExistingExtendedContentSlots()) { - if (aNullParent || !mParent->IsInShadowTree()) { + if (nsExtendedContentSlots* slots = GetExistingExtendedContentSlots()) { slots->mContainingShadow = nullptr; } } diff --git a/dom/base/CharacterData.h b/dom/base/CharacterData.h index 8e008b134b..50ff159eef 100644 --- a/dom/base/CharacterData.h +++ b/dom/base/CharacterData.h @@ -106,7 +106,7 @@ class CharacterData : public nsIContent { // Implementation for nsIContent nsresult BindToTree(BindContext&, nsINode& aParent) override; - void UnbindFromTree(bool aNullParent = true) override; + void UnbindFromTree(UnbindContext&) override; const nsTextFragment* GetText() override { return &mText; } uint32_t TextLength() const final { return TextDataLength(); } diff --git a/dom/base/ChromeUtils.cpp b/dom/base/ChromeUtils.cpp index be06bb083a..0df1cd3c9b 100644 --- a/dom/base/ChromeUtils.cpp +++ b/dom/base/ChromeUtils.cpp @@ -602,23 +602,6 @@ void ChromeUtils::Import(const GlobalObject& aGlobal, aRetval.set(exports); } -static mozJSModuleLoader* GetContextualESLoader( - const Optional& aLoadInDevToolsLoader, JSObject* aGlobal) { - RefPtr devToolsModuleloader = mozJSModuleLoader::GetDevToolsLoader(); - // We should load the module in the DevTools loader if: - // - ChromeUtils.importESModule's `loadInDevToolsLoader` option is true, or, - // - if the callsite is from a module loaded in the DevTools loader and - // `loadInDevToolsLoader` isn't an explicit false. - bool shouldUseDevToolsLoader = - (aLoadInDevToolsLoader.WasPassed() && aLoadInDevToolsLoader.Value()) || - (devToolsModuleloader && !aLoadInDevToolsLoader.WasPassed() && - devToolsModuleloader->IsLoaderGlobal(aGlobal)); - if (shouldUseDevToolsLoader) { - return mozJSModuleLoader::GetOrCreateDevToolsLoader(); - } - return mozJSModuleLoader::Get(); -} - static mozJSModuleLoader* GetModuleLoaderForCurrentGlobal( JSContext* aCx, const GlobalObject& aGlobal, Maybe& @@ -629,7 +612,7 @@ static mozJSModuleLoader* GetModuleLoaderForCurrentGlobal( return mozJSModuleLoader::Get(); } if (mozJSModuleLoader::IsDevToolsLoaderGlobal(global)) { - return mozJSModuleLoader::GetOrCreateDevToolsLoader(); + return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx); } if (loader::NonSharedGlobalSyncModuleLoaderScope::IsActive()) { @@ -681,7 +664,7 @@ static mozJSModuleLoader* GetModuleLoaderForOptions( Maybe& aMaybeSyncLoaderScope) { if (!aOptions.mGlobal.WasPassed()) { - return GetContextualESLoader(aOptions.mLoadInDevToolsLoader, aGlobal.Get()); + return mozJSModuleLoader::Get(); } switch (aOptions.mGlobal.Value()) { @@ -689,7 +672,7 @@ static mozJSModuleLoader* GetModuleLoaderForOptions( return mozJSModuleLoader::Get(); case ImportESModuleTargetGlobal::Devtools: - return mozJSModuleLoader::GetOrCreateDevToolsLoader(); + return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx); case ImportESModuleTargetGlobal::Contextual: { if (!NS_IsMainThread()) { @@ -700,7 +683,7 @@ static mozJSModuleLoader* GetModuleLoaderForOptions( RefPtr devToolsModuleloader = mozJSModuleLoader::GetDevToolsLoader(); if (devToolsModuleloader && devToolsModuleloader->IsLoaderGlobal(aGlobal.Get())) { - return mozJSModuleLoader::GetOrCreateDevToolsLoader(); + return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx); } return mozJSModuleLoader::Get(); } @@ -715,7 +698,8 @@ static mozJSModuleLoader* GetModuleLoaderForOptions( } static bool ValidateImportOptions( - JSContext* aCx, const ImportESModuleOptionsDictionary& aOptions) { + JSContext* aCx, const GlobalObject& aGlobal, + const ImportESModuleOptionsDictionary& aOptions) { if (!NS_IsMainThread() && (!aOptions.mGlobal.WasPassed() || (aOptions.mGlobal.Value() != ImportESModuleTargetGlobal::Current && @@ -727,12 +711,17 @@ static bool ValidateImportOptions( return false; } - if (aOptions.mGlobal.WasPassed() && - aOptions.mLoadInDevToolsLoader.WasPassed()) { - JS_ReportErrorASCII(aCx, - "global option and loadInDevToolsLoader option " - "cannot be used at the same time"); - return false; + if (NS_IsMainThread()) { + nsCOMPtr global = + do_QueryInterface(aGlobal.GetAsSupports()); + + if (mozJSModuleLoader::IsDevToolsLoaderGlobal(global) && + !aOptions.mGlobal.WasPassed()) { + JS_ReportErrorASCII(aCx, + "ChromeUtils.importESModule: global option is " + "required in DevTools distinct global"); + return false; + } } return true; @@ -745,7 +734,7 @@ void ChromeUtils::ImportESModule( JS::MutableHandle aRetval, ErrorResult& aRv) { JSContext* cx = aGlobal.Context(); - if (!ValidateImportOptions(cx, aOptions)) { + if (!ValidateImportOptions(cx, aGlobal, aOptions)) { aRv.Throw(NS_ERROR_FAILURE); return; } @@ -789,21 +778,11 @@ void ChromeUtils::ImportESModule( class EncodedOptions { public: explicit EncodedOptions(const ImportESModuleOptionsDictionary& aOptions) { - uint32_t globalFlag = 0; if (aOptions.mGlobal.WasPassed()) { - globalFlag = uint32_t(aOptions.mGlobal.Value()) + 1; - } - - uint32_t devtoolsFlag = 0; - if (aOptions.mLoadInDevToolsLoader.WasPassed()) { - if (aOptions.mLoadInDevToolsLoader.Value()) { - devtoolsFlag = DevToolsFlag_True; - } else { - devtoolsFlag = DevToolsFlag_False; - } + mValue = uint32_t(aOptions.mGlobal.Value()) + 1; + } else { + mValue = 0; } - - mValue = globalFlag | devtoolsFlag; } explicit EncodedOptions(uint32_t aValue) : mValue(aValue) {} @@ -811,37 +790,14 @@ class EncodedOptions { int32_t toInt32() const { return int32_t(mValue); } void DecodeInto(ImportESModuleOptionsDictionary& aOptions) { - uint32_t globalFlag = mValue & GlobalFlag_Mask; - if (globalFlag == 0) { + if (mValue == 0) { aOptions.mGlobal.Reset(); } else { - aOptions.mGlobal.Construct(ImportESModuleTargetGlobal(globalFlag - 1)); - } - - uint32_t devtoolsFlag = mValue & DevToolsFlag_Mask; - switch (devtoolsFlag) { - case DevToolsFlag_NotPassed: - aOptions.mLoadInDevToolsLoader.Reset(); - break; - case DevToolsFlag_False: - aOptions.mLoadInDevToolsLoader.Construct(false); - break; - case DevToolsFlag_True: - aOptions.mLoadInDevToolsLoader.Construct(true); - break; - default: - MOZ_CRASH("Unknown DevToolsFlag"); + aOptions.mGlobal.Construct(ImportESModuleTargetGlobal(mValue - 1)); } } private: - static constexpr uint32_t GlobalFlag_Mask = 0xF; - - static constexpr uint32_t DevToolsFlag_NotPassed = 0x00; - static constexpr uint32_t DevToolsFlag_False = 0x10; - static constexpr uint32_t DevToolsFlag_True = 0x20; - static constexpr uint32_t DevToolsFlag_Mask = 0x0F0; - uint32_t mValue = 0; }; @@ -1017,10 +973,6 @@ static bool ModuleGetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp, ImportESModuleOptionsDictionary options; encodedOptions.DecodeInto(options); - if (!ValidateImportOptions(aCx, options)) { - return false; - } - GlobalObject global(aCx, callee); Maybe maybeSyncLoaderScope; @@ -1198,6 +1150,11 @@ void ChromeUtils::DefineESModuleGetters( return; } + if (!ValidateImportOptions(cx, global, aOptions)) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + EncodedOptions encodedOptions(aOptions); JS::Rooted prop(cx); @@ -1411,7 +1368,8 @@ void ChromeUtils::ClearStyleSheetCache(GlobalObject&) { static WebIDLProcType ProcTypeToWebIDL(mozilla::ProcType aType) { // Max is the value of the last enum, not the length, so add one. static_assert( - WebIDLProcTypeValues::Count == static_cast(ProcType::Max) + 1, + static_cast(MaxContiguousEnumValue::value) == + static_cast(ProcType::Max), "In order for this static cast to be okay, " "WebIDLProcType must match ProcType exactly"); @@ -2118,9 +2076,9 @@ unsigned ChromeUtils::AliveUtilityProcesses(const GlobalObject&) { void ChromeUtils::GetAllPossibleUtilityActorNames(GlobalObject& aGlobal, nsTArray& aNames) { aNames.Clear(); - for (size_t i = 0; i < WebIDLUtilityActorNameValues::Count; ++i) { - auto idlName = static_cast(i); - aNames.AppendElement(WebIDLUtilityActorNameValues::GetString(idlName)); + for (UtilityActorName idlName : + MakeWebIDLEnumeratedRange()) { + aNames.AppendElement(GetEnumString(idlName)); } } diff --git a/dom/base/ChromeUtils.h b/dom/base/ChromeUtils.h index 804fc44e4a..4c2d043ecb 100644 --- a/dom/base/ChromeUtils.h +++ b/dom/base/ChromeUtils.h @@ -129,8 +129,7 @@ class ChromeUtils { static bool IsOriginAttributesEqualIgnoringFPD( const dom::OriginAttributesDictionary& aA, const dom::OriginAttributesDictionary& aB) { - return aA.mInIsolatedMozBrowser == aB.mInIsolatedMozBrowser && - aA.mUserContextId == aB.mUserContextId && + return aA.mUserContextId == aB.mUserContextId && aA.mPrivateBrowsingId == aB.mPrivateBrowsingId; } diff --git a/dom/base/ContentProcessMessageManager.cpp b/dom/base/ContentProcessMessageManager.cpp index 7fe9f4c2c7..7661d1036f 100644 --- a/dom/base/ContentProcessMessageManager.cpp +++ b/dom/base/ContentProcessMessageManager.cpp @@ -6,7 +6,6 @@ #include "ContentProcessMessageManager.h" -#include "nsContentCID.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/MessageManagerBinding.h" #include "mozilla/dom/ParentProcessMessageManager.h" @@ -31,7 +30,7 @@ ContentProcessMessageManager::~ContentProcessMessageManager() { ContentProcessMessageManager* ContentProcessMessageManager::Get() { nsCOMPtr service = - do_GetService(NS_CHILDPROCESSMESSAGEMANAGER_CONTRACTID); + do_GetService("@mozilla.org/childprocessmessagemanager;1"); if (!service) { return nullptr; } diff --git a/dom/base/DOMParser.cpp b/dom/base/DOMParser.cpp index 87bac20093..b3cf6ba04b 100644 --- a/dom/base/DOMParser.cpp +++ b/dom/base/DOMParser.cpp @@ -181,12 +181,10 @@ already_AddRefed DOMParser::ParseFromStream(nsIInputStream* aStream, // Create a fake channel nsCOMPtr parserChannel; - NS_NewInputStreamChannel( - getter_AddRefs(parserChannel), mDocumentURI, - nullptr, // aStream - mPrincipal, nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL, - nsIContentPolicy::TYPE_OTHER, - nsDependentCSubstring(SupportedTypeValues::GetString(aType))); + NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mDocumentURI, + nullptr, // aStream + mPrincipal, nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL, + nsIContentPolicy::TYPE_OTHER, GetEnumString(aType)); if (NS_WARN_IF(!parserChannel)) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; diff --git a/dom/base/DOMRequest.cpp b/dom/base/DOMRequest.cpp deleted file mode 100644 index 93c1d75d89..0000000000 --- a/dom/base/DOMRequest.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "DOMRequest.h" - -#include "DOMException.h" -#include "nsThreadUtils.h" -#include "mozilla/HoldDropJSObjects.h" -#include "mozilla/ErrorResult.h" -#include "mozilla/dom/Event.h" -#include "mozilla/dom/Promise.h" -#include "mozilla/dom/ScriptSettings.h" -#include "jsfriendapi.h" -#include "nsContentUtils.h" - -using mozilla::dom::AnyCallback; -using mozilla::dom::AutoJSAPI; -using mozilla::dom::DOMException; -using mozilla::dom::DOMRequest; -using mozilla::dom::DOMRequestService; -using mozilla::dom::Promise; -using mozilla::dom::RootingCx; - -DOMRequest::DOMRequest(nsPIDOMWindowInner* aWindow) - : DOMEventTargetHelper(aWindow), - mResult(JS::UndefinedValue()), - mDone(false) {} - -DOMRequest::DOMRequest(nsIGlobalObject* aGlobal) - : DOMEventTargetHelper(aGlobal), - mResult(JS::UndefinedValue()), - mDone(false) {} - -DOMRequest::~DOMRequest() { mozilla::DropJSObjects(this); } - -NS_IMPL_CYCLE_COLLECTION_INHERITED_WITH_JS_MEMBERS(DOMRequest, - DOMEventTargetHelper, - (mError, mPromise), - (mResult)) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMRequest) -NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) - -NS_IMPL_ADDREF_INHERITED(DOMRequest, DOMEventTargetHelper) -NS_IMPL_RELEASE_INHERITED(DOMRequest, DOMEventTargetHelper) - -/* virtual */ -JSObject* DOMRequest::WrapObject(JSContext* aCx, - JS::Handle aGivenProto) { - return DOMRequest_Binding::Wrap(aCx, this, aGivenProto); -} - -void DOMRequest::FireSuccess(JS::Handle aResult) { - NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!"); - NS_ASSERTION(!mError, "mError shouldn't have been set!"); - NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!"); - - mDone = true; - if (aResult.isGCThing()) { - RootResultVal(); - } - mResult = aResult; - - FireEvent(u"success"_ns, false, false); - - if (mPromise) { - mPromise->MaybeResolve(mResult); - } -} - -void DOMRequest::FireError(const nsAString& aError) { - NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!"); - NS_ASSERTION(!mError, "mError shouldn't have been set!"); - NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!"); - - mDone = true; - // XXX Error code chosen arbitrarily - mError = DOMException::Create(NS_ERROR_DOM_UNKNOWN_ERR, - NS_ConvertUTF16toUTF8(aError)); - - FireEvent(u"error"_ns, true, true); - - if (mPromise) { - mPromise->MaybeRejectBrokenly(mError); - } -} - -void DOMRequest::FireError(nsresult aError) { - NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!"); - NS_ASSERTION(!mError, "mError shouldn't have been set!"); - NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!"); - - mDone = true; - mError = DOMException::Create(aError); - - FireEvent(u"error"_ns, true, true); - - if (mPromise) { - mPromise->MaybeRejectBrokenly(mError); - } -} - -void DOMRequest::FireDetailedError(DOMException& aError) { - NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!"); - NS_ASSERTION(!mError, "mError shouldn't have been set!"); - NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!"); - - mDone = true; - mError = &aError; - - FireEvent(u"error"_ns, true, true); - - if (mPromise) { - mPromise->MaybeRejectBrokenly(mError); - } -} - -void DOMRequest::FireEvent(const nsAString& aType, bool aBubble, - bool aCancelable) { - if (NS_FAILED(CheckCurrentGlobalCorrectness())) { - return; - } - - RefPtr event = NS_NewDOMEvent(this, nullptr, nullptr); - event->InitEvent(aType, aBubble, aCancelable); - event->SetTrusted(true); - - DispatchEvent(*event); -} - -void DOMRequest::RootResultVal() { mozilla::HoldJSObjects(this); } - -void DOMRequest::Then(JSContext* aCx, AnyCallback* aResolveCallback, - AnyCallback* aRejectCallback, - JS::MutableHandle aRetval, - mozilla::ErrorResult& aRv) { - if (!mPromise) { - mPromise = Promise::Create(DOMEventTargetHelper::GetParentObject(), aRv); - if (aRv.Failed()) { - return; - } - if (mDone) { - // Since we create mPromise lazily, it's possible that the DOMRequest - // object has already fired its success/error event. In that case we - // should manually resolve/reject mPromise here. mPromise will take care - // of calling the callbacks on |promise| as needed. - if (mError) { - mPromise->MaybeRejectBrokenly(mError); - } else { - mPromise->MaybeResolve(mResult); - } - } - } - - // Just use the global of the Promise itself as the callee global. - JS::Rooted global(aCx, mPromise->PromiseObj()); - global = JS::GetNonCCWObjectGlobal(global); - mPromise->Then(aCx, global, aResolveCallback, aRejectCallback, aRetval, aRv); -} - -NS_IMPL_ISUPPORTS(DOMRequestService, nsIDOMRequestService) - -NS_IMETHODIMP -DOMRequestService::CreateRequest(mozIDOMWindow* aWindow, - DOMRequest** aRequest) { - MOZ_ASSERT(NS_IsMainThread()); - NS_ENSURE_STATE(aWindow); - auto* win = nsPIDOMWindowInner::From(aWindow); - RefPtr req = new DOMRequest(win); - req.forget(aRequest); - - return NS_OK; -} - -NS_IMETHODIMP -DOMRequestService::FireSuccess(DOMRequest* aRequest, - JS::Handle aResult) { - NS_ENSURE_STATE(aRequest); - aRequest->FireSuccess(aResult); - - return NS_OK; -} - -NS_IMETHODIMP -DOMRequestService::FireError(DOMRequest* aRequest, const nsAString& aError) { - NS_ENSURE_STATE(aRequest); - aRequest->FireError(aError); - - return NS_OK; -} - -class FireSuccessAsyncTask : public mozilla::Runnable { - FireSuccessAsyncTask(DOMRequest* aRequest, const JS::Value& aResult) - : mozilla::Runnable("FireSuccessAsyncTask"), - mReq(aRequest), - mResult(RootingCx(), aResult) {} - - public: - // Due to the fact that initialization can fail during shutdown (since we - // can't fetch a js context), set up an initiatization function to make sure - // we can return the failure appropriately - static nsresult Dispatch(DOMRequest* aRequest, const JS::Value& aResult) { - RefPtr asyncTask = - new FireSuccessAsyncTask(aRequest, aResult); - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(asyncTask)); - return NS_OK; - } - - NS_IMETHOD - Run() override { - mReq->FireSuccess( - JS::Handle::fromMarkedLocation(mResult.address())); - return NS_OK; - } - - private: - RefPtr mReq; - JS::PersistentRooted mResult; -}; - -class FireErrorAsyncTask : public mozilla::Runnable { - public: - FireErrorAsyncTask(DOMRequest* aRequest, const nsAString& aError) - : mozilla::Runnable("FireErrorAsyncTask"), - mReq(aRequest), - mError(aError) {} - - NS_IMETHOD - Run() override { - mReq->FireError(mError); - return NS_OK; - } - - private: - RefPtr mReq; - nsString mError; -}; - -NS_IMETHODIMP -DOMRequestService::FireSuccessAsync(DOMRequest* aRequest, - JS::Handle aResult) { - NS_ENSURE_STATE(aRequest); - return FireSuccessAsyncTask::Dispatch(aRequest, aResult); -} - -NS_IMETHODIMP -DOMRequestService::FireErrorAsync(DOMRequest* aRequest, - const nsAString& aError) { - NS_ENSURE_STATE(aRequest); - nsCOMPtr asyncTask = new FireErrorAsyncTask(aRequest, aError); - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(asyncTask)); - return NS_OK; -} diff --git a/dom/base/DOMRequest.h b/dom/base/DOMRequest.h deleted file mode 100644 index b0e7c23112..0000000000 --- a/dom/base/DOMRequest.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_domrequest_h__ -#define mozilla_dom_domrequest_h__ - -#include "nsIDOMRequestService.h" -#include "mozilla/Attributes.h" -#include "mozilla/DOMEventTargetHelper.h" -#include "mozilla/dom/DOMException.h" -#include "mozilla/dom/DOMRequestBinding.h" - -#include "nsCOMPtr.h" - -namespace mozilla { - -class ErrorResult; - -namespace dom { - -class AnyCallback; -class Promise; - -class DOMRequest : public DOMEventTargetHelper { - protected: - JS::Heap mResult; - RefPtr mError; - RefPtr mPromise; - bool mDone; - - public: - NS_DECL_ISUPPORTS_INHERITED - - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(DOMRequest, - DOMEventTargetHelper) - - // WrapperCache - nsPIDOMWindowInner* GetParentObject() const { return GetOwner(); } - - virtual JSObject* WrapObject(JSContext* aCx, - JS::Handle aGivenProto) override; - - // WebIDL Interface - DOMRequestReadyState ReadyState() const { - return mDone ? DOMRequestReadyState::Done : DOMRequestReadyState::Pending; - } - - void GetResult(JSContext*, JS::MutableHandle aRetval) const { - NS_ASSERTION(mDone || mResult.isUndefined(), - "Result should be undefined when pending"); - aRetval.set(mResult); - } - - DOMException* GetError() const { - NS_ASSERTION(mDone || !mError, "Error should be null when pending"); - return mError; - } - - IMPL_EVENT_HANDLER(success) - IMPL_EVENT_HANDLER(error) - - void Then(JSContext* aCx, AnyCallback* aResolveCallback, - AnyCallback* aRejectCallback, JS::MutableHandle aRetval, - mozilla::ErrorResult& aRv); - - void FireSuccess(JS::Handle aResult); - void FireError(const nsAString& aError); - void FireError(nsresult aError); - void FireDetailedError(DOMException& aError); - - explicit DOMRequest(nsPIDOMWindowInner* aWindow); - explicit DOMRequest(nsIGlobalObject* aGlobal); - - protected: - virtual ~DOMRequest(); - - void FireEvent(const nsAString& aType, bool aBubble, bool aCancelable); - - void RootResultVal(); -}; - -class DOMRequestService final : public nsIDOMRequestService { - ~DOMRequestService() = default; - - public: - NS_DECL_ISUPPORTS - NS_DECL_NSIDOMREQUESTSERVICE - - // No one should call this but the factory. - static already_AddRefed FactoryCreate() { - return MakeAndAddRef(); - } -}; - -} // namespace dom -} // namespace mozilla - -#define DOMREQUEST_SERVICE_CONTRACTID "@mozilla.org/dom/dom-request-service;1" - -#endif // mozilla_dom_domrequest_h__ diff --git a/dom/base/DOMRequestHelper.sys.mjs b/dom/base/DOMRequestHelper.sys.mjs deleted file mode 100644 index 832c06c4de..0000000000 --- a/dom/base/DOMRequestHelper.sys.mjs +++ /dev/null @@ -1,335 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Helper object for APIs that deal with DOMRequests and Promises. - * It allows objects inheriting from it to create and keep track of DOMRequests - * and Promises objects in the common scenario where requests are created in - * the child, handed out to content and delivered to the parent within an async - * message (containing the identifiers of these requests). The parent may send - * messages back as answers to different requests and the child will use this - * helper to get the right request object. This helper also takes care of - * releasing the requests objects when the window goes out of scope. - * - * DOMRequestIPCHelper also deals with message listeners, allowing to add them - * to the child side of frame and process message manager and removing them - * when needed. - */ -export function DOMRequestIpcHelper() { - // _listeners keeps a list of messages for which we added a listener and the - // kind of listener that we added (strong or weak). It's an object of this - // form: - // { - // "message1": true, - // "messagen": false - // } - // - // where each property is the name of the message and its value is a boolean - // that indicates if the listener is weak or not. - this._listeners = null; - this._requests = null; - this._window = null; -} - -DOMRequestIpcHelper.prototype = { - /** - * An object which "inherits" from DOMRequestIpcHelper and declares its own - * queryInterface method MUST implement Ci.nsISupportsWeakReference. - */ - QueryInterface: ChromeUtils.generateQI([ - "nsISupportsWeakReference", - "nsIObserver", - ]), - - /** - * 'aMessages' is expected to be an array of either: - * - objects of this form: - * { - * name: "messageName", - * weakRef: false - * } - * where 'name' is the message identifier and 'weakRef' a boolean - * indicating if the listener should be a weak referred one or not. - * - * - or only strings containing the message name, in which case the listener - * will be added as a strong reference by default. - */ - addMessageListeners(aMessages) { - if (!aMessages) { - return; - } - - if (!this._listeners) { - this._listeners = {}; - } - - if (!Array.isArray(aMessages)) { - aMessages = [aMessages]; - } - - aMessages.forEach(aMsg => { - let name = aMsg.name || aMsg; - // If the listener is already set and it is of the same type we just - // increase the count and bail out. If it is not of the same type, - // we throw an exception. - if (this._listeners[name] != undefined) { - if (!!aMsg.weakRef == this._listeners[name].weakRef) { - this._listeners[name].count++; - return; - } - throw Components.Exception("", Cr.NS_ERROR_FAILURE); - } - - aMsg.weakRef - ? Services.cpmm.addWeakMessageListener(name, this) - : Services.cpmm.addMessageListener(name, this); - this._listeners[name] = { - weakRef: !!aMsg.weakRef, - count: 1, - }; - }); - }, - - /** - * 'aMessages' is expected to be a string or an array of strings containing - * the message names of the listeners to be removed. - */ - removeMessageListeners(aMessages) { - if (!this._listeners || !aMessages) { - return; - } - - if (!Array.isArray(aMessages)) { - aMessages = [aMessages]; - } - - aMessages.forEach(aName => { - if (this._listeners[aName] == undefined) { - return; - } - - // Only remove the listener really when we don't have anybody that could - // be waiting on a message. - if (!--this._listeners[aName].count) { - this._listeners[aName].weakRef - ? Services.cpmm.removeWeakMessageListener(aName, this) - : Services.cpmm.removeMessageListener(aName, this); - delete this._listeners[aName]; - } - }); - }, - - /** - * Initialize the helper adding the corresponding listeners to the messages - * provided as the second parameter. - * - * 'aMessages' is expected to be an array of either: - * - * - objects of this form: - * { - * name: 'messageName', - * weakRef: false - * } - * where 'name' is the message identifier and 'weakRef' a boolean - * indicating if the listener should be a weak referred one or not. - * - * - or only strings containing the message name, in which case the listener - * will be added as a strong referred one by default. - */ - initDOMRequestHelper(aWindow, aMessages) { - // Query our required interfaces to force a fast fail if they are not - // provided. These calls will throw if the interface is not available. - this.QueryInterface(Ci.nsISupportsWeakReference); - this.QueryInterface(Ci.nsIObserver); - - if (aMessages) { - this.addMessageListeners(aMessages); - } - - this._id = this._getRandomId(); - - this._window = aWindow; - if (this._window) { - // We don't use this.innerWindowID, but other classes rely on it. - this.innerWindowID = this._window.windowGlobalChild.innerWindowId; - } - - this._destroyed = false; - - Services.obs.addObserver( - this, - "inner-window-destroyed", - /* weak-ref */ true - ); - }, - - destroyDOMRequestHelper() { - if (this._destroyed) { - return; - } - - this._destroyed = true; - - Services.obs.removeObserver(this, "inner-window-destroyed"); - - if (this._listeners) { - Object.keys(this._listeners).forEach(aName => { - this._listeners[aName].weakRef - ? Services.cpmm.removeWeakMessageListener(aName, this) - : Services.cpmm.removeMessageListener(aName, this); - }); - } - - this._listeners = null; - this._requests = null; - - // Objects inheriting from DOMRequestIPCHelper may have an uninit function. - if (this.uninit) { - this.uninit(); - } - - this._window = null; - }, - - observe(aSubject, aTopic, aData) { - if (aTopic !== "inner-window-destroyed") { - return; - } - - let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data; - if (wId != this.innerWindowID) { - return; - } - - this.destroyDOMRequestHelper(); - }, - - getRequestId(aRequest) { - if (!this._requests) { - this._requests = {}; - } - - let id = "id" + this._getRandomId(); - this._requests[id] = aRequest; - return id; - }, - - getPromiseResolverId(aPromiseResolver) { - // Delegates to getRequest() since the lookup table is agnostic about - // storage. - return this.getRequestId(aPromiseResolver); - }, - - getRequest(aId) { - if (this._requests && this._requests[aId]) { - return this._requests[aId]; - } - return undefined; - }, - - getPromiseResolver(aId) { - // Delegates to getRequest() since the lookup table is agnostic about - // storage. - return this.getRequest(aId); - }, - - removeRequest(aId) { - if (this._requests && this._requests[aId]) { - delete this._requests[aId]; - } - }, - - removePromiseResolver(aId) { - // Delegates to getRequest() since the lookup table is agnostic about - // storage. - this.removeRequest(aId); - }, - - takeRequest(aId) { - if (!this._requests || !this._requests[aId]) { - return null; - } - let request = this._requests[aId]; - delete this._requests[aId]; - return request; - }, - - takePromiseResolver(aId) { - // Delegates to getRequest() since the lookup table is agnostic about - // storage. - return this.takeRequest(aId); - }, - - _getRandomId() { - return Services.uuid.generateUUID().toString(); - }, - - createRequest() { - // If we don't have a valid window object, throw. - if (!this._window) { - console.error( - "DOMRequestHelper trying to create a DOMRequest without a valid window, failing." - ); - throw Components.Exception("", Cr.NS_ERROR_FAILURE); - } - return Services.DOMRequest.createRequest(this._window); - }, - - /** - * createPromise() creates a new Promise, with `aPromiseInit` as the - * PromiseInit callback. The promise constructor is obtained from the - * reference to window owned by this DOMRequestIPCHelper. - */ - createPromise(aPromiseInit) { - // If we don't have a valid window object, throw. - if (!this._window) { - console.error( - "DOMRequestHelper trying to create a Promise without a valid window, failing." - ); - throw Components.Exception("", Cr.NS_ERROR_FAILURE); - } - return new this._window.Promise(aPromiseInit); - }, - - /** - * createPromiseWithId() creates a new Promise, accepting a callback - * which is immediately called with the generated resolverId. - */ - createPromiseWithId(aCallback) { - return this.createPromise((aResolve, aReject) => { - let resolverId = this.getPromiseResolverId({ - resolve: aResolve, - reject: aReject, - }); - aCallback(resolverId); - }); - }, - - forEachRequest(aCallback) { - if (!this._requests) { - return; - } - - Object.keys(this._requests).forEach(aKey => { - if (this._window.DOMRequest.isInstance(this.getRequest(aKey))) { - aCallback(aKey); - } - }); - }, - - forEachPromiseResolver(aCallback) { - if (!this._requests) { - return; - } - - Object.keys(this._requests).forEach(aKey => { - if ( - "resolve" in this.getPromiseResolver(aKey) && - "reject" in this.getPromiseResolver(aKey) - ) { - aCallback(aKey); - } - }); - }, -}; diff --git a/dom/base/DirectionalityUtils.cpp b/dom/base/DirectionalityUtils.cpp index 46229cfbd3..dd427c61b1 100644 --- a/dom/base/DirectionalityUtils.cpp +++ b/dom/base/DirectionalityUtils.cpp @@ -5,8 +5,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* - Implementation description from https://etherpad.mozilla.org/dir-auto - Static case =========== When we see a new content node with @dir=auto from the parser, we set the @@ -45,23 +43,8 @@ I will call this algorithm "upward propagation". - Each text node should maintain a list of elements which have their - directionality determined by the first strong character of that text node. - This is useful to make dynamic changes more efficient. One way to implement - this is to have a per-document hash table mapping a text node to a set of - elements. I'll call this data structure TextNodeDirectionalityMap. The - algorithm for appending a new text node above needs to update this data - structure. - - *IMPLEMENTATION NOTE* - In practice, the implementation uses two per-node properties: - - dirAutoSetBy, which is set on a node with auto-directionality, and points to - the textnode that contains the strong character which determines the - directionality of the node. - - textNodeDirectionalityMap, which is set on a text node and points to a hash - table listing the nodes whose directionality is determined by the text node. + Each text node keeps a flag if it might determine the directionality of any + ancestor. This is useful to make dynamic changes more efficient. Handling dynamic changes ======================== @@ -90,16 +73,15 @@ (I'll call this the "downward propagation algorithm".) by walking the child subtree in tree order. Note that an element with @dir=auto should not affect other elements in its document with @dir=auto. So there is no need to walk up - the parent chain in this case. TextNodeDirectionalityMap needs to be updated - as appropriate. + the parent chain in this case. 3a. When the dir attribute is set to any valid value on an element that didn't have a valid dir attribute before, this means that any descendant of that element will not affect the directionality of any of its ancestors. So we need - to check whether any text node descendants of the element are listed in - TextNodeDirectionalityMap, and whether the elements whose direction they set - are ancestors of the element. If so, we need to rerun the downward propagation - algorithm for those ancestors. + to check whether any text node descendants of the element can set the dir of + any ancestor, and whether the elements whose direction they set are ancestors + of the element. If so, we need to rerun the downward propagation algorithm for + those ancestors. That's done by OnSetDirAttr. 4. When the dir attribute is changed from auto to something else (including the case where it gets removed) on a textarea or an input element with @@ -118,80 +100,29 @@ should still retain the same flag.) * We resolve the directionality of the element based on the value of the @dir attribute on the element itself or its parent element. - TextNodeDirectionalityMap needs to be updated as appropriate. 5a. When the dir attribute is removed or set to an invalid value on any element (except a bdi element) with the NodeAncestorHasDirAuto flag which previously had a valid dir attribute, it might have a text node descendant that did not previously affect the directionality of any of its ancestors but - should now begin to affect them. We run the following algorithm: - * Walk up the parent chain from the element. - * For any element that appears in the TextNodeDirectionalityMap, remove the - element from the map and rerun the downward propagation algorithm - (see section 3). - * If we reach an element without either of the NodeHasDirAuto or - NodeAncestorHasDirAuto flags, abort the parent chain walk. + should now begin to affect them. We run OnSetDirAttr. 6. When an element with @dir=auto is added to the document, we should handle it similar to the case 2/3 above. 7. When an element with NodeHasDirAuto or NodeAncestorHasDirAuto is removed from the document, we should handle it similar to the case 4/5 above, - except that we don't need to handle anything in the child subtree. We should - also remove all of the occurrences of that node and its descendants from - TextNodeDirectionalityMap. (This is the conceptual description of what needs - to happen but in the implementation UnbindFromTree is going to be called on - all of the descendants so we don't need to descend into the child subtree). + except that we don't need to handle anything in the child subtree. 8. When the contents of a text node is changed either from script or by the - user, we need to run the following algorithm: - * If the change has happened after the first character with strong - directionality in the text node, do nothing. - * If the text node is a child of a bdi, script or style element, do nothing. - * If the text node belongs to a textarea with NodeHasDirAuto, we need to - update the directionality of the textarea. - * Grab a list of elements affected by this text node from - TextNodeDirectionalityMap and re-resolve the directionality of each one of - them based on the new contents of the text node. - * If the text node does not exist in TextNodeDirectionalityMap, and it has the - NodeAncestorHasDirAuto flag set, this could potentially be a text node - which is going to start affecting the directionality of its parent @dir=auto - elements. In this case, we need to fall back to the (potentially expensive) - "upward propagation algorithm". The TextNodeDirectionalityMap data structure - needs to be update during this algorithm. - * If the new contents of the text node do not have any strong characters, and - the old contents used to, and the text node used to exist in - TextNodeDirectionalityMap and it has the NodeAncestorHasDirAuto flag set, - the elements associated with this text node inside TextNodeDirectionalityMap - will now get their directionality from another text node. In this case, for - each element in the list retrieved from TextNodeDirectionalityMap, run the - downward propagation algorithm (section 3), and remove the text node from - TextNodeDirectionalityMap. - - 9. When a new text node is injected into a document, we need to run the - following algorithm: - * If the contents of the text node do not have any characters with strong - direction, do nothing. - * If the text node is a child of a bdi, script or style element, do nothing. - * If the text node is appended to a textarea element with NodeHasDirAuto, we - need to update the directionality of the textarea. - * If the text node has NodeAncestorHasDirAuto, we need to run the "upward - propagation algorithm". The TextNodeDirectionalityMap data structure needs to - be update during this algorithm. - - 10. When a text node is removed from a document, we need to run the following - algorithm: - * If the contents of the text node do not have any characters with strong - direction, do nothing. - * If the text node is a child of a bdi, script or style element, do nothing. - * If the text node is removed from a textarea element with NodeHasDirAuto, - set the directionality to "ltr". (This is what the spec currently says, but - I'm filing a spec bug to get it fixed -- the directionality should depend on - the parent element here.) - * If the text node has NodeAncestorHasDirAuto, we need to look at the list - of elements being affected by this text node from TextNodeDirectionalityMap, - run the "downward propagation algorithm" (section 3) for each one of them, - while updating TextNodeDirectionalityMap along the way. + user, we need to run TextNode{WillChange,Changed}Direction, see inline docs + for details. + + 9. When a new text node is injected into a document, we need to run + SetDirectionFromNewTextNode. + + 10. When a text node is removed from a document, we need to run + ResetDirectionSetByTextNode. 11. If the value of the @dir attribute on a bdi element is changed to an invalid value (or if it's removed), determine the new directionality similar @@ -210,18 +141,16 @@ #include "nsIContent.h" #include "nsIContentInlines.h" #include "mozilla/dom/Document.h" -#include "mozilla/AutoRestore.h" -#include "mozilla/DebugOnly.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLInputElement.h" #include "mozilla/dom/HTMLSlotElement.h" #include "mozilla/dom/ShadowRoot.h" +#include "mozilla/dom/UnbindContext.h" #include "mozilla/intl/UnicodeProperties.h" #include "nsUnicodeProperties.h" #include "nsTextFragment.h" #include "nsAttrValue.h" #include "nsTextNode.h" -#include "nsCheapSets.h" namespace mozilla { @@ -230,75 +159,53 @@ using mozilla::dom::HTMLInputElement; using mozilla::dom::HTMLSlotElement; using mozilla::dom::ShadowRoot; -static nsIContent* GetParentOrHostOrSlot( - const nsIContent* aContent, bool* aCrossedShadowBoundary = nullptr) { +static nsIContent* GetParentOrHostOrSlot(const nsIContent* aContent) { if (HTMLSlotElement* slot = aContent->GetAssignedSlot()) { - if (aCrossedShadowBoundary) { - *aCrossedShadowBoundary = true; - } return slot; } - - nsIContent* parent = aContent->GetParent(); - if (parent) { + if (nsIContent* parent = aContent->GetParent()) { return parent; } - - const ShadowRoot* sr = ShadowRoot::FromNode(aContent); - if (sr) { - if (aCrossedShadowBoundary) { - *aCrossedShadowBoundary = true; - } - return sr->Host(); + if (const ShadowRoot* sr = ShadowRoot::FromNode(aContent)) { + return sr->GetHost(); } - return nullptr; } -static bool AncestorChainCrossesShadowBoundary(nsIContent* aDescendant, - nsIContent* aAncestor) { - bool crossedShadowBoundary = false; - nsIContent* content = aDescendant; - while (content && content != aAncestor) { - content = GetParentOrHostOrSlot(content, &crossedShadowBoundary); - if (crossedShadowBoundary) { - return true; - } - } - - return false; -} - /** - * Returns true if aElement is one of the elements whose text content should not - * affect its own direction, nor the direction of ancestors with dir=auto. + * Returns true if aElement is one of the elements whose text content should + * affect its own direction, or the direction of ancestors with dir=auto. * * Note that this does not include , whose content does affect its own * direction when it has dir=auto (which it has by default), so one needs to - * test for it separately, e.g. with DoesNotAffectDirectionOfAncestors. + * test for it separately, e.g. with AffectsDirectionOfAncestors. * It *does* include textarea, because even if a textarea has dir=auto, it has * unicode-bidi: plaintext and is handled automatically in bidi resolution. * It also includes `input`, because it takes the `dir` value from its value * attribute, instead of the child nodes. */ -static bool DoesNotParticipateInAutoDirection(const nsIContent* aContent) { - mozilla::dom::NodeInfo* nodeInfo = aContent->NodeInfo(); - return ((!aContent->IsHTMLElement() || nodeInfo->Equals(nsGkAtoms::script) || - nodeInfo->Equals(nsGkAtoms::style) || - nodeInfo->Equals(nsGkAtoms::input) || - nodeInfo->Equals(nsGkAtoms::textarea) || - aContent->IsInNativeAnonymousSubtree())) && - !aContent->IsShadowRoot(); +static bool ParticipatesInAutoDirection(const nsIContent* aContent) { + if (aContent->IsInNativeAnonymousSubtree()) { + return false; + } + if (aContent->IsShadowRoot()) { + return true; + } + dom::NodeInfo* ni = aContent->NodeInfo(); + return ni->NamespaceID() == kNameSpaceID_XHTML && + !ni->Equals(nsGkAtoms::script) && !ni->Equals(nsGkAtoms::style) && + !ni->Equals(nsGkAtoms::input) && !ni->Equals(nsGkAtoms::textarea); } /** - * Returns true if aElement is one of the element whose text content should not - * affect the direction of ancestors with dir=auto (though it may affect its own - * direction, e.g. ) + * Returns true if aElement is one of the element whose text should affect the + * direction of ancestors with dir=auto (though note that even if it returns + * false it may affect its own direction, e.g. or dir=auto itself) */ -static bool DoesNotAffectDirectionOfAncestors(const Element* aElement) { - return (DoesNotParticipateInAutoDirection(aElement) || - aElement->IsHTMLElement(nsGkAtoms::bdi) || aElement->HasFixedDir()); +static bool AffectsDirectionOfAncestors(const Element* aElement) { + return ParticipatesInAutoDirection(aElement) && + !aElement->IsHTMLElement(nsGkAtoms::bdi) && !aElement->HasFixedDir() && + !aElement->HasDirAuto(); } /** @@ -318,11 +225,15 @@ static Directionality GetDirectionFromChar(uint32_t ch) { } } -inline static bool NodeAffectsDirAutoAncestor(nsIContent* aTextNode) { +inline static bool TextChildrenAffectDirAutoAncestor(nsIContent* aContent) { + return ParticipatesInAutoDirection(aContent) && + aContent->NodeOrAncestorHasDirAuto(); +} + +inline static bool NodeAffectsDirAutoAncestor(nsTextNode* aTextNode) { nsIContent* parent = GetParentOrHostOrSlot(aTextNode); - return (parent && !DoesNotParticipateInAutoDirection(parent) && - parent->NodeOrAncestorHasDirAuto() && - !aTextNode->IsInNativeAnonymousSubtree()); + return parent && TextChildrenAffectDirAutoAncestor(parent) && + !aTextNode->IsInNativeAnonymousSubtree(); } Directionality GetDirectionFromText(const char16_t* aText, @@ -394,11 +305,11 @@ static Directionality GetDirectionFromText(const mozilla::dom::Text* aTextNode, } static nsTextNode* WalkDescendantsAndGetDirectionFromText( - nsINode* aRoot, nsINode* aSkip, Directionality* aDirectionality) { + nsINode* aRoot, Directionality* aDirectionality) { nsIContent* child = aRoot->GetFirstChild(); while (child) { if ((child->IsElement() && - DoesNotAffectDirectionOfAncestors(child->AsElement())) || + !AffectsDirectionOfAncestors(child->AsElement())) || child->GetAssignedSlot()) { child = child->GetNextNonChildNode(aRoot); continue; @@ -409,19 +320,16 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText( for (uint32_t i = 0; i < assignedNodes.Length(); ++i) { nsIContent* assignedNode = assignedNodes[i]->AsContent(); if (assignedNode->NodeType() == nsINode::TEXT_NODE) { - auto text = static_cast(assignedNode); - if (assignedNode != aSkip) { - Directionality textNodeDir = GetDirectionFromText(text); - if (textNodeDir != Directionality::Unset) { - *aDirectionality = textNodeDir; - return text; - } + auto* text = static_cast(assignedNode); + Directionality textNodeDir = GetDirectionFromText(text); + if (textNodeDir != Directionality::Unset) { + *aDirectionality = textNodeDir; + return text; } } else if (assignedNode->IsElement() && - !DoesNotAffectDirectionOfAncestors( - assignedNode->AsElement())) { + AffectsDirectionOfAncestors(assignedNode->AsElement())) { nsTextNode* text = WalkDescendantsAndGetDirectionFromText( - assignedNode, aSkip, aDirectionality); + assignedNode, aDirectionality); if (text) { return text; } @@ -429,8 +337,8 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText( } } - if (child->NodeType() == nsINode::TEXT_NODE && child != aSkip) { - auto text = static_cast(child); + if (child->NodeType() == nsINode::TEXT_NODE) { + auto* text = static_cast(child); Directionality textNodeDir = GetDirectionFromText(text); if (textNodeDir != Directionality::Unset) { *aDirectionality = textNodeDir; @@ -447,17 +355,14 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText( * Set the directionality of a node with dir=auto as defined in * http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#the-directionality * - * @param[in] changedNode If we call this method because the content of a text - * node is about to change, pass in the changed node, so that we - * know not to return it * @return the text node containing the character that determined the direction */ -static nsTextNode* WalkDescendantsSetDirectionFromText( - Element* aElement, bool aNotify, nsINode* aChangedNode = nullptr) { +static nsTextNode* WalkDescendantsSetDirectionFromText(Element* aElement, + bool aNotify) { MOZ_ASSERT(aElement, "Must have an element"); MOZ_ASSERT(aElement->HasDirAuto(), "Element must have dir=auto"); - if (DoesNotParticipateInAutoDirection(aElement)) { + if (!ParticipatesInAutoDirection(aElement)) { return nullptr; } @@ -465,8 +370,8 @@ static nsTextNode* WalkDescendantsSetDirectionFromText( // Check the text in Shadow DOM. if (ShadowRoot* shadowRoot = aElement->GetShadowRoot()) { - nsTextNode* text = WalkDescendantsAndGetDirectionFromText( - shadowRoot, aChangedNode, &textNodeDir); + nsTextNode* text = + WalkDescendantsAndGetDirectionFromText(shadowRoot, &textNodeDir); if (text) { aElement->SetDirectionality(textNodeDir, aNotify); return text; @@ -474,8 +379,8 @@ static nsTextNode* WalkDescendantsSetDirectionFromText( } // Check the text in light DOM. - nsTextNode* text = WalkDescendantsAndGetDirectionFromText( - aElement, aChangedNode, &textNodeDir); + nsTextNode* text = + WalkDescendantsAndGetDirectionFromText(aElement, &textNodeDir); if (text) { aElement->SetDirectionality(textNodeDir, aNotify); return text; @@ -487,194 +392,6 @@ static nsTextNode* WalkDescendantsSetDirectionFromText( return nullptr; } -class nsTextNodeDirectionalityMap { - static void nsTextNodeDirectionalityMapDtor(void* aObject, - nsAtom* aPropertyName, - void* aPropertyValue, - void* aData) { - nsINode* textNode = static_cast(aObject); - textNode->ClearHasTextNodeDirectionalityMap(); - - nsTextNodeDirectionalityMap* map = - reinterpret_cast(aPropertyValue); - map->EnsureMapIsClear(); - delete map; - } - - public: - explicit nsTextNodeDirectionalityMap(nsINode* aTextNode) - : mElementToBeRemoved(nullptr) { - MOZ_ASSERT(aTextNode, "Null text node"); - MOZ_COUNT_CTOR(nsTextNodeDirectionalityMap); - aTextNode->SetProperty(nsGkAtoms::textNodeDirectionalityMap, this, - nsTextNodeDirectionalityMapDtor); - aTextNode->SetHasTextNodeDirectionalityMap(); - } - - MOZ_COUNTED_DTOR(nsTextNodeDirectionalityMap) - - static void nsTextNodeDirectionalityMapPropertyDestructor( - void* aObject, nsAtom* aProperty, void* aPropertyValue, void* aData) { - nsTextNode* textNode = static_cast(aPropertyValue); - nsTextNodeDirectionalityMap* map = GetDirectionalityMap(textNode); - if (map) { - map->RemoveEntryForProperty(static_cast(aObject)); - } - NS_RELEASE(textNode); - } - - void AddEntry(nsTextNode* aTextNode, Element* aElement) { - if (!mElements.Contains(aElement)) { - mElements.Put(aElement); - NS_ADDREF(aTextNode); - aElement->SetProperty(nsGkAtoms::dirAutoSetBy, aTextNode, - nsTextNodeDirectionalityMapPropertyDestructor); - aElement->SetHasDirAutoSet(); - } - } - - void RemoveEntry(nsTextNode* aTextNode, Element* aElement) { - NS_ASSERTION(mElements.Contains(aElement), - "element already removed from map"); - - mElements.Remove(aElement); - aElement->ClearHasDirAutoSet(); - aElement->RemoveProperty(nsGkAtoms::dirAutoSetBy); - } - - void RemoveEntryForProperty(Element* aElement) { - if (mElementToBeRemoved != aElement) { - mElements.Remove(aElement); - } - aElement->ClearHasDirAutoSet(); - } - - private: - nsCheapSet> mElements; - // Only used for comparison. - Element* mElementToBeRemoved; - - static nsTextNodeDirectionalityMap* GetDirectionalityMap(nsINode* aTextNode) { - MOZ_ASSERT(aTextNode->NodeType() == nsINode::TEXT_NODE, - "Must be a text node"); - nsTextNodeDirectionalityMap* map = nullptr; - - if (aTextNode->HasTextNodeDirectionalityMap()) { - map = static_cast( - aTextNode->GetProperty(nsGkAtoms::textNodeDirectionalityMap)); - } - - return map; - } - - static nsCheapSetOperator SetNodeDirection(nsPtrHashKey* aEntry, - void* aDir) { - aEntry->GetKey()->SetDirectionality( - *reinterpret_cast(aDir), true); - return OpNext; - } - - struct nsTextNodeDirectionalityMapAndElement { - nsTextNodeDirectionalityMap* mMap; - nsCOMPtr mNode; - }; - - static nsCheapSetOperator ResetNodeDirection(nsPtrHashKey* aEntry, - void* aData) { - // run the downward propagation algorithm - // and remove the text node from the map - nsTextNodeDirectionalityMapAndElement* data = - static_cast(aData); - nsINode* oldTextNode = data->mNode; - Element* rootNode = aEntry->GetKey(); - nsTextNode* newTextNode = nullptr; - if (rootNode->GetParentNode() && rootNode->HasDirAuto()) { - newTextNode = - WalkDescendantsSetDirectionFromText(rootNode, true, oldTextNode); - } - - AutoRestore restore(data->mMap->mElementToBeRemoved); - data->mMap->mElementToBeRemoved = rootNode; - if (newTextNode) { - nsINode* oldDirAutoSetBy = static_cast( - rootNode->GetProperty(nsGkAtoms::dirAutoSetBy)); - if (oldDirAutoSetBy == newTextNode) { - // We're already registered. - return OpNext; - } - nsTextNodeDirectionalityMap::AddEntryToMap(newTextNode, rootNode); - } else { - rootNode->ClearHasDirAutoSet(); - rootNode->RemoveProperty(nsGkAtoms::dirAutoSetBy); - } - return OpRemove; - } - - static nsCheapSetOperator TakeEntries(nsPtrHashKey* aEntry, - void* aData) { - AutoTArray* entries = - static_cast*>(aData); - entries->AppendElement(aEntry->GetKey()); - return OpRemove; - } - - public: - uint32_t UpdateAutoDirection(Directionality aDir) { - return mElements.EnumerateEntries(SetNodeDirection, &aDir); - } - - void ResetAutoDirection(nsINode* aTextNode) { - nsTextNodeDirectionalityMapAndElement data = {this, aTextNode}; - mElements.EnumerateEntries(ResetNodeDirection, &data); - } - - void EnsureMapIsClear() { - AutoRestore restore(mElementToBeRemoved); - AutoTArray entries; - mElements.EnumerateEntries(TakeEntries, &entries); - for (Element* el : entries) { - el->ClearHasDirAutoSet(); - el->RemoveProperty(nsGkAtoms::dirAutoSetBy); - } - } - - static void RemoveElementFromMap(nsTextNode* aTextNode, Element* aElement) { - if (aTextNode->HasTextNodeDirectionalityMap()) { - GetDirectionalityMap(aTextNode)->RemoveEntry(aTextNode, aElement); - } - } - - static void AddEntryToMap(nsTextNode* aTextNode, Element* aElement) { - nsTextNodeDirectionalityMap* map = GetDirectionalityMap(aTextNode); - if (!map) { - map = new nsTextNodeDirectionalityMap(aTextNode); - } - - map->AddEntry(aTextNode, aElement); - } - - static uint32_t UpdateTextNodeDirection(nsINode* aTextNode, - Directionality aDir) { - MOZ_ASSERT(aTextNode->HasTextNodeDirectionalityMap(), - "Map missing in UpdateTextNodeDirection"); - return GetDirectionalityMap(aTextNode)->UpdateAutoDirection(aDir); - } - - static void ResetTextNodeDirection(nsTextNode* aTextNode, - nsTextNode* aChangedTextNode) { - MOZ_ASSERT(aTextNode->HasTextNodeDirectionalityMap(), - "Map missing in ResetTextNodeDirection"); - RefPtr textNode = aTextNode; - GetDirectionalityMap(textNode)->ResetAutoDirection(aChangedTextNode); - } - - static void EnsureMapIsClearFor(nsINode* aTextNode) { - if (aTextNode->HasTextNodeDirectionalityMap()) { - GetDirectionalityMap(aTextNode)->EnsureMapIsClear(); - } - } -}; - Directionality GetParentDirectionality(const Element* aElement) { if (nsIContent* parent = GetParentOrHostOrSlot(aElement)) { if (ShadowRoot* shadow = ShadowRoot::FromNode(parent)) { @@ -729,7 +446,7 @@ static inline bool IsBoundary(const Element& aElement) { static void SetDirectionalityOnDescendantsInternal(nsINode* aNode, Directionality aDir, bool aNotify) { - if (Element* element = Element::FromNode(aNode)) { + if (auto* element = Element::FromNode(aNode)) { if (ShadowRoot* shadow = element->GetShadowRoot()) { SetDirectionalityOnDescendantsInternal(shadow, aDir, aNotify); } @@ -778,66 +495,37 @@ void SetDirectionalityOnDescendants(Element* aElement, Directionality aDir, } static void ResetAutoDirection(Element* aElement, bool aNotify) { - if (aElement->HasDirAutoSet()) { - // If the parent has the DirAutoSet flag, its direction is determined by - // some text node descendant. - // Remove it from the map and reset its direction by the downward - // propagation algorithm - nsTextNode* setByNode = static_cast( - aElement->GetProperty(nsGkAtoms::dirAutoSetBy)); - if (setByNode) { - nsTextNodeDirectionalityMap::RemoveElementFromMap(setByNode, aElement); - } - } - - if (aElement->HasDirAuto()) { - nsTextNode* setByNode = - WalkDescendantsSetDirectionFromText(aElement, aNotify); - if (setByNode) { - nsTextNodeDirectionalityMap::AddEntryToMap(setByNode, aElement); - } - SetDirectionalityOnDescendants(aElement, aElement->GetDirectionality(), - aNotify); + MOZ_ASSERT(aElement->HasDirAuto()); + nsTextNode* setByNode = + WalkDescendantsSetDirectionFromText(aElement, aNotify); + if (setByNode) { + setByNode->SetMaySetDirAuto(); } + SetDirectionalityOnDescendants(aElement, aElement->GetDirectionality(), + aNotify); } /** - * Walk the parent chain of a text node whose dir attribute has been removed and - * reset the direction of any of its ancestors which have dir=auto and whose - * directionality is determined by a text node descendant. + * Walk the parent chain of a text node whose dir attribute has been removed or + * added and reset the direction of any of its ancestors which have dir=auto and + * whose directionality is determined by a text node descendant. */ void WalkAncestorsResetAutoDirection(Element* aElement, bool aNotify) { - nsTextNode* setByNode; - nsIContent* parent = GetParentOrHostOrSlot(aElement); - while (parent && parent->NodeOrAncestorHasDirAuto()) { - if (!parent->IsElement()) { - parent = GetParentOrHostOrSlot(parent); + for (nsIContent* parent = GetParentOrHostOrSlot(aElement); + parent && parent->NodeOrAncestorHasDirAuto(); + parent = GetParentOrHostOrSlot(parent)) { + auto* parentElement = Element::FromNode(*parent); + if (!parentElement || !parentElement->HasDirAuto()) { continue; } - - Element* parentElement = parent->AsElement(); - if (parent->HasDirAutoSet()) { - // If the parent has the DirAutoSet flag, its direction is determined by - // some text node descendant. - // Remove it from the map and reset its direction by the downward - // propagation algorithm - setByNode = static_cast( - parent->GetProperty(nsGkAtoms::dirAutoSetBy)); - if (setByNode) { - nsTextNodeDirectionalityMap::RemoveElementFromMap(setByNode, - parentElement); - } - } - if (parentElement->HasDirAuto()) { - setByNode = WalkDescendantsSetDirectionFromText(parentElement, aNotify); - if (setByNode) { - nsTextNodeDirectionalityMap::AddEntryToMap(setByNode, parentElement); - } - SetDirectionalityOnDescendants( - parentElement, parentElement->GetDirectionality(), aNotify); - break; + nsTextNode* setByNode = + WalkDescendantsSetDirectionFromText(parentElement, aNotify); + if (setByNode) { + setByNode->SetMaySetDirAuto(); } - parent = GetParentOrHostOrSlot(parent); + SetDirectionalityOnDescendants(parentElement, + parentElement->GetDirectionality(), aNotify); + break; } } @@ -901,26 +589,6 @@ void SlotStateChanged(HTMLSlotElement* aSlot, bool aAllAssignedNodesChanged) { } } -void WalkDescendantsResetAutoDirection(Element* aElement) { - nsIContent* child = aElement->GetFirstChild(); - while (child) { - if (child->IsElement() && child->AsElement()->HasDirAuto()) { - child = child->GetNextNonChildNode(aElement); - continue; - } - - if (child->NodeType() == nsINode::TEXT_NODE && - child->HasTextNodeDirectionalityMap()) { - nsTextNodeDirectionalityMap::ResetTextNodeDirection( - static_cast(child), nullptr); - // Don't call nsTextNodeDirectionalityMap::EnsureMapIsClearFor(child) - // since ResetTextNodeDirection may have kept elements in child's - // DirectionalityMap. - } - child = child->GetNextNode(aElement); - } -} - static void SetAncestorHasDirAutoOnDescendants(nsINode* aRoot); static void MaybeSetAncestorHasDirAutoOnShadowDOM(nsINode* aNode) { @@ -938,7 +606,7 @@ static void SetAncestorHasDirAutoOnDescendants(nsINode* aRoot) { nsIContent* child = aRoot->GetFirstChild(); while (child) { if (child->IsElement() && - DoesNotAffectDirectionOfAncestors(child->AsElement())) { + !AffectsDirectionOfAncestors(child->AsElement())) { child = child->GetNextNonChildNode(aRoot); continue; } @@ -961,20 +629,20 @@ static void SetAncestorHasDirAutoOnDescendants(nsINode* aRoot) { } void WalkDescendantsSetDirAuto(Element* aElement, bool aNotify) { - // Only test for DoesNotParticipateInAutoDirection -- in other words, if - // aElement is a which is having its dir attribute set to auto (or + // Only test for ParticipatesInAutoDirection -- in other words, if aElement is + // a which is having its dir attribute set to auto (or // removed or set to an invalid value, which are equivalent to dir=auto for // , we *do* want to set AncestorHasDirAuto on its descendants, unlike // in SetDirOnBind where we don't propagate AncestorHasDirAuto to a // being bound to an existing node with dir=auto. - if (!DoesNotParticipateInAutoDirection(aElement) && + if (ParticipatesInAutoDirection(aElement) && !aElement->AncestorHasDirAuto()) { SetAncestorHasDirAutoOnDescendants(aElement); } nsTextNode* textNode = WalkDescendantsSetDirectionFromText(aElement, aNotify); if (textNode) { - nsTextNodeDirectionalityMap::AddEntryToMap(textNode, aElement); + textNode->SetMaySetDirAuto(); } } @@ -1022,98 +690,67 @@ void WalkDescendantsClearAncestorDirAuto(nsIContent* aContent) { } } -void SetAncestorDirectionIfAuto(nsTextNode* aTextNode, Directionality aDir, - bool aNotify = true) { - MOZ_ASSERT(aTextNode->NodeType() == nsINode::TEXT_NODE, - "Must be a text node"); +struct DirAutoElementResult { + Element* mElement = nullptr; + // This is false when we hit the top of the ancestor chain without finding a + // dir=auto element or an element with a fixed direction. This is useful when + // processing node removals, since we might need to look at the subtree we're + // removing from. + bool mAnswerIsDefinitive = false; +}; - bool crossedShadowBoundary = false; - nsIContent* parent = GetParentOrHostOrSlot(aTextNode, &crossedShadowBoundary); - while (parent && parent->NodeOrAncestorHasDirAuto()) { - if (!parent->IsElement()) { - parent = GetParentOrHostOrSlot(parent, &crossedShadowBoundary); +static DirAutoElementResult FindDirAutoElementFrom(nsIContent* aContent) { + for (nsIContent* parent = aContent; + parent && parent->NodeOrAncestorHasDirAuto(); + parent = GetParentOrHostOrSlot(parent)) { + auto* parentElement = Element::FromNode(*parent); + if (!parentElement) { continue; } - - Element* parentElement = parent->AsElement(); - if (DoesNotParticipateInAutoDirection(parentElement) || + if (!ParticipatesInAutoDirection(parentElement) || parentElement->HasFixedDir()) { - break; + return {nullptr, true}; } - if (parentElement->HasDirAuto()) { - bool resetDirection = false; - nsTextNode* directionWasSetByTextNode = static_cast( - parent->GetProperty(nsGkAtoms::dirAutoSetBy)); - - if (!parent->HasDirAutoSet()) { - // Fast path if parent's direction is not yet set by any descendant - MOZ_ASSERT(!directionWasSetByTextNode, - "dirAutoSetBy property should be null"); - resetDirection = true; - } else { - // If parent's direction is already set, we need to know if - // aTextNode is before or after the text node that had set it. - // We will walk parent's descendants in tree order starting from - // aTextNode to optimize for the most common case where text nodes are - // being appended to tree. - if (!directionWasSetByTextNode) { - resetDirection = true; - } else if (directionWasSetByTextNode != aTextNode) { - if (crossedShadowBoundary || AncestorChainCrossesShadowBoundary( - directionWasSetByTextNode, parent)) { - // Need to take the slow path when the path from either the old or - // new text node to the dir=auto element crosses shadow boundary. - ResetAutoDirection(parentElement, aNotify); - return; - } - - nsIContent* child = aTextNode->GetNextNode(parent); - while (child) { - if (child->IsElement() && - DoesNotAffectDirectionOfAncestors(child->AsElement())) { - child = child->GetNextNonChildNode(parent); - continue; - } - - if (child == directionWasSetByTextNode) { - // we found the node that set the element's direction after our - // text node, so we need to reset the direction - resetDirection = true; - break; - } - - child = child->GetNextNode(parent); - } - } - } - - if (resetDirection) { - if (directionWasSetByTextNode) { - nsTextNodeDirectionalityMap::RemoveElementFromMap( - directionWasSetByTextNode, parentElement); - } - parentElement->SetDirectionality(aDir, aNotify); - nsTextNodeDirectionalityMap::AddEntryToMap(aTextNode, parentElement); - SetDirectionalityOnDescendants(parentElement, aDir, aNotify); - } + return {parentElement, true}; + } + } + return {nullptr, false}; +} - // Since we found an element with dir=auto, we can stop walking the - // parent chain: none of its ancestors will have their direction set by - // any of its descendants. - return; +static DirAutoElementResult FindDirAutoElementForText(nsTextNode* aTextNode) { + MOZ_ASSERT(aTextNode->NodeType() == nsINode::TEXT_NODE, + "Must be a text node"); + return FindDirAutoElementFrom(GetParentOrHostOrSlot(aTextNode)); +} + +static DirAutoElementResult SetAncestorDirectionIfAuto(nsTextNode* aTextNode, + Directionality aDir, + bool aNotify = true) { + auto result = FindDirAutoElementForText(aTextNode); + if (Element* parentElement = result.mElement) { + if (parentElement->GetDirectionality() == aDir) { + // If we know that the directionality is already correct, we don't need to + // reset it. But we might be responsible for the directionality of + // parentElement. + MOZ_ASSERT(aDir != Directionality::Unset); + aTextNode->SetMaySetDirAuto(); + } else { + // Otherwise recompute the directionality of parentElement. + ResetAutoDirection(parentElement, aNotify); } - parent = GetParentOrHostOrSlot(parent, &crossedShadowBoundary); } + return result; } bool TextNodeWillChangeDirection(nsTextNode* aTextNode, Directionality* aOldDir, uint32_t aOffset) { if (!NodeAffectsDirAutoAncestor(aTextNode)) { - nsTextNodeDirectionalityMap::EnsureMapIsClearFor(aTextNode); return false; } + // If the change has happened after the first character with strong + // directionality in the text node, do nothing. uint32_t firstStrong; *aOldDir = GetDirectionFromText(aTextNode, &firstStrong); return (aOffset <= firstStrong); @@ -1121,29 +758,17 @@ bool TextNodeWillChangeDirection(nsTextNode* aTextNode, Directionality* aOldDir, void TextNodeChangedDirection(nsTextNode* aTextNode, Directionality aOldDir, bool aNotify) { + MOZ_ASSERT(NodeAffectsDirAutoAncestor(aTextNode), "Caller should check"); Directionality newDir = GetDirectionFromText(aTextNode); - if (newDir == Directionality::Unset) { - if (aOldDir != Directionality::Unset && - aTextNode->HasTextNodeDirectionalityMap()) { - // This node used to have a strong directional character but no - // longer does. ResetTextNodeDirection() will re-resolve the - // directionality of any elements whose directionality was - // determined by this node. - nsTextNodeDirectionalityMap::ResetTextNodeDirection(aTextNode, aTextNode); - } - } else { - // This node has a strong directional character. If it has a - // TextNodeDirectionalityMap property, it already determines the - // directionality of some element(s), so call UpdateTextNodeDirection to - // reresolve their directionality. If it has no map, or if - // UpdateTextNodeDirection returns zero, indicating that the map is - // empty, call SetAncestorDirectionIfAuto to find ancestor elements - // which should have their directionality determined by this node. - if (aTextNode->HasTextNodeDirectionalityMap() && - nsTextNodeDirectionalityMap::UpdateTextNodeDirection(aTextNode, - newDir)) { - return; - } + if (newDir == aOldDir) { + return; + } + // If the old directionality is Unset, we might determine now dir=auto + // ancestor direction now, even if we don't have the MaySetDirAuto flag. + // + // Otherwise we used to have a strong directionality and either no longer + // does, or it changed. We might need to reset the direction. + if (aOldDir == Directionality::Unset || aTextNode->MaySetDirAuto()) { SetAncestorDirectionIfAuto(aTextNode, newDir, aNotify); } } @@ -1164,17 +789,39 @@ void SetDirectionFromNewTextNode(nsTextNode* aTextNode) { } } -void ResetDirectionSetByTextNode(nsTextNode* aTextNode) { - if (!NodeAffectsDirAutoAncestor(aTextNode)) { - nsTextNodeDirectionalityMap::EnsureMapIsClearFor(aTextNode); +void ResetDirectionSetByTextNode(nsTextNode* aTextNode, + dom::UnbindContext& aContext) { + MOZ_ASSERT(!aTextNode->IsInComposedDoc(), "Should be disconnected already"); + if (!aTextNode->MaySetDirAuto()) { + return; + } + auto result = FindDirAutoElementForText(aTextNode); + if (result.mAnswerIsDefinitive) { + // The dir=auto element is in our (now detached) subtree. We're done, as + // nothing really changed for our purposes. + return; + } + MOZ_ASSERT(!result.mElement); + // The dir=auto element might have been on the element we're unbinding from. + // In any case, this text node is clearly no longer what determines its + // directionality. + aTextNode->ClearMaySetDirAuto(); + auto* unboundFrom = + nsIContent::FromNodeOrNull(aContext.GetOriginalSubtreeParent()); + if (!unboundFrom || !TextChildrenAffectDirAutoAncestor(unboundFrom)) { return; } Directionality dir = GetDirectionFromText(aTextNode); - if (dir != Directionality::Unset && - aTextNode->HasTextNodeDirectionalityMap()) { - nsTextNodeDirectionalityMap::ResetTextNodeDirection(aTextNode, aTextNode); + if (dir == Directionality::Unset) { + return; + } + + result = FindDirAutoElementFrom(unboundFrom); + if (!result.mElement || result.mElement->GetDirectionality() != dir) { + return; } + ResetAutoDirection(result.mElement, /* aNotify = */ true); } void SetDirectionalityFromValue(Element* aElement, const nsAString& value, @@ -1192,26 +839,15 @@ void SetDirectionalityFromValue(Element* aElement, const nsAString& value, void OnSetDirAttr(Element* aElement, const nsAttrValue* aNewValue, bool hadValidDir, bool hadDirAuto, bool aNotify) { - if (aElement->IsHTMLElement(nsGkAtoms::input) || - aElement->IsHTMLElement(nsGkAtoms::textarea)) { + if (aElement->IsAnyOfHTMLElements(nsGkAtoms::input, nsGkAtoms::textarea)) { return; } if (aElement->AncestorHasDirAuto()) { - if (!hadValidDir) { - // The element is a descendant of an element with dir = auto, is - // having its dir attribute set, and previously didn't have a valid dir - // attribute. - // Check whether any of its text node descendants determine the - // direction of any of its ancestors, and redetermine their direction - WalkDescendantsResetAutoDirection(aElement); - } else if (!aElement->HasValidDir()) { - // The element is a descendant of an element with dir = auto and is - // having its dir attribute removed or set to an invalid value. - // Reset the direction of any of its ancestors whose direction is - // determined by a text node descendant - WalkAncestorsResetAutoDirection(aElement, aNotify); - } + // The element is a descendant of an element with dir = auto, is having its + // dir attribute changed. Reset the direction of any of its ancestors whose + // direction might be determined by a text node descendant + WalkAncestorsResetAutoDirection(aElement, aNotify); } else if (hadDirAuto && !aElement->HasDirAuto()) { // The element isn't a descendant of an element with dir = auto, and is // having its dir attribute set to something other than auto. @@ -1231,11 +867,6 @@ void OnSetDirAttr(Element* aElement, const nsAttrValue* aNewValue, if (aElement->HasDirAuto()) { WalkDescendantsSetDirAuto(aElement, aNotify); } else { - if (aElement->HasDirAutoSet()) { - nsTextNode* setByNode = static_cast( - aElement->GetProperty(nsGkAtoms::dirAutoSetBy)); - nsTextNodeDirectionalityMap::RemoveElementFromMap(setByNode, aElement); - } SetDirectionalityOnDescendants( aElement, RecomputeDirectionality(aElement, aNotify), aNotify); } @@ -1244,7 +875,7 @@ void OnSetDirAttr(Element* aElement, const nsAttrValue* aNewValue, void SetDirOnBind(Element* aElement, nsIContent* aParent) { // Set the AncestorHasDirAuto flag, unless this element shouldn't affect // ancestors that have dir=auto - if (!DoesNotParticipateInAutoDirection(aElement) && + if (ParticipatesInAutoDirection(aElement) && !aElement->IsHTMLElement(nsGkAtoms::bdi) && aParent && aParent->NodeOrAncestorHasDirAuto()) { aElement->SetAncestorHasDirAuto(); @@ -1265,12 +896,6 @@ void SetDirOnBind(Element* aElement, nsIContent* aParent) { } void ResetDir(Element* aElement) { - if (aElement->HasDirAutoSet()) { - nsTextNode* setByNode = static_cast( - aElement->GetProperty(nsGkAtoms::dirAutoSetBy)); - nsTextNodeDirectionalityMap::RemoveElementFromMap(setByNode, aElement); - } - if (!aElement->HasDirAuto()) { RecomputeDirectionality(aElement, false); } diff --git a/dom/base/DirectionalityUtils.h b/dom/base/DirectionalityUtils.h index 17cec80485..0012a1d4be 100644 --- a/dom/base/DirectionalityUtils.h +++ b/dom/base/DirectionalityUtils.h @@ -18,6 +18,7 @@ class nsTextNode; namespace mozilla::dom { class Element; class HTMLSlotElement; +struct UnbindContext; } // namespace mozilla::dom namespace mozilla { @@ -133,10 +134,8 @@ void SetDirectionFromNewTextNode(nsTextNode* aTextNode); /** * When a text node is removed from a document, find any ancestors whose * directionality it determined and redetermine their directionality - * - * @param aTextNode the text node */ -void ResetDirectionSetByTextNode(nsTextNode* aTextNode); +void ResetDirectionSetByTextNode(nsTextNode*, dom::UnbindContext&); /** * Set the directionality of an element according to the directionality of the diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index 819cd8c11d..4e9286a91e 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -104,6 +104,7 @@ #include "mozilla/SMILTimeContainer.h" #include "mozilla/ScopeExit.h" #include "mozilla/Components.h" +#include "mozilla/SVGUtils.h" #include "mozilla/ServoStyleConsts.h" #include "mozilla/ServoTypes.h" #include "mozilla/SizeOfState.h" @@ -1399,6 +1400,7 @@ Document::Document(const char* aContentType) mShouldResistFingerprinting(false), mCloningForSVGUse(false), mAllowDeclarativeShadowRoots(false), + mSuspendDOMNotifications(false), mXMLDeclarationBits(0), mOnloadBlockCount(0), mWriteLevel(0), @@ -1430,7 +1432,6 @@ Document::Document(const char* aContentType) mHttpsOnlyStatus(nsILoadInfo::HTTPS_ONLY_UNINITIALIZED), mViewportType(Unknown), mViewportFit(ViewportFitType::Auto), - mSubDocuments(nullptr), mHeaderData(nullptr), mServoRestyleRootDirtyBits(0), mThrowOnDynamicMarkupInsertionCounter(0), @@ -2333,7 +2334,6 @@ Document::~Document() { // Kill the subdocument map, doing this will release its strong // references, if any. - delete mSubDocuments; mSubDocuments = nullptr; nsAutoScriptBlocker scriptBlocker; @@ -2505,7 +2505,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(Document) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnloadBlocker) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLazyLoadObserver) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLastRememberedSizeObserver) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElementsObservedForLastRememberedSize) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMImplementation) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageMaps) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOrientationPendingPromise) @@ -2627,7 +2627,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Document) NS_IMPL_CYCLE_COLLECTION_UNLINK(mSecurityInfo) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK(mLazyLoadObserver) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mLastRememberedSizeObserver) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mElementsObservedForLastRememberedSize); NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet) NS_IMPL_CYCLE_COLLECTION_UNLINK(mReadyForIdle) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentL10n) @@ -2687,7 +2687,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Document) tmp->mStyleSheetSetList = nullptr; } - delete tmp->mSubDocuments; tmp->mSubDocuments = nullptr; NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameRequestManager) @@ -2848,7 +2847,6 @@ void Document::DisconnectNodeTree() { // Delete references to sub-documents and kill the subdocument map, // if any. This is not strictly needed, but makes the node tree // teardown a bit faster. - delete mSubDocuments; mSubDocuments = nullptr; bool oldVal = mInUnlinkOrDeletion; @@ -6319,9 +6317,11 @@ void Document::DeferredContentEditableCountChange(Element* aElement) { if (aElement) { if (RefPtr htmlEditor = GetHTMLEditor()) { nsCOMPtr spellChecker; - rv = htmlEditor->GetInlineSpellChecker(false, - getter_AddRefs(spellChecker)); - NS_ENSURE_SUCCESS_VOID(rv); + DebugOnly rvIgnored = htmlEditor->GetInlineSpellChecker( + false, getter_AddRefs(spellChecker)); + NS_WARNING_ASSERTION( + NS_SUCCEEDED(rvIgnored), + "EditorBase::GetInlineSpellChecker() failed, but ignored"); if (spellChecker && aElement->InclusiveDescendantMayNeedSpellchecking(htmlEditor)) { @@ -7205,7 +7205,8 @@ nsresult Document::SetSubDocumentFor(Element* aElement, Document* aSubDoc) { PLDHashTable::HashVoidPtrKeyStub, PLDHashTable::MatchEntryStub, PLDHashTable::MoveEntryStub, SubDocClearEntry, SubDocInitEntry}; - mSubDocuments = new PLDHashTable(&hash_table_ops, sizeof(SubDocMapEntry)); + mSubDocuments = + MakeUnique(&hash_table_ops, sizeof(SubDocMapEntry)); } // Add a mapping to the hash table @@ -12394,7 +12395,8 @@ already_AddRefed Document::ResolvePreloadImage( void Document::PreLoadImage(nsIURI* aUri, const nsAString& aCrossOriginAttr, ReferrerPolicyEnum aReferrerPolicy, bool aIsImgSet, - bool aLinkPreload, uint64_t aEarlyHintPreloaderId) { + bool aLinkPreload, uint64_t aEarlyHintPreloaderId, + const nsAString& aFetchPriority) { nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL | nsContentUtils::CORSModeToLoadImageFlags( Element::StringToCORSMode(aCrossOriginAttr)); @@ -12415,7 +12417,8 @@ void Document::PreLoadImage(nsIURI* aUri, const nsAString& aCrossOriginAttr, nsresult rv = nsContentUtils::LoadImage( aUri, static_cast(this), this, NodePrincipal(), 0, referrerInfo, nullptr /* no observer */, loadFlags, initiator, getter_AddRefs(request), - policyType, false /* urgent */, aLinkPreload, aEarlyHintPreloaderId); + policyType, false /* urgent */, aLinkPreload, aEarlyHintPreloaderId, + nsGenericHTMLElement::ToFetchPriority(aFetchPriority)); // Pin image-reference to avoid evicting it from the img-cache before // the "real" load occurs. Unpinned in DispatchContentLoadedEvents and @@ -12428,7 +12431,8 @@ void Document::PreLoadImage(nsIURI* aUri, const nsAString& aCrossOriginAttr, void Document::MaybePreLoadImage(nsIURI* aUri, const nsAString& aCrossOriginAttr, ReferrerPolicyEnum aReferrerPolicy, - bool aIsImgSet, bool aLinkPreload) { + bool aIsImgSet, bool aLinkPreload, + const nsAString& aFetchPriority) { const CORSMode corsMode = dom::Element::StringToCORSMode(aCrossOriginAttr); if (aLinkPreload) { // Check if the image was already preloaded in this document to avoid @@ -12437,7 +12441,7 @@ void Document::MaybePreLoadImage(nsIURI* aUri, PreloadHashKey::CreateAsImage(aUri, NodePrincipal(), corsMode); if (!mPreloadService.PreloadExists(key)) { PreLoadImage(aUri, aCrossOriginAttr, aReferrerPolicy, aIsImgSet, - aLinkPreload, 0); + aLinkPreload, 0, aFetchPriority); } return; } @@ -12451,7 +12455,7 @@ void Document::MaybePreLoadImage(nsIURI* aUri, // Image not in cache - trigger preload PreLoadImage(aUri, aCrossOriginAttr, aReferrerPolicy, aIsImgSet, aLinkPreload, - 0); + 0, aFetchPriority); } void Document::MaybePreconnect(nsIURI* aOrigURI, mozilla::CORSMode aCORSMode) { @@ -14751,6 +14755,10 @@ void Document::TopLayerPush(Element& aElement) { const bool modal = aElement.State().HasState(ElementState::MODAL); TopLayerPop(aElement); + if (nsIFrame* f = aElement.GetPrimaryFrame()) { + f->MarkNeedsDisplayItemRebuild(); + } + mTopLayer.AppendElement(do_GetWeakReference(&aElement)); NS_ASSERTION(GetTopLayerTop() == &aElement, "Should match"); @@ -14804,6 +14812,9 @@ Element* Document::TopLayerPop(FunctionRef aPredicate) { nsCOMPtr element(do_QueryReferent(mTopLayer[i])); if (element && aPredicate(element)) { removedElement = element; + if (nsIFrame* f = element->GetPrimaryFrame()) { + f->MarkNeedsDisplayItemRebuild(); + } mTopLayer.RemoveElementAt(i); break; } @@ -14818,6 +14829,12 @@ Element* Document::TopLayerPop(FunctionRef aPredicate) { while (!mTopLayer.IsEmpty()) { Element* element = GetTopLayerTop(); if (!element || element->GetComposedDoc() != this) { + if (element) { + if (nsIFrame* f = element->GetPrimaryFrame()) { + f->MarkNeedsDisplayItemRebuild(); + } + } + mTopLayer.RemoveLastElement(); } else { // The top element of the stack is now an in-doc element. Return here. @@ -16432,27 +16449,79 @@ DOMIntersectionObserver& Document::EnsureLazyLoadObserver() { return *mLazyLoadObserver; } -ResizeObserver& Document::EnsureLastRememberedSizeObserver() { - if (!mLastRememberedSizeObserver) { - mLastRememberedSizeObserver = - ResizeObserver::CreateLastRememberedSizeObserver(*this); - } - return *mLastRememberedSizeObserver; -} - void Document::ObserveForLastRememberedSize(Element& aElement) { if (NS_WARN_IF(!IsActive())) { return; } - // Options are initialized with ResizeObserverBoxOptions::Content_box by - // default, which is what we want. - static ResizeObserverOptions options; - EnsureLastRememberedSizeObserver().Observe(aElement, options); + mElementsObservedForLastRememberedSize.Insert(&aElement); } void Document::UnobserveForLastRememberedSize(Element& aElement) { - if (mLastRememberedSizeObserver) { - mLastRememberedSizeObserver->Unobserve(aElement); + mElementsObservedForLastRememberedSize.Remove(&aElement); +} + +void Document::UpdateLastRememberedSizes() { + auto shouldRemoveElement = [&](auto* element) { + if (element->GetComposedDoc() != this) { + element->RemoveLastRememberedBSize(); + element->RemoveLastRememberedISize(); + return true; + } + return !element->GetPrimaryFrame(); + }; + + for (auto it = mElementsObservedForLastRememberedSize.begin(), + end = mElementsObservedForLastRememberedSize.end(); + it != end; ++it) { + if (shouldRemoveElement(*it)) { + mElementsObservedForLastRememberedSize.Remove(it); + continue; + } + const auto element = *it; + MOZ_ASSERT(element->GetComposedDoc() == this); + nsIFrame* frame = element->GetPrimaryFrame(); + MOZ_ASSERT(frame); + + // As for ResizeObserver, skip nodes hidden `content-visibility`. + if (frame->IsHiddenByContentVisibilityOnAnyAncestor()) { + continue; + } + + MOZ_ASSERT(!frame->IsLineParticipant() || frame->IsReplaced(), + "Should have unobserved non-replaced inline."); + MOZ_ASSERT(!frame->HidesContent(), + "Should have unobserved element skipping its contents."); + const nsStylePosition* stylePos = frame->StylePosition(); + const WritingMode wm = frame->GetWritingMode(); + bool canUpdateBSize = stylePos->ContainIntrinsicBSize(wm).HasAuto(); + bool canUpdateISize = stylePos->ContainIntrinsicISize(wm).HasAuto(); + MOZ_ASSERT(canUpdateBSize || !element->HasLastRememberedBSize(), + "Should have removed the last remembered block size."); + MOZ_ASSERT(canUpdateISize || !element->HasLastRememberedISize(), + "Should have removed the last remembered inline size."); + MOZ_ASSERT(canUpdateBSize || canUpdateISize, + "Should have unobserved if we can't update any size."); + + AutoTArray contentSizeList = + ResizeObserver::CalculateBoxSize(element, + ResizeObserverBoxOptions::Content_box, + /* aForceFragmentHandling */ true); + MOZ_ASSERT(!contentSizeList.IsEmpty()); + + if (canUpdateBSize) { + float bSize = 0; + for (const auto& current : contentSizeList) { + bSize += current.BSize(); + } + element->SetLastRememberedBSize(bSize); + } + if (canUpdateISize) { + float iSize = 0; + for (const auto& current : contentSizeList) { + iSize = std::max(iSize, current.ISize()); + } + element->SetLastRememberedISize(iSize); + } } } @@ -17103,13 +17172,7 @@ bool Document::IsExtensionPage() const { void Document::AddResizeObserver(ResizeObserver& aObserver) { MOZ_ASSERT(!mResizeObservers.Contains(&aObserver)); - // Insert internal ResizeObservers before scripted ones, since they may have - // observable side-effects and we don't want to expose the insertion time. - if (aObserver.HasNativeCallback()) { - mResizeObservers.InsertElementAt(0, &aObserver); - } else { - mResizeObservers.AppendElement(&aObserver); - } + mResizeObservers.AppendElement(&aObserver); } void Document::RemoveResizeObserver(ResizeObserver& aObserver) { @@ -17164,6 +17227,18 @@ void Document::DetermineProximityToViewportAndNotifyResizeObservers() { // sub-documents or ancestors, so flushing layout for the whole browsing // context tree makes sure we don't miss anyone. FlushLayoutForWholeBrowsingContextTree(*this); + + // Last remembered sizes are recorded "at the time that ResizeObserver + // events are determined and delivered". + // https://drafts.csswg.org/css-sizing-4/#last-remembered + // + // We do it right after layout to make sure sizes are up-to-date. If we do + // it after determining the proximities to viewport of + // 'content-visibility: auto' nodes, and if one of such node ever becomes + // relevant to the user, then we would be incorrectly recording the size + // of its rendering when it was skipping its content. + UpdateLastRememberedSizes(); + if (PresShell* presShell = GetPresShell()) { auto result = presShell->DetermineProximityToViewport(); if (result.mHadInitialDetermination) { @@ -18627,7 +18702,7 @@ nsIPrincipal* Document::EffectiveStoragePrincipal() const { } // Calling StorageAllowedForDocument will notify the ContentBlockLog. This - // loads TrackingDBService.jsm, which in turn pulls in osfile.jsm, making us + // loads TrackingDBService.sys.mjs, making us potentially // fail // browser/base/content/test/performance/browser_startup.js. To avoid // that, we short-circuit the check here by allowing storage access to system // and addon principles, avoiding the test-failure. diff --git a/dom/base/Document.h b/dom/base/Document.h index 6a2bd55a9c..a52c61addf 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h @@ -57,7 +57,6 @@ #include "mozilla/dom/LargestContentfulPaint.h" #include "mozilla/dom/UserActivation.h" #include "mozilla/dom/WakeLockBinding.h" -#include "mozilla/glean/GleanMetrics.h" #include "nsAtom.h" #include "nsCOMArray.h" #include "nsCOMPtr.h" @@ -320,6 +319,9 @@ enum BFCacheStatus { }; } // namespace dom +namespace glean::perf { +struct PageLoadExtra; +} } // namespace mozilla namespace mozilla::net { @@ -2930,10 +2932,11 @@ class Document : public nsINode, */ void MaybePreLoadImage(nsIURI* uri, const nsAString& aCrossOriginAttr, ReferrerPolicyEnum aReferrerPolicy, bool aIsImgSet, - bool aLinkPreload); + bool aLinkPreload, const nsAString& aFetchPriority); void PreLoadImage(nsIURI* uri, const nsAString& aCrossOriginAttr, ReferrerPolicyEnum aReferrerPolicy, bool aIsImgSet, - bool aLinkPreload, uint64_t aEarlyHintPreloaderId); + bool aLinkPreload, uint64_t aEarlyHintPreloaderId, + const nsAString& aFetchPriority); /** * Called by images to forget an image preload when they start doing @@ -3722,12 +3725,12 @@ class Document : public nsINode, DOMIntersectionObserver* GetLazyLoadObserver() { return mLazyLoadObserver; } DOMIntersectionObserver& EnsureLazyLoadObserver(); - ResizeObserver* GetLastRememberedSizeObserver() { - return mLastRememberedSizeObserver; + bool HasElementsWithLastRememberedSize() const { + return !mElementsObservedForLastRememberedSize.IsEmpty(); } - ResizeObserver& EnsureLastRememberedSizeObserver(); void ObserveForLastRememberedSize(Element&); void UnobserveForLastRememberedSize(Element&); + void UpdateLastRememberedSizes(); // Dispatch a runnable related to the document. nsresult Dispatch(already_AddRefed&& aRunnable) const; @@ -3875,6 +3878,17 @@ class Document : public nsINode, void SetAllowDeclarativeShadowRoots(bool aAllowDeclarativeShadowRoots); bool AllowsDeclarativeShadowRoots() const; + void SuspendDOMNotifications() { + MOZ_ASSERT(IsHTMLDocument(), + "Currently suspending DOM notifications is supported only on " + "HTML documents."); + mSuspendDOMNotifications = true; + } + + void ResumeDOMNotifications() { mSuspendDOMNotifications = false; } + + bool DOMNotificationsSuspended() const { return mSuspendDOMNotifications; } + protected: RefPtr mDocumentL10n; @@ -4866,6 +4880,8 @@ class Document : public nsINode, bool mAllowDeclarativeShadowRoots : 1; + bool mSuspendDOMNotifications : 1; + // The fingerprinting protections overrides for this document. The value will // override the default enabled fingerprinting protections for this document. // This will only get populated if these is one that comes from the local @@ -5125,7 +5141,11 @@ class Document : public nsINode, // https://drafts.csswg.org/css-round-display/#viewport-fit-descriptor ViewportFitType mViewportFit; - PLDHashTable* mSubDocuments; + // XXXdholbert This should really be modernized to a nsTHashMap or similar, + // though note that the modernization will need to take care to also convert + // the special hash_table_ops logic (e.g. how SubDocClearEntry clears the + // parent document as part of cleaning up an entry in this table). + UniquePtr mSubDocuments; class HeaderData; UniquePtr mHeaderData; @@ -5162,9 +5182,9 @@ class Document : public nsINode, RefPtr mLazyLoadObserver; - // ResizeObserver for storing and removing the last remembered size. + // Elements observed for a last remembered size. // @see {@link https://drafts.csswg.org/css-sizing-4/#last-remembered} - RefPtr mLastRememberedSizeObserver; + nsTHashSet> mElementsObservedForLastRememberedSize; // Stack of top layer elements. nsTArray mTopLayer; diff --git a/dom/base/DocumentFragment.h b/dom/base/DocumentFragment.h index 4b1c11c480..9b8cc69673 100644 --- a/dom/base/DocumentFragment.h +++ b/dom/base/DocumentFragment.h @@ -66,7 +66,7 @@ class DocumentFragment : public FragmentOrElement { return NS_ERROR_NOT_IMPLEMENTED; } - virtual void UnbindFromTree(bool aNullParent) override { + virtual void UnbindFromTree(UnbindContext&) override { NS_ASSERTION(false, "Trying to unbind a fragment from a tree"); } diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index f653363f48..be31000278 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -54,7 +54,6 @@ #include "mozilla/PresShellForwards.h" #include "mozilla/ReflowOutput.h" #include "mozilla/RelativeTo.h" -#include "mozilla/ScrollOrigin.h" #include "mozilla/ScrollTypes.h" #include "mozilla/ServoStyleConsts.h" #include "mozilla/ServoStyleConstsInlines.h" @@ -106,6 +105,7 @@ #include "mozilla/dom/ScriptLoader.h" #include "mozilla/dom/ShadowRoot.h" #include "mozilla/dom/Text.h" +#include "mozilla/dom/UnbindContext.h" #include "mozilla/dom/WindowBinding.h" #include "mozilla/dom/XULCommandEvent.h" #include "mozilla/dom/nsCSPContext.h" @@ -113,6 +113,7 @@ #include "mozilla/gfx/BaseRect.h" #include "mozilla/gfx/BaseSize.h" #include "mozilla/gfx/Matrix.h" +#include "mozilla/widget/Screen.h" #include "nsAtom.h" #include "nsAttrName.h" #include "nsAttrValueInlines.h" @@ -161,7 +162,6 @@ #include "nsIInterfaceRequestor.h" #include "nsIMemoryReporter.h" #include "nsIPrincipal.h" -#include "nsIScreenManager.h" #include "nsIScriptError.h" #include "nsIScrollableFrame.h" #include "nsISpeculativeConnect.h" @@ -780,8 +780,6 @@ void Element::ScrollIntoView(const ScrollIntoViewOptions& aOptions) { return WhereToScroll::Center; case ScrollLogicalPosition::End: return WhereToScroll::End; - case ScrollLogicalPosition::EndGuard_: - MOZ_FALLTHROUGH_ASSERT("Unexpected block direction value"); case ScrollLogicalPosition::Nearest: break; } @@ -1048,20 +1046,13 @@ int32_t Element::ScreenY() { } already_AddRefed Element::GetScreen() { - nsIFrame* frame = GetPrimaryFrame(FlushType::Layout); - if (!frame) { - return nullptr; + // Flush layout to guarantee that frames are created if needed, and preserve + // behavior. + Unused << GetPrimaryFrame(FlushType::Frames); + if (nsIWidget* widget = nsContentUtils::WidgetForContent(this)) { + return widget->GetWidgetScreen(); } - nsCOMPtr screenMgr = - do_GetService("@mozilla.org/gfx/screenmanager;1"); - if (!screenMgr) { - return nullptr; - } - nsPresContext* pc = frame->PresContext(); - const CSSIntRect rect = frame->GetScreenRect(); - DesktopRect desktopRect = rect * pc->CSSToDevPixelScale() / - pc->DeviceContext()->GetDesktopToDeviceScale(); - return screenMgr->ScreenForRect(DesktopIntRect::Round(desktopRect)); + return nullptr; } already_AddRefed Element::GetBoundingClientRect() { @@ -1722,8 +1713,7 @@ already_AddRefed Element::GetElementsByClassName( } Element* Element::GetAttrAssociatedElement(nsAtom* aAttr) const { - const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); - if (slots) { + if (const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) { nsWeakPtr weakAttrEl = slots->mExplicitlySetAttrElements.Get(aAttr); if (nsCOMPtr attrEl = do_QueryReferent(weakAttrEl)) { // If reflectedTarget's explicitly set attr-element |attrEl| is @@ -1774,16 +1764,56 @@ void Element::ClearExplicitlySetAttrElement(nsAtom* aAttr) { } void Element::ExplicitlySetAttrElement(nsAtom* aAttr, Element* aElement) { +#ifdef ACCESSIBILITY + nsAccessibilityService* accService = GetAccService(); +#endif + // Accessibility requires that no other attribute changes occur between + // AttrElementWillChange and AttrElementChanged. Scripts could cause + // this, so don't let them run here. We do this even if accessibility isn't + // running so that the JS behavior is consistent regardless of accessibility. + // Otherwise, JS might be able to use this difference to determine whether + // accessibility is running, which would be a privacy concern. + nsAutoScriptBlocker scriptBlocker; if (aElement) { +#ifdef ACCESSIBILITY + if (accService) { + accService->NotifyAttrElementWillChange(this, aAttr); + } +#endif SetAttr(aAttr, EmptyString(), IgnoreErrors()); nsExtendedDOMSlots* slots = ExtendedDOMSlots(); slots->mExplicitlySetAttrElements.InsertOrUpdate( aAttr, do_GetWeakReference(aElement)); +#ifdef ACCESSIBILITY + if (accService) { + accService->NotifyAttrElementChanged(this, aAttr); + } +#endif return; } +#ifdef ACCESSIBILITY + if (accService) { + accService->NotifyAttrElementWillChange(this, aAttr); + } +#endif ClearExplicitlySetAttrElement(aAttr); UnsetAttr(aAttr, IgnoreErrors()); +#ifdef ACCESSIBILITY + if (accService) { + accService->NotifyAttrElementChanged(this, aAttr); + } +#endif +} + +Element* Element::GetExplicitlySetAttrElement(nsAtom* aAttr) const { + if (const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) { + nsWeakPtr weakAttrEl = slots->mExplicitlySetAttrElements.Get(aAttr); + if (nsCOMPtr attrEl = do_QueryReferent(weakAttrEl)) { + return attrEl; + } + } + return nullptr; } void Element::GetElementsWithGrid(nsTArray>& aElements) { @@ -1958,7 +1988,8 @@ nsresult Element::BindToTree(BindContext& aContext, nsINode& aParent) { return NS_OK; } -bool WillDetachFromShadowOnUnbind(const Element& aElement, bool aNullParent) { +static bool WillDetachFromShadowOnUnbind(const Element& aElement, + bool aNullParent) { // If our parent still is in a shadow tree by now, and we're not removing // ourselves from it, then we're still going to be in a shadow tree after // this. @@ -1966,12 +1997,14 @@ bool WillDetachFromShadowOnUnbind(const Element& aElement, bool aNullParent) { (aNullParent || !aElement.GetParent()->IsInShadowTree()); } -void Element::UnbindFromTree(bool aNullParent) { - HandleShadowDOMRelatedRemovalSteps(aNullParent); +void Element::UnbindFromTree(UnbindContext& aContext) { + const bool nullParent = aContext.IsUnbindRoot(this); + + HandleShadowDOMRelatedRemovalSteps(nullParent); if (HasFlag(ELEMENT_IS_DATALIST_OR_HAS_DATALIST_ANCESTOR) && !IsHTMLElement(nsGkAtoms::datalist)) { - if (aNullParent) { + if (nullParent) { UnsetFlags(ELEMENT_IS_DATALIST_OR_HAS_DATALIST_ANCESTOR); } else { nsIContent* parent = GetParent(); @@ -1983,7 +2016,7 @@ void Element::UnbindFromTree(bool aNullParent) { } const bool detachingFromShadow = - WillDetachFromShadowOnUnbind(*this, aNullParent); + WillDetachFromShadowOnUnbind(*this, nullParent); // Make sure to only remove from the ID table if our subtree root is actually // changing. if (IsInUncomposedDoc() || detachingFromShadow) { @@ -2033,7 +2066,7 @@ void Element::UnbindFromTree(bool aNullParent) { data->ClearAllAnimationCollections(); } - if (aNullParent) { + if (nullParent) { if (GetParent()) { RefPtr p; p.swap(mParent); @@ -2071,15 +2104,13 @@ void Element::UnbindFromTree(bool aNullParent) { ClearElementCreatedFromPrototypeAndHasUnmodifiedL10n(); } - if (aNullParent || !mParent->IsInShadowTree()) { + if (nullParent || !mParent->IsInShadowTree()) { UnsetFlags(NODE_IS_IN_SHADOW_TREE); // Begin keeping track of our subtree root. - SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot()); - } + SetSubtreeRootPointer(nullParent ? this : mParent->SubtreeRoot()); - if (nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) { - if (aNullParent || !mParent->IsInShadowTree()) { + if (nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots()) { slots->mContainingShadow = nullptr; } } @@ -2103,11 +2134,10 @@ void Element::UnbindFromTree(bool aNullParent) { } if (HasLastRememberedBSize() || HasLastRememberedISize()) { - // Need to remove the last remembered size at the next ResizeObserver - // opportunity, so observe the element. But if already observed, we still - // want the callback to be invoked even if the size was already 0x0, so - // unobserve it first. - document->UnobserveForLastRememberedSize(*this); + // Make sure the element is observed so that remembered sizes are kept + // until the next time "ResizeObserver events are determined and + // delivered". See "Disconnected element" tests from + // css/css-sizing/contain-intrinsic-size/auto-006.html document->ObserveForLastRememberedSize(*this); } } @@ -2121,9 +2151,7 @@ void Element::UnbindFromTree(bool aNullParent) { for (nsIContent* child = GetFirstChild(); child; child = child->GetNextSibling()) { - // Note that we pass false for aNullParent here, since we don't want - // the kids to forget us. - child->UnbindFromTree(false); + child->UnbindFromTree(aContext); } MutationObservers::NotifyParentChainChanged(this); @@ -2751,6 +2779,12 @@ bool Element::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, return true; } + if (aAttribute == nsGkAtoms::aria_activedescendant) { + // String in aria-activedescendant is an id, so store as an atom. + aResult.ParseAtom(aValue); + return true; + } + if (aAttribute == nsGkAtoms::id) { // Store id as an atom. id="" means that the element has no id, // not that it has an emptystring as the id. @@ -2805,6 +2839,8 @@ void Element::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, if (ShadowRoot* shadow = GetParent()->GetShadowRoot()) { shadow->MaybeReassignContent(*this); } + } else if (aName == nsGkAtoms::aria_activedescendant) { + ClearExplicitlySetAttrElement(aName); } } } @@ -2856,6 +2892,11 @@ void Element::OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName, ElementCallbackType::eAttributeChanged, this, args, definition); } } + + if (aNamespaceID == kNameSpaceID_None && + aName == nsGkAtoms::aria_activedescendant) { + ClearExplicitlySetAttrElement(aName); + } } EventListenerManager* Element::GetEventListenerManagerForAttr(nsAtom* aAttrName, @@ -3397,14 +3438,6 @@ nsresult Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor) { void Element::GetLinkTarget(nsAString& aTarget) { aTarget.Truncate(); } -static nsStaticAtom* const sPropertiesToTraverseAndUnlink[] = { - nsGkAtoms::dirAutoSetBy, nullptr}; - -// static -nsStaticAtom* const* Element::HTMLSVGPropertiesToTraverseAndUnlink() { - return sPropertiesToTraverseAndUnlink; -} - nsresult Element::CopyInnerTo(Element* aDst, ReparseAttributes aReparse) { nsresult rv = aDst->mAttrs.EnsureCapacityToClone(mAttrs); NS_ENSURE_SUCCESS(rv, rv); @@ -5048,4 +5081,14 @@ void Element::SetHTMLUnsafe(const nsAString& aHTML) { nsContentUtils::SetHTMLUnsafe(this, this, aHTML); } +bool Element::BlockingContainsRender() const { + const nsAttrValue* attrValue = GetParsedAttr(nsGkAtoms::blocking); + if (!attrValue || !StaticPrefs::dom_element_blocking_enabled()) { + return false; + } + MOZ_ASSERT(attrValue->Type() == nsAttrValue::eAtomArray, + "Checking blocking attribute on element that doesn't parse it?"); + return attrValue->Contains(nsGkAtoms::render, eIgnoreCase); +} + } // namespace mozilla::dom diff --git a/dom/base/Element.h b/dom/base/Element.h index 6c717bfc88..40a8052aef 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -90,7 +90,6 @@ class nsIDOMXULSelectControlElement; class nsIDOMXULSelectControlItemElement; class nsIFrame; class nsIHTMLCollection; -class nsIMozBrowserFrame; class nsIPrincipal; class nsIScreen; class nsIScrollableFrame; @@ -244,6 +243,15 @@ class Grid; SetOrRemoveNullableStringAttr(nsGkAtoms::attr, aValue, aRv); \ } +#define REFLECT_NULLABLE_ELEMENT_ATTR(method, attr) \ + Element* Get##method() const { \ + return GetAttrAssociatedElement(nsGkAtoms::attr); \ + } \ + \ + void Set##method(Element* aElement) { \ + ExplicitlySetAttrElement(nsGkAtoms::attr, aElement); \ + } + class Element : public FragmentOrElement { public: #ifdef MOZILLA_INTERNAL_API @@ -458,23 +466,14 @@ class Element : public FragmentOrElement { */ virtual bool IsInteractiveHTMLContent() const; - /** - * Returns |this| as an nsIMozBrowserFrame* if the element is a frame or - * iframe element. - * - * We have this method, rather than using QI, so that we can use it during - * the servo traversal, where we can't QI DOM nodes because of non-thread-safe - * refcounts. - */ - virtual nsIMozBrowserFrame* GetAsMozBrowserFrame() { return nullptr; } - /** * Is the attribute named aAttribute a mapped attribute? */ NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const; nsresult BindToTree(BindContext&, nsINode& aParent) override; - void UnbindFromTree(bool aNullParent = true) override; + void UnbindFromTree(UnbindContext&) override; + using nsIContent::UnbindFromTree; virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const; static void MapNoAttributesInto(mozilla::MappedDeclarationsBuilder&); @@ -658,8 +657,13 @@ class Element : public FragmentOrElement { REFLECT_NULLABLE_DOMSTRING_ATTR(Role, role) // AriaAttributes + REFLECT_NULLABLE_ELEMENT_ATTR(AriaActiveDescendantElement, + aria_activedescendant) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaAtomic, aria_atomic) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaAutoComplete, aria_autocomplete) + REFLECT_NULLABLE_DOMSTRING_ATTR(AriaBrailleLabel, aria_braillelabel) + REFLECT_NULLABLE_DOMSTRING_ATTR(AriaBrailleRoleDescription, + aria_brailleroledescription) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaBusy, aria_busy) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaChecked, aria_checked) REFLECT_NULLABLE_DOMSTRING_ATTR(AriaColCount, aria_colcount) @@ -1107,8 +1111,6 @@ class Element : public FragmentOrElement { return FindAttributeDependence(aAttribute, aMaps, N); } - static nsStaticAtom* const* HTMLSVGPropertiesToTraverseAndUnlink(); - MOZ_CAN_RUN_SCRIPT virtual void HandleInvokeInternal(nsAtom* aAction, ErrorResult& aRv) {} @@ -1245,6 +1247,16 @@ class Element : public FragmentOrElement { void ClearExplicitlySetAttrElement(nsAtom*); + /** + * Gets the attribute element for the given attribute. + * https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#explicitly-set-attr-element + * Unlike GetAttrAssociatedElement, this returns the target even if it isn't + * a descendant of any of this element's shadow-including ancestors. It also + * doesn't attempt to retrieve an element using a string id set in the content + * attribute. + */ + Element* GetExplicitlySetAttrElement(nsAtom* aAttr) const; + PseudoStyleType GetPseudoElementType() const { nsresult rv = NS_OK; auto raw = GetProperty(nsGkAtoms::pseudoProperty, &rv); @@ -1332,6 +1344,10 @@ class Element : public FragmentOrElement { void GetLoading(nsAString& aValue) const; bool ParseLoadingAttribute(const nsAString& aValue, nsAttrValue& aResult); + // https://html.spec.whatwg.org/#potentially-render-blocking + virtual bool IsPotentiallyRenderBlocking() { return false; } + bool BlockingContainsRender() const; + // Shadow DOM v1 enum class ShadowRootDeclarative : bool { No, Yes }; diff --git a/dom/base/EventSource.cpp b/dom/base/EventSource.cpp index 52cb13f097..f70db487dd 100644 --- a/dom/base/EventSource.cpp +++ b/dom/base/EventSource.cpp @@ -849,7 +849,8 @@ EventSourceImpl::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) { aStatusCode != NS_ERROR_NET_PARTIAL_TRANSFER && aStatusCode != NS_ERROR_NET_TIMEOUT_EXTERNAL && aStatusCode != NS_ERROR_PROXY_CONNECTION_REFUSED && - aStatusCode != NS_ERROR_DNS_LOOKUP_QUEUE_FULL) { + aStatusCode != NS_ERROR_DNS_LOOKUP_QUEUE_FULL && + aStatusCode != NS_ERROR_INVALID_CONTENT_ENCODING) { DispatchFailConnection(); return NS_ERROR_ABORT; } diff --git a/dom/base/FlushType.h b/dom/base/FlushType.h index 04a253c534..c90cbbd16f 100644 --- a/dom/base/FlushType.h +++ b/dom/base/FlushType.h @@ -40,7 +40,7 @@ enum class FlushType : uint8_t { // Flush type strings that will be displayed in the profiler // clang-format off -const EnumeratedArray +const EnumeratedArray kFlushTypeNames = { "", "Event", diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 9811ce5ace..87fd81bfa3 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -16,11 +16,11 @@ #include "mozilla/dom/FragmentOrElement.h" #include "DOMIntersectionObserver.h" #include "mozilla/AsyncEventDispatcher.h" -#include "mozilla/DeclarationBlock.h" #include "mozilla/EffectSet.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventListenerManager.h" #include "mozilla/ElementAnimationData.h" +#include "mozilla/DeclarationBlock.h" #include "mozilla/HTMLEditor.h" #include "mozilla/mozInlineSpellChecker.h" #include "mozilla/PresShell.h" @@ -30,39 +30,31 @@ #include "mozilla/URLExtraData.h" #include "mozilla/dom/Attr.h" #include "mozilla/dom/RadioGroupContainer.h" +#include "mozilla/dom/UnbindContext.h" #include "nsDOMAttributeMap.h" #include "nsAtom.h" #include "mozilla/dom/NodeInfo.h" #include "mozilla/dom/Event.h" #include "mozilla/dom/ScriptLoader.h" -#include "mozilla/dom/TouchEvent.h" #include "mozilla/dom/CustomElementRegistry.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/DocumentInlines.h" #include "nsIControllers.h" #include "nsIDocumentEncoder.h" #include "nsFocusManager.h" -#include "nsIScriptGlobalObject.h" #include "nsNetUtil.h" #include "nsIFrame.h" #include "nsIAnonymousContentCreator.h" #include "nsPresContext.h" -#include "nsStyleConsts.h" #include "nsString.h" -#include "nsUnicharUtils.h" -#include "nsDOMCID.h" #include "nsDOMCSSAttrDeclaration.h" #include "nsNameSpaceManager.h" #include "nsContentList.h" #include "nsDOMTokenList.h" #include "nsError.h" -#include "nsDOMString.h" #include "nsXULElement.h" #include "mozilla/InternalMutationEvent.h" #include "mozilla/MouseEvents.h" -#include "nsAttrValueOrString.h" -#include "nsQueryObject.h" -#include "nsFrameSelection.h" #ifdef DEBUG # include "nsRange.h" #endif @@ -73,7 +65,6 @@ #include "nsGkAtoms.h" #include "nsContentUtils.h" #include "nsTextFragment.h" -#include "nsContentCID.h" #include "nsWindowSizes.h" #include "nsIWidget.h" @@ -82,12 +73,10 @@ #include "nsGenericHTMLElement.h" #include "nsContentCreatorFunctions.h" #include "nsView.h" -#include "nsViewManager.h" #include "nsIScrollableFrame.h" #include "ChildIterator.h" -#include "nsTextNode.h" #include "mozilla/dom/NodeListBinding.h" - +#include "mozilla/dom/MutationObservers.h" #include "nsCCUncollectableMarker.h" #include "mozAutoDocUpdate.h" @@ -97,16 +86,12 @@ #include "nsWrapperCacheInlines.h" #include "nsCycleCollector.h" #include "xpcpublic.h" -#include "mozilla/Telemetry.h" - -#include "mozilla/CORSMode.h" #include "mozilla/dom/ShadowRoot.h" #include "mozilla/dom/HTMLSlotElement.h" #include "mozilla/dom/HTMLTemplateElement.h" #include "mozilla/dom/SVGUseElement.h" -#include "nsStyledElement.h" #include "nsIContentInlines.h" #include "nsChildContentList.h" #include "mozilla/BloomFilter.h" @@ -169,6 +154,11 @@ nsIContent* nsIContent::FindFirstNonChromeOnlyAccessContent() const { return nullptr; } +void nsIContent::UnbindFromTree() { + UnbindContext context(*this); + UnbindFromTree(context); +} + // https://dom.spec.whatwg.org/#dom-slotable-assignedslot HTMLSlotElement* nsIContent::GetAssignedSlotByMode() const { /** @@ -1337,14 +1327,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement) Element* elem = tmp->AsElement(); elem->UnlinkIntersectionObservers(); } - - if (tmp->IsHTMLElement() || tmp->IsSVGElement()) { - nsStaticAtom* const* props = - Element::HTMLSVGPropertiesToTraverseAndUnlink(); - for (uint32_t i = 0; props[i]; ++i) { - tmp->RemoveProperty(props[i]); - } - } } // Unlink child content (and unbind our subtree). @@ -1815,15 +1797,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement) } } } - if (tmp->IsHTMLElement() || tmp->IsSVGElement()) { - nsStaticAtom* const* props = - Element::HTMLSVGPropertiesToTraverseAndUnlink(); - for (uint32_t i = 0; props[i]; ++i) { - nsISupports* property = - static_cast(tmp->GetProperty(props[i])); - cb.NoteXPCOMChild(property); - } - } } if (tmp->IsElement()) { Element* element = tmp->AsElement(); @@ -2029,6 +2002,7 @@ void FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML, } if (doc->IsHTMLDocument()) { + doc->SuspendDOMNotifications(); nsAtom* contextLocalName = parseContext->NodeInfo()->NameAtom(); int32_t contextNameSpaceID = parseContext->GetNameSpaceID(); @@ -2036,6 +2010,10 @@ void FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML, aError = nsContentUtils::ParseFragmentHTML( aInnerHTML, target, contextLocalName, contextNameSpaceID, doc->GetCompatibilityMode() == eCompatibility_NavQuirks, true); + doc->ResumeDOMNotifications(); + if (target->GetFirstChild()) { + MutationObservers::NotifyContentAppended(target, target->GetFirstChild()); + } mb.NodesAdded(); // HTML5 parser has notified, but not fired mutation events. nsContentUtils::FireMutationEventsForDirectParsing(doc, target, diff --git a/dom/base/IDTracker.cpp b/dom/base/IDTracker.cpp index 4db592534d..813aa44e11 100644 --- a/dom/base/IDTracker.cpp +++ b/dom/base/IDTracker.cpp @@ -132,13 +132,30 @@ void IDTracker::ResetWithLocalRef(Element& aFrom, const nsAString& aLocalRef, bool aWatch) { MOZ_ASSERT(nsContentUtils::IsLocalRefURL(aLocalRef)); - nsAutoCString ref; - if (!AppendUTF16toUTF8(Substring(aLocalRef, 1), ref, mozilla::fallible)) { + auto ref = Substring(aLocalRef, 1); + if (ref.IsEmpty()) { Unlink(); return; } - NS_UnescapeURL(ref); - RefPtr idAtom = NS_Atomize(ref); + + nsAutoCString utf8Ref; + if (!AppendUTF16toUTF8(ref, utf8Ref, mozilla::fallible)) { + Unlink(); + return; + } + + // Only unescape ASCII characters; if we were to unescape arbitrary bytes, + // we'd potentially end up with invalid UTF-8. + nsAutoCString unescaped; + bool appended; + if (NS_FAILED(NS_UnescapeURL(utf8Ref.BeginReading(), utf8Ref.Length(), + esc_OnlyASCII | esc_AlwaysCopy, unescaped, + appended, mozilla::fallible))) { + Unlink(); + return; + } + + RefPtr idAtom = NS_Atomize(unescaped); ResetWithID(aFrom, idAtom, aWatch); } diff --git a/dom/base/InProcessBrowserChildMessageManager.cpp b/dom/base/InProcessBrowserChildMessageManager.cpp index 191ec9f7b5..830c57591b 100644 --- a/dom/base/InProcessBrowserChildMessageManager.cpp +++ b/dom/base/InProcessBrowserChildMessageManager.cpp @@ -13,7 +13,6 @@ #include "nsFrameLoaderOwner.h" #include "nsQueryObject.h" #include "xpcpublic.h" -#include "nsIMozBrowserFrame.h" #include "mozilla/EventDispatcher.h" #include "mozilla/dom/ChromeMessageSender.h" #include "mozilla/dom/Document.h" @@ -100,15 +99,6 @@ InProcessBrowserChildMessageManager::InProcessBrowserChildMessageManager( mOwner(aOwner), mChromeMessageManager(aChrome) { mozilla::HoldJSObjects(this); - - // If owner corresponds to an + + +"> + + + + diff --git a/dom/security/metrics.yaml b/dom/security/metrics.yaml new file mode 100644 index 0000000000..02084407b1 --- /dev/null +++ b/dom/security/metrics.yaml @@ -0,0 +1,153 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Adding a new metric? We have docs for that! +# https://firefox-source-docs.mozilla.org/toolkit/components/glean/user/new_definitions_file.html + +--- +$schema: moz://mozilla.org/schemas/glean/metrics/2-0-0 +$tags: + - 'Core :: DOM: Security' + +httpsfirst: + upgraded: + type: counter + description: > + Counts how often a load is marked to be upgraded to HTTPS because of + HTTPS-First (`dom.security.https_first` enabled). + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10 + data_sensitivity: + - technical + notification_emails: + - mjurgens@mozilla.com + - seceng-telemetry@mozilla.com + expires: never + + upgraded_schemeless: + type: counter + description: > + Counts how often a load is marked to be upgraded to HTTPS because of + schemeless HTTPS-First (`dom.security.https_first` disabled, but load + marked as schemeless). + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10 + data_sensitivity: + - technical + notification_emails: + - mjurgens@mozilla.com + - seceng-telemetry@mozilla.com + expires: never + + downgraded: + type: counter + description: > + How many regular HTTPS-First (`dom.security.https_first` enabled) + upgrades get downgraded again. + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10 + data_sensitivity: + - technical + notification_emails: + - mjurgens@mozilla.com + - seceng-telemetry@mozilla.com + expires: never + + downgraded_schemeless: + type: counter + description: > + How many schemeless HTTPS-First (`dom.security.https_first` disabled, but + load marked as schemeless) upgrades get downgraded again. + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10 + data_sensitivity: + - technical + notification_emails: + - mjurgens@mozilla.com + - seceng-telemetry@mozilla.com + expires: never + + downgraded_on_timer: + type: rate + description: > + How many HTTPS-First (`dom.security.https_first` enabled) upgrades get + downgraded again because the HTTP request fired after 3s received a answer + faster than the HTTPS request. + denominator_metric: httpsfirst.downgraded + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10 + data_sensitivity: + - technical + notification_emails: + - mjurgens@mozilla.com + - seceng-telemetry@mozilla.com + expires: never + + downgraded_on_timer_schemeless: + type: rate + description: > + How many of schemeless HTTPS-First (`dom.security.https_first` disabled, + but load marked as schemeless) upgrades get downgraded again because the + HTTP request fired after 3s received a answer faster than the HTTPS + request + denominator_metric: httpsfirst.downgraded_schemeless + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10 + data_sensitivity: + - technical + notification_emails: + - mjurgens@mozilla.com + - seceng-telemetry@mozilla.com + expires: never + + downgrade_time: + type: timing_distribution + description: > + If a HTTPS-First (`dom.security.https_first` enabled) upgrade isn't + successful, measures the timespan between the navigation start and the + downgrade. This is essentially the overhead caused by HTTPS-First if a + site does not support HTTPS. + time_unit: millisecond + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10 + data_sensitivity: + - technical + notification_emails: + - mjurgens@mozilla.com + - seceng-telemetry@mozilla.com + expires: never + + downgrade_time_schemeless: + type: timing_distribution + description: > + If a schemeless HTTPS-First (`dom.security.https_first` disabled, but + load marked as schemeless) upgrade isn't successful, measures the + timespan between the navigation start and the downgrade. This is + essentially the overhead caused by HTTPS-First if a site does not support + HTTPS. + time_unit: millisecond + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10 + data_sensitivity: + - technical + notification_emails: + - mjurgens@mozilla.com + - seceng-telemetry@mozilla.com + expires: never diff --git a/dom/security/moz.build b/dom/security/moz.build index 0f2aed6a1f..f63fa22db6 100644 --- a/dom/security/moz.build +++ b/dom/security/moz.build @@ -9,7 +9,7 @@ with Files("*"): TEST_DIRS += ["test"] -DIRS += ["featurepolicy", "sanitizer"] +DIRS += ["featurepolicy", "sanitizer", "trusted-types"] EXPORTS.mozilla.dom += [ "CSPEvalChecker.h", diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp index aafd2b64f2..ed44304484 100644 --- a/dom/security/nsCSPContext.cpp +++ b/dom/security/nsCSPContext.cpp @@ -189,10 +189,11 @@ bool nsCSPContext::permitsInternal( bool permits = true; nsAutoString violatedDirective; + nsAutoString violatedDirectiveString; for (uint32_t p = 0; p < mPolicies.Length(); p++) { if (!mPolicies[p]->permits(aDir, aLoadInfo, aContentLocation, !!aOriginalURIIfRedirect, aSpecific, - violatedDirective)) { + violatedDirective, violatedDirectiveString)) { // If the policy is violated and not report-only, reject the load and // report to the console if (!mPolicies[p]->getReportOnlyFlag()) { @@ -200,12 +201,6 @@ bool nsCSPContext::permitsInternal( permits = false; } - // In CSP 3.0 the effective directive doesn't become the actually used - // directive in case of a fallback from e.g. script-src-elem to - // script-src or default-src. - nsAutoString effectiveDirective; - effectiveDirective.AssignASCII(CSP_CSPDirectiveToString(aDir)); - // Callers should set |aSendViolationReports| to false if this is a // preload - the decision may be wrong due to the inability to get the // nonce, and will incorrectly fail the unit tests. @@ -226,9 +221,11 @@ bool nsCSPContext::permitsInternal( BlockedContentSource::eUnknown, /* a BlockedContentSource */ aOriginalURIIfRedirect, /* in case of redirect originalURI is not null */ - violatedDirective, effectiveDirective, p, /* policy index */ - u""_ns, /* no observer subject */ - spec, /* source file */ + violatedDirective, violatedDirectiveString, + aDir, // aViolatedDirective + p, // policy index + u""_ns, // no observer subject + spec, // source file false, // aReportSample (no sample) u""_ns, /* no script sample */ lineNumber, /* line number */ @@ -519,7 +516,8 @@ void nsCSPContext::reportInlineViolation( CSPDirective aDirective, Element* aTriggeringElement, nsICSPEventListener* aCSPEventListener, const nsAString& aNonce, bool aReportSample, const nsAString& aSample, - const nsAString& aViolatedDirective, const nsAString& aEffectiveDirective, + const nsAString& aViolatedDirective, + const nsAString& aViolatedDirectiveString, CSPDirective aEffectiveDirective, uint32_t aViolatedPolicyIndex, // TODO, use report only flag for that uint32_t aLineNumber, uint32_t aColumnNumber) { nsString observerSubject; @@ -564,14 +562,15 @@ void nsCSPContext::reportInlineViolation( BlockedContentSource::eInline, // aBlockedSource mSelfURI, // aOriginalURI aViolatedDirective, // aViolatedDirective - aEffectiveDirective, // aEffectiveDirective - aViolatedPolicyIndex, // aViolatedPolicyIndex - observerSubject, // aObserverSubject - sourceFile, // aSourceFile - aReportSample, // aReportSample - aSample, // aScriptSample - lineNumber, // aLineNum - columnNumber); // aColumnNum + aViolatedDirectiveString, + aEffectiveDirective, // aEffectiveDirective + aViolatedPolicyIndex, // aViolatedPolicyIndex + observerSubject, // aObserverSubject + sourceFile, // aSourceFile + aReportSample, // aReportSample + aSample, // aScriptSample + lineNumber, // aLineNum + columnNumber); // aColumnNum } NS_IMETHODIMP @@ -672,19 +671,16 @@ nsCSPContext::GetAllowsInline(CSPDirective aDirective, bool aHasUnsafeHash, *outAllowsInline = false; } nsAutoString violatedDirective; + nsAutoString violatedDirectiveString; bool reportSample = false; - mPolicies[i]->getDirectiveStringAndReportSampleForContentType( - aDirective, violatedDirective, &reportSample); - - // In CSP 3.0 the effective directive doesn't become the actually used - // directive in case of a fallback from e.g. script-src-elem to - // script-src or default-src. - nsAutoString effectiveDirective; - effectiveDirective.AssignASCII(CSP_CSPDirectiveToString(aDirective)); + mPolicies[i]->getViolatedDirectiveInformation( + aDirective, violatedDirective, violatedDirectiveString, + &reportSample); reportInlineViolation(aDirective, aTriggeringElement, aCSPEventListener, aNonce, reportSample, content, violatedDirective, - effectiveDirective, i, aLineNumber, aColumnNumber); + violatedDirectiveString, aDirective, i, aLineNumber, + aColumnNumber); } } @@ -747,15 +743,18 @@ nsCSPContext::LogViolationDetails( } nsAutoString violatedDirective; + nsAutoString violatedDirectiveString; bool reportSample = false; - mPolicies[p]->getDirectiveStringAndReportSampleForContentType( - SCRIPT_SRC_DIRECTIVE, violatedDirective, &reportSample); + mPolicies[p]->getViolatedDirectiveInformation( + SCRIPT_SRC_DIRECTIVE, violatedDirective, violatedDirectiveString, + &reportSample); - AsyncReportViolation(aTriggeringElement, aCSPEventListener, nullptr, - blockedContentSource, nullptr, violatedDirective, - u"script-src"_ns /* aEffectiveDirective */, p, - observerSubject, aSourceFile, reportSample, - aScriptSample, aLineNum, aColumnNum); + AsyncReportViolation( + aTriggeringElement, aCSPEventListener, nullptr, blockedContentSource, + nullptr, violatedDirective, violatedDirectiveString, + CSPDirective::SCRIPT_SRC_DIRECTIVE /* aEffectiveDirective */, p, + observerSubject, aSourceFile, reportSample, aScriptSample, aLineNum, + aColumnNum); } return NS_OK; } @@ -1375,10 +1374,12 @@ class CSPReportSenderRunnable final : public Runnable { nsIURI* aBlockedURI, nsCSPContext::BlockedContentSource aBlockedContentSource, nsIURI* aOriginalURI, uint32_t aViolatedPolicyIndex, bool aReportOnlyFlag, - const nsAString& aViolatedDirective, const nsAString& aEffectiveDirective, - const nsAString& aObserverSubject, const nsAString& aSourceFile, - bool aReportSample, const nsAString& aScriptSample, uint32_t aLineNum, - uint32_t aColumnNum, nsCSPContext* aCSPContext) + const nsAString& aViolatedDirective, + const nsAString& aViolatedDirectiveString, + const CSPDirective aEffectiveDirective, const nsAString& aObserverSubject, + const nsAString& aSourceFile, bool aReportSample, + const nsAString& aScriptSample, uint32_t aLineNum, uint32_t aColumnNum, + nsCSPContext* aCSPContext) : mozilla::Runnable("CSPReportSenderRunnable"), mTriggeringElement(aTriggeringElement), mCSPEventListener(aCSPEventListener), @@ -1389,6 +1390,7 @@ class CSPReportSenderRunnable final : public Runnable { mReportOnlyFlag(aReportOnlyFlag), mReportSample(aReportSample), mViolatedDirective(aViolatedDirective), + mViolatedDirectiveString(aViolatedDirectiveString), mEffectiveDirective(aEffectiveDirective), mSourceFile(aSourceFile), mScriptSample(aScriptSample), @@ -1436,16 +1438,18 @@ class CSPReportSenderRunnable final : public Runnable { NS_IMETHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); - nsresult rv; - // 0) prepare violation data mozilla::dom::SecurityPolicyViolationEventInit init; nsAutoCString blockedContentSource; BlockedContentSourceToString(mBlockedContentSource, blockedContentSource); - rv = mCSPContext->GatherSecurityPolicyViolationEventData( - mBlockedURI, blockedContentSource, mOriginalURI, mEffectiveDirective, + nsAutoString effectiveDirective; + effectiveDirective.AssignASCII( + CSP_CSPDirectiveToString(mEffectiveDirective)); + + nsresult rv = mCSPContext->GatherSecurityPolicyViolationEventData( + mBlockedURI, blockedContentSource, mOriginalURI, effectiveDirective, mViolatedPolicyIndex, mSourceFile, mReportSample ? mScriptSample : EmptyString(), mLineNum, mColumnNum, init); @@ -1464,32 +1468,7 @@ class CSPReportSenderRunnable final : public Runnable { mCSPContext->SendReports(init, mViolatedPolicyIndex); // 3) log to console (one per policy violation) - - if (mBlockedURI) { - mBlockedURI->GetSpec(blockedContentSource); - if (blockedContentSource.Length() > - nsCSPContext::ScriptSampleMaxLength()) { - bool isData = mBlockedURI->SchemeIs("data"); - if (NS_SUCCEEDED(rv) && isData && - blockedContentSource.Length() > - nsCSPContext::ScriptSampleMaxLength()) { - blockedContentSource.Truncate(nsCSPContext::ScriptSampleMaxLength()); - blockedContentSource.Append( - NS_ConvertUTF16toUTF8(nsContentUtils::GetLocalizedEllipsis())); - } - } - } - - if (blockedContentSource.Length() > 0) { - nsString blockedContentSource16 = - NS_ConvertUTF8toUTF16(blockedContentSource); - AutoTArray params = {mViolatedDirective, - blockedContentSource16}; - mCSPContext->logToConsole( - mReportOnlyFlag ? "CSPROViolationWithURI" : "CSPViolationWithURI", - params, mSourceFile, mScriptSample, mLineNum, mColumnNum, - nsIScriptError::errorFlag); - } + ReportToConsole(); // 4) fire violation event // A frame-ancestors violation has occurred, but we should not dispatch @@ -1503,6 +1482,104 @@ class CSPReportSenderRunnable final : public Runnable { } private: + void ReportToConsole() const { + NS_ConvertUTF8toUTF16 effectiveDirective( + CSP_CSPDirectiveToString(mEffectiveDirective)); + + switch (mBlockedContentSource) { + case nsCSPContext::BlockedContentSource::eInline: { + const char* errorName = nullptr; + if (mEffectiveDirective == CSPDirective::STYLE_SRC_ATTR_DIRECTIVE || + mEffectiveDirective == CSPDirective::STYLE_SRC_ELEM_DIRECTIVE) { + errorName = mReportOnlyFlag ? "CSPROInlineStyleViolation" + : "CSPInlineStyleViolation"; + } else if (mEffectiveDirective == + CSPDirective::SCRIPT_SRC_ATTR_DIRECTIVE) { + errorName = mReportOnlyFlag ? "CSPROEventHandlerScriptViolation" + : "CSPEventHandlerScriptViolation"; + } else { + MOZ_ASSERT(mEffectiveDirective == + CSPDirective::SCRIPT_SRC_ELEM_DIRECTIVE); + errorName = mReportOnlyFlag ? "CSPROInlineScriptViolation" + : "CSPInlineScriptViolation"; + } + + AutoTArray params = {mViolatedDirectiveString, + effectiveDirective}; + mCSPContext->logToConsole(errorName, params, mSourceFile, mScriptSample, + mLineNum, mColumnNum, + nsIScriptError::errorFlag); + break; + } + + case nsCSPContext::BlockedContentSource::eEval: { + AutoTArray params = {mViolatedDirectiveString, + effectiveDirective}; + mCSPContext->logToConsole(mReportOnlyFlag ? "CSPROEvalScriptViolation" + : "CSPEvalScriptViolation", + params, mSourceFile, mScriptSample, mLineNum, + mColumnNum, nsIScriptError::errorFlag); + break; + } + + case nsCSPContext::BlockedContentSource::eWasmEval: { + AutoTArray params = {mViolatedDirectiveString, + effectiveDirective}; + mCSPContext->logToConsole(mReportOnlyFlag + ? "CSPROWasmEvalScriptViolation" + : "CSPWasmEvalScriptViolation", + params, mSourceFile, mScriptSample, mLineNum, + mColumnNum, nsIScriptError::errorFlag); + break; + } + + case nsCSPContext::BlockedContentSource::eSelf: + case nsCSPContext::BlockedContentSource::eUnknown: { + nsAutoString source(u""_ns); + if (mBlockedURI) { + nsAutoCString uri; + mBlockedURI->GetSpec(uri); + + if (mBlockedURI->SchemeIs("data") && + uri.Length() > nsCSPContext::ScriptSampleMaxLength()) { + uri.Truncate(nsCSPContext::ScriptSampleMaxLength()); + uri.Append( + NS_ConvertUTF16toUTF8(nsContentUtils::GetLocalizedEllipsis())); + } + + if (!uri.IsEmpty()) { + CopyUTF8toUTF16(uri, source); + } + } + + const char* errorName = nullptr; + switch (mEffectiveDirective) { + case CSPDirective::STYLE_SRC_ELEM_DIRECTIVE: + errorName = + mReportOnlyFlag ? "CSPROStyleViolation" : "CSPStyleViolation"; + break; + case CSPDirective::SCRIPT_SRC_ELEM_DIRECTIVE: + errorName = + mReportOnlyFlag ? "CSPROScriptViolation" : "CSPScriptViolation"; + break; + case CSPDirective::WORKER_SRC_DIRECTIVE: + errorName = + mReportOnlyFlag ? "CSPROWorkerViolation" : "CSPWorkerViolation"; + break; + default: + errorName = mReportOnlyFlag ? "CSPROGenericViolation" + : "CSPGenericViolation"; + } + + AutoTArray params = {mViolatedDirectiveString, source, + effectiveDirective}; + mCSPContext->logToConsole(errorName, params, mSourceFile, mScriptSample, + mLineNum, mColumnNum, + nsIScriptError::errorFlag); + } + } + } + RefPtr mTriggeringElement; nsCOMPtr mCSPEventListener; nsCOMPtr mBlockedURI; @@ -1512,7 +1589,8 @@ class CSPReportSenderRunnable final : public Runnable { bool mReportOnlyFlag; bool mReportSample; nsString mViolatedDirective; - nsString mEffectiveDirective; + nsString mViolatedDirectiveString; + CSPDirective mEffectiveDirective; nsCOMPtr mObserverSubject; nsString mSourceFile; nsString mScriptSample; @@ -1554,7 +1632,8 @@ nsresult nsCSPContext::AsyncReportViolation( Element* aTriggeringElement, nsICSPEventListener* aCSPEventListener, nsIURI* aBlockedURI, BlockedContentSource aBlockedContentSource, nsIURI* aOriginalURI, const nsAString& aViolatedDirective, - const nsAString& aEffectiveDirective, uint32_t aViolatedPolicyIndex, + const nsAString& aViolatedDirectiveString, + const CSPDirective aEffectiveDirective, uint32_t aViolatedPolicyIndex, const nsAString& aObserverSubject, const nsAString& aSourceFile, bool aReportSample, const nsAString& aScriptSample, uint32_t aLineNum, uint32_t aColumnNum) { @@ -1565,8 +1644,8 @@ nsresult nsCSPContext::AsyncReportViolation( aTriggeringElement, aCSPEventListener, aBlockedURI, aBlockedContentSource, aOriginalURI, aViolatedPolicyIndex, mPolicies[aViolatedPolicyIndex]->getReportOnlyFlag(), aViolatedDirective, - aEffectiveDirective, aObserverSubject, aSourceFile, aReportSample, - aScriptSample, aLineNum, aColumnNum, this); + aViolatedDirectiveString, aEffectiveDirective, aObserverSubject, + aSourceFile, aReportSample, aScriptSample, aLineNum, aColumnNum, this); if (XRE_IsContentProcess()) { if (mEventTarget) { diff --git a/dom/security/nsCSPContext.h b/dom/security/nsCSPContext.h index 0c1438e573..ae47e34cb3 100644 --- a/dom/security/nsCSPContext.h +++ b/dom/security/nsCSPContext.h @@ -126,10 +126,12 @@ class nsCSPContext : public nsIContentSecurityPolicy { mozilla::dom::Element* aTriggeringElement, nsICSPEventListener* aCSPEventListener, nsIURI* aBlockedURI, BlockedContentSource aBlockedContentSource, nsIURI* aOriginalURI, - const nsAString& aViolatedDirective, const nsAString& aEffectiveDirective, - uint32_t aViolatedPolicyIndex, const nsAString& aObserverSubject, - const nsAString& aSourceFile, bool aReportSample, - const nsAString& aScriptSample, uint32_t aLineNum, uint32_t aColumnNum); + const nsAString& aViolatedDirective, + const nsAString& aViolatedDirectiveString, + const CSPDirective aEffectiveDirective, uint32_t aViolatedPolicyIndex, + const nsAString& aObserverSubject, const nsAString& aSourceFile, + bool aReportSample, const nsAString& aScriptSample, uint32_t aLineNum, + uint32_t aColumnNum); // Hands off! Don't call this method unless you know what you // are doing. It's only supposed to be called from within @@ -168,7 +170,8 @@ class nsCSPContext : public nsIContentSecurityPolicy { const nsAString& aNonce, bool aReportSample, const nsAString& aSample, const nsAString& aViolatedDirective, - const nsAString& aEffectiveDirective, + const nsAString& aViolatedDirectiveString, + CSPDirective aEffectiveDirective, uint32_t aViolatedPolicyIndex, uint32_t aLineNumber, uint32_t aColumnNumber); diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp index 50730b691b..11d09909f7 100644 --- a/dom/security/nsCSPUtils.cpp +++ b/dom/security/nsCSPUtils.cpp @@ -1569,7 +1569,8 @@ nsCSPPolicy::~nsCSPPolicy() { bool nsCSPPolicy::permits(CSPDirective aDir, nsILoadInfo* aLoadInfo, nsIURI* aUri, bool aWasRedirected, bool aSpecific, - nsAString& outViolatedDirective) const { + nsAString& outViolatedDirective, + nsAString& outViolatedDirectiveString) const { if (CSPUTILSLOGENABLED()) { CSPUTILSLOG(("nsCSPPolicy::permits, aUri: %s, aDir: %s, aSpecific: %s", aUri->GetSpecOrDefault().get(), CSP_CSPDirectiveToString(aDir), @@ -1578,6 +1579,7 @@ bool nsCSPPolicy::permits(CSPDirective aDir, nsILoadInfo* aLoadInfo, NS_ASSERTION(aUri, "permits needs an uri to perform the check!"); outViolatedDirective.Truncate(); + outViolatedDirectiveString.Truncate(); nsCSPDirective* defaultDir = nullptr; @@ -1589,6 +1591,7 @@ bool nsCSPPolicy::permits(CSPDirective aDir, nsILoadInfo* aLoadInfo, if (!mDirectives[i]->permits(aDir, aLoadInfo, aUri, aWasRedirected, mReportOnly, mUpgradeInsecDir)) { mDirectives[i]->getDirName(outViolatedDirective); + mDirectives[i]->toString(outViolatedDirectiveString); return false; } return true; @@ -1604,6 +1607,7 @@ bool nsCSPPolicy::permits(CSPDirective aDir, nsILoadInfo* aLoadInfo, if (!defaultDir->permits(aDir, aLoadInfo, aUri, aWasRedirected, mReportOnly, mUpgradeInsecDir)) { defaultDir->getDirName(outViolatedDirective); + defaultDir->toString(outViolatedDirectiveString); return false; } return true; @@ -1692,43 +1696,22 @@ bool nsCSPPolicy::allowsAllInlineBehavior(CSPDirective aDir) const { * The parameter outDirective is the equivalent of 'outViolatedDirective' * for the ::permits() function family. */ -void nsCSPPolicy::getDirectiveStringAndReportSampleForContentType( - CSPDirective aDirective, nsAString& outDirective, - bool* aReportSample) const { - MOZ_ASSERT(aReportSample); +void nsCSPPolicy::getViolatedDirectiveInformation(CSPDirective aDirective, + nsAString& outDirective, + nsAString& outDirectiveString, + bool* aReportSample) const { *aReportSample = false; - - nsCSPDirective* defaultDir = nullptr; - for (uint32_t i = 0; i < mDirectives.Length(); i++) { - if (mDirectives[i]->isDefaultDirective()) { - defaultDir = mDirectives[i]; - continue; - } - if (mDirectives[i]->equals(aDirective)) { - mDirectives[i]->getDirName(outDirective); - *aReportSample = mDirectives[i]->hasReportSampleKeyword(); - return; - } - } - // if we haven't found a matching directive yet, - // the contentType must be restricted by the default directive - if (defaultDir) { - defaultDir->getDirName(outDirective); - *aReportSample = defaultDir->hasReportSampleKeyword(); + nsCSPDirective* directive = matchingOrDefaultDirective(aDirective); + if (!directive) { + MOZ_ASSERT_UNREACHABLE("Can not query violated directive"); + outDirective.AppendLiteral("couldNotQueryViolatedDirective"); + outDirective.Truncate(); return; } - NS_ASSERTION(false, "Can not query directive string for contentType!"); - outDirective.AppendLiteral("couldNotQueryViolatedDirective"); -} -void nsCSPPolicy::getDirectiveAsString(CSPDirective aDir, - nsAString& outDirective) const { - for (uint32_t i = 0; i < mDirectives.Length(); i++) { - if (mDirectives[i]->equals(aDir)) { - mDirectives[i]->toString(outDirective); - return; - } - } + directive->getDirName(outDirective); + directive->toString(outDirectiveString); + *aReportSample = directive->hasReportSampleKeyword(); } /* diff --git a/dom/security/nsCSPUtils.h b/dom/security/nsCSPUtils.h index 2692681d03..eeccaf0c4a 100644 --- a/dom/security/nsCSPUtils.h +++ b/dom/security/nsCSPUtils.h @@ -619,7 +619,8 @@ class nsCSPPolicy { bool permits(CSPDirective aDirective, nsILoadInfo* aLoadInfo, nsIURI* aUri, bool aWasRedirected, bool aSpecific, - nsAString& outViolatedDirective) const; + nsAString& outViolatedDirective, + nsAString& outViolatedDirectiveString) const; bool allows(CSPDirective aDirective, enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const; void toString(nsAString& outStr) const; @@ -650,11 +651,10 @@ class nsCSPPolicy { void getReportURIs(nsTArray& outReportURIs) const; - void getDirectiveStringAndReportSampleForContentType( - CSPDirective aDirective, nsAString& outDirective, - bool* aReportSample) const; - - void getDirectiveAsString(CSPDirective aDir, nsAString& outDirective) const; + void getViolatedDirectiveInformation(CSPDirective aDirective, + nsAString& outDirective, + nsAString& outDirectiveString, + bool* aReportSample) const; uint32_t getSandboxFlags() const; diff --git a/dom/security/nsContentSecurityUtils.cpp b/dom/security/nsContentSecurityUtils.cpp index a483522499..01e9c6d5db 100644 --- a/dom/security/nsContentSecurityUtils.cpp +++ b/dom/security/nsContentSecurityUtils.cpp @@ -1365,6 +1365,7 @@ void nsContentSecurityUtils::AssertAboutPageHasCSP(Document* aDocument) { // preferences and downloads allow legacy inline scripts through hash src. MOZ_ASSERT(!foundScriptSrc || StringBeginsWith(aboutSpec, "about:preferences"_ns) || + StringBeginsWith(aboutSpec, "about:settings"_ns) || StringBeginsWith(aboutSpec, "about:downloads"_ns) || StringBeginsWith(aboutSpec, "about:asrouter"_ns) || StringBeginsWith(aboutSpec, "about:newtab"_ns) || @@ -1383,6 +1384,7 @@ void nsContentSecurityUtils::AssertAboutPageHasCSP(Document* aDocument) { // remote web resources MOZ_ASSERT(!foundWebScheme || StringBeginsWith(aboutSpec, "about:preferences"_ns) || + StringBeginsWith(aboutSpec, "about:settings"_ns) || StringBeginsWith(aboutSpec, "about:addons"_ns) || StringBeginsWith(aboutSpec, "about:newtab"_ns) || StringBeginsWith(aboutSpec, "about:debugging"_ns) || @@ -1411,6 +1413,7 @@ void nsContentSecurityUtils::AssertAboutPageHasCSP(Document* aDocument) { // Bug 1579160: Remove 'unsafe-inline' from style-src within // about:preferences "about:preferences"_ns, + "about:settings"_ns, // Bug 1571346: Remove 'unsafe-inline' from style-src within about:addons "about:addons"_ns, // Bug 1584485: Remove 'unsafe-inline' from style-src within: @@ -1553,7 +1556,7 @@ bool nsContentSecurityUtils::ValidateScriptFilename(JSContext* cx, // and this is the most reasonable. See 1727770 u"about:downloads"_ns, // We think this is the same problem as about:downloads - u"about:preferences"_ns, + u"about:preferences"_ns, u"about:settings"_ns, // Browser console will give a filename of 'debugger' See 1763943 // Sometimes it's 'debugger eager eval code', other times just 'debugger // eval code' @@ -1667,37 +1670,25 @@ long nsContentSecurityUtils::ClassifyDownload( nsCOMPtr contentLocation; aChannel->GetURI(getter_AddRefs(contentLocation)); - nsCOMPtr loadingPrincipal = loadInfo->GetLoadingPrincipal(); - if (!loadingPrincipal) { - loadingPrincipal = loadInfo->TriggeringPrincipal(); - } - // Creating a fake Loadinfo that is just used for the MCB check. - nsCOMPtr secCheckLoadInfo = new mozilla::net::LoadInfo( - loadingPrincipal, loadInfo->TriggeringPrincipal(), nullptr, - nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK, - nsIContentPolicy::TYPE_FETCH); - // Disable HTTPS-Only checks for that loadinfo. This is required because - // otherwise nsMixedContentBlocker::ShouldLoad would assume that the request - // is safe, because HTTPS-Only is handling it. - secCheckLoadInfo->SetHttpsOnlyStatus(nsILoadInfo::HTTPS_ONLY_EXEMPT); - - int16_t decission = nsIContentPolicy::ACCEPT; - nsMixedContentBlocker::ShouldLoad(false, // aHadInsecureImageRedirect - contentLocation, // aContentLocation, - secCheckLoadInfo, // aLoadinfo - false, // aReportError - &decission // aDecision - ); - Telemetry::Accumulate(mozilla::Telemetry::MIXED_CONTENT_DOWNLOADS, - decission != nsIContentPolicy::ACCEPT); - - if (StaticPrefs::dom_block_download_insecure() && - decission != nsIContentPolicy::ACCEPT) { - nsCOMPtr httpChannel = do_QueryInterface(aChannel); - if (httpChannel) { - LogMessageToConsole(httpChannel, "MixedContentBlockedDownload"); + if (StaticPrefs::dom_block_download_insecure()) { + // If we are not dealing with a potentially trustworthy origin, or a URI + // that is safe to be loaded like e.g. data:, then we block the load. + bool isInsecureDownload = + !nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin( + contentLocation) && + !nsMixedContentBlocker::URISafeToBeLoadedInSecureContext( + contentLocation); + + Telemetry::Accumulate(mozilla::Telemetry::INSECURE_DOWNLOADS, + isInsecureDownload); + + if (isInsecureDownload) { + nsCOMPtr httpChannel = do_QueryInterface(aChannel); + if (httpChannel) { + LogMessageToConsole(httpChannel, "BlockedInsecureDownload"); + } + return nsITransfer::DOWNLOAD_POTENTIALLY_UNSAFE; } - return nsITransfer::DOWNLOAD_POTENTIALLY_UNSAFE; } if (loadInfo->TriggeringPrincipal()->IsSystemPrincipal()) { diff --git a/dom/security/nsHTTPSOnlyUtils.cpp b/dom/security/nsHTTPSOnlyUtils.cpp index 2a3880ba70..535efaba4e 100644 --- a/dom/security/nsHTTPSOnlyUtils.cpp +++ b/dom/security/nsHTTPSOnlyUtils.cpp @@ -6,6 +6,8 @@ #include "mozilla/Components.h" #include "mozilla/ClearOnShutdown.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/glean/GleanMetrics.h" #include "mozilla/NullPrincipal.h" #include "mozilla/StaticPrefs_dom.h" #include "mozilla/net/DNS.h" @@ -438,7 +440,7 @@ bool nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(nsIURI* aURI, // We can upgrade the request - let's log to the console and set the status // so we know that we upgraded the request. if (aLoadInfo->GetWasSchemelessInput() && - mozilla::StaticPrefs::dom_security_https_first_schemeless()) { + !IsHttpsFirstModeEnabled(isPrivateWin)) { nsAutoCString urlCString; aURI->GetSpec(urlCString); NS_ConvertUTF8toUTF16 urlString(urlCString); @@ -447,6 +449,8 @@ bool nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(nsIURI* aURI, nsHTTPSOnlyUtils::LogLocalizedString("HTTPSFirstSchemeless", params, nsIScriptError::warningFlag, aLoadInfo, aURI, true); + + mozilla::glean::httpsfirst::upgraded_schemeless.Add(); } else { nsAutoCString scheme; @@ -461,7 +465,12 @@ bool nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(nsIURI* aURI, isSpeculative ? "HTTPSOnlyUpgradeSpeculativeConnection" : "HTTPSOnlyUpgradeRequest", params, nsIScriptError::warningFlag, aLoadInfo, aURI, true); + + if (!isSpeculative) { + mozilla::glean::httpsfirst::upgraded.Add(); + } } + // Set flag so we know that we upgraded the request httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST; aLoadInfo->SetHttpsOnlyStatus(httpsOnlyStatus); @@ -470,9 +479,11 @@ bool nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(nsIURI* aURI, /* static */ already_AddRefed -nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(nsIChannel* aChannel, - nsresult aStatus) { - nsCOMPtr loadInfo = aChannel->LoadInfo(); +nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest( + mozilla::net::DocumentLoadListener* aDocumentLoadListener, + nsresult aStatus) { + nsCOMPtr channel = aDocumentLoadListener->GetChannel(); + nsCOMPtr loadInfo = channel->LoadInfo(); uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus(); // Only downgrade if we this request was upgraded using HTTPS-First Mode if (!(httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST)) { @@ -488,7 +499,7 @@ nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(nsIChannel* aChannel, // to check each NS_OK for those errors. // Only downgrade an NS_OK status if it is an 4xx or 5xx error. if (NS_SUCCEEDED(aStatus)) { - nsCOMPtr httpChannel = do_QueryInterface(aChannel); + nsCOMPtr httpChannel = do_QueryInterface(channel); // If no httpChannel exists we have nothing to do here. if (!httpChannel) { return nullptr; @@ -532,7 +543,7 @@ nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(nsIChannel* aChannel, } nsCOMPtr uri; - nsresult rv = aChannel->GetURI(getter_AddRefs(uri)); + nsresult rv = channel->GetURI(getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, nullptr); nsAutoCString spec; @@ -584,6 +595,33 @@ nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(nsIChannel* aChannel, nsIScriptError::warningFlag, loadInfo, uri, true); + // Record telemety + nsDOMNavigationTiming* timing = aDocumentLoadListener->GetTiming(); + if (timing) { + mozilla::TimeStamp navigationStart = timing->GetNavigationStartTimeStamp(); + if (navigationStart) { + mozilla::TimeDuration duration = + mozilla::TimeStamp::Now() - navigationStart; + bool isPrivateWin = + loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0; + + if (loadInfo->GetWasSchemelessInput() && + !IsHttpsFirstModeEnabled(isPrivateWin)) { + mozilla::glean::httpsfirst::downgraded_schemeless.Add(); + if (timing) { + mozilla::glean::httpsfirst::downgrade_time_schemeless + .AccumulateRawDuration(duration); + } + } else { + mozilla::glean::httpsfirst::downgraded.Add(); + if (timing) { + mozilla::glean::httpsfirst::downgrade_time.AccumulateRawDuration( + duration); + } + } + } + } + return newURI.forget(); } @@ -954,6 +992,19 @@ TestHTTPAnswerRunnable::OnStartRequest(nsIRequest* aRequest) { nsresult httpsOnlyChannelStatus; httpsOnlyChannel->GetStatus(&httpsOnlyChannelStatus); if (httpsOnlyChannelStatus == NS_OK) { + bool isPrivateWin = + loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0; + if (!nsHTTPSOnlyUtils::IsHttpsOnlyModeEnabled(isPrivateWin)) { + // Record HTTPS-First Telemetry + if (loadInfo->GetWasSchemelessInput() && + !nsHTTPSOnlyUtils::IsHttpsFirstModeEnabled(isPrivateWin)) { + mozilla::glean::httpsfirst::downgraded_on_timer_schemeless + .AddToNumerator(); + } else { + mozilla::glean::httpsfirst::downgraded_on_timer.AddToNumerator(); + } + } + httpsOnlyChannel->Cancel(NS_ERROR_NET_TIMEOUT_EXTERNAL); } } diff --git a/dom/security/nsHTTPSOnlyUtils.h b/dom/security/nsHTTPSOnlyUtils.h index 73a5219082..7e36bfadbd 100644 --- a/dom/security/nsHTTPSOnlyUtils.h +++ b/dom/security/nsHTTPSOnlyUtils.h @@ -95,12 +95,13 @@ class nsHTTPSOnlyUtils { /** * Determines if the request was previously upgraded with HTTPS-First, creates * a downgraded URI and logs to console. - * @param aStatus Status code - * @param aChannel Failed channel - * @return URI with http-scheme or nullptr + * @param aStatus Status code + * @param aDocumentLoadListener Failed document load listener + * @return URI with http-scheme or nullptr */ static already_AddRefed PotentiallyDowngradeHttpsFirstRequest( - nsIChannel* aChannel, nsresult aStatus); + mozilla::net::DocumentLoadListener* aDocumentLoadListener, + nsresult aStatus); /** * Checks if the error code is on a block-list of codes that are probably diff --git a/dom/security/test/csp/file_csp_error_messages.html b/dom/security/test/csp/file_csp_error_messages.html new file mode 100644 index 0000000000..65d26ac57e --- /dev/null +++ b/dom/security/test/csp/file_csp_error_messages.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dom/security/test/csp/mochitest.toml b/dom/security/test/csp/mochitest.toml index 8d8c6c31f5..5dd9a14222 100644 --- a/dom/security/test/csp/mochitest.toml +++ b/dom/security/test/csp/mochitest.toml @@ -433,6 +433,9 @@ skip-if = [ ["test_connect-src.html"] +["test_csp_error_messages.html"] +support-files = ["file_csp_error_messages.html"] + ["test_csp_frame_ancestors_about_blank.html"] support-files = [ "file_csp_frame_ancestors_about_blank.html", diff --git a/dom/security/test/csp/test_csp_error_messages.html b/dom/security/test/csp/test_csp_error_messages.html new file mode 100644 index 0000000000..51be37e7c0 --- /dev/null +++ b/dom/security/test/csp/test_csp_error_messages.html @@ -0,0 +1,75 @@ + + + + + Test some specialized CSP errors + + + + + + + + + + diff --git a/dom/security/test/general/browser.toml b/dom/security/test/general/browser.toml index 0f4ec5b224..c6d6b4bf79 100644 --- a/dom/security/test/general/browser.toml +++ b/dom/security/test/general/browser.toml @@ -48,6 +48,16 @@ support-files = [ "file_gpc_server.sjs", ] +["browser_test_http_download.js"] +skip-if = [ + "win11_2009", # Bug 1784764 + "os == 'linux' && !debug", +] +support-files = [ + "http_download_page.html", + "http_download_server.sjs" +] + ["browser_test_referrer_loadInOtherProcess.js"] ["browser_test_report_blocking.js"] diff --git a/dom/security/test/general/browser_restrict_privileged_about_script.js b/dom/security/test/general/browser_restrict_privileged_about_script.js index 0baa6e3d4d..7dfb6d691a 100644 --- a/dom/security/test/general/browser_restrict_privileged_about_script.js +++ b/dom/security/test/general/browser_restrict_privileged_about_script.js @@ -20,7 +20,7 @@ add_task(async function test_principal_click() { }); await BrowserTestUtils.withNewTab( "about:test-about-privileged-with-scripts", - async function (browser) { + async function () { // Wait for page to fully load info("Waiting for tab to be loaded.."); // let's look into the fully loaded about page diff --git a/dom/security/test/general/browser_test_data_download.js b/dom/security/test/general/browser_test_data_download.js index df5a8aeac4..9cebb97b30 100644 --- a/dom/security/test/general/browser_test_data_download.js +++ b/dom/security/test/general/browser_test_data_download.js @@ -22,13 +22,13 @@ function addWindowListener(aURL) { resolve(domwindow); }, domwindow); }, - onCloseWindow(aXULWindow) {}, + onCloseWindow() {}, }); }); } function waitDelay(delay) { - return new Promise((resolve, reject) => { + return new Promise(resolve => { /* eslint-disable mozilla/no-arbitrary-setTimeout */ window.setTimeout(resolve, delay); }); diff --git a/dom/security/test/general/browser_test_data_text_csv.js b/dom/security/test/general/browser_test_data_text_csv.js index 9855ddce46..b6c9f46336 100644 --- a/dom/security/test/general/browser_test_data_text_csv.js +++ b/dom/security/test/general/browser_test_data_text_csv.js @@ -6,7 +6,7 @@ const kTestPath = getRootDirectory(gTestPath).replace( ); const kTestURI = kTestPath + "file_data_text_csv.html"; -function addWindowListener(aURL, aCallback) { +function addWindowListener(aURL) { return new Promise(resolve => { Services.wm.addListener({ onOpenWindow(aXULWindow) { @@ -22,7 +22,7 @@ function addWindowListener(aURL, aCallback) { resolve(domwindow); }, domwindow); }, - onCloseWindow(aXULWindow) {}, + onCloseWindow() {}, }); }); } diff --git a/dom/security/test/general/browser_test_http_download.js b/dom/security/test/general/browser_test_http_download.js new file mode 100644 index 0000000000..35e3fdfc4b --- /dev/null +++ b/dom/security/test/general/browser_test_http_download.js @@ -0,0 +1,275 @@ +/* Any copyright is dedicated to the Public Domain. + * https://creativecommons.org/publicdomain/zero/1.0/ */ + +ChromeUtils.defineESModuleGetters(this, { + Downloads: "resource://gre/modules/Downloads.sys.mjs", + DownloadsCommon: "resource:///modules/DownloadsCommon.sys.mjs", +}); + +const HandlerService = Cc[ + "@mozilla.org/uriloader/handler-service;1" +].getService(Ci.nsIHandlerService); + +const MIMEService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); + +// Using insecure HTTP URL for a test cases around HTTP downloads +let INSECURE_BASE_URL = + getRootDirectory(gTestPath).replace( + "chrome://mochitests/content/", + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com/" + ) + "http_download_page.html"; + +function promiseFocus() { + return new Promise(resolve => { + waitForFocus(resolve); + }); +} + +async function task_openPanel() { + await promiseFocus(); + + let promise = BrowserTestUtils.waitForPopupEvent( + DownloadsPanel.panel, + "shown" + ); + DownloadsPanel.showPanel(); + await promise; +} + +const downloadMonitoringView = { + _listeners: [], + onDownloadAdded(download) { + for (let listener of this._listeners) { + listener(download); + } + this._listeners = []; + }, + waitForDownload(listener) { + this._listeners.push(listener); + }, +}; + +/** + * Waits until a download is triggered. + * Unless the always_ask_before_handling_new_types pref is true, the download + * will simply be saved, so resolve when the view is notified of the new + * download. Otherwise, it waits until a prompt is shown, selects the choosen + * , then accepts the dialog + * @param [action] Which action to select, either: + * "handleInternally", "save" or "open". + * @returns {Promise} Resolved once done. + */ + +function shouldTriggerDownload(action = "save") { + if ( + Services.prefs.getBoolPref( + "browser.download.always_ask_before_handling_new_types" + ) + ) { + return new Promise((resolve, reject) => { + Services.wm.addListener({ + onOpenWindow(xulWin) { + Services.wm.removeListener(this); + let win = xulWin.docShell.domWindow; + waitForFocus(() => { + if ( + win.location == + "chrome://mozapps/content/downloads/unknownContentType.xhtml" + ) { + let dialog = win.document.getElementById("unknownContentType"); + let button = dialog.getButton("accept"); + let actionRadio = win.document.getElementById(action); + actionRadio.click(); + button.disabled = false; + dialog.acceptDialog(); + resolve(); + } else { + reject(); + } + }, win); + }, + }); + }); + } + return new Promise(res => { + downloadMonitoringView.waitForDownload(res); + }); +} + +const CONSOLE_ERROR_MESSAGE = "We blocked a download that’s not secure"; + +function shouldConsoleError() { + // Waits until CONSOLE_ERROR_MESSAGE was logged + return new Promise((resolve, reject) => { + function listener(msgObj) { + let text = msgObj.message; + if (text.includes(CONSOLE_ERROR_MESSAGE)) { + Services.console.unregisterListener(listener); + resolve(); + } + } + Services.console.registerListener(listener); + }); +} + +async function resetDownloads() { + // Removes all downloads from the download List + const types = new Set(); + let publicList = await Downloads.getList(Downloads.PUBLIC); + let downloads = await publicList.getAll(); + for (let download of downloads) { + if (download.contentType) { + types.add(download.contentType); + } + publicList.remove(download); + await download.finalize(true); + } + + if (types.size) { + // reset handlers for the contentTypes of any files previously downloaded + for (let type of types) { + const mimeInfo = MIMEService.getFromTypeAndExtension(type, ""); + info("resetting handler for type: " + type); + HandlerService.remove(mimeInfo); + } + } +} + +function shouldNotifyDownloadUI() { + return new Promise(res => { + downloadMonitoringView.waitForDownload(async aDownload => { + let { error } = aDownload; + if ( + error.becauseBlockedByReputationCheck && + error.reputationCheckVerdict == Downloads.Error.BLOCK_VERDICT_INSECURE + ) { + // It's an insecure Download, now Check that it has been cleaned up properly + if ((await IOUtils.stat(aDownload.target.path)).size != 0) { + throw new Error(`Download target is not empty!`); + } + if ((await IOUtils.stat(aDownload.target.path)).size != 0) { + throw new Error(`Download partFile was not cleaned up properly`); + } + // Assert that the Referrer is presnt + if (!aDownload.source.referrerInfo) { + throw new Error("The Blocked download is missing the ReferrerInfo"); + } + + res(aDownload); + } else { + ok(false, "No error for download that was expected to error!"); + } + }); + }); +} + +async function runTest(url, link, checkFunction, description) { + await SpecialPowers.pushPrefEnv({ + set: [["dom.block_download_insecure", true]], + }); + await resetDownloads(); + + let tab = BrowserTestUtils.addTab(gBrowser, url); + gBrowser.selectedTab = tab; + + let browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + + info("Checking: " + description); + + let checkPromise = checkFunction(); + // Click the Link to trigger the download + SpecialPowers.spawn(gBrowser.selectedBrowser, [link], contentLink => { + content.document.getElementById(contentLink).click(); + }); + + await checkPromise; + + ok(true, description); + BrowserTestUtils.removeTab(tab); + + await SpecialPowers.popPrefEnv(); +} + +add_setup(async () => { + let list = await Downloads.getList(Downloads.ALL); + list.addView(downloadMonitoringView); + registerCleanupFunction(() => list.removeView(downloadMonitoringView)); +}); + +// Test Blocking +add_task(async function test_blocking() { + for (let prefVal of [true, false]) { + await SpecialPowers.pushPrefEnv({ + set: [["browser.download.always_ask_before_handling_new_types", prefVal]], + }); + await runTest( + INSECURE_BASE_URL, + "http-link", + () => + Promise.all([ + shouldTriggerDownload(), + shouldNotifyDownloadUI(), + shouldConsoleError(), + ]), + "Insecure (HTTP) toplevel -> Insecure (HTTP) download should Error" + ); + await SpecialPowers.popPrefEnv(); + } +}); + +// Test Manual Unblocking +add_task(async function test_manual_unblocking() { + for (let prefVal of [true, false]) { + await SpecialPowers.pushPrefEnv({ + set: [["browser.download.always_ask_before_handling_new_types", prefVal]], + }); + await runTest( + INSECURE_BASE_URL, + "http-link", + async () => { + let [, download] = await Promise.all([ + shouldTriggerDownload(), + shouldNotifyDownloadUI(), + ]); + await download.unblock(); + Assert.equal( + download.error, + null, + "There should be no error after unblocking" + ); + }, + "A blocked download should succeed to download after a manual unblock" + ); + await SpecialPowers.popPrefEnv(); + } +}); + +// Test Unblock Download Visible +add_task(async function test_unblock_download_visible() { + for (let prefVal of [true, false]) { + await SpecialPowers.pushPrefEnv({ + set: [["browser.download.always_ask_before_handling_new_types", prefVal]], + }); + await promiseFocus(); + await runTest( + INSECURE_BASE_URL, + "http-link", + async () => { + let panelHasOpened = BrowserTestUtils.waitForPopupEvent( + DownloadsPanel.panel, + "shown" + ); + info("awaiting that the download is triggered and added to the list"); + await Promise.all([shouldTriggerDownload(), shouldNotifyDownloadUI()]); + info("awaiting that the Download list shows itself"); + await panelHasOpened; + DownloadsPanel.hidePanel(); + ok(true, "The Download Panel should have opened on blocked download"); + }, + "A blocked download should open the download panel" + ); + await SpecialPowers.popPrefEnv(); + } +}); diff --git a/dom/security/test/general/browser_test_report_blocking.js b/dom/security/test/general/browser_test_report_blocking.js index ebd7514097..ab66f1d836 100644 --- a/dom/security/test/general/browser_test_report_blocking.js +++ b/dom/security/test/general/browser_test_report_blocking.js @@ -108,7 +108,7 @@ async function testReporting(test) { return iframe.browsingContext; }); - await SpecialPowers.spawn(frameBC, [type], async obj => { + await SpecialPowers.spawn(frameBC, [type], async () => { // Wait until the reporting UI is visible. await ContentTaskUtils.waitForCondition(() => { let reportUI = content.document.getElementById("blockingErrorReporting"); diff --git a/dom/security/test/general/browser_test_toplevel_data_navigations.js b/dom/security/test/general/browser_test_toplevel_data_navigations.js index 0e006f1fd2..cf7c116eba 100644 --- a/dom/security/test/general/browser_test_toplevel_data_navigations.js +++ b/dom/security/test/general/browser_test_toplevel_data_navigations.js @@ -15,7 +15,7 @@ add_task(async function test_nav_data_uri() { await SpecialPowers.pushPrefEnv({ set: [["security.data_uri.block_toplevel_data_uri_navigations", true]], }); - await BrowserTestUtils.withNewTab(kDataURI, async function (browser) { + await BrowserTestUtils.withNewTab(kDataURI, async function () { await SpecialPowers.spawn( gBrowser.selectedBrowser, [{ kDataBody }], diff --git a/dom/security/test/general/browser_test_view_image_data_navigation.js b/dom/security/test/general/browser_test_view_image_data_navigation.js index 90aace1e3e..6e4173e343 100644 --- a/dom/security/test/general/browser_test_view_image_data_navigation.js +++ b/dom/security/test/general/browser_test_view_image_data_navigation.js @@ -8,7 +8,7 @@ add_task(async function test_principal_right_click_open_link_in_new_tab() { const TEST_PAGE = getRootDirectory(gTestPath) + "file_view_image_data_navigation.html"; - await BrowserTestUtils.withNewTab(TEST_PAGE, async function (browser) { + await BrowserTestUtils.withNewTab(TEST_PAGE, async function () { let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true); // simulate right-click->view-image @@ -43,7 +43,7 @@ add_task(async function test_right_click_open_bg_image() { const TEST_PAGE = getRootDirectory(gTestPath) + "file_view_bg_image_data_navigation.html"; - await BrowserTestUtils.withNewTab(TEST_PAGE, async function (browser) { + await BrowserTestUtils.withNewTab(TEST_PAGE, async function () { let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true); // simulate right-click->view-image diff --git a/dom/security/test/general/http_download_page.html b/dom/security/test/general/http_download_page.html new file mode 100644 index 0000000000..c5461eaed3 --- /dev/null +++ b/dom/security/test/general/http_download_page.html @@ -0,0 +1,23 @@ + + + + Test for the download attribute + + + hi + + + + diff --git a/dom/security/test/general/http_download_server.sjs b/dom/security/test/general/http_download_server.sjs new file mode 100644 index 0000000000..e659df2f40 --- /dev/null +++ b/dom/security/test/general/http_download_server.sjs @@ -0,0 +1,20 @@ +// force the Browser to Show a Download Prompt + +function handleRequest(request, response) { + let type = "image/png"; + let filename = "hello.png"; + request.queryString.split("&").forEach(val => { + var [key, value] = val.split("="); + if (key == "type") { + type = value; + } + if (key == "name") { + filename = value; + } + }); + + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Disposition", `attachment; filename=${filename}`); + response.setHeader("Content-Type", type); + response.write("🙈🙊🐵🙊"); +} diff --git a/dom/security/test/general/test_block_script_wrong_mime.html b/dom/security/test/general/test_block_script_wrong_mime.html index 93a4b9d220..7122363dfc 100644 --- a/dom/security/test/general/test_block_script_wrong_mime.html +++ b/dom/security/test/general/test_block_script_wrong_mime.html @@ -25,7 +25,7 @@ const MIMETypes = [ // + ` + ); + } +} diff --git a/dom/security/test/referrer-policy/referrer_helper.js b/dom/security/test/referrer-policy/referrer_helper.js index b892017eef..92593fa907 100644 --- a/dom/security/test/referrer-policy/referrer_helper.js +++ b/dom/security/test/referrer-policy/referrer_helper.js @@ -61,7 +61,7 @@ function checkIndividualResults(aTestname, aExpectedReferrer, aName) { ); advance(); }; - var onerror = xhr => { + var onerror = () => { ok(false, "Can't get results from the counter server."); SimpleTest.finish(); }; @@ -69,7 +69,7 @@ function checkIndividualResults(aTestname, aExpectedReferrer, aName) { } function resetState() { - doXHR(RESET_STATE, advance, function (xhr) { + doXHR(RESET_STATE, advance, function () { ok(false, "error in reset state"); SimpleTest.finish(); }); diff --git a/dom/security/test/referrer-policy/test_img_referrer.html b/dom/security/test/referrer-policy/test_img_referrer.html index fcc80929d2..5e3a2e6ddf 100644 --- a/dom/security/test/referrer-policy/test_img_referrer.html +++ b/dom/security/test/referrer-policy/test_img_referrer.html @@ -64,7 +64,7 @@ function checkIndividualResults(aTestname, aExpectedImg, aName) { advance(); }, - function(xhr) { + function() { ok(false, "Can't get results from the counter server."); SimpleTest.finish(); }); @@ -73,7 +73,7 @@ function checkIndividualResults(aTestname, aExpectedImg, aName) { function resetState() { doXHR('/tests/dom/security/test/referrer-policy/img_referrer_testserver.sjs?action=resetState', advance, - function(xhr) { + function() { ok(false, "error in reset state"); SimpleTest.finish(); }); diff --git a/dom/security/test/sec-fetch/browser_external_loads.js b/dom/security/test/sec-fetch/browser_external_loads.js index 0340b46899..070342e800 100644 --- a/dom/security/test/sec-fetch/browser_external_loads.js +++ b/dom/security/test/sec-fetch/browser_external_loads.js @@ -7,7 +7,7 @@ const TEST_PATH = getRootDirectory(gTestPath).replace( var gExpectedHeader = {}; -function checkSecFetchUser(subject, topic, data) { +function checkSecFetchUser(subject) { let channel = subject.QueryInterface(Ci.nsIHttpChannel); if (!channel.URI.spec.startsWith("https://example.com")) { return; @@ -45,7 +45,7 @@ add_task(async function external_load() { Services.obs.addObserver(checkSecFetchUser, "http-on-stop-request"); let headersChecked = new Promise(resolve => { - let reqStopped = async (subject, topic, data) => { + let reqStopped = async () => { Services.obs.removeObserver(reqStopped, "http-on-stop-request"); resolve(); }; diff --git a/dom/security/test/sec-fetch/browser_navigation.js b/dom/security/test/sec-fetch/browser_navigation.js index d203391356..2d51a7d1f5 100644 --- a/dom/security/test/sec-fetch/browser_navigation.js +++ b/dom/security/test/sec-fetch/browser_navigation.js @@ -10,7 +10,7 @@ async function setup() { waitForExplicitFinish(); } -function checkSecFetchUser(subject, topic, data) { +function checkSecFetchUser(subject) { let channel = subject.QueryInterface(Ci.nsIHttpChannel); if (!channel.URI.spec.startsWith("https://example.com/")) { return; diff --git a/dom/security/test/sec-fetch/test_iframe_history_manipulation.html b/dom/security/test/sec-fetch/test_iframe_history_manipulation.html index 5ec749bf4d..65d79fa530 100644 --- a/dom/security/test/sec-fetch/test_iframe_history_manipulation.html +++ b/dom/security/test/sec-fetch/test_iframe_history_manipulation.html @@ -18,7 +18,7 @@ let testFrame; var script = SpecialPowers.loadChromeScript(() => { /* eslint-env mozilla/chrome-script */ - Services.obs.addObserver(function onExamResp(subject, topic, data) { + Services.obs.addObserver(function onExamResp(subject) { let channel = subject.QueryInterface(Ci.nsIHttpChannel); info("request observed: " + channel.URI.spec); if (!channel.URI.spec.startsWith("https://example.org")) { diff --git a/dom/security/test/sec-fetch/test_iframe_src_metaRedirect.html b/dom/security/test/sec-fetch/test_iframe_src_metaRedirect.html index 28eae80226..d05ae4df70 100644 --- a/dom/security/test/sec-fetch/test_iframe_src_metaRedirect.html +++ b/dom/security/test/sec-fetch/test_iframe_src_metaRedirect.html @@ -25,7 +25,7 @@ let testPassCounter = 0; var script = SpecialPowers.loadChromeScript(() => { /* eslint-env mozilla/chrome-script */ - Services.obs.addObserver(function onExamResp(subject, topic, data) { + Services.obs.addObserver(function onExamResp(subject) { let channel = subject.QueryInterface(Ci.nsIHttpChannel); if (!channel.URI.spec.startsWith("https://example.com/tests/dom/security/test/sec-fetch/file_redirect.sjs")) { return; diff --git a/dom/security/test/sec-fetch/test_iframe_srcdoc_metaRedirect.html b/dom/security/test/sec-fetch/test_iframe_srcdoc_metaRedirect.html index adee5afe84..1a3fa85603 100644 --- a/dom/security/test/sec-fetch/test_iframe_srcdoc_metaRedirect.html +++ b/dom/security/test/sec-fetch/test_iframe_srcdoc_metaRedirect.html @@ -25,7 +25,7 @@ let testPassCounter = 0; var script = SpecialPowers.loadChromeScript(() => { /* eslint-env mozilla/chrome-script */ - Services.obs.addObserver(function onExamResp(subject, topic, data) { + Services.obs.addObserver(function onExamResp(subject) { let channel = subject.QueryInterface(Ci.nsIHttpChannel); if (!channel.URI.spec.startsWith("https://example.com/tests/dom/security/test/sec-fetch/file_redirect.sjs")) { return; diff --git a/dom/security/test/sec-fetch/test_iframe_window_open_metaRedirect.html b/dom/security/test/sec-fetch/test_iframe_window_open_metaRedirect.html index b532baeb5e..1dd7f8864e 100644 --- a/dom/security/test/sec-fetch/test_iframe_window_open_metaRedirect.html +++ b/dom/security/test/sec-fetch/test_iframe_window_open_metaRedirect.html @@ -26,7 +26,7 @@ let testWindow; var script = SpecialPowers.loadChromeScript(() => { /* eslint-env mozilla/chrome-script */ - Services.obs.addObserver(function onExamResp(subject, topic, data) { + Services.obs.addObserver(function onExamResp(subject) { let channel = subject.QueryInterface(Ci.nsIHttpChannel); if (!channel.URI.spec.startsWith("https://example.com/tests/dom/security/test/sec-fetch/file_redirect.sjs")) { return; diff --git a/dom/security/test/sec-fetch/test_trustworthy_loopback.html b/dom/security/test/sec-fetch/test_trustworthy_loopback.html index 95ecac17ed..3b44895e77 100644 --- a/dom/security/test/sec-fetch/test_trustworthy_loopback.html +++ b/dom/security/test/sec-fetch/test_trustworthy_loopback.html @@ -23,7 +23,7 @@ function checkTestsDone() { var script = SpecialPowers.loadChromeScript(() => { /* eslint-env mozilla/chrome-script */ - Services.obs.addObserver(function onExamResp(subject, topic, data) { + Services.obs.addObserver(function onExamResp(subject) { let channel = subject.QueryInterface(Ci.nsIHttpChannel); if (!channel.URI.spec.includes("localhost") || channel.URI.spec.startsWith("http://localhost:9898/tests/dom/security/test/sec-fetch/file_trustworthy_loopback.html")) { diff --git a/dom/security/test/sec-fetch/test_websocket.html b/dom/security/test/sec-fetch/test_websocket.html index 5df0553a4f..4613419040 100644 --- a/dom/security/test/sec-fetch/test_websocket.html +++ b/dom/security/test/sec-fetch/test_websocket.html @@ -21,7 +21,7 @@ function checkTestsDone() { var script = SpecialPowers.loadChromeScript(() => { /* eslint-env mozilla/chrome-script */ - Services.obs.addObserver(function onExamResp(subject, topic, data) { + Services.obs.addObserver(function onExamResp(subject) { let channel = subject.QueryInterface(Ci.nsIHttpChannel); if (!channel.URI.spec.startsWith("https://example.com/tests/dom/security/test/sec-fetch/file_websocket")) { return; @@ -61,11 +61,11 @@ script.addMessageListener("test-end", () => { }); var wssSocket = new WebSocket("wss://example.com/tests/dom/security/test/sec-fetch/file_websocket"); -wssSocket.onopen = function(e) { +wssSocket.onopen = function() { ok(true, "sanity: wssSocket onopen"); checkTestsDone(); }; -wssSocket.onerror = function(e) { +wssSocket.onerror = function() { ok(false, "sanity: wssSocket onerror"); }; diff --git a/dom/security/test/unit/test_csp_reports.js b/dom/security/test/unit/test_csp_reports.js index 36da1a13e5..3d5a00b0f6 100644 --- a/dom/security/test/unit/test_csp_reports.js +++ b/dom/security/test/unit/test_csp_reports.js @@ -23,7 +23,7 @@ const REPORT_SERVER_URI = "http://localhost"; * or fails a test based on what it gets. */ function makeReportHandler(testpath, message, expectedJSON) { - return function (request, response) { + return function (request) { // we only like "POST" submissions for reports! if (request.method !== "POST") { do_throw("violation report should be a POST request"); diff --git a/dom/security/test/unit/test_csp_upgrade_insecure_request_header.js b/dom/security/test/unit/test_csp_upgrade_insecure_request_header.js index 26758d261d..1c5fdabf31 100644 --- a/dom/security/test/unit/test_csp_upgrade_insecure_request_header.js +++ b/dom/security/test/unit/test_csp_upgrade_insecure_request_header.js @@ -45,11 +45,11 @@ var tests = [ function ChannelListener() {} ChannelListener.prototype = { - onStartRequest(request) {}, - onDataAvailable(request, stream, offset, count) { + onStartRequest() {}, + onDataAvailable() { do_throw("Should not get any data!"); }, - onStopRequest(request, status) { + onStopRequest(request) { var upgrade_insecure_header = false; try { if (request.getRequestHeader("Upgrade-Insecure-Requests")) { @@ -76,7 +76,7 @@ function setupChannel(aContentType) { return chan; } -function serverHandler(metadata, response) { +function serverHandler() { // no need to perform anything here } diff --git a/dom/security/test/unit/test_https_only_https_first_default_port.js b/dom/security/test/unit/test_https_only_https_first_default_port.js index bd4d6717eb..06ffb80eee 100644 --- a/dom/security/test/unit/test_https_only_https_first_default_port.js +++ b/dom/security/test/unit/test_https_only_https_first_default_port.js @@ -41,13 +41,13 @@ const TESTS = [ function ChannelListener() {} ChannelListener.prototype = { - onStartRequest(request) { + onStartRequest() { // dummy implementation }, - onDataAvailable(request, stream, offset, count) { + onDataAvailable() { do_throw("Should not get any data!"); }, - onStopRequest(request, status) { + onStopRequest(request) { var chan = request.QueryInterface(Ci.nsIChannel); let requestURL = chan.URI; Assert.equal( @@ -79,7 +79,7 @@ function setUpChannel() { return chan; } -function serverHandler(metadata, response) { +function serverHandler() { // dummy implementation } diff --git a/dom/security/test/unit/test_https_only_https_first_prefs.js b/dom/security/test/unit/test_https_only_https_first_prefs.js index 9c6ced1fcb..6c7e112d9b 100644 --- a/dom/security/test/unit/test_https_only_https_first_prefs.js +++ b/dom/security/test/unit/test_https_only_https_first_prefs.js @@ -272,10 +272,10 @@ ChannelListener.prototype = { var authHeader = httpChan.getRequestHeader("Authorization"); Assert.equal(authHeader, "Basic user:pass", curTest.description); }, - onDataAvailable(request, stream, offset, count) { + onDataAvailable() { do_throw("Should not get any data!"); }, - onStopRequest(request, status) { + onStopRequest(request) { var chan = request.QueryInterface(Ci.nsIChannel); let requestURL = chan.URI; Assert.equal( @@ -331,7 +331,7 @@ function setUpChannel() { return chan; } -function serverHandler(metadata, response) { +function serverHandler() { // dummy implementation } diff --git a/dom/security/trusted-types/TrustedHTML.cpp b/dom/security/trusted-types/TrustedHTML.cpp new file mode 100644 index 0000000000..005cab8c63 --- /dev/null +++ b/dom/security/trusted-types/TrustedHTML.cpp @@ -0,0 +1,13 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/TrustedHTML.h" + +namespace mozilla::dom { + +IMPL_TRUSTED_TYPE_CLASS(TrustedHTML) + +} // namespace mozilla::dom diff --git a/dom/security/trusted-types/TrustedHTML.h b/dom/security/trusted-types/TrustedHTML.h new file mode 100644 index 0000000000..68a642c83a --- /dev/null +++ b/dom/security/trusted-types/TrustedHTML.h @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DOM_SECURITY_TRUSTED_TYPES_TRUSTEDHTML_H_ +#define DOM_SECURITY_TRUSTED_TYPES_TRUSTEDHTML_H_ + +#include "mozilla/dom/TrustedTypeUtils.h" + +namespace mozilla::dom { + +// https://w3c.github.io/trusted-types/dist/spec/#trusted-html +DECL_TRUSTED_TYPE_CLASS(TrustedHTML) + +} // namespace mozilla::dom + +#endif // DOM_SECURITY_TRUSTED_TYPES_TRUSTEDHTML_H_ diff --git a/dom/security/trusted-types/TrustedScript.cpp b/dom/security/trusted-types/TrustedScript.cpp new file mode 100644 index 0000000000..496c53278a --- /dev/null +++ b/dom/security/trusted-types/TrustedScript.cpp @@ -0,0 +1,13 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/TrustedScript.h" + +namespace mozilla::dom { + +IMPL_TRUSTED_TYPE_CLASS(TrustedScript) + +} // namespace mozilla::dom diff --git a/dom/security/trusted-types/TrustedScript.h b/dom/security/trusted-types/TrustedScript.h new file mode 100644 index 0000000000..0b6e0965ed --- /dev/null +++ b/dom/security/trusted-types/TrustedScript.h @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DOM_SECURITY_TRUSTED_TYPES_TRUSTEDSCRIPT_H_ +#define DOM_SECURITY_TRUSTED_TYPES_TRUSTEDSCRIPT_H_ + +#include "mozilla/dom/TrustedTypeUtils.h" + +namespace mozilla::dom { + +// https://w3c.github.io/trusted-types/dist/spec/#trusted-script +DECL_TRUSTED_TYPE_CLASS(TrustedScript) + +} // namespace mozilla::dom + +#endif // DOM_SECURITY_TRUSTED_TYPES_TRUSTEDSCRIPT_H_ diff --git a/dom/security/trusted-types/TrustedScriptURL.cpp b/dom/security/trusted-types/TrustedScriptURL.cpp new file mode 100644 index 0000000000..8de2448f91 --- /dev/null +++ b/dom/security/trusted-types/TrustedScriptURL.cpp @@ -0,0 +1,14 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/TrustedScriptURL.h" + +namespace mozilla::dom { + +// https://w3c.github.io/trusted-types/dist/spec/#trused-script-url +IMPL_TRUSTED_TYPE_CLASS(TrustedScriptURL) + +} // namespace mozilla::dom diff --git a/dom/security/trusted-types/TrustedScriptURL.h b/dom/security/trusted-types/TrustedScriptURL.h new file mode 100644 index 0000000000..6e71235cb9 --- /dev/null +++ b/dom/security/trusted-types/TrustedScriptURL.h @@ -0,0 +1,18 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DOM_SECURITY_TRUSTED_TYPES_TRUSTEDSCRIPTURL_H_ +#define DOM_SECURITY_TRUSTED_TYPES_TRUSTEDSCRIPTURL_H_ + +#include "mozilla/dom/TrustedTypeUtils.h" + +namespace mozilla::dom { + +DECL_TRUSTED_TYPE_CLASS(TrustedScriptURL) + +} // namespace mozilla::dom + +#endif // DOM_SECURITY_TRUSTED_TYPES_TRUSTEDSCRIPTURL_H_ diff --git a/dom/security/trusted-types/TrustedTypePolicy.cpp b/dom/security/trusted-types/TrustedTypePolicy.cpp new file mode 100644 index 0000000000..3c4e758ed0 --- /dev/null +++ b/dom/security/trusted-types/TrustedTypePolicy.cpp @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/TrustedTypePolicy.h" + +#include "mozilla/AlreadyAddRefed.h" +#include "mozilla/dom/TrustedTypePolicyFactory.h" +#include "mozilla/dom/TrustedTypesBinding.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TrustedTypePolicy, mParentObject) + +JSObject* TrustedTypePolicy::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return TrustedTypePolicy_Binding::Wrap(aCx, this, aGivenProto); +} + +UniquePtr TrustedTypePolicy::CreateHTML( + JSContext* aJSContext, const nsAString& aInput, + const Sequence& aArguments) const { + // TODO: implement the spec. + return MakeUnique(); +} + +UniquePtr TrustedTypePolicy::CreateScript( + JSContext* aJSContext, const nsAString& aInput, + const Sequence& aArguments) const { + // TODO: implement the spec. + return MakeUnique(); +} + +UniquePtr TrustedTypePolicy::CreateScriptURL( + JSContext* aJSContext, const nsAString& aInput, + const Sequence& aArguments) const { + // TODO: implement the spec. + return MakeUnique(); +} + +} // namespace mozilla::dom diff --git a/dom/security/trusted-types/TrustedTypePolicy.h b/dom/security/trusted-types/TrustedTypePolicy.h new file mode 100644 index 0000000000..22d99947b3 --- /dev/null +++ b/dom/security/trusted-types/TrustedTypePolicy.h @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEPOLICY_H_ +#define DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEPOLICY_H_ + +#include "js/TypeDecls.h" +#include "js/Value.h" +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/DOMString.h" +#include "mozilla/dom/TrustedHTML.h" +#include "mozilla/dom/TrustedScript.h" +#include "mozilla/dom/TrustedScriptURL.h" +#include "nsISupportsImpl.h" +#include "nsStringFwd.h" +#include "nsWrapperCache.h" + +namespace mozilla::dom { + +class TrustedTypePolicyFactory; + +// https://w3c.github.io/trusted-types/dist/spec/#trusted-type-policy +class TrustedTypePolicy : public nsWrapperCache { + public: + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(TrustedTypePolicy) + NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(TrustedTypePolicy) + + explicit TrustedTypePolicy(TrustedTypePolicyFactory* aParentObject) + : mParentObject{aParentObject} {} + + // Required for Web IDL binding. + TrustedTypePolicyFactory* GetParentObject() const { return mParentObject; } + + // Required for Web IDL binding. + JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + // https://w3c.github.io/trusted-types/dist/spec/#trustedtypepolicy-name + void GetName(DOMString& aResult) const { + // TODO: impl. + } + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicy-createhtml + UniquePtr CreateHTML( + JSContext* aJSContext, const nsAString& aInput, + const Sequence& aArguments) const; + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicy-createscript + UniquePtr CreateScript( + JSContext* aJSContext, const nsAString& aInput, + const Sequence& aArguments) const; + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicy-createscripturl + UniquePtr CreateScriptURL( + JSContext* aJSContext, const nsAString& aInput, + const Sequence& aArguments) const; + + private: + // Required because this class is ref-counted. + virtual ~TrustedTypePolicy() = default; + + RefPtr mParentObject; +}; + +} // namespace mozilla::dom + +#endif // DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEPOLICY_H_ diff --git a/dom/security/trusted-types/TrustedTypePolicyFactory.cpp b/dom/security/trusted-types/TrustedTypePolicyFactory.cpp new file mode 100644 index 0000000000..448c51eb3b --- /dev/null +++ b/dom/security/trusted-types/TrustedTypePolicyFactory.cpp @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/TrustedTypePolicyFactory.h" + +#include "mozilla/AlreadyAddRefed.h" +#include "mozilla/RefPtr.h" +#include "mozilla/dom/TrustedTypePolicy.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TrustedTypePolicyFactory, mGlobalObject) + +JSObject* TrustedTypePolicyFactory::WrapObject( + JSContext* aCx, JS::Handle aGivenProto) { + return TrustedTypePolicyFactory_Binding::Wrap(aCx, this, aGivenProto); +} + +already_AddRefed TrustedTypePolicyFactory::CreatePolicy( + const nsAString& aPolicyName, + const TrustedTypePolicyOptions& aPolicyOptions) { + // TODO: implement the spec. + return MakeRefPtr(this).forget(); +} + +UniquePtr TrustedTypePolicyFactory::EmptyHTML() { + // Preserving the wrapper ensures: + // ``` + // const e = trustedTypes.emptyHTML; + // e === trustedTypes.emptyHTML; + // ``` + // which comes with the cost of keeping the factory, one per global, alive. + // An additional benefit is it saves the cost of re-instantiating potentially + // multiple emptyHML objects. Both, the JS- and the C++-objects. + dom::PreserveWrapper(this); + + return MakeUnique(); +} + +UniquePtr TrustedTypePolicyFactory::EmptyScript() { + // See the explanation in `EmptyHTML()`. + dom::PreserveWrapper(this); + + return MakeUnique(); +} + +} // namespace mozilla::dom diff --git a/dom/security/trusted-types/TrustedTypePolicyFactory.h b/dom/security/trusted-types/TrustedTypePolicyFactory.h new file mode 100644 index 0000000000..fea5312cf8 --- /dev/null +++ b/dom/security/trusted-types/TrustedTypePolicyFactory.h @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEPOLICYFACTORY_H_ +#define DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEPOLICYFACTORY_H_ + +#include "js/TypeDecls.h" +#include "mozilla/dom/TrustedHTML.h" +#include "mozilla/dom/TrustedScript.h" +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" +#include "nsIGlobalObject.h" +#include "nsISupportsImpl.h" +#include "nsStringFwd.h" +#include "nsWrapperCache.h" + +template +struct already_AddRefed; + +class DOMString; + +namespace mozilla::dom { + +class TrustedTypePolicy; + +// https://w3c.github.io/trusted-types/dist/spec/#trusted-type-policy-factory +class TrustedTypePolicyFactory : public nsWrapperCache { + public: + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(TrustedTypePolicyFactory) + NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(TrustedTypePolicyFactory) + + explicit TrustedTypePolicyFactory(nsIGlobalObject* aGlobalObject) + : mGlobalObject{aGlobalObject} {} + + // Required for Web IDL binding. + nsIGlobalObject* GetParentObject() const { return mGlobalObject; } + + // Required for Web IDL binding. + JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-createpolicy + already_AddRefed CreatePolicy( + const nsAString& aPolicyName, + const TrustedTypePolicyOptions& aPolicyOptions); + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-ishtml + bool IsHTML(JSContext* aJSContext, + const JS::Handle& aValue) const { + // TODO: impl. + return false; + } + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-isscript + bool IsScript(JSContext* aJSContext, + const JS::Handle& aValue) const { + // TODO: impl. + return false; + } + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-isscripturl + bool IsScriptURL(JSContext* aJSContext, + const JS::Handle& aValue) const { + // TODO: impl. + return false; + } + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-emptyhtml + UniquePtr EmptyHTML(); + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-emptyscript + UniquePtr EmptyScript(); + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-getattributetype + void GetAttributeType(const nsAString& aTagName, const nsAString& aAttribute, + const nsAString& aElementNs, const nsAString& aAttrNs, + DOMString& aResult) { + // TODO: impl. + } + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-getpropertytype + void GetPropertyType(const nsAString& aTagName, const nsAString& aProperty, + const nsAString& aElementNs, DOMString& aResult) { + // TODO: impl + } + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-defaultpolicy + TrustedTypePolicy* GetDefaultPolicy() const { + // TODO: impl + return nullptr; + } + + private: + // Required because this class is ref-counted. + virtual ~TrustedTypePolicyFactory() = default; + + RefPtr mGlobalObject; +}; + +} // namespace mozilla::dom + +#endif // DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEPOLICYFACTORY_H_ diff --git a/dom/security/trusted-types/TrustedTypeUtils.h b/dom/security/trusted-types/TrustedTypeUtils.h new file mode 100644 index 0000000000..90ffc50c38 --- /dev/null +++ b/dom/security/trusted-types/TrustedTypeUtils.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEUTILS_H_ +#define DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEUTILS_H_ + +#include "mozilla/dom/DOMString.h" +#include "mozilla/dom/NonRefcountedDOMObject.h" +#include "mozilla/dom/TrustedTypesBinding.h" +#include "nsStringFwd.h" + +#define DECL_TRUSTED_TYPE_CLASS(_class) \ + class _class : public mozilla::dom::NonRefcountedDOMObject { \ + public: \ + /* Required for Web IDL binding. */ \ + bool WrapObject(JSContext* aCx, JS::Handle aGivenProto, \ + JS::MutableHandle aObject); \ + \ + void Stringify(nsAString& aResult) const { /* TODO: impl. */ \ + } \ + \ + void ToJSON(DOMString& aResult) const { /* TODO: impl. */ \ + } \ + }; + +#define IMPL_TRUSTED_TYPE_CLASS(_class) \ + bool _class::WrapObject(JSContext* aCx, JS::Handle aGivenProto, \ + JS::MutableHandle aObject) { \ + return _class##_Binding::Wrap(aCx, this, aGivenProto, aObject); \ + } + +#endif // DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEUTILS_H_ diff --git a/dom/security/trusted-types/moz.build b/dom/security/trusted-types/moz.build new file mode 100644 index 0000000000..159a54ff02 --- /dev/null +++ b/dom/security/trusted-types/moz.build @@ -0,0 +1,27 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +with Files("**"): + BUG_COMPONENT = ("Core", "DOM: Security") + +EXPORTS.mozilla.dom += [ + "TrustedHTML.h", + "TrustedScript.h", + "TrustedScriptURL.h", + "TrustedTypePolicy.h", + "TrustedTypePolicyFactory.h", + "TrustedTypeUtils.h", +] + +UNIFIED_SOURCES += [ + "TrustedHTML.cpp", + "TrustedScript.cpp", + "TrustedScriptURL.cpp", + "TrustedTypePolicy.cpp", + "TrustedTypePolicyFactory.cpp", +] + +FINAL_LIBRARY = "xul" diff --git a/dom/serializers/nsDOMSerializer.cpp b/dom/serializers/nsDOMSerializer.cpp index 98d92e64ce..468ea7a5e1 100644 --- a/dom/serializers/nsDOMSerializer.cpp +++ b/dom/serializers/nsDOMSerializer.cpp @@ -10,7 +10,6 @@ #include "mozilla/dom/Document.h" #include "nsIDocumentEncoder.h" #include "nsComponentManagerUtils.h" -#include "nsContentCID.h" #include "nsContentUtils.h" #include "nsError.h" #include "nsINode.h" diff --git a/dom/serviceworkers/ServiceWorkerEvents.cpp b/dom/serviceworkers/ServiceWorkerEvents.cpp index 531e29e905..6027625021 100644 --- a/dom/serviceworkers/ServiceWorkerEvents.cpp +++ b/dom/serviceworkers/ServiceWorkerEvents.cpp @@ -624,8 +624,7 @@ void RespondWithHandler::ResolvedCallback(JSContext* aCx, if (response->Type() == ResponseType::Opaque && mRequestMode != RequestMode::No_cors) { - NS_ConvertASCIItoUTF16 modeString( - RequestModeValues::GetString(mRequestMode)); + NS_ConvertASCIItoUTF16 modeString(GetEnumString(mRequestMode)); autoCancel.SetCancelMessage("BadOpaqueInterceptionRequestModeWithURL"_ns, mRequestURL, modeString); diff --git a/dom/serviceworkers/ServiceWorkerIPCUtils.h b/dom/serviceworkers/ServiceWorkerIPCUtils.h index bd867f877a..9931af94e7 100644 --- a/dom/serviceworkers/ServiceWorkerIPCUtils.h +++ b/dom/serviceworkers/ServiceWorkerIPCUtils.h @@ -11,6 +11,7 @@ // Undo X11/X.h's definition of None #undef None +#include "mozilla/dom/BindingIPCUtils.h" #include "mozilla/dom/ServiceWorkerBinding.h" #include "mozilla/dom/ServiceWorkerRegistrationBinding.h" @@ -18,17 +19,13 @@ namespace IPC { template <> struct ParamTraits - : public ContiguousEnumSerializer< - mozilla::dom::ServiceWorkerState, - mozilla::dom::ServiceWorkerState::Parsed, - mozilla::dom::ServiceWorkerState::EndGuard_> {}; + : public mozilla::dom::WebIDLEnumSerializer< + mozilla::dom::ServiceWorkerState> {}; template <> struct ParamTraits - : public ContiguousEnumSerializer< - mozilla::dom::ServiceWorkerUpdateViaCache, - mozilla::dom::ServiceWorkerUpdateViaCache::Imports, - mozilla::dom::ServiceWorkerUpdateViaCache::EndGuard_> {}; + : public mozilla::dom::WebIDLEnumSerializer< + mozilla::dom::ServiceWorkerUpdateViaCache> {}; } // namespace IPC diff --git a/dom/serviceworkers/ServiceWorkerInfo.cpp b/dom/serviceworkers/ServiceWorkerInfo.cpp index 9998cfed6b..2689af6ee9 100644 --- a/dom/serviceworkers/ServiceWorkerInfo.cpp +++ b/dom/serviceworkers/ServiceWorkerInfo.cpp @@ -43,7 +43,7 @@ static_assert(nsIServiceWorkerInfo::STATE_REDUNDANT == "ServiceWorkerState enumeration value should match state values " "from nsIServiceWorkerInfo."); static_assert(nsIServiceWorkerInfo::STATE_UNKNOWN == - ServiceWorkerStateValues::Count, + ContiguousEnumSize::value, "ServiceWorkerState enumeration value should match state values " "from nsIServiceWorkerInfo."); @@ -165,8 +165,6 @@ void ServiceWorkerInfo::UpdateState(ServiceWorkerState aState) { // Any state can directly transition to redundant, but everything else is // ordered. if (aState != ServiceWorkerState::Redundant) { - MOZ_ASSERT_IF(State() == ServiceWorkerState::EndGuard_, - aState == ServiceWorkerState::Installing); MOZ_ASSERT_IF(State() == ServiceWorkerState::Installing, aState == ServiceWorkerState::Installed); MOZ_ASSERT_IF(State() == ServiceWorkerState::Installed, diff --git a/dom/serviceworkers/ServiceWorkerManager.cpp b/dom/serviceworkers/ServiceWorkerManager.cpp index b0dcfca893..842939d785 100644 --- a/dom/serviceworkers/ServiceWorkerManager.cpp +++ b/dom/serviceworkers/ServiceWorkerManager.cpp @@ -127,7 +127,7 @@ static_assert( static_cast(RequestRedirect::Manual), "RequestRedirect enumeration value should make Necko Redirect mode value."); static_assert( - 3 == RequestRedirectValues::Count, + 3 == ContiguousEnumSize::value, "RequestRedirect enumeration value should make Necko Redirect mode value."); static_assert( @@ -155,7 +155,7 @@ static_assert( static_cast(RequestCache::Only_if_cached), "RequestCache enumeration value should match Necko Cache mode value."); static_assert( - 6 == RequestCacheValues::Count, + 6 == ContiguousEnumSize::value, "RequestCache enumeration value should match Necko Cache mode value."); static_assert(static_cast(ServiceWorkerUpdateViaCache::Imports) == diff --git a/dom/serviceworkers/ServiceWorkerManagerParent.cpp b/dom/serviceworkers/ServiceWorkerManagerParent.cpp index 5ed0f4faa8..d2d0a64275 100644 --- a/dom/serviceworkers/ServiceWorkerManagerParent.cpp +++ b/dom/serviceworkers/ServiceWorkerManagerParent.cpp @@ -91,9 +91,9 @@ mozilla::ipc::IPCResult ServiceWorkerManagerParent::RecvPropagateUnregister( // one and only ServiceWorkerManager, but it is necessary for us to have run // the unregister call above because until Bug 1183245 is fixed, // nsIServiceWorkerManager.propagateUnregister() is a de facto API for - // clearing ServiceWorker registrations by Sanitizer.jsm via - // ServiceWorkerCleanUp.jsm, as well as devtools "unregister" affordance and - // the no-longer-relevant about:serviceworkers UI. + // clearing ServiceWorker registrations by Sanitizer.sys.mjs via + // ServiceWorkerCleanUp.sys.mjs, as well as devtools "unregister" affordance + // and the no-longer-relevant about:serviceworkers UI. return IPC_OK(); } diff --git a/dom/serviceworkers/ServiceWorkerOp.cpp b/dom/serviceworkers/ServiceWorkerOp.cpp index 8811404a0f..9c4fc569d1 100644 --- a/dom/serviceworkers/ServiceWorkerOp.cpp +++ b/dom/serviceworkers/ServiceWorkerOp.cpp @@ -1428,8 +1428,7 @@ void FetchEventOp::ResolvedCallback(JSContext* aCx, if (response->Type() == ResponseType::Opaque && requestMode != RequestMode::No_cors) { - NS_ConvertASCIItoUTF16 modeString( - RequestModeValues::GetString(requestMode)); + NS_ConvertASCIItoUTF16 modeString(GetEnumString(requestMode)); nsAutoString requestURL; GetRequestURL(requestURL); diff --git a/dom/serviceworkers/test/browser_download.js b/dom/serviceworkers/test/browser_download.js index 0c69a48d17..70622a2349 100644 --- a/dom/serviceworkers/test/browser_download.js +++ b/dom/serviceworkers/test/browser_download.js @@ -3,7 +3,7 @@ var gTestRoot = getRootDirectory(gTestPath).replace( "chrome://mochitests/content/", - "http://mochi.test:8888/" + "https://example.com/" ); function getFile(aFilename) { diff --git a/dom/serviceworkers/test/close_test.js b/dom/serviceworkers/test/close_test.js index 07f85617ef..0609782e5e 100644 --- a/dom/serviceworkers/test/close_test.js +++ b/dom/serviceworkers/test/close_test.js @@ -1,3 +1,5 @@ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + function ok(v, msg) { client.postMessage({ status: "ok", result: !!v, message: msg }); } diff --git a/dom/serviceworkers/test/eventsource/eventsource_cors_response_intercept_worker.js b/dom/serviceworkers/test/eventsource/eventsource_cors_response_intercept_worker.js index c2e5d416e7..31a8165625 100644 --- a/dom/serviceworkers/test/eventsource/eventsource_cors_response_intercept_worker.js +++ b/dom/serviceworkers/test/eventsource/eventsource_cors_response_intercept_worker.js @@ -1,3 +1,5 @@ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + // Cross origin request var prefix = "http://example.com/tests/dom/serviceworkers/test/eventsource/"; diff --git a/dom/serviceworkers/test/eventsource/eventsource_mixed_content_cors_response_intercept_worker.js b/dom/serviceworkers/test/eventsource/eventsource_mixed_content_cors_response_intercept_worker.js index 9cb8d2d61f..9cfca63db9 100644 --- a/dom/serviceworkers/test/eventsource/eventsource_mixed_content_cors_response_intercept_worker.js +++ b/dom/serviceworkers/test/eventsource/eventsource_mixed_content_cors_response_intercept_worker.js @@ -1,3 +1,5 @@ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + var prefix = "http://example.com/tests/dom/serviceworkers/test/eventsource/"; self.importScripts("eventsource_worker_helper.js"); diff --git a/dom/serviceworkers/test/eventsource/eventsource_opaque_response_intercept_worker.js b/dom/serviceworkers/test/eventsource/eventsource_opaque_response_intercept_worker.js index 5c8c75a161..84d406ac47 100644 --- a/dom/serviceworkers/test/eventsource/eventsource_opaque_response_intercept_worker.js +++ b/dom/serviceworkers/test/eventsource/eventsource_opaque_response_intercept_worker.js @@ -1,3 +1,5 @@ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + // Cross origin request var prefix = "http://example.com/tests/dom/serviceworkers/test/eventsource/"; diff --git a/dom/serviceworkers/test/eventsource/eventsource_synthetic_response_intercept_worker.js b/dom/serviceworkers/test/eventsource/eventsource_synthetic_response_intercept_worker.js index 72780e2979..ec3f0309c2 100644 --- a/dom/serviceworkers/test/eventsource/eventsource_synthetic_response_intercept_worker.js +++ b/dom/serviceworkers/test/eventsource/eventsource_synthetic_response_intercept_worker.js @@ -1,3 +1,5 @@ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + self.importScripts("eventsource_worker_helper.js"); self.addEventListener("fetch", function (event) { diff --git a/dom/serviceworkers/test/gtest/TestReadWrite.cpp b/dom/serviceworkers/test/gtest/TestReadWrite.cpp index 823647d22e..66b966f9e2 100644 --- a/dom/serviceworkers/test/gtest/TestReadWrite.cpp +++ b/dom/serviceworkers/test/gtest/TestReadWrite.cpp @@ -219,7 +219,7 @@ TEST(ServiceWorkerRegistrar, TestReadData) nsAutoCString suffix0; cInfo0.attrs().CreateSuffix(suffix0); - ASSERT_STREQ("^inBrowser=1", suffix0.get()); + ASSERT_STREQ("", suffix0.get()); ASSERT_STREQ("https://scope_0.org", cInfo0.spec().get()); ASSERT_STREQ("https://scope_0.org", data[0].scope().get()); ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get()); @@ -280,30 +280,24 @@ TEST(ServiceWorkerRegistrar, TestWriteData) { RefPtr swr = new ServiceWorkerRegistrarTest; - for (int i = 0; i < 2; ++i) { - ServiceWorkerRegistrationData reg; - - reg.scope() = nsPrintfCString("https://scope_write_%d.org", i); - reg.currentWorkerURL() = nsPrintfCString("currentWorkerURL write %d", i); - reg.currentWorkerHandlesFetch() = true; - reg.cacheName() = - NS_ConvertUTF8toUTF16(nsPrintfCString("cacheName write %d", i)); - reg.updateViaCache() = - nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS; + ServiceWorkerRegistrationData reg; - reg.currentWorkerInstalledTime() = PR_Now(); - reg.currentWorkerActivatedTime() = PR_Now(); - reg.lastUpdateTime() = PR_Now(); + reg.scope() = "https://scope_write_0.org"_ns; + reg.currentWorkerURL() = "currentWorkerURL write 0"_ns; + reg.currentWorkerHandlesFetch() = true; + reg.cacheName() = u"cacheName write 0"_ns; + reg.updateViaCache() = + nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS; - nsAutoCString spec; - spec.AppendPrintf("spec write %d", i); + reg.currentWorkerInstalledTime() = PR_Now(); + reg.currentWorkerActivatedTime() = PR_Now(); + reg.lastUpdateTime() = PR_Now(); - reg.principal() = mozilla::ipc::ContentPrincipalInfo( - mozilla::OriginAttributes(i % 2), spec, spec, mozilla::Nothing(), - spec); + const auto spec = "spec write 0"_ns; + reg.principal() = mozilla::ipc::ContentPrincipalInfo( + mozilla::OriginAttributes(), spec, spec, mozilla::Nothing(), spec); - swr->TestRegisterServiceWorker(reg); - } + swr->TestRegisterServiceWorker(reg); nsresult rv = swr->TestWriteData(); ASSERT_EQ(NS_OK, rv) << "WriteData() should not fail"; @@ -314,47 +308,37 @@ TEST(ServiceWorkerRegistrar, TestWriteData) nsresult rv = swr->TestReadData(); ASSERT_EQ(NS_OK, rv) << "ReadData() should not fail"; - const nsTArray& data = swr->TestGetData(); - ASSERT_EQ((uint32_t)2, data.Length()) << "2 entries should be found"; - - for (int i = 0; i < 2; ++i) { - nsAutoCString test; - - ASSERT_EQ(data[i].principal().type(), - mozilla::ipc::PrincipalInfo::TContentPrincipalInfo); - const mozilla::ipc::ContentPrincipalInfo& cInfo = data[i].principal(); + const nsTArray& dataArr = swr->TestGetData(); + ASSERT_EQ((uint32_t)1, dataArr.Length()) << "1 entries should be found"; - mozilla::OriginAttributes attrs(i % 2); - nsAutoCString suffix, expectSuffix; - attrs.CreateSuffix(expectSuffix); - cInfo.attrs().CreateSuffix(suffix); + const auto& data = dataArr[0]; - ASSERT_STREQ(expectSuffix.get(), suffix.get()); + ASSERT_EQ(data.principal().type(), + mozilla::ipc::PrincipalInfo::TContentPrincipalInfo); + const mozilla::ipc::ContentPrincipalInfo& cInfo = data.principal(); - test.AppendPrintf("https://scope_write_%d.org", i); - ASSERT_STREQ(test.get(), cInfo.spec().get()); + mozilla::OriginAttributes attrs; + nsAutoCString suffix, expectSuffix; + attrs.CreateSuffix(expectSuffix); + cInfo.attrs().CreateSuffix(suffix); - test.Truncate(); - test.AppendPrintf("https://scope_write_%d.org", i); - ASSERT_STREQ(test.get(), data[i].scope().get()); + ASSERT_STREQ(expectSuffix.get(), suffix.get()); - test.Truncate(); - test.AppendPrintf("currentWorkerURL write %d", i); - ASSERT_STREQ(test.get(), data[i].currentWorkerURL().get()); + ASSERT_STREQ("https://scope_write_0.org", cInfo.spec().get()); + ASSERT_STREQ("https://scope_write_0.org", data.scope().get()); + ASSERT_STREQ("currentWorkerURL write 0", data.currentWorkerURL().get()); - ASSERT_EQ(true, data[i].currentWorkerHandlesFetch()); + ASSERT_EQ(true, data.currentWorkerHandlesFetch()); - test.Truncate(); - test.AppendPrintf("cacheName write %d", i); - ASSERT_STREQ(test.get(), NS_ConvertUTF16toUTF8(data[i].cacheName()).get()); + ASSERT_STREQ("cacheName write 0", + NS_ConvertUTF16toUTF8(data.cacheName()).get()); - ASSERT_EQ(nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS, - data[i].updateViaCache()); + ASSERT_EQ(nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS, + data.updateViaCache()); - ASSERT_NE((int64_t)0, data[i].currentWorkerInstalledTime()); - ASSERT_NE((int64_t)0, data[i].currentWorkerActivatedTime()); - ASSERT_NE((int64_t)0, data[i].lastUpdateTime()); - } + ASSERT_NE((int64_t)0, data.currentWorkerInstalledTime()); + ASSERT_NE((int64_t)0, data.currentWorkerActivatedTime()); + ASSERT_NE((int64_t)0, data.lastUpdateTime()); } TEST(ServiceWorkerRegistrar, TestVersion2Migration) @@ -394,7 +378,7 @@ TEST(ServiceWorkerRegistrar, TestVersion2Migration) nsAutoCString suffix0; cInfo0.attrs().CreateSuffix(suffix0); - ASSERT_STREQ("^inBrowser=1", suffix0.get()); + ASSERT_STREQ("", suffix0.get()); ASSERT_STREQ("https://scope_0.org", cInfo0.spec().get()); ASSERT_STREQ("https://scope_0.org", data[0].scope().get()); ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get()); @@ -464,7 +448,7 @@ TEST(ServiceWorkerRegistrar, TestVersion3Migration) nsAutoCString suffix0; cInfo0.attrs().CreateSuffix(suffix0); - ASSERT_STREQ("^inBrowser=1", suffix0.get()); + ASSERT_STREQ("", suffix0.get()); ASSERT_STREQ("https://scope_0.org", cInfo0.spec().get()); ASSERT_STREQ("https://scope_0.org", data[0].scope().get()); ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get()); @@ -532,7 +516,7 @@ TEST(ServiceWorkerRegistrar, TestVersion4Migration) nsAutoCString suffix0; cInfo0.attrs().CreateSuffix(suffix0); - ASSERT_STREQ("^inBrowser=1", suffix0.get()); + ASSERT_STREQ("", suffix0.get()); ASSERT_STREQ("https://scope_0.org", cInfo0.spec().get()); ASSERT_STREQ("https://scope_0.org", data[0].scope().get()); ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get()); @@ -604,7 +588,7 @@ TEST(ServiceWorkerRegistrar, TestVersion5Migration) nsAutoCString suffix0; cInfo0.attrs().CreateSuffix(suffix0); - ASSERT_STREQ("^inBrowser=1", suffix0.get()); + ASSERT_STREQ("", suffix0.get()); ASSERT_STREQ("https://scope_0.org", cInfo0.spec().get()); ASSERT_STREQ("https://scope_0.org", data[0].scope().get()); ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get()); @@ -678,7 +662,7 @@ TEST(ServiceWorkerRegistrar, TestVersion6Migration) nsAutoCString suffix0; cInfo0.attrs().CreateSuffix(suffix0); - ASSERT_STREQ("^inBrowser=1", suffix0.get()); + ASSERT_STREQ("", suffix0.get()); ASSERT_STREQ("https://scope_0.org", cInfo0.spec().get()); ASSERT_STREQ("https://scope_0.org", data[0].scope().get()); ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get()); @@ -765,7 +749,7 @@ TEST(ServiceWorkerRegistrar, TestVersion7Migration) nsAutoCString suffix0; cInfo0.attrs().CreateSuffix(suffix0); - ASSERT_STREQ("^inBrowser=1", suffix0.get()); + ASSERT_STREQ("", suffix0.get()); ASSERT_STREQ("https://scope_0.org", cInfo0.spec().get()); ASSERT_STREQ("https://scope_0.org", data[0].scope().get()); ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get()); @@ -850,7 +834,7 @@ TEST(ServiceWorkerRegistrar, TestDedupeRead) nsAutoCString suffix0; cInfo0.attrs().CreateSuffix(suffix0); - ASSERT_STREQ("^inBrowser=1", suffix0.get()); + ASSERT_STREQ("", suffix0.get()); ASSERT_STREQ("https://scope_0.org", cInfo0.spec().get()); ASSERT_STREQ("https://scope_0.org", data[0].scope().get()); ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get()); @@ -903,8 +887,7 @@ TEST(ServiceWorkerRegistrar, TestDedupeWrite) spec.AppendPrintf("spec write dedupe/%d", i); reg.principal() = mozilla::ipc::ContentPrincipalInfo( - mozilla::OriginAttributes(false), spec, spec, mozilla::Nothing(), - spec); + mozilla::OriginAttributes(), spec, spec, mozilla::Nothing(), spec); swr->TestRegisterServiceWorker(reg); } @@ -926,7 +909,7 @@ TEST(ServiceWorkerRegistrar, TestDedupeWrite) mozilla::ipc::PrincipalInfo::TContentPrincipalInfo); const mozilla::ipc::ContentPrincipalInfo& cInfo = data[0].principal(); - mozilla::OriginAttributes attrs(false); + mozilla::OriginAttributes attrs; nsAutoCString suffix, expectSuffix; attrs.CreateSuffix(expectSuffix); cInfo.attrs().CreateSuffix(suffix); diff --git a/dom/serviceworkers/test/test_serviceworker_interfaces.js b/dom/serviceworkers/test/test_serviceworker_interfaces.js index 1cf0896edf..c13c228d71 100644 --- a/dom/serviceworkers/test/test_serviceworker_interfaces.js +++ b/dom/serviceworkers/test/test_serviceworker_interfaces.js @@ -1,3 +1,5 @@ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + // This is a list of all interfaces that are exposed to workers. // Please only add things to this list with great care and proper review // from the associated module peers. @@ -173,8 +175,6 @@ let interfaceNamesInGlobalScope = [ // IMPORTANT: Do not change this list without review from a DOM peer! "DOMRectReadOnly", // IMPORTANT: Do not change this list without review from a DOM peer! - { name: "DOMRequest", disabled: true }, - // IMPORTANT: Do not change this list without review from a DOM peer! "DOMStringList", // IMPORTANT: Do not change this list without review from a DOM peer! "ErrorEvent", diff --git a/dom/smil/SMILAnimationController.cpp b/dom/smil/SMILAnimationController.cpp index 2c103b0f16..99abc07b58 100644 --- a/dom/smil/SMILAnimationController.cpp +++ b/dom/smil/SMILAnimationController.cpp @@ -51,8 +51,8 @@ SMILAnimationController::~SMILAnimationController() { NS_ASSERTION(mAnimationElementTable.IsEmpty(), "Animation controller shouldn't be tracking any animation" " elements when it dies"); - NS_ASSERTION(!mRegisteredWithRefreshDriver, - "Leaving stale entry in refresh driver's observer list"); + MOZ_RELEASE_ASSERT(!mRegisteredWithRefreshDriver, + "Leaving stale entry in refresh driver's observer list"); } void SMILAnimationController::Disconnect() { diff --git a/dom/storage/SessionStorageManager.cpp b/dom/storage/SessionStorageManager.cpp index 020083730a..a64d578426 100644 --- a/dom/storage/SessionStorageManager.cpp +++ b/dom/storage/SessionStorageManager.cpp @@ -26,6 +26,7 @@ #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/BackgroundParent.h" #include "mozilla/ipc/PBackgroundChild.h" +#include "nsIXULRuntime.h" #include "nsTHashMap.h" #include "nsThreadUtils.h" @@ -918,7 +919,7 @@ void BackgroundSessionStorageManager::SetCurrentBrowsingContextId( } void BackgroundSessionStorageManager::MaybeScheduleSessionStoreUpdate() { - if (!StaticPrefs::browser_sessionstore_platform_collection_AtStartup()) { + if (!SessionStorePlatformCollection()) { return; } diff --git a/dom/storage/StorageDBUpdater.cpp b/dom/storage/StorageDBUpdater.cpp index 7dec6425e2..255deddb4d 100644 --- a/dom/storage/StorageDBUpdater.cpp +++ b/dom/storage/StorageDBUpdater.cpp @@ -15,6 +15,7 @@ #include "mozilla/Tokenizer.h" #include "mozIStorageConnection.h" #include "mozStorageHelper.h" +#include "mozilla/StorageOriginAttributes.h" // Current version of the database schema #define CURRENT_SCHEMA_VERSION 2 @@ -131,8 +132,8 @@ class ExtractOriginData : protected mozilla::Tokenizer { } } } else { - OriginAttributes attrs(inIsolatedMozBrowser); - attrs.CreateSuffix(suffix); + StorageOriginAttributes originAttributes(inIsolatedMozBrowser); + originAttributes.CreateSuffix(suffix); } // Consume the rest of the input as "origin". diff --git a/dom/storage/StorageUtils.cpp b/dom/storage/StorageUtils.cpp index 39a69c3f08..cb7a74c73f 100644 --- a/dom/storage/StorageUtils.cpp +++ b/dom/storage/StorageUtils.cpp @@ -13,6 +13,7 @@ #include "nsIURI.h" #include "nsNetUtil.h" #include "nsPrintfCString.h" +#include "mozilla/StorageOriginAttributes.h" namespace mozilla::dom::StorageUtils { @@ -61,16 +62,16 @@ nsCString Scheme0Scope(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix) { nsCString result; - OriginAttributes oa; + StorageOriginAttributes oa; if (!aOriginSuffix.IsEmpty()) { DebugOnly success = oa.PopulateFromSuffix(aOriginSuffix); MOZ_ASSERT(success); } - if (oa.mInIsolatedMozBrowser) { + if (oa.InIsolatedMozBrowser()) { result.AppendInt(0); // This is the appId to be removed. result.Append(':'); - result.Append(oa.mInIsolatedMozBrowser ? 't' : 'f'); + result.Append(oa.InIsolatedMozBrowser() ? 't' : 'f'); result.Append(':'); } @@ -80,7 +81,7 @@ nsCString Scheme0Scope(const nsACString& aOriginSuffix, // with originAttributes and originKey columns) so that switch between // schema 1 and 0 always works in both ways. nsAutoCString remaining; - oa.mInIsolatedMozBrowser = false; + oa.SetInIsolatedMozBrowser(false); oa.CreateSuffix(remaining); if (!remaining.IsEmpty()) { MOZ_ASSERT(!aOriginSuffix.IsEmpty()); diff --git a/dom/streams/test/xpcshell/bug-1387503-1.js b/dom/streams/test/xpcshell/bug-1387503-1.js index 777f614c44..0be334e230 100644 --- a/dom/streams/test/xpcshell/bug-1387503-1.js +++ b/dom/streams/test/xpcshell/bug-1387503-1.js @@ -18,8 +18,8 @@ add_task(async function test() { async function fn() { try { let stream = new ReadableStream({ - start(controller) {}, - pull(controller) { + start() {}, + pull() { // eslint-disable-next-line no-debugger debugger; }, diff --git a/dom/streams/test/xpcshell/bug-1773237.js b/dom/streams/test/xpcshell/bug-1773237.js index 0d0107fe85..2ce8d33439 100644 --- a/dom/streams/test/xpcshell/bug-1773237.js +++ b/dom/streams/test/xpcshell/bug-1773237.js @@ -7,5 +7,5 @@ var stream = new ReadableStream({ var response = new Response(stream); var text = response.text().then( () => {}, - e => {} + () => {} ); diff --git a/dom/streams/test/xpcshell/dom_stream_prototype_test.js b/dom/streams/test/xpcshell/dom_stream_prototype_test.js index b127368318..e3c59c675f 100644 --- a/dom/streams/test/xpcshell/dom_stream_prototype_test.js +++ b/dom/streams/test/xpcshell/dom_stream_prototype_test.js @@ -2,7 +2,7 @@ var log = []; const stream = new ReadableStream({ - start(controller) { + start() { log.push("started"); }, pull(controller) { diff --git a/dom/streams/test/xpcshell/response.js b/dom/streams/test/xpcshell/response.js index ead1be527f..884cbfea29 100644 --- a/dom/streams/test/xpcshell/response.js +++ b/dom/streams/test/xpcshell/response.js @@ -1,10 +1,10 @@ "use strict"; -add_task(async function (test) { +add_task(async function () { return new Response(new Blob([], { type: "text/plain" })).body.cancel(); }); -add_task(function (test) { +add_task(function () { var response = new Response( new Blob(["This is data"], { type: "text/plain" }) ); @@ -13,14 +13,14 @@ add_task(function (test) { return reader.cancel(); }); -add_task(function (test) { +add_task(function () { var response = new Response(new Blob(["T"], { type: "text/plain" })); var reader = response.body.getReader(); var closedPromise = reader.closed.then(function () { return reader.cancel(); }); - reader.read().then(function readMore({ done, value }) { + reader.read().then(function readMore({ done }) { if (!done) { return reader.read().then(readMore); } diff --git a/dom/streams/test/xpcshell/subclassing.js b/dom/streams/test/xpcshell/subclassing.js index b2b86cf353..8b6192b840 100644 --- a/dom/streams/test/xpcshell/subclassing.js +++ b/dom/streams/test/xpcshell/subclassing.js @@ -19,7 +19,7 @@ add_task(function subclass_helper() { // The base class constructor is called. let stream = new PartyStreamer({ // (The ReadableStream constructor calls this start method.) - start(c) { + start() { started = true; }, }); diff --git a/dom/svg/SVGAElement.cpp b/dom/svg/SVGAElement.cpp index 8df685e674..d27e8735ad 100644 --- a/dom/svg/SVGAElement.cpp +++ b/dom/svg/SVGAElement.cpp @@ -149,8 +149,8 @@ nsresult SVGAElement::BindToTree(BindContext& aContext, nsINode& aParent) { return NS_OK; } -void SVGAElement::UnbindFromTree(bool aNullParent) { - SVGAElementBase::UnbindFromTree(aNullParent); +void SVGAElement::UnbindFromTree(UnbindContext& aContext) { + SVGAElementBase::UnbindFromTree(aContext); // Without removing the link state we risk a dangling pointer // in the mStyledLinks hashtable Link::UnbindFromTree(); diff --git a/dom/svg/SVGAElement.h b/dom/svg/SVGAElement.h index 994481a386..166a146436 100644 --- a/dom/svg/SVGAElement.h +++ b/dom/svg/SVGAElement.h @@ -48,7 +48,7 @@ class SVGAElement final : public SVGAElementBase, // nsIContent nsresult BindToTree(BindContext&, nsINode& aParent) override; - void UnbindFromTree(bool aNullParent = true) override; + void UnbindFromTree(UnbindContext&) override; int32_t TabIndexDefault() override; Focusable IsFocusableWithoutStyle(bool aWithMouse) override; diff --git a/dom/svg/SVGAnimationElement.cpp b/dom/svg/SVGAnimationElement.cpp index ee5ad40f25..fea2a2595e 100644 --- a/dom/svg/SVGAnimationElement.cpp +++ b/dom/svg/SVGAnimationElement.cpp @@ -157,7 +157,7 @@ nsresult SVGAnimationElement::BindToTree(BindContext& aContext, return NS_OK; } -void SVGAnimationElement::UnbindFromTree(bool aNullParent) { +void SVGAnimationElement::UnbindFromTree(UnbindContext& aContext) { SMILAnimationController* controller = OwnerDoc()->GetAnimationController(); if (controller) { controller->UnregisterAnimationElement(this); @@ -168,7 +168,7 @@ void SVGAnimationElement::UnbindFromTree(bool aNullParent) { AnimationNeedsResample(); - SVGAnimationElementBase::UnbindFromTree(aNullParent); + SVGAnimationElementBase::UnbindFromTree(aContext); } bool SVGAnimationElement::ParseAttribute(int32_t aNamespaceID, diff --git a/dom/svg/SVGAnimationElement.h b/dom/svg/SVGAnimationElement.h index 163aa08ea7..02602172a8 100644 --- a/dom/svg/SVGAnimationElement.h +++ b/dom/svg/SVGAnimationElement.h @@ -41,7 +41,7 @@ class SVGAnimationElement : public SVGAnimationElementBase, public SVGTests { // nsIContent specializations nsresult BindToTree(BindContext&, nsINode& aParent) override; - void UnbindFromTree(bool aNullParent) override; + void UnbindFromTree(UnbindContext&) override; // Element specializations bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, diff --git a/dom/svg/SVGFEImageElement.cpp b/dom/svg/SVGFEImageElement.cpp index acf1f821f5..f9c5f96758 100644 --- a/dom/svg/SVGFEImageElement.cpp +++ b/dom/svg/SVGFEImageElement.cpp @@ -170,9 +170,9 @@ nsresult SVGFEImageElement::BindToTree(BindContext& aContext, return rv; } -void SVGFEImageElement::UnbindFromTree(bool aNullParent) { - nsImageLoadingContent::UnbindFromTree(aNullParent); - SVGFEImageElementBase::UnbindFromTree(aNullParent); +void SVGFEImageElement::UnbindFromTree(UnbindContext& aContext) { + nsImageLoadingContent::UnbindFromTree(); + SVGFEImageElementBase::UnbindFromTree(aContext); } void SVGFEImageElement::DestroyContent() { diff --git a/dom/svg/SVGFEImageElement.h b/dom/svg/SVGFEImageElement.h index 8d79e155f3..41b28b83a9 100644 --- a/dom/svg/SVGFEImageElement.h +++ b/dom/svg/SVGFEImageElement.h @@ -70,7 +70,7 @@ class SVGFEImageElement final : public SVGFEImageElementBase, const nsAttrValue* aValue, const nsAttrValue* aOldValue, nsIPrincipal* aSubjectPrincipal, bool aNotify) override; nsresult BindToTree(BindContext&, nsINode& aParent) override; - void UnbindFromTree(bool aNullParent) override; + void UnbindFromTree(UnbindContext&) override; void DestroyContent() override; NS_DECL_IMGINOTIFICATIONOBSERVER diff --git a/dom/svg/SVGImageElement.cpp b/dom/svg/SVGImageElement.cpp index 014303c912..264c03da09 100644 --- a/dom/svg/SVGImageElement.cpp +++ b/dom/svg/SVGImageElement.cpp @@ -260,9 +260,9 @@ nsresult SVGImageElement::BindToTree(BindContext& aContext, nsINode& aParent) { return rv; } -void SVGImageElement::UnbindFromTree(bool aNullParent) { - nsImageLoadingContent::UnbindFromTree(aNullParent); - SVGImageElementBase::UnbindFromTree(aNullParent); +void SVGImageElement::UnbindFromTree(UnbindContext& aContext) { + nsImageLoadingContent::UnbindFromTree(); + SVGImageElementBase::UnbindFromTree(aContext); } void SVGImageElement::DestroyContent() { diff --git a/dom/svg/SVGImageElement.h b/dom/svg/SVGImageElement.h index 880ba5d457..06770e2576 100644 --- a/dom/svg/SVGImageElement.h +++ b/dom/svg/SVGImageElement.h @@ -60,7 +60,7 @@ class SVGImageElement final : public SVGImageElementBase, nsIPrincipal* aSubjectPrincipal, bool aNotify) override; nsresult BindToTree(BindContext&, nsINode& aParent) override; - void UnbindFromTree(bool aNullParent) override; + void UnbindFromTree(UnbindContext&) override; void DestroyContent() override; diff --git a/dom/svg/SVGMPathElement.cpp b/dom/svg/SVGMPathElement.cpp index 2695cc3aa1..8ff21f61cd 100644 --- a/dom/svg/SVGMPathElement.cpp +++ b/dom/svg/SVGMPathElement.cpp @@ -68,10 +68,10 @@ already_AddRefed SVGMPathElement::Href() { //---------------------------------------------------------------------- // nsIContent methods -void SVGMPathElement::UnbindFromTree(bool aNullParent) { +void SVGMPathElement::UnbindFromTree(UnbindContext& aContext) { mMPathObserver = nullptr; NotifyParentOfMpathChange(); - SVGMPathElementBase::UnbindFromTree(aNullParent); + SVGMPathElementBase::UnbindFromTree(aContext); } void SVGMPathElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, diff --git a/dom/svg/SVGMPathElement.h b/dom/svg/SVGMPathElement.h index 273ff45e93..bc02a27460 100644 --- a/dom/svg/SVGMPathElement.h +++ b/dom/svg/SVGMPathElement.h @@ -38,7 +38,7 @@ class SVGMPathElement final : public SVGMPathElementBase { // nsIContent interface nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override; - void UnbindFromTree(bool aNullParent) override; + void UnbindFromTree(UnbindContext&) override; void AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, const nsAttrValue* aValue, const nsAttrValue* aOldValue, nsIPrincipal* aMaybeScriptedPrincipal, diff --git a/dom/svg/SVGSVGElement.cpp b/dom/svg/SVGSVGElement.cpp index 070bfa2bf0..f7282569f9 100644 --- a/dom/svg/SVGSVGElement.cpp +++ b/dom/svg/SVGSVGElement.cpp @@ -337,12 +337,12 @@ nsresult SVGSVGElement::BindToTree(BindContext& aContext, nsINode& aParent) { return rv; } -void SVGSVGElement::UnbindFromTree(bool aNullParent) { +void SVGSVGElement::UnbindFromTree(UnbindContext& aContext) { if (mTimedDocumentRoot) { mTimedDocumentRoot->SetParent(nullptr); } - SVGGraphicsElement::UnbindFromTree(aNullParent); + SVGGraphicsElement::UnbindFromTree(aContext); } SVGAnimatedTransformList* SVGSVGElement::GetAnimatedTransformList( diff --git a/dom/svg/SVGSVGElement.h b/dom/svg/SVGSVGElement.h index 5c0cec383e..0e800e8bd1 100644 --- a/dom/svg/SVGSVGElement.h +++ b/dom/svg/SVGSVGElement.h @@ -128,7 +128,7 @@ class SVGSVGElement final : public SVGSVGElementBase { // SVGElement overrides nsresult BindToTree(BindContext&, nsINode& aParent) override; - void UnbindFromTree(bool aNullParent) override; + void UnbindFromTree(UnbindContext&) override; SVGAnimatedTransformList* GetAnimatedTransformList( uint32_t aFlags = 0) override; diff --git a/dom/svg/SVGStyleElement.cpp b/dom/svg/SVGStyleElement.cpp index 999c240b65..6eaa2cd6fd 100644 --- a/dom/svg/SVGStyleElement.cpp +++ b/dom/svg/SVGStyleElement.cpp @@ -69,10 +69,10 @@ nsresult SVGStyleElement::BindToTree(BindContext& aContext, nsINode& aParent) { return rv; } -void SVGStyleElement::UnbindFromTree(bool aNullParent) { +void SVGStyleElement::UnbindFromTree(UnbindContext& aContext) { nsCOMPtr oldDoc = GetUncomposedDoc(); ShadowRoot* oldShadow = GetContainingShadow(); - SVGStyleElementBase::UnbindFromTree(aNullParent); + SVGStyleElementBase::UnbindFromTree(aContext); Unused << UpdateStyleSheetInternal(oldDoc, oldShadow); } diff --git a/dom/svg/SVGStyleElement.h b/dom/svg/SVGStyleElement.h index b1b1850add..357beaf152 100644 --- a/dom/svg/SVGStyleElement.h +++ b/dom/svg/SVGStyleElement.h @@ -40,7 +40,7 @@ class SVGStyleElement final : public SVGStyleElementBase, // nsIContent nsresult BindToTree(BindContext&, nsINode& aParent) override; - void UnbindFromTree(bool aNullParent = true) override; + void UnbindFromTree(UnbindContext&) override; virtual void AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName, const nsAttrValue* aValue, const nsAttrValue* aOldValue, diff --git a/dom/svg/SVGTitleElement.cpp b/dom/svg/SVGTitleElement.cpp index f352383fa5..873499c40e 100644 --- a/dom/svg/SVGTitleElement.cpp +++ b/dom/svg/SVGTitleElement.cpp @@ -63,11 +63,11 @@ nsresult SVGTitleElement::BindToTree(BindContext& aContext, nsINode& aParent) { return NS_OK; } -void SVGTitleElement::UnbindFromTree(bool aNullParent) { +void SVGTitleElement::UnbindFromTree(UnbindContext& aContext) { SendTitleChangeEvent(false); // Let this fall through. - SVGTitleElementBase::UnbindFromTree(aNullParent); + SVGTitleElementBase::UnbindFromTree(aContext); } void SVGTitleElement::DoneAddingChildren(bool aHaveNotified) { diff --git a/dom/svg/SVGTitleElement.h b/dom/svg/SVGTitleElement.h index 52f8bf886c..0141b84d54 100644 --- a/dom/svg/SVGTitleElement.h +++ b/dom/svg/SVGTitleElement.h @@ -45,7 +45,7 @@ class SVGTitleElement final : public SVGTitleElementBase, nsresult BindToTree(BindContext&, nsINode& aParent) override; - void UnbindFromTree(bool aNullParent = true) override; + void UnbindFromTree(UnbindContext&) override; void DoneAddingChildren(bool aHaveNotified) override; diff --git a/dom/svg/SVGUseElement.cpp b/dom/svg/SVGUseElement.cpp index 5e671fc802..2db8649ba1 100644 --- a/dom/svg/SVGUseElement.cpp +++ b/dom/svg/SVGUseElement.cpp @@ -19,6 +19,7 @@ #include "mozilla/dom/SVGGraphicsElement.h" #include "mozilla/dom/SVGLengthBinding.h" #include "mozilla/dom/SVGSVGElement.h" +#include "mozilla/dom/SVGSwitchElement.h" #include "mozilla/dom/SVGSymbolElement.h" #include "mozilla/dom/SVGUseElementBinding.h" #include "nsGkAtoms.h" @@ -166,8 +167,8 @@ nsresult SVGUseElement::BindToTree(BindContext& aContext, nsINode& aParent) { return NS_OK; } -void SVGUseElement::UnbindFromTree(bool aNullParent) { - SVGUseElementBase::UnbindFromTree(aNullParent); +void SVGUseElement::UnbindFromTree(UnbindContext& aContext) { + SVGUseElementBase::UnbindFromTree(aContext); OwnerDoc()->UnscheduleSVGUseElementShadowTreeUpdate(*this); } @@ -251,7 +252,17 @@ static bool NodeCouldBeRendered(const nsINode& aNode) { if (const auto* symbol = SVGSymbolElement::FromNode(aNode)) { return symbol->CouldBeRendered(); } - // TODO: Do we have other cases we can optimize out easily? + if (const auto* svgGraphics = SVGGraphicsElement::FromNode(aNode)) { + if (!svgGraphics->PassesConditionalProcessingTests()) { + return false; + } + } + if (auto* svgSwitch = + SVGSwitchElement::FromNodeOrNull(aNode.GetParentNode())) { + if (&aNode != svgSwitch->GetActiveChild()) { + return false; + } + } return true; } diff --git a/dom/svg/SVGUseElement.h b/dom/svg/SVGUseElement.h index bd155ca0c3..3bdf3fc5bb 100644 --- a/dom/svg/SVGUseElement.h +++ b/dom/svg/SVGUseElement.h @@ -50,7 +50,7 @@ class SVGUseElement final : public SVGUseElementBase, NS_IMPL_FROMNODE_WITH_TAG(SVGUseElement, kNameSpaceID_SVG, use) nsresult BindToTree(BindContext&, nsINode& aParent) override; - void UnbindFromTree(bool aNullParent = true) override; + void UnbindFromTree(UnbindContext&) override; // interfaces: NS_DECL_ISUPPORTS_INHERITED diff --git a/dom/svg/test/test_SVGTransformListAddition.xhtml b/dom/svg/test/test_SVGTransformListAddition.xhtml index b3b908466c..ca0a7e23ac 100644 --- a/dom/svg/test/test_SVGTransformListAddition.xhtml +++ b/dom/svg/test/test_SVGTransformListAddition.xhtml @@ -40,7 +40,7 @@ function Transform(type, angle) { this.angle = angle; } -function main(g) { +function main() { var cases = [ new AdditionTestCase("Not additive", "translate(150 50)", diff --git a/dom/svg/test/test_bounds.html b/dom/svg/test/test_bounds.html index 0cf0001065..3b17c62d25 100644 --- a/dom/svg/test/test_bounds.html +++ b/dom/svg/test/test_bounds.html @@ -115,7 +115,7 @@ function runTest() { const sin45 = Math.sin(Math.PI / 4); - isfuzzy(text1Bounds.left, 24, 1, "text1.getBoundingClientRect().left"); + isfuzzy(text1Bounds.left, 23, 1, "text1.getBoundingClientRect().left"); is(text2Bounds.left, text1Bounds.left + 100, "text2.getBoundingClientRect().left"); is(text2Bounds.top, text1Bounds.top, "text2.getBoundingClientRect().top"); @@ -194,9 +194,9 @@ function runTest() { var text2aBounds = doc.getElementById("text2a").getBoundingClientRect(); - isfuzzy(text1aBounds.left, 82, 1, "text1a.getBoundingClientRect().left"); + isfuzzy(text1aBounds.left, 81, 1, "text1a.getBoundingClientRect().left"); is(text1aBounds.width, text1Bounds.width + 4, "text1a.getBoundingClientRect().width"); - is(text1bBounds.width, text1Bounds.width, "text1b.getBoundingClientRect().width"); + isfuzzy(text1bBounds.width, text1Bounds.width + 170, 1, "text1b.getBoundingClientRect().width"); isfuzzy(text1bBounds.height, 196, 5, "text1b.getBoundingClientRect().height"); is(text2aBounds.left, text1aBounds.left + 100 - 3, "text2a.getBoundingClientRect().left"); diff --git a/dom/svg/test/test_bug1426594.html b/dom/svg/test/test_bug1426594.html index ac975093c8..a3f830e9d0 100644 --- a/dom/svg/test/test_bug1426594.html +++ b/dom/svg/test/test_bug1426594.html @@ -12,10 +12,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1426594 function runTests() { let textElement = document.getElementById("textId"), - tspanElement = document.getElementById("tspanId"); + textClientRect = textElement.getBoundingClientRect(), + tspanClientRect = document.getElementById("tspanId").getBoundingClientRect(); - isfuzzy(textElement.getBoundingClientRect().width, tspanElement.getBoundingClientRect().width, 5); - isfuzzy(textElement.getBoundingClientRect().height, tspanElement.getBoundingClientRect().height, 5); + // TODO: tspan bounds should account for stroke, decorations and text-shadow + isfuzzy(textClientRect.width, tspanClientRect.width, 6, "unexpected width"); + isfuzzy(textClientRect.height, tspanClientRect.height, 6, "unexpected height"); SimpleTest.finish(); } diff --git a/dom/svg/test/test_fragments.html b/dom/svg/test/test_fragments.html index b12833e899..e7d0f29714 100644 --- a/dom/svg/test/test_fragments.html +++ b/dom/svg/test/test_fragments.html @@ -21,8 +21,7 @@ var svg = $("svg"); SimpleTest.waitForExplicitFinish(); -function Test(svgFragmentIdentifier, viewBoxString, - preserveAspectRatioString, zoomAndPanString) { +function Test(svgFragmentIdentifier) { this.svgFragmentIdentifier = svgFragmentIdentifier; } diff --git a/dom/svg/test/test_selectSubString.xhtml b/dom/svg/test/test_selectSubString.xhtml index 6755b65c56..66038237cb 100644 --- a/dom/svg/test/test_selectSubString.xhtml +++ b/dom/svg/test/test_selectSubString.xhtml @@ -39,7 +39,7 @@ function runTests() { } } - function expectNoThrow(charnum, nchars, expected) { + function expectNoThrow(charnum, nchars) { try { text.selectSubString(charnum, nchars); ok(true, diff --git a/dom/svg/test/test_text_selection.html b/dom/svg/test/test_text_selection.html index 7160461db9..2f275ac436 100644 --- a/dom/svg/test/test_text_selection.html +++ b/dom/svg/test/test_text_selection.html @@ -78,7 +78,7 @@ function testSelection() { deselect(); // Drag from left of the text to the right of the text to select it. - drag(90, 50, 110 + text[0].getComputedTextLength(), 50); + drag(101, 50, 99 + text[0].getComputedTextLength(), 50); selection_is("hello there", "selecting entire simple text by dragging around it"); deselect(); diff --git a/dom/system/IOUtils.cpp b/dom/system/IOUtils.cpp index 08e2173452..4b989c6c0c 100644 --- a/dom/system/IOUtils.cpp +++ b/dom/system/IOUtils.cpp @@ -79,17 +79,23 @@ # include "base/process_util.h" #endif -#define REJECT_IF_INIT_PATH_FAILED(_file, _path, _promise) \ +#define REJECT_IF_INIT_PATH_FAILED(_file, _path, _promise, _msg, ...) \ do { \ if (nsresult _rv = PathUtils::InitFileWithPath((_file), (_path)); \ NS_FAILED(_rv)) { \ - (_promise)->MaybeRejectWithOperationError( \ - FormatErrorMessage(_rv, "Could not parse path (%s)", \ - NS_ConvertUTF16toUTF8(_path).get())); \ + (_promise)->MaybeRejectWithOperationError(FormatErrorMessage( \ + _rv, _msg ": could not parse path", ##__VA_ARGS__)); \ return; \ } \ } while (0) +#define IOUTILS_TRY_WITH_CONTEXT(_expr, _fmt, ...) \ + do { \ + if (nsresult _rv = (_expr); NS_FAILED(_rv)) { \ + return Err(IOUtils::IOError(_rv, _fmt, ##__VA_ARGS__)); \ + } \ + } while (0) + static constexpr auto SHUTDOWN_ERROR = "IOUtils: Shutting down and refusing additional I/O tasks"_ns; @@ -121,34 +127,32 @@ static bool IsNotDirectory(nsresult aResult) { /** * Formats an error message and appends the error name to the end. */ -template -static nsCString FormatErrorMessage(nsresult aError, const char* const aMessage, - Args... aArgs) { - nsPrintfCString msg(aMessage, aArgs...); +static nsCString MOZ_FORMAT_PRINTF(2, 3) + FormatErrorMessage(nsresult aError, const char* const aFmt, ...) { + nsAutoCString errorName; + GetErrorName(aError, errorName); - if (const char* errName = GetStaticErrorName(aError)) { - msg.AppendPrintf(": %s", errName); - } else { - // In the exceptional case where there is no error name, print the literal - // integer value of the nsresult as an upper case hex value so it can be - // located easily in searchfox. - msg.AppendPrintf(": 0x%" PRIX32, static_cast(aError)); - } + nsCString msg; + + va_list ap; + va_start(ap, aFmt); + msg.AppendVprintf(aFmt, ap); + va_end(ap); - return std::move(msg); + msg.AppendPrintf(" (%s)", errorName.get()); + + return msg; } static nsCString FormatErrorMessage(nsresult aError, - const char* const aMessage) { - const char* errName = GetStaticErrorName(aError); - if (errName) { - return nsPrintfCString("%s: %s", aMessage, errName); - } - // In the exceptional case where there is no error name, print the literal - // integer value of the nsresult as an upper case hex value so it can be - // located easily in searchfox. - return nsPrintfCString("%s: 0x%" PRIX32, aMessage, - static_cast(aError)); + const nsCString& aMessage) { + nsAutoCString errorName; + GetErrorName(aError, errorName); + + nsCString msg(aMessage); + msg.AppendPrintf(" (%s)", errorName.get()); + + return msg; } [[nodiscard]] inline bool ToJSValue( @@ -183,99 +187,82 @@ static void ResolveJSPromise(Promise* aPromise, T&& aValue) { } static void RejectJSPromise(Promise* aPromise, const IOUtils::IOError& aError) { - const auto& errMsg = aError.Message(); + const auto errMsg = FormatErrorMessage(aError.Code(), aError.Message()); switch (aError.Code()) { case NS_ERROR_FILE_UNRESOLVABLE_SYMLINK: - [[fallthrough]]; // to NS_ERROR_FILE_INVALID_PATH + [[fallthrough]]; case NS_ERROR_FILE_NOT_FOUND: - [[fallthrough]]; // to NS_ERROR_FILE_INVALID_PATH + [[fallthrough]]; case NS_ERROR_FILE_INVALID_PATH: - aPromise->MaybeRejectWithNotFoundError(errMsg.refOr("File not found"_ns)); + [[fallthrough]]; + case NS_ERROR_NOT_AVAILABLE: + aPromise->MaybeRejectWithNotFoundError(errMsg); break; + case NS_ERROR_FILE_IS_LOCKED: - [[fallthrough]]; // to NS_ERROR_FILE_ACCESS_DENIED + [[fallthrough]]; case NS_ERROR_FILE_ACCESS_DENIED: - aPromise->MaybeRejectWithNotAllowedError( - errMsg.refOr("Access was denied to the target file"_ns)); + aPromise->MaybeRejectWithNotAllowedError(errMsg); break; + case NS_ERROR_FILE_TOO_BIG: - aPromise->MaybeRejectWithNotReadableError( - errMsg.refOr("Target file is too big"_ns)); - break; + [[fallthrough]]; case NS_ERROR_FILE_NO_DEVICE_SPACE: - aPromise->MaybeRejectWithNotReadableError( - errMsg.refOr("Target device is full"_ns)); + [[fallthrough]]; + case NS_ERROR_FILE_DEVICE_FAILURE: + [[fallthrough]]; + case NS_ERROR_FILE_FS_CORRUPTED: + [[fallthrough]]; + case NS_ERROR_FILE_CORRUPTED: + aPromise->MaybeRejectWithNotReadableError(errMsg); break; + case NS_ERROR_FILE_ALREADY_EXISTS: - aPromise->MaybeRejectWithNoModificationAllowedError( - errMsg.refOr("Target file already exists"_ns)); + aPromise->MaybeRejectWithNoModificationAllowedError(errMsg); break; + case NS_ERROR_FILE_COPY_OR_MOVE_FAILED: - aPromise->MaybeRejectWithOperationError( - errMsg.refOr("Failed to copy or move the target file"_ns)); + [[fallthrough]]; + case NS_ERROR_FILE_NAME_TOO_LONG: + [[fallthrough]]; + case NS_ERROR_FILE_UNRECOGNIZED_PATH: + [[fallthrough]]; + case NS_ERROR_FILE_DIR_NOT_EMPTY: + aPromise->MaybeRejectWithOperationError(errMsg); break; + case NS_ERROR_FILE_READ_ONLY: - aPromise->MaybeRejectWithReadOnlyError( - errMsg.refOr("Target file is read only"_ns)); + aPromise->MaybeRejectWithReadOnlyError(errMsg); break; + case NS_ERROR_FILE_NOT_DIRECTORY: - [[fallthrough]]; // to NS_ERROR_FILE_DESTINATION_NOT_DIR + [[fallthrough]]; case NS_ERROR_FILE_DESTINATION_NOT_DIR: - aPromise->MaybeRejectWithInvalidAccessError( - errMsg.refOr("Target file is not a directory"_ns)); - break; + [[fallthrough]]; case NS_ERROR_FILE_IS_DIRECTORY: - aPromise->MaybeRejectWithInvalidAccessError( - errMsg.refOr("Target file is a directory"_ns)); - break; + [[fallthrough]]; case NS_ERROR_FILE_UNKNOWN_TYPE: - aPromise->MaybeRejectWithInvalidAccessError( - errMsg.refOr("Target file is of unknown type"_ns)); - break; - case NS_ERROR_FILE_NAME_TOO_LONG: - aPromise->MaybeRejectWithOperationError( - errMsg.refOr("Target file path is too long"_ns)); - break; - case NS_ERROR_FILE_UNRECOGNIZED_PATH: - aPromise->MaybeRejectWithOperationError( - errMsg.refOr("Target file path is not recognized"_ns)); - break; - case NS_ERROR_FILE_DIR_NOT_EMPTY: - aPromise->MaybeRejectWithOperationError( - errMsg.refOr("Target directory is not empty"_ns)); - break; - case NS_ERROR_FILE_DEVICE_FAILURE: - [[fallthrough]]; // to NS_ERROR_FILE_FS_CORRUPTED - case NS_ERROR_FILE_FS_CORRUPTED: - aPromise->MaybeRejectWithNotReadableError( - errMsg.refOr("Target file system may be corrupt or unavailable"_ns)); - break; - case NS_ERROR_FILE_CORRUPTED: - aPromise->MaybeRejectWithNotReadableError( - errMsg.refOr("Target file could not be read and may be corrupt"_ns)); + aPromise->MaybeRejectWithInvalidAccessError(errMsg); break; + case NS_ERROR_ILLEGAL_INPUT: - [[fallthrough]]; // NS_ERROR_ILLEGAL_VALUE + [[fallthrough]]; case NS_ERROR_ILLEGAL_VALUE: - aPromise->MaybeRejectWithDataError( - errMsg.refOr("Argument is not allowed"_ns)); - break; - case NS_ERROR_NOT_AVAILABLE: - aPromise->MaybeRejectWithNotFoundError(errMsg.refOr("Unavailable"_ns)); + aPromise->MaybeRejectWithDataError(errMsg); break; + case NS_ERROR_ABORT: - aPromise->MaybeRejectWithAbortError(errMsg.refOr("Operation aborted"_ns)); + aPromise->MaybeRejectWithAbortError(errMsg); break; + default: - aPromise->MaybeRejectWithUnknownError(FormatErrorMessage( - aError.Code(), errMsg.refOr("Unexpected error"_ns).get())); + aPromise->MaybeRejectWithUnknownError(errMsg); } } static void RejectShuttingDown(Promise* aPromise) { - RejectJSPromise(aPromise, - IOUtils::IOError(NS_ERROR_ABORT).WithMessage(SHUTDOWN_ERROR)); + RejectJSPromise(aPromise, IOUtils::IOError(NS_ERROR_ABORT, SHUTDOWN_ERROR)); } static bool AssertParentProcessWithCallerLocationImpl(GlobalObject& aGlobal, @@ -368,10 +355,20 @@ already_AddRefed IOUtils::Read(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, "Could not read `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); Maybe toRead = Nothing(); if (!aOptions.mMaxBytes.IsNull()) { + if (aOptions.mDecompress) { + RejectJSPromise( + promise, IOError(NS_ERROR_ILLEGAL_INPUT, + "Could not read `%s': the `maxBytes' and " + "`decompress' options are mutually exclusive", + file->HumanReadablePath().get())); + return; + } + if (aOptions.mMaxBytes.Value() == 0) { // Resolve with an empty buffer. nsTArray arr(0); @@ -437,7 +434,8 @@ already_AddRefed IOUtils::ReadUTF8(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, "Could not read `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve( state->mEventQueue, promise, @@ -455,7 +453,8 @@ already_AddRefed IOUtils::ReadJSON(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, "Could not read `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); RefPtr workerRef; if (!NS_IsMainThread()) { @@ -476,8 +475,12 @@ already_AddRefed IOUtils::ReadJSON(GlobalObject& aGlobal, file](JsBuffer&& aBuffer) { AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(promise->GetGlobalObject()))) { - promise->MaybeRejectWithUnknownError( - "Could not initialize JS API"); + RejectJSPromise( + promise, + IOError( + NS_ERROR_DOM_UNKNOWN_ERR, + "Could not read `%s': could not initialize JS API", + file->HumanReadablePath().get())); return; } JSContext* cx = jsapi.cx(); @@ -486,7 +489,12 @@ already_AddRefed IOUtils::ReadJSON(GlobalObject& aGlobal, cx, IOUtils::JsBuffer::IntoString(cx, std::move(aBuffer))); if (!jsonStr) { - RejectJSPromise(promise, IOError(NS_ERROR_OUT_OF_MEMORY)); + RejectJSPromise( + promise, + IOError( + NS_ERROR_OUT_OF_MEMORY, + "Could not read `%s': failed to allocate buffer", + file->HumanReadablePath().get())); return; } @@ -497,13 +505,11 @@ already_AddRefed IOUtils::ReadJSON(GlobalObject& aGlobal, JS_ClearPendingException(cx); promise->MaybeReject(exn); } else { - RejectJSPromise( - promise, - IOError(NS_ERROR_DOM_UNKNOWN_ERR) - .WithMessage( - "ParseJSON threw an uncatchable exception " - "while parsing file(%s)", - file->HumanReadablePath().get())); + RejectJSPromise(promise, + IOError(NS_ERROR_DOM_UNKNOWN_ERR, + "Could not read `%s': ParseJSON " + "threw an uncatchable exception", + file->HumanReadablePath().get())); } return; @@ -526,25 +532,31 @@ already_AddRefed IOUtils::Write(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not write to `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); Maybe> buf = aData.CreateFromData>(); if (buf.isNothing()) { - promise->MaybeRejectWithOperationError( - "Out of memory: Could not allocate buffer while writing to file"); + promise->MaybeRejectWithOperationError(nsPrintfCString( + "Could not write to `%s': could not allocate buffer", + file->HumanReadablePath().get())); return; } - auto opts = InternalWriteOpts::FromBinding(aOptions); - if (opts.isErr()) { - RejectJSPromise(promise, opts.unwrapErr()); + auto result = InternalWriteOpts::FromBinding(aOptions); + if (result.isErr()) { + RejectJSPromise( + promise, + IOError::WithCause(result.unwrapErr(), "Could not write to `%s'", + file->HumanReadablePath().get())); return; } DispatchAndResolve( state->mEventQueue, promise, [file = std::move(file), buf = buf.extract(), - opts = opts.unwrap()]() { return WriteSync(file, buf, opts); }); + opts = result.unwrap()]() { return WriteSync(file, buf, opts); }); }); } @@ -557,18 +569,23 @@ already_AddRefed IOUtils::WriteUTF8(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not write to `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); - auto opts = InternalWriteOpts::FromBinding(aOptions); - if (opts.isErr()) { - RejectJSPromise(promise, opts.unwrapErr()); + auto result = InternalWriteOpts::FromBinding(aOptions); + if (result.isErr()) { + RejectJSPromise( + promise, + IOError::WithCause(result.unwrapErr(), "Could not write to `%s'", + file->HumanReadablePath().get())); return; } DispatchAndResolve( state->mEventQueue, promise, [file = std::move(file), str = nsCString(aString), - opts = opts.unwrap()]() { + opts = result.unwrap()]() { return WriteSync(file, AsBytes(Span(str)), opts); }); }); @@ -583,18 +600,27 @@ already_AddRefed IOUtils::WriteJSON(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not write to `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); - auto opts = InternalWriteOpts::FromBinding(aOptions); - if (opts.isErr()) { - RejectJSPromise(promise, opts.unwrapErr()); + auto result = InternalWriteOpts::FromBinding(aOptions); + if (result.isErr()) { + RejectJSPromise( + promise, + IOError::WithCause(result.unwrapErr(), "Could not write to `%s'", + file->HumanReadablePath().get())); return; } - if (opts.inspect().mMode == WriteMode::Append || - opts.inspect().mMode == WriteMode::AppendOrCreate) { + auto opts = result.unwrap(); + + if (opts.mMode == WriteMode::Append || + opts.mMode == WriteMode::AppendOrCreate) { promise->MaybeRejectWithNotSupportedError( - "IOUtils.writeJSON does not support appending to files."_ns); + nsPrintfCString("Could not write to `%s': IOUtils.writeJSON does " + "not support appending to files.", + file->HumanReadablePath().get())); return; } @@ -608,10 +634,9 @@ already_AddRefed IOUtils::WriteJSON(GlobalObject& aGlobal, JS_ClearPendingException(cx); promise->MaybeReject(exn); } else { - RejectJSPromise( - promise, - IOError(NS_ERROR_DOM_UNKNOWN_ERR) - .WithMessage("Could not serialize object to JSON")); + RejectJSPromise(promise, + IOError(NS_ERROR_DOM_UNKNOWN_ERR, + "Could not serialize object to JSON"_ns)); } return; } @@ -619,10 +644,13 @@ already_AddRefed IOUtils::WriteJSON(GlobalObject& aGlobal, DispatchAndResolve( state->mEventQueue, promise, [file = std::move(file), string = std::move(string), - opts = opts.unwrap()]() -> Result { + opts = std::move(opts)]() -> Result { nsAutoCString utf8Str; if (!CopyUTF16toUTF8(string, utf8Str, fallible)) { - return Err(IOError(NS_ERROR_OUT_OF_MEMORY)); + return Err(IOError( + NS_ERROR_OUT_OF_MEMORY, + "Failed to write to `%s': could not allocate buffer", + file->HumanReadablePath().get())); } return WriteSync(file, AsBytes(Span(utf8Str)), opts); }); @@ -638,10 +666,16 @@ already_AddRefed IOUtils::Move(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr sourceFile = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(sourceFile, aSourcePath, promise); + REJECT_IF_INIT_PATH_FAILED(sourceFile, aSourcePath, promise, + "Could not move `%s' to `%s'", + NS_ConvertUTF16toUTF8(aSourcePath).get(), + NS_ConvertUTF16toUTF8(aDestPath).get()); nsCOMPtr destFile = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(destFile, aDestPath, promise); + REJECT_IF_INIT_PATH_FAILED(destFile, aDestPath, promise, + "Could not move `%s' to `%s'", + NS_ConvertUTF16toUTF8(aSourcePath).get(), + NS_ConvertUTF16toUTF8(aDestPath).get()); DispatchAndResolve( state->mEventQueue, promise, @@ -660,7 +694,9 @@ already_AddRefed IOUtils::Remove(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not remove `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve( state->mEventQueue, promise, @@ -679,7 +715,9 @@ already_AddRefed IOUtils::MakeDirectory( return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not make directory `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve(state->mEventQueue, promise, [file = std::move(file), @@ -699,7 +737,8 @@ already_AddRefed IOUtils::Stat(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, "Could not stat `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve( state->mEventQueue, promise, @@ -716,10 +755,16 @@ already_AddRefed IOUtils::Copy(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr sourceFile = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(sourceFile, aSourcePath, promise); + REJECT_IF_INIT_PATH_FAILED(sourceFile, aSourcePath, promise, + "Could not copy `%s' to `%s'", + NS_ConvertUTF16toUTF8(aSourcePath).get(), + NS_ConvertUTF16toUTF8(aDestPath).get()); nsCOMPtr destFile = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(destFile, aDestPath, promise); + REJECT_IF_INIT_PATH_FAILED(destFile, aDestPath, promise, + "Could not copy `%s' to `%s'", + NS_ConvertUTF16toUTF8(aSourcePath).get(), + NS_ConvertUTF16toUTF8(aDestPath).get()); DispatchAndResolve( state->mEventQueue, promise, @@ -736,7 +781,7 @@ already_AddRefed IOUtils::SetAccessTime( GlobalObject& aGlobal, const nsAString& aPath, const Optional& aAccess, ErrorResult& aError) { return SetTime(aGlobal, aPath, aAccess, &nsIFile::SetLastAccessedTime, - aError); + "access", aError); } /* static */ @@ -744,7 +789,7 @@ already_AddRefed IOUtils::SetModificationTime( GlobalObject& aGlobal, const nsAString& aPath, const Optional& aModification, ErrorResult& aError) { return SetTime(aGlobal, aPath, aModification, &nsIFile::SetLastModifiedTime, - aError); + "modification", aError); } /* static */ @@ -752,11 +797,14 @@ already_AddRefed IOUtils::SetTime(GlobalObject& aGlobal, const nsAString& aPath, const Optional& aNewTime, IOUtils::SetTimeFn aSetTimeFn, + const char* const aTimeKind, ErrorResult& aError) { return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not set %s time on `%s'", aTimeKind, + NS_ConvertUTF16toUTF8(aPath).get()); int64_t newTime = aNewTime.WasPassed() ? aNewTime.Value() : PR_Now() / PR_USEC_PER_MSEC; @@ -775,7 +823,9 @@ already_AddRefed IOUtils::GetChildren( return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not get children of `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve>( state->mEventQueue, promise, @@ -800,7 +850,9 @@ already_AddRefed IOUtils::SetPermissions(GlobalObject& aGlobal, #endif nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not set permissions on `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve( state->mEventQueue, promise, @@ -817,7 +869,9 @@ already_AddRefed IOUtils::Exists(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not determine if `%s' exists", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve( state->mEventQueue, promise, @@ -853,14 +907,21 @@ already_AddRefed IOUtils::CreateUnique(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aParent, promise); + REJECT_IF_INIT_PATH_FAILED( + file, aParent, promise, "Could not create unique %s in `%s'", + aFileType == nsIFile::NORMAL_FILE_TYPE ? "file" : "directory", + NS_ConvertUTF16toUTF8(aParent).get()); if (nsresult rv = file->Append(aPrefix); NS_FAILED(rv)) { - RejectJSPromise(promise, - IOError(rv).WithMessage( - "Could not append prefix `%s' to parent `%s'", - NS_ConvertUTF16toUTF8(aPrefix).get(), - file->HumanReadablePath().get())); + RejectJSPromise( + promise, + IOError( + rv, + "Could not create unique %s: could not append prefix `%s' to " + "parent `%s'", + aFileType == nsIFile::NORMAL_FILE_TYPE ? "file" : "directory", + NS_ConvertUTF16toUTF8(aPrefix).get(), + file->HumanReadablePath().get())); return; } @@ -881,14 +942,14 @@ already_AddRefed IOUtils::ComputeHexDigest( return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { if (!nssInitialized) { - RejectJSPromise(promise, - IOError(NS_ERROR_UNEXPECTED) - .WithMessage("Could not initialize NSS")); + RejectJSPromise(promise, IOError(NS_ERROR_UNEXPECTED, + "Could not initialize NSS"_ns)); return; } nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, "Could not hash `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve(state->mEventQueue, promise, [file = std::move(file), aAlgorithm]() { @@ -907,7 +968,10 @@ already_AddRefed IOUtils::GetWindowsAttributes(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not get Windows file attributes of " + "`%s'", + NS_ConvertUTF16toUTF8(aPath).get()); RefPtr workerRef; if (!NS_IsMainThread()) { @@ -945,7 +1009,10 @@ already_AddRefed IOUtils::SetWindowsAttributes( return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED( + file, aPath, promise, + "Could not set Windows file attributes on `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); uint32_t setAttrs = 0; uint32_t clearAttrs = 0; @@ -992,7 +1059,11 @@ already_AddRefed IOUtils::HasMacXAttr(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED( + file, aPath, promise, + "Could not read the extended attribute `%s' from `%s'", + PromiseFlatCString(aAttr).get(), + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve( state->mEventQueue, promise, @@ -1010,7 +1081,11 @@ already_AddRefed IOUtils::GetMacXAttr(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED( + file, aPath, promise, + "Could not read extended attribute `%s' from `%s'", + PromiseFlatCString(aAttr).get(), + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve>( state->mEventQueue, promise, @@ -1029,16 +1104,21 @@ already_AddRefed IOUtils::SetMacXAttr(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED( + file, aPath, promise, + "Could not set the extended attribute `%s' on `%s'", + PromiseFlatCString(aAttr).get(), + NS_ConvertUTF16toUTF8(aPath).get()); nsTArray value; if (!aValue.AppendDataTo(value)) { RejectJSPromise( - promise, - IOError(NS_ERROR_OUT_OF_MEMORY) - .WithMessage( - "Could not allocate buffer to set extended attribute")); + promise, IOError(NS_ERROR_OUT_OF_MEMORY, + "Could not set extended attribute `%s' on `%s': " + "could not allocate buffer", + PromiseFlatCString(aAttr).get(), + file->HumanReadablePath().get())); return; } @@ -1058,7 +1138,11 @@ already_AddRefed IOUtils::DelMacXAttr(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED( + file, aPath, promise, + "Could not delete extended attribute `%s' on `%s'", + PromiseFlatCString(aAttr).get(), + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve( state->mEventQueue, promise, @@ -1086,8 +1170,10 @@ already_AddRefed IOUtils::GetFile( nsCOMPtr parent; if (nsresult rv = file->GetParent(getter_AddRefs(parent)); NS_FAILED(rv)) { - RejectJSPromise(promise, IOError(rv).WithMessage( - "Could not get parent directory")); + RejectJSPromise(promise, IOError(rv, + "Could not get nsIFile for `%s': " + "could not get parent directory", + file->HumanReadablePath().get())); return; } @@ -1153,19 +1239,16 @@ Result IOUtils::ReadSync( nsIFile* aFile, const uint64_t aOffset, const Maybe aMaxBytes, const bool aDecompress, IOUtils::BufferKind aBufferKind) { MOZ_ASSERT(!NS_IsMainThread()); - - if (aMaxBytes.isSome() && aDecompress) { - return Err( - IOError(NS_ERROR_ILLEGAL_INPUT) - .WithMessage( - "The `maxBytes` and `decompress` options are not compatible")); - } + // This is checked in IOUtils::Read. + MOZ_ASSERT(aMaxBytes.isNothing() || !aDecompress, + "maxBytes and decompress are mutually exclusive"); if (aOffset > static_cast(INT64_MAX)) { - return Err(IOError(NS_ERROR_ILLEGAL_INPUT) - .WithMessage("Requested offset is too large (%" PRIu64 - " > %" PRId64 ")", - aOffset, INT64_MAX)); + return Err( + IOError(NS_ERROR_ILLEGAL_INPUT, + "Could not read `%s': requested offset is too large (%" PRIu64 + " > %" PRId64 ")", + aFile->HumanReadablePath().get(), aOffset, INT64_MAX)); } const int64_t offset = static_cast(aOffset); @@ -1174,8 +1257,12 @@ Result IOUtils::ReadSync( if (nsresult rv = stream->Init(aFile, PR_RDONLY | nsIFile::OS_READAHEAD, 0666, 0); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage("Could not open the file at %s", - aFile->HumanReadablePath().get())); + if (IsFileNotFound(rv)) { + return Err(IOError(rv, "Could not open `%s': file does not exist", + aFile->HumanReadablePath().get())); + } + return Err( + IOError(rv, "Could not open `%s'", aFile->HumanReadablePath().get())); } uint32_t bufSize = 0; @@ -1187,9 +1274,10 @@ Result IOUtils::ReadSync( int64_t rawStreamSize = -1; if (nsresult rv = stream->GetSize(&rawStreamSize); NS_FAILED(rv)) { - return Err(IOError(NS_ERROR_FILE_ACCESS_DENIED) - .WithMessage("Could not get info for the file at %s", - aFile->HumanReadablePath().get())); + return Err( + IOError(NS_ERROR_FILE_ACCESS_DENIED, + "Could not open `%s': could not stat file or directory", + aFile->HumanReadablePath().get())); } MOZ_RELEASE_ASSERT(rawStreamSize >= 0); @@ -1198,10 +1286,9 @@ Result IOUtils::ReadSync( bufSize = 0; } else { if (streamSize - offset > static_cast(UINT32_MAX)) { - return Err(IOError(NS_ERROR_FILE_TOO_BIG) - .WithMessage( - "Could not read the file at %s with offset %" PRIu32 - " because it is too large(size=%" PRIu64 " bytes)", + return Err(IOError(NS_ERROR_FILE_TOO_BIG, + "Could not read `%s' with offset %" PRIu64 + ": file is too large (%" PRIu64 " bytes)", aFile->HumanReadablePath().get(), offset, streamSize)); } @@ -1214,9 +1301,9 @@ Result IOUtils::ReadSync( if (offset > 0) { if (nsresult rv = stream->Seek(PR_SEEK_SET, offset); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not seek to position %" PRId64 " in file %s", offset, - aFile->HumanReadablePath().get())); + return Err(IOError( + rv, "Could not read `%s': could not seek to position %" PRId64, + aFile->HumanReadablePath().get(), offset)); } } @@ -1225,7 +1312,8 @@ Result IOUtils::ReadSync( if (bufSize > 0) { auto result = JsBuffer::Create(aBufferKind, bufSize); if (result.isErr()) { - return result.propagateErr(); + return Err(IOError::WithCause(result.unwrapErr(), "Could not read `%s'", + aFile->HumanReadablePath().get())); } buffer = result.unwrap(); Span toRead = buffer.BeginWriting(); @@ -1241,9 +1329,9 @@ Result IOUtils::ReadSync( if (nsresult rv = stream->Read(toRead.Elements(), bytesToReadThisChunk, &bytesRead); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Encountered an unexpected error while reading file(%s)", - aFile->HumanReadablePath().get())); + return Err( + IOError(rv, "Could not read `%s': encountered an unexpected error", + aFile->HumanReadablePath().get())); } if (bytesRead == 0) { break; @@ -1257,7 +1345,13 @@ Result IOUtils::ReadSync( // Decompress the file contents, if required. if (aDecompress) { - return MozLZ4::Decompress(AsBytes(buffer.BeginReading()), aBufferKind); + auto result = + MozLZ4::Decompress(AsBytes(buffer.BeginReading()), aBufferKind); + if (result.isErr()) { + return Err(IOError::WithCause(result.unwrapErr(), "Could not read `%s'", + aFile->HumanReadablePath().get())); + } + return result; } return std::move(buffer); @@ -1273,11 +1367,9 @@ Result IOUtils::ReadUTF8Sync( JsBuffer buffer = result.unwrap(); if (!IsUtf8(buffer.BeginReading())) { - return Err( - IOError(NS_ERROR_FILE_CORRUPTED) - .WithMessage( - "Could not read file(%s) because it is not UTF-8 encoded", - aFile->HumanReadablePath().get())); + return Err(IOError(NS_ERROR_FILE_CORRUPTED, + "Could not read `%s': file is not UTF-8 encoded", + aFile->HumanReadablePath().get())); } return buffer; @@ -1293,14 +1385,16 @@ Result IOUtils::WriteSync( nsIFile* tempFile = aOptions.mTmpFile; bool exists = false; - MOZ_TRY(aFile->Exists(&exists)); + IOUTILS_TRY_WITH_CONTEXT( + aFile->Exists(&exists), + "Could not write to `%s': could not stat file or directory", + aFile->HumanReadablePath().get()); if (exists && aOptions.mMode == WriteMode::Create) { - return Err(IOError(NS_ERROR_FILE_ALREADY_EXISTS) - .WithMessage("Refusing to overwrite the file at %s\n" - "Specify `mode: \"overwrite\"` to allow " - "overwriting the destination", - aFile->HumanReadablePath().get())); + return Err(IOError(NS_ERROR_FILE_ALREADY_EXISTS, + "Could not write to `%s': refusing to overwrite file, " + "`mode' is not \"overwrite\"", + aFile->HumanReadablePath().get())); } // If backupFile was specified, perform the backup as a move. @@ -1316,11 +1410,12 @@ Result IOUtils::WriteSync( bool noOverwrite = aOptions.mMode == WriteMode::Create; - if (MoveSync(toMove, backupFile, noOverwrite).isErr()) { - return Err(IOError(NS_ERROR_FILE_COPY_OR_MOVE_FAILED) - .WithMessage("Failed to backup the source file(%s) to %s", - aFile->HumanReadablePath().get(), - backupFile->HumanReadablePath().get())); + if (auto result = MoveSync(toMove, backupFile, noOverwrite); + result.isErr()) { + return Err(IOError::WithCause( + result.unwrapErr(), + "Could not write to `%s': failed to back up source file", + aFile->HumanReadablePath().get())); } } @@ -1369,11 +1464,13 @@ Result IOUtils::WriteSync( nsTArray compressed; Span bytes; if (aOptions.mCompress) { - auto rv = MozLZ4::Compress(aByteArray); - if (rv.isErr()) { - return rv.propagateErr(); + auto result = MozLZ4::Compress(aByteArray); + if (result.isErr()) { + return Err(IOError::WithCause(result.unwrapErr(), + "Could not write to `%s'", + writeFile->HumanReadablePath().get())); } - compressed = rv.unwrap(); + compressed = result.unwrap(); bytes = Span(reinterpret_cast(compressed.Elements()), compressed.Length()); } else { @@ -1388,9 +1485,9 @@ Result IOUtils::WriteSync( if (rv == nsresult::NS_ERROR_FILE_IS_DIRECTORY) { rv = NS_ERROR_FILE_ACCESS_DENIED; } - return Err( - IOError(rv).WithMessage("Could not open the file at %s for writing", - writeFile->HumanReadablePath().get())); + return Err(IOError( + rv, "Could not write to `%s': failed to open file for writing", + writeFile->HumanReadablePath().get())); } // nsFileRandomAccessStream::Write uses PR_Write under the hood, which @@ -1407,10 +1504,10 @@ Result IOUtils::WriteSync( if (nsresult rv = stream->Write(pendingBytes.Elements(), chunkSize, &bytesWritten); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not write chunk (size = %" PRIu32 - ") to file %s. The file may be corrupt.", - chunkSize, writeFile->HumanReadablePath().get())); + return Err(IOError(rv, + "Could not write to `%s': failed to write chunk; " + "the file may be corrupt", + writeFile->HumanReadablePath().get())); } pendingBytes = pendingBytes.From(bytesWritten); totalWritten += bytesWritten; @@ -1433,8 +1530,9 @@ Result IOUtils::WriteSync( bool isDir = false; if (nsresult rv = aFile->IsDirectory(&isDir); NS_FAILED(rv) && !IsFileNotFound(rv)) { - return Err(IOError(rv).WithMessage("Could not stat the file at %s", - aFile->HumanReadablePath().get())); + return Err(IOError( + rv, "Could not write to `%s': could not stat file or directory", + aFile->HumanReadablePath().get())); } // If we attempt to write to a directory *without* a temp file, we get a @@ -1445,20 +1543,19 @@ Result IOUtils::WriteSync( // inside the directory, which is not what we want. In this case, we are // just going to bail out early. if (isDir) { - return Err( - IOError(NS_ERROR_FILE_ACCESS_DENIED) - .WithMessage("Could not open the file at %s for writing", - aFile->HumanReadablePath().get())); + return Err(IOError(NS_ERROR_FILE_ACCESS_DENIED, + "Could not write to `%s': file is a directory", + aFile->HumanReadablePath().get())); } } - if (MoveSync(writeFile, aFile, /* aNoOverwrite = */ false).isErr()) { - return Err( - IOError(NS_ERROR_FILE_COPY_OR_MOVE_FAILED) - .WithMessage( - "Could not move temporary file(%s) to destination(%s)", - writeFile->HumanReadablePath().get(), - aFile->HumanReadablePath().get())); + if (auto result = MoveSync(writeFile, aFile, /* aNoOverwrite = */ false); + result.isErr()) { + return Err(IOError::WithCause( + result.unwrapErr(), + "Could not write to `%s': could not move overwite with temporary " + "file", + aFile->HumanReadablePath().get())); } } } @@ -1474,13 +1571,18 @@ Result IOUtils::MoveSync(nsIFile* aSourceFile, // Ensure the source file exists before continuing. If it doesn't exist, // subsequent operations can fail in different ways on different platforms. bool srcExists = false; - MOZ_TRY(aSourceFile->Exists(&srcExists)); + IOUTILS_TRY_WITH_CONTEXT( + aSourceFile->Exists(&srcExists), + "Could not move `%s' to `%s': could not stat source file or directory", + aSourceFile->HumanReadablePath().get(), + aDestFile->HumanReadablePath().get()); + if (!srcExists) { return Err( - IOError(NS_ERROR_FILE_NOT_FOUND) - .WithMessage( - "Could not move source file(%s) because it does not exist", - aSourceFile->HumanReadablePath().get())); + IOError(NS_ERROR_FILE_NOT_FOUND, + "Could not move `%s' to `%s': source file does not exist", + aSourceFile->HumanReadablePath().get(), + aDestFile->HumanReadablePath().get())); } return CopyOrMoveSync(&nsIFile::MoveToFollowingLinks, "move", aSourceFile, @@ -1497,28 +1599,35 @@ Result IOUtils::CopySync(nsIFile* aSourceFile, // Ensure the source file exists before continuing. If it doesn't exist, // subsequent operations can fail in different ways on different platforms. bool srcExists; - MOZ_TRY(aSourceFile->Exists(&srcExists)); + IOUTILS_TRY_WITH_CONTEXT( + aSourceFile->Exists(&srcExists), + "Could not copy `%s' to `%s': could not stat source file or directory", + aSourceFile->HumanReadablePath().get(), + aDestFile->HumanReadablePath().get()); + if (!srcExists) { return Err( - IOError(NS_ERROR_FILE_NOT_FOUND) - .WithMessage( - "Could not copy source file(%s) because it does not exist", - aSourceFile->HumanReadablePath().get())); + IOError(NS_ERROR_FILE_NOT_FOUND, + "Could not copy `%s' to `%s': source file does not exist", + aSourceFile->HumanReadablePath().get(), + aDestFile->HumanReadablePath().get())); } // If source is a directory, fail immediately unless the recursive option is // true. bool srcIsDir = false; - MOZ_TRY(aSourceFile->IsDirectory(&srcIsDir)); + IOUTILS_TRY_WITH_CONTEXT( + aSourceFile->IsDirectory(&srcIsDir), + "Could not copy `%s' to `%s': could not stat source file or directory", + aSourceFile->HumanReadablePath().get(), + aDestFile->HumanReadablePath().get()); + if (srcIsDir && !aRecursive) { - return Err( - IOError(NS_ERROR_FILE_COPY_OR_MOVE_FAILED) - .WithMessage( - "Refused to copy source directory(%s) to the destination(%s)\n" - "Specify the `recursive: true` option to allow copying " - "directories", - aSourceFile->HumanReadablePath().get(), - aDestFile->HumanReadablePath().get())); + return Err(IOError(NS_ERROR_FILE_COPY_OR_MOVE_FAILED, + "Refused to copy directory `%s' to `%s': `recursive' is " + "false\n", + aSourceFile->HumanReadablePath().get(), + aDestFile->HumanReadablePath().get())); } return CopyOrMoveSync(&nsIFile::CopyToFollowingLinks, "copy", aSourceFile, @@ -1542,10 +1651,9 @@ Result IOUtils::CopyOrMoveSync(CopyOrMoveFn aMethod, if (NS_SUCCEEDED(rv) && destIsDir) { rv = (aSource->*aMethod)(aDest, u""_ns); if (NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not %s source file(%s) to destination directory(%s)", - aMethodName, aSource->HumanReadablePath().get(), - aDest->HumanReadablePath().get())); + return Err(IOError(rv, "Could not %s `%s' to `%s'", aMethodName, + aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get())); } return Ok(); } @@ -1554,7 +1662,9 @@ Result IOUtils::CopyOrMoveSync(CopyOrMoveFn aMethod, if (!IsFileNotFound(rv)) { // It's ok if the dest file doesn't exist. Case 2 handles this below. // Bail out early for any other kind of error though. - return Err(IOError(rv)); + return Err(IOError(rv, "Could not %s `%s' to `%s'", aMethodName, + aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get())); } destExists = false; } @@ -1564,37 +1674,41 @@ Result IOUtils::CopyOrMoveSync(CopyOrMoveFn aMethod, // If the destination exists and the source is not a regular file, // then this may fail. if (aNoOverwrite && destExists) { - return Err( - IOError(NS_ERROR_FILE_ALREADY_EXISTS) - .WithMessage( - "Could not %s source file(%s) to destination(%s) because the " - "destination already exists and overwrites are not allowed\n" - "Specify the `noOverwrite: false` option to mitigate this " - "error", - aMethodName, aSource->HumanReadablePath().get(), - aDest->HumanReadablePath().get())); + return Err(IOError(NS_ERROR_FILE_ALREADY_EXISTS, + "Could not %s `%s' to `%s': destination file exists and " + "`noOverwrite' is true", + aMethodName, aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get())); } if (destExists && !destIsDir) { // If the source file is a directory, but the target is a file, abort early. // Different implementations of |CopyTo| and |MoveTo| seem to handle this // error case differently (or not at all), so we explicitly handle it here. bool srcIsDir = false; - MOZ_TRY(aSource->IsDirectory(&srcIsDir)); + IOUTILS_TRY_WITH_CONTEXT( + aSource->IsDirectory(&srcIsDir), + "Could not %s `%s' to `%s': could not stat source file or directory", + aMethodName, aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get()); if (srcIsDir) { - return Err(IOError(NS_ERROR_FILE_DESTINATION_NOT_DIR) - .WithMessage("Could not %s the source directory(%s) to " - "the destination(%s) because the destination " - "is not a directory", - aMethodName, - aSource->HumanReadablePath().get(), - aDest->HumanReadablePath().get())); + return Err(IOError( + NS_ERROR_FILE_DESTINATION_NOT_DIR, + "Could not %s directory `%s' to `%s': destination is not a directory", + aMethodName, aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get())); } } - nsCOMPtr destDir; + // We would have already thrown if the path was zero-length. nsAutoString destName; - MOZ_TRY(aDest->GetLeafName(destName)); - MOZ_TRY(aDest->GetParent(getter_AddRefs(destDir))); + MOZ_ALWAYS_SUCCEEDS(aDest->GetLeafName(destName)); + + nsCOMPtr destDir; + IOUTILS_TRY_WITH_CONTEXT( + aDest->GetParent(getter_AddRefs(destDir)), + "Could not %s `%s` to `%s': path `%s' does not have a parent", + aMethodName, aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get(), aDest->HumanReadablePath().get()); // We know `destName` is a file and therefore must have a parent directory. MOZ_RELEASE_ASSERT(destDir); @@ -1603,9 +1717,9 @@ Result IOUtils::CopyOrMoveSync(CopyOrMoveFn aMethod, // |MoveToFollowingLinks| will create it. rv = (aSource->*aMethod)(destDir, destName); if (NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not %s the source file(%s) to the destination(%s)", aMethodName, - aSource->HumanReadablePath().get(), aDest->HumanReadablePath().get())); + return Err(IOError(rv, "Could not %s `%s' to `%s'", aMethodName, + aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get())); } return Ok(); } @@ -1625,32 +1739,35 @@ Result IOUtils::RemoveSync(nsIFile* aFile, return Ok(); } if (NS_FAILED(rv)) { - IOError err(rv); if (IsFileNotFound(rv)) { - return Err(err.WithMessage( - "Could not remove the file at %s because it does not exist.\n" - "Specify the `ignoreAbsent: true` option to mitigate this error", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not remove `%s': file does not exist", + aFile->HumanReadablePath().get())); } if (rv == NS_ERROR_FILE_DIR_NOT_EMPTY) { - return Err(err.WithMessage( - "Could not remove the non-empty directory at %s.\n" - "Specify the `recursive: true` option to mitigate this error", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, + "Could not remove `%s': the directory is not empty", + aFile->HumanReadablePath().get())); } #ifdef XP_WIN if (rv == NS_ERROR_FILE_ACCESS_DENIED && aRetryReadonly) { - MOZ_TRY(SetWindowsAttributesSync(aFile, 0, FILE_ATTRIBUTE_READONLY)); + if (auto result = + SetWindowsAttributesSync(aFile, 0, FILE_ATTRIBUTE_READONLY); + result.isErr()) { + return Err(IOError::WithCause( + result.unwrapErr(), + "Could not remove `%s': could not clear readonly attribute", + aFile->HumanReadablePath().get())); + } return RemoveSync(aFile, aIgnoreAbsent, aRecursive, /* aRetryReadonly = */ false); } #endif - return Err(err.WithMessage("Could not remove the file at %s", - aFile->HumanReadablePath().get())); + return Err( + IOError(rv, "Could not remove `%s'", aFile->HumanReadablePath().get())); } return Ok(); } @@ -1663,7 +1780,10 @@ Result IOUtils::MakeDirectorySync(nsIFile* aFile, MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr parent; - MOZ_TRY(aFile->GetParent(getter_AddRefs(parent))); + IOUTILS_TRY_WITH_CONTEXT( + aFile->GetParent(getter_AddRefs(parent)), + "Could not make directory `%s': could not get parent directory", + aFile->HumanReadablePath().get()); if (!parent) { // If we don't have a parent directory, we were called with a // root directory. If the directory doesn't already exist (e.g., asking @@ -1677,7 +1797,11 @@ Result IOUtils::MakeDirectorySync(nsIFile* aFile, // Otherwise, we fall through to `nsiFile::Create()` and let it fail there // instead. bool exists = false; - MOZ_TRY(aFile->Exists(&exists)); + IOUTILS_TRY_WITH_CONTEXT( + aFile->Exists(&exists), + "Could not make directory `%s': could not stat file or directory", + aFile->HumanReadablePath().get()); + if (exists) { return Ok(); } @@ -1692,13 +1816,16 @@ Result IOUtils::MakeDirectorySync(nsIFile* aFile, // an existing file, since trying to create a directory where a regular // file exists may be indicative of a logic error. bool isDirectory; - MOZ_TRY(aFile->IsDirectory(&isDirectory)); + IOUTILS_TRY_WITH_CONTEXT( + aFile->IsDirectory(&isDirectory), + "Could not make directory `%s': could not stat file or directory", + aFile->HumanReadablePath().get()); + if (!isDirectory) { - return Err(IOError(NS_ERROR_FILE_NOT_DIRECTORY) - .WithMessage("Could not create directory because the " - "target file(%s) exists " - "and is not a directory", - aFile->HumanReadablePath().get())); + return Err(IOError(NS_ERROR_FILE_NOT_DIRECTORY, + "Could not create directory `%s': file exists and " + "is not a directory", + aFile->HumanReadablePath().get())); } // The directory exists. // The caller may suppress this error. @@ -1706,14 +1833,12 @@ Result IOUtils::MakeDirectorySync(nsIFile* aFile, return Ok(); } // Otherwise, forward it. - return Err(IOError(rv).WithMessage( - "Could not create directory because it already exists at %s\n" - "Specify the `ignoreExisting: true` option to mitigate this " - "error", + return Err(IOError( + rv, "Could not create directory `%s': directory already exists", aFile->HumanReadablePath().get())); } - return Err(IOError(rv).WithMessage("Could not create directory at %s", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not create directory `%s'", + aFile->HumanReadablePath().get())); } return Ok(); } @@ -1731,26 +1856,27 @@ Result IOUtils::StatSync( // Any subsequent errors are unexpected and will just be forwarded. nsresult rv = aFile->IsFile(&isRegular); if (NS_FAILED(rv)) { - IOError err(rv); if (IsFileNotFound(rv)) { - return Err( - err.WithMessage("Could not stat file(%s) because it does not exist", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not stat `%s': file does not exist", + aFile->HumanReadablePath().get())); } - return Err(err); + return Err( + IOError(rv, "Could not stat `%s'", aFile->HumanReadablePath().get())); } // Now we can populate the info object by querying the file. info.mType = FileType::Regular; if (!isRegular) { bool isDir = false; - MOZ_TRY(aFile->IsDirectory(&isDir)); + IOUTILS_TRY_WITH_CONTEXT(aFile->IsDirectory(&isDir), "Could not stat `%s'", + aFile->HumanReadablePath().get()); info.mType = isDir ? FileType::Directory : FileType::Other; } int64_t size = -1; if (info.mType == FileType::Regular) { - MOZ_TRY(aFile->GetFileSize(&size)); + IOUTILS_TRY_WITH_CONTEXT(aFile->GetFileSize(&size), "Could not stat `%s'", + aFile->HumanReadablePath().get()); } info.mSize = size; @@ -1759,18 +1885,27 @@ Result IOUtils::StatSync( info.mCreationTime.emplace(static_cast(creationTime)); } else if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) { // This field is only supported on some platforms. - return Err(IOError(rv)); + return Err( + IOError(rv, "Could not stat `%s'", aFile->HumanReadablePath().get())); } PRTime lastAccessed = 0; - MOZ_TRY(aFile->GetLastAccessedTime(&lastAccessed)); + IOUTILS_TRY_WITH_CONTEXT(aFile->GetLastAccessedTime(&lastAccessed), + "Could not stat `%s'", + aFile->HumanReadablePath().get()); + info.mLastAccessed = static_cast(lastAccessed); PRTime lastModified = 0; - MOZ_TRY(aFile->GetLastModifiedTime(&lastModified)); + IOUTILS_TRY_WITH_CONTEXT(aFile->GetLastModifiedTime(&lastModified), + "Could not stat `%s'", + aFile->HumanReadablePath().get()); + info.mLastModified = static_cast(lastModified); - MOZ_TRY(aFile->GetPermissions(&info.mPermissions)); + IOUTILS_TRY_WITH_CONTEXT(aFile->GetPermissions(&info.mPermissions), + "Could not stat `%s'", + aFile->HumanReadablePath().get()); return info; } @@ -1788,26 +1923,23 @@ Result IOUtils::SetTimeSync( // If it ever becomes possible to set a file time to 0, this check should be // removed, though this use case seems rare. if (aNewTime == 0) { - return Err( - IOError(NS_ERROR_ILLEGAL_VALUE) - .WithMessage( - "Refusing to set the modification time of file(%s) to 0.\n" - "To use the current system time, call `setModificationTime` " - "with no arguments", - aFile->HumanReadablePath().get())); + return Err(IOError( + NS_ERROR_ILLEGAL_VALUE, + "Refusing to set modification time of `%s' to 0: to use the current " + "system time, call `setModificationTime' with no arguments", + aFile->HumanReadablePath().get())); } nsresult rv = (aFile->*aSetTimeFn)(aNewTime); if (NS_FAILED(rv)) { - IOError err(rv); if (IsFileNotFound(rv)) { - return Err( - err.WithMessage("Could not set modification time of file(%s) " - "because it does not exist", - aFile->HumanReadablePath().get())); + return Err(IOError( + rv, "Could not set modification time of `%s': file does not exist", + aFile->HumanReadablePath().get())); } - return Err(err); + return Err(IOError(rv, "Could not set modification time of `%s'", + aFile->HumanReadablePath().get())); } return aNewTime; } @@ -1824,31 +1956,43 @@ Result, IOUtils::IOError> IOUtils::GetChildrenSync( return children; } if (NS_FAILED(rv)) { - IOError err(rv); if (IsFileNotFound(rv)) { - return Err(err.WithMessage( - "Could not get children of file(%s) because it does not exist", + return Err(IOError( + rv, "Could not get children of `%s': directory does not exist", aFile->HumanReadablePath().get())); } if (IsNotDirectory(rv)) { - return Err(err.WithMessage( - "Could not get children of file(%s) because it is not a directory", - aFile->HumanReadablePath().get())); + return Err( + IOError(rv, "Could not get children of `%s': file is not a directory", + aFile->HumanReadablePath().get())); } - return Err(err); + return Err(IOError(rv, "Could not get children of `%s'", + aFile->HumanReadablePath().get())); } bool hasMoreElements = false; - MOZ_TRY(iter->HasMoreElements(&hasMoreElements)); + IOUTILS_TRY_WITH_CONTEXT( + iter->HasMoreElements(&hasMoreElements), + "Could not get children of `%s': could not iterate children", + aFile->HumanReadablePath().get()); + while (hasMoreElements) { nsCOMPtr child; - MOZ_TRY(iter->GetNextFile(getter_AddRefs(child))); + IOUTILS_TRY_WITH_CONTEXT( + iter->GetNextFile(getter_AddRefs(child)), + "Could not get children of `%s': could not retrieve child file", + aFile->HumanReadablePath().get()); + if (child) { nsString path; - MOZ_TRY(child->GetPath(path)); + MOZ_ALWAYS_SUCCEEDS(child->GetPath(path)); children.AppendElement(path); } - MOZ_TRY(iter->HasMoreElements(&hasMoreElements)); + + IOUTILS_TRY_WITH_CONTEXT( + iter->HasMoreElements(&hasMoreElements), + "Could not get children of `%s': could not iterate children", + aFile->HumanReadablePath().get()); } return children; @@ -1859,7 +2003,10 @@ Result IOUtils::SetPermissionsSync( nsIFile* aFile, const uint32_t aPermissions) { MOZ_ASSERT(!NS_IsMainThread()); - MOZ_TRY(aFile->SetPermissions(aPermissions)); + IOUTILS_TRY_WITH_CONTEXT(aFile->SetPermissions(aPermissions), + "Could not set permissions on `%s'", + aFile->HumanReadablePath().get()); + return Ok{}; } @@ -1868,7 +2015,8 @@ Result IOUtils::ExistsSync(nsIFile* aFile) { MOZ_ASSERT(!NS_IsMainThread()); bool exists = false; - MOZ_TRY(aFile->Exists(&exists)); + IOUTILS_TRY_WITH_CONTEXT(aFile->Exists(&exists), "Could not stat `%s'", + aFile->HumanReadablePath().get()); return exists; } @@ -1880,7 +2028,13 @@ Result IOUtils::CreateUniqueSync( if (nsresult rv = aFile->CreateUnique(aFileType, aPermissions); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage("Could not create unique path")); + nsCOMPtr aParent = nullptr; + MOZ_ALWAYS_SUCCEEDS(aFile->GetParent(getter_AddRefs(aParent))); + MOZ_RELEASE_ASSERT(aParent); + return Err( + IOError(rv, "Could not create unique %s in `%s'", + aFileType == nsIFile::NORMAL_FILE_TYPE ? "file" : "directory", + aParent->HumanReadablePath().get())); } nsString path; @@ -1914,24 +2068,25 @@ Result IOUtils::ComputeHexDigestSync( Digest digest; if (nsresult rv = digest.Begin(alg); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage("Could not hash file at %s", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not hash `%s': could not create digest", + aFile->HumanReadablePath().get())); } RefPtr stream; if (nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), aFile); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage("Could not open the file at %s", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not hash `%s': could not open for reading", + aFile->HumanReadablePath().get())); } char buffer[BUFFER_SIZE]; uint32_t read = 0; for (;;) { if (nsresult rv = stream->Read(buffer, BUFFER_SIZE, &read); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Encountered an unexpected error while reading file(%s)", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, + "Could not hash `%s': encountered an unexpected error " + "while reading file", + aFile->HumanReadablePath().get())); } if (read == 0) { break; @@ -1940,20 +2095,22 @@ Result IOUtils::ComputeHexDigestSync( if (nsresult rv = digest.Update(reinterpret_cast(buffer), read); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage("Could not hash file at %s", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not hash `%s': could not update digest", + aFile->HumanReadablePath().get())); } } AutoTArray rawDigest; if (nsresult rv = digest.End(rawDigest); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage("Could not hash file at %s", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not hash `%s': could not compute digest", + aFile->HumanReadablePath().get())); } nsCString hexDigest; if (!hexDigest.SetCapacity(2 * rawDigest.Length(), fallible)) { - return Err(IOError(NS_ERROR_OUT_OF_MEMORY)); + return Err(IOError(NS_ERROR_OUT_OF_MEMORY, + "Could not hash `%s': out of memory", + aFile->HumanReadablePath().get())); } const char HEX[] = "0123456789abcdef"; @@ -1977,9 +2134,8 @@ Result IOUtils::GetWindowsAttributesSync( MOZ_ASSERT(file); if (nsresult rv = file->GetWindowsFileAttributes(&attrs); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not get Windows file attributes for the file at `%s'", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not get Windows file attributes for `%s'", + aFile->HumanReadablePath().get())); } return attrs; } @@ -1993,9 +2149,8 @@ Result IOUtils::SetWindowsAttributesSync( if (nsresult rv = file->SetWindowsFileAttributes(aSetAttrs, aClearAttrs); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not set Windows file attributes for the file at `%s'", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not set Windows file attributes for `%s'", + aFile->HumanReadablePath().get())); } return Ok{}; @@ -2013,9 +2168,8 @@ Result IOUtils::HasMacXAttrSync( bool hasAttr = false; if (nsresult rv = file->HasXAttr(aAttr, &hasAttr); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not read the extended attribute `%s' from the file `%s'", - aAttr.get(), aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not read extended attribute `%s' from `%s'", + aAttr.get(), aFile->HumanReadablePath().get())); } return hasAttr; @@ -2031,17 +2185,15 @@ Result, IOUtils::IOError> IOUtils::GetMacXAttrSync( nsTArray value; if (nsresult rv = file->GetXAttr(aAttr, value); NS_FAILED(rv)) { - auto err = IOError(rv); - if (rv == NS_ERROR_NOT_AVAILABLE) { - return Err(err.WithMessage( - "The file `%s' does not have an extended attribute `%s'", - aFile->HumanReadablePath().get(), aAttr.get())); + return Err(IOError(rv, + "Could not get extended attribute `%s' from `%s': the " + "file does not have the attribute", + aAttr.get(), aFile->HumanReadablePath().get())); } - return Err(err.WithMessage( - "Could not read the extended attribute `%s' from the file `%s'", - aAttr.get(), aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not read extended attribute `%s' from `%s'", + aAttr.get(), aFile->HumanReadablePath().get())); } return value; @@ -2056,9 +2208,8 @@ Result IOUtils::SetMacXAttrSync( MOZ_ASSERT(file); if (nsresult rv = file->SetXAttr(aAttr, aValue); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not set extended attribute `%s' on file `%s'", aAttr.get(), - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not set extended attribute `%s' on `%s'", + aAttr.get(), aFile->HumanReadablePath().get())); } return Ok{}; @@ -2073,17 +2224,15 @@ Result IOUtils::DelMacXAttrSync(nsIFile* aFile, MOZ_ASSERT(file); if (nsresult rv = file->DelXAttr(aAttr); NS_FAILED(rv)) { - auto err = IOError(rv); - if (rv == NS_ERROR_NOT_AVAILABLE) { - return Err(err.WithMessage( - "The file `%s' does not have an extended attribute `%s'", - aFile->HumanReadablePath().get(), aAttr.get())); + return Err(IOError(rv, + "Could not delete extended attribute `%s' from " + "`%s': the file does not have the attribute", + aAttr.get(), aFile->HumanReadablePath().get())); } - return Err(IOError(rv).WithMessage( - "Could not delete extended attribute `%s' on file `%s'", aAttr.get(), - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not delete extended attribute `%s' from `%s'", + aAttr.get(), aFile->HumanReadablePath().get())); } return Ok{}; @@ -2374,8 +2523,8 @@ Result, IOUtils::IOError> IOUtils::MozLZ4::Compress( size_t worstCaseSize = Compression::LZ4::maxCompressedSize(aUncompressed.Length()) + HEADER_SIZE; if (!result.SetCapacity(worstCaseSize, fallible)) { - return Err(IOError(NS_ERROR_OUT_OF_MEMORY) - .WithMessage("Could not allocate buffer to compress data")); + return Err(IOError(NS_ERROR_OUT_OF_MEMORY, + "could not allocate buffer to compress data"_ns)); } result.AppendElements(Span(MAGIC_NUMBER.data(), MAGIC_NUMBER.size())); std::array contentSizeBytes{}; @@ -2394,8 +2543,7 @@ Result, IOUtils::IOError> IOUtils::MozLZ4::Compress( aUncompressed.Length(), reinterpret_cast(result.Elements()) + HEADER_SIZE); if (!compressed) { - return Err( - IOError(NS_ERROR_UNEXPECTED).WithMessage("Could not compress data")); + return Err(IOError(NS_ERROR_UNEXPECTED, "could not compress data"_ns)); } result.SetLength(HEADER_SIZE + compressed); return result; @@ -2405,10 +2553,8 @@ Result, IOUtils::IOError> IOUtils::MozLZ4::Compress( Result IOUtils::MozLZ4::Decompress( Span aFileContents, IOUtils::BufferKind aBufferKind) { if (aFileContents.LengthBytes() < HEADER_SIZE) { - return Err( - IOError(NS_ERROR_FILE_CORRUPTED) - .WithMessage( - "Could not decompress file because the buffer is too short")); + return Err(IOError(NS_ERROR_FILE_CORRUPTED, + "could not decompress file: buffer is too small"_ns)); } auto header = aFileContents.To(HEADER_SIZE); if (!std::equal(std::begin(MAGIC_NUMBER), std::end(MAGIC_NUMBER), @@ -2420,10 +2566,10 @@ Result IOUtils::MozLZ4::Decompress( } magicStr.AppendPrintf("%02X", header.at(i)); - return Err(IOError(NS_ERROR_FILE_CORRUPTED) - .WithMessage("Could not decompress file because it has an " - "invalid LZ4 header (wrong magic number: '%s')", - magicStr.get())); + return Err(IOError(NS_ERROR_FILE_CORRUPTED, + "could not decompress file: invalid LZ4 header: wrong " + "magic number: `%s'", + magicStr.get())); } size_t numBytes = sizeof(uint32_t); Span sizeBytes = header.Last(numBytes); @@ -2435,7 +2581,9 @@ Result IOUtils::MozLZ4::Decompress( auto contents = aFileContents.From(HEADER_SIZE); auto result = JsBuffer::Create(aBufferKind, expectedDecompressedSize); if (result.isErr()) { - return result.propagateErr(); + return Err(IOError::WithCause( + result.unwrapErr(), + "could not decompress file: could not allocate buffer"_ns)); } JsBuffer decompressed = result.unwrap(); @@ -2445,9 +2593,8 @@ Result IOUtils::MozLZ4::Decompress( reinterpret_cast(decompressed.Elements()), expectedDecompressedSize, &actualSize)) { return Err( - IOError(NS_ERROR_FILE_CORRUPTED) - .WithMessage( - "Could not decompress file contents, the file may be corrupt")); + IOError(NS_ERROR_FILE_CORRUPTED, + "could not decompress file: the file may be corrupt"_ns)); } decompressed.SetLength(actualSize); return decompressed; @@ -2583,8 +2730,8 @@ IOUtils::InternalWriteOpts::FromBinding(const WriteOptions& aOptions) { if (nsresult rv = PathUtils::InitFileWithPath(opts.mBackupFile, aOptions.mBackupFile.Value()); NS_FAILED(rv)) { - return Err(IOUtils::IOError(rv).WithMessage( - "Could not parse path of backupFile (%s)", + return Err(IOUtils::IOError( + rv, "Could not parse path of backupFile `%s'", NS_ConvertUTF16toUTF8(aOptions.mBackupFile.Value()).get())); } } @@ -2594,8 +2741,8 @@ IOUtils::InternalWriteOpts::FromBinding(const WriteOptions& aOptions) { if (nsresult rv = PathUtils::InitFileWithPath(opts.mTmpFile, aOptions.mTmpPath.Value()); NS_FAILED(rv)) { - return Err(IOUtils::IOError(rv).WithMessage( - "Could not parse path of temp file (%s)", + return Err(IOUtils::IOError( + rv, "Could not parse path of temp file `%s'", NS_ConvertUTF16toUTF8(aOptions.mTmpPath.Value()).get())); } } @@ -2609,8 +2756,7 @@ Result IOUtils::JsBuffer::Create( IOUtils::BufferKind aBufferKind, size_t aCapacity) { JsBuffer buffer(aBufferKind, aCapacity); if (aCapacity != 0 && !buffer.mBuffer) { - return Err(IOError(NS_ERROR_OUT_OF_MEMORY) - .WithMessage("Could not allocate buffer")); + return Err(IOError(NS_ERROR_OUT_OF_MEMORY, "Could not allocate buffer"_ns)); } return buffer; } @@ -2787,8 +2933,8 @@ void SyncReadFile::ReadBytesInto(const Uint8Array& aDestArray, } if (nsresult rv = mStream->Seek(PR_SEEK_SET, aOffset); NS_FAILED(rv)) { - return aRv.ThrowOperationError( - FormatErrorMessage(rv, "Could not seek to position %lld", aOffset)); + return aRv.ThrowOperationError(FormatErrorMessage( + rv, "Could not seek to position %" PRId64, aOffset)); } Span toRead = AsWritableChars(aData); @@ -2805,7 +2951,8 @@ void SyncReadFile::ReadBytesInto(const Uint8Array& aDestArray, &bytesRead); NS_FAILED(rv)) { return aRv.ThrowOperationError(FormatErrorMessage( - rv, "Encountered an unexpected error while reading file stream")); + rv, + "Encountered an unexpected error while reading file stream"_ns)); } if (bytesRead == 0) { return aRv.ThrowOperationError( @@ -2896,3 +3043,4 @@ uint32_t IOUtils::LaunchProcess(GlobalObject& aGlobal, } // namespace mozilla::dom #undef REJECT_IF_INIT_PATH_FAILED +#undef IOUTILS_TRY_WITH_CONTEXT diff --git a/dom/system/IOUtils.h b/dom/system/IOUtils.h index 82ea30eaa8..6acfcbfb24 100644 --- a/dom/system/IOUtils.h +++ b/dom/system/IOUtils.h @@ -69,8 +69,8 @@ class IOUtils final { }; template - using PhaseArray = - EnumeratedArray; + using PhaseArray = EnumeratedArray; static already_AddRefed Read(GlobalObject& aGlobal, const nsAString& aPath, @@ -148,6 +148,7 @@ class IOUtils final { const nsAString& aPath, const Optional& aNewTime, SetTimeFn aSetTimeFn, + const char* const aTimeKind, ErrorResult& aError); public: @@ -653,23 +654,34 @@ class IOUtils::EventQueue final { */ class IOUtils::IOError { public: - MOZ_IMPLICIT IOError(nsresult aCode) : mCode(aCode), mMessage(Nothing()) {} - - /** - * Replaces the message associated with this error. - */ - template - IOError WithMessage(const char* const aMessage, Args... aArgs) { - mMessage.emplace(nsPrintfCString(aMessage, aArgs...)); - return *this; + IOError(nsresult aCode, const nsCString& aMsg) + : mCode(aCode), mMessage(aMsg) {} + + IOError(nsresult aCode, const char* const aFmt, ...) MOZ_FORMAT_PRINTF(3, 4) + : mCode(aCode) { + va_list ap; + va_start(ap, aFmt); + mMessage.AppendVprintf(aFmt, ap); + va_end(ap); } - IOError WithMessage(const char* const aMessage) { - mMessage.emplace(nsCString(aMessage)); - return *this; + + static IOError WithCause(const IOError& aCause, const nsCString& aMsg) { + IOError e(aCause.mCode, aMsg); + e.mMessage.AppendPrintf(": %s", aCause.mMessage.get()); + return e; } - IOError WithMessage(const nsCString& aMessage) { - mMessage.emplace(aMessage); - return *this; + + static IOError WithCause(const IOError& aCause, const char* const aFmt, ...) + MOZ_FORMAT_PRINTF(2, 3) { + va_list ap; + va_start(ap, aFmt); + + IOError e(aCause.mCode, EmptyCString()); + e.mMessage.AppendVprintf(aFmt, ap); + e.mMessage.AppendPrintf(": %s", aCause.mMessage.get()); + + va_end(ap); + return e; } /** @@ -678,13 +690,13 @@ class IOUtils::IOError { nsresult Code() const { return mCode; } /** - * Maybe returns a message associated with this error. + * Returns the message associated with this error. */ - const Maybe& Message() const { return mMessage; } + const nsCString& Message() const { return mMessage; } private: nsresult mCode; - Maybe mMessage; + nsCString mMessage; }; /** diff --git a/dom/system/NetworkGeolocationProvider.sys.mjs b/dom/system/NetworkGeolocationProvider.sys.mjs index 1bee69a282..2e929c066f 100644 --- a/dom/system/NetworkGeolocationProvider.sys.mjs +++ b/dom/system/NetworkGeolocationProvider.sys.mjs @@ -391,7 +391,7 @@ NetworkGeolocationProvider.prototype = { } }, - notify(timer) { + notify() { this.onStatus(false, "wifi-timeout"); this.sendLocationRequest(null); }, diff --git a/dom/system/PathUtils.h b/dom/system/PathUtils.h index ff01ddfc1e..1870d92f23 100644 --- a/dom/system/PathUtils.h +++ b/dom/system/PathUtils.h @@ -241,7 +241,8 @@ class PathUtils::DirectoryCache final { void ResolveWithDirectory(Promise* aPromise, const Directory aRequestedDir); template - using DirectoryArray = EnumeratedArray; + using DirectoryArray = + EnumeratedArray; DirectoryArray mDirectories; DirectoryArray> mPromises; diff --git a/dom/system/tests/ioutils/file_ioutils_worker.js b/dom/system/tests/ioutils/file_ioutils_worker.js index e367eb4d99..f8cf286f8e 100644 --- a/dom/system/tests/ioutils/file_ioutils_worker.js +++ b/dom/system/tests/ioutils/file_ioutils_worker.js @@ -14,7 +14,7 @@ importScripts("chrome://mochikit/content/tests/SimpleTest/WorkerSimpleTest.js"); importScripts("file_ioutils_test_fixtures.js"); -self.onmessage = async function (msg) { +self.onmessage = async function () { const tmpDir = await PathUtils.getTempDir(); // IOUtils functionality is the same when called from the main thread, or a diff --git a/dom/system/tests/ioutils/test_ioutils_copy_move.html b/dom/system/tests/ioutils/test_ioutils_copy_move.html index 408bb82f39..0761447bc6 100644 --- a/dom/system/tests/ioutils/test_ioutils_copy_move.html +++ b/dom/system/tests/ioutils/test_ioutils_copy_move.html @@ -24,7 +24,7 @@ info("Test moving a file to a relative destination"); await Assert.rejects( IOUtils.move(tmpFileName, dest), - /Could not parse path/, + /OperationError: Could not move `.*' to `.*': could not parse path \(NS_ERROR_FILE_UNRECOGNIZED_PATH\)/, "IOUtils::move only works with absolute paths" ); ok( @@ -56,7 +56,7 @@ // Test. await Assert.rejects( IOUtils.move(tmpFileName, destFileName, { noOverwrite: true }), - /Could not move source file\(.*\) to destination\(.*\) because the destination already exists and overwrites are not allowed/, + /Could not move `.*' to `.*': destination file exists and `noOverwrite' is true/, "IOUtils::move will refuse to move a file if overwrites are disabled" ); ok( @@ -161,7 +161,7 @@ // Test. await Assert.rejects( IOUtils.move(notExistsSrc, notExistsDest), - /Could not move source file\(.*\) because it does not exist/, + /NotFoundError: Could not move `.*' to `.*': source file does not exist/, "IOUtils::move throws if source file does not exist" ); ok( @@ -178,7 +178,7 @@ // Test. await Assert.rejects( IOUtils.move(srcDir, destFile), - /Could not move the source directory\(.*\) to the destination\(.*\) because the destination is not a directory/, + /InvalidAccessError: Could not move directory `.*' to `.*': destination is not a directory/, "IOUtils::move throws if try to move dir into an existing file" ); @@ -206,7 +206,7 @@ // Test. await Assert.rejects( IOUtils.copy(tmpFileName, destFileName, { noOverwrite: true }), - /Could not copy source file\(.*\) to destination\(.*\) because the destination already exists and overwrites are not allowed/, + /NoModificationAllowedError: Could not copy `.*' to `.*': destination file exists and `noOverwrite' is true/, "IOUtils::copy will refuse to copy to existing destination if overwrites are disabled" ); ok( @@ -311,7 +311,7 @@ // Test. await Assert.rejects( IOUtils.copy(notExistsSrc, notExistsDest), - /Could not copy source file\(.*\) because it does not exist/, + /NotFoundError: Could not copy `.*' to `.*': source file does not exist/, "IOUtils::copy throws if source file does not exist" ); ok( @@ -328,8 +328,8 @@ // Test. await Assert.rejects( IOUtils.copy(srcDir, destFile, { recursive: true }), - /Could not copy the source directory\(.*\) to the destination\(.*\) because the destination is not a directory/, - "IOUtils::copy throws if try to move dir into an existing file" + /InvalidAccessError: Could not copy directory `.*' to `.*': destination is not a directory/, + "IOUtils::copy throws when trying to move a directory into an existing file" ); ok(await fileHasTextContents(destFile, ""), "IOUtils::copy failure does not affect destination"); @@ -339,7 +339,7 @@ // Test. await Assert.rejects( IOUtils.copy(srcDir, notExistsDest, { recursive: false }), - /Refused to copy source directory\(.*\) to the destination\(.*\)/, + /OperationError: Refused to copy directory `.*' to `.*': `recursive' is false/, "IOUtils::copy throws if try to copy a directory with { recursive: false }" ); console.log(`${notExistsDest} exists?`, await IOUtils.exists(notExistsDest)) diff --git a/dom/system/tests/ioutils/test_ioutils_dir_iteration.html b/dom/system/tests/ioutils/test_ioutils_dir_iteration.html index 54168235b0..1e3653d876 100644 --- a/dom/system/tests/ioutils/test_ioutils_dir_iteration.html +++ b/dom/system/tests/ioutils/test_ioutils_dir_iteration.html @@ -21,7 +21,7 @@ await Assert.rejects( IOUtils.getChildren(notExists), - /Could not get children of file\(.*\) because it does not exist/, + /NotFoundError: Could not get children of `.*': directory does not exist/, "IOUtils::getChildren rejects if the file does not exist" ); ok(!await fileExists(notExists), `Expected ${notExists} not to exist`); @@ -31,7 +31,7 @@ let tmpFileName = PathUtils.join(PathUtils.tempDir, 'iterator_file.tmp'); await createFile(tmpFileName) await Assert.rejects(IOUtils.getChildren(tmpFileName), - /Could not get children of file\(.*\) because it is not a directory/, + /InvalidAccessError: Could not get children of `.*': file is not a directory/, "IOUtils::getChildren rejects if the file is not a dir" ); diff --git a/dom/system/tests/ioutils/test_ioutils_mac_xattr.html b/dom/system/tests/ioutils/test_ioutils_mac_xattr.html index 6af9b2e6f8..775490976e 100644 --- a/dom/system/tests/ioutils/test_ioutils_mac_xattr.html +++ b/dom/system/tests/ioutils/test_ioutils_mac_xattr.html @@ -36,7 +36,7 @@ info("Testing getting an attribute that does not exist"); await Assert.rejects( IOUtils.getMacXAttr(path, ATTR), - /NotFoundError: The file `.+' does not have an extended attribute/, + /NotFoundError: Could not get extended attribute `bogus.attr' from `.*': the file does not have the attribute/, "IOUtils::getMacXAttr rejects when the attribute does not exist" ); @@ -61,7 +61,7 @@ await IOUtils.delMacXAttr(path, ATTR); await Assert.rejects( IOUtils.getMacXAttr(path, ATTR), - /NotFoundError: The file `.+' does not have an extended attribute/, + /NotFoundError: Could not get extended attribute `bogus.attr' from `.*': the file does not have the attribute/, "IOUtils::delMacXAttr removes the attribute" ); @@ -73,7 +73,7 @@ info("Testing removing an attribute that does not exist"); await Assert.rejects( IOUtils.delMacXAttr(path, ATTR), - /NotFoundError: The file `.+' does not have an extended attribute/, + /NotFoundError: Could not delete extended attribute `bogus.attr' from `.*': the file does not have the attribute/, "IOUtils::delMacXAttr rejects when the attribute does not exist" ); diff --git a/dom/system/tests/ioutils/test_ioutils_mkdir.html b/dom/system/tests/ioutils/test_ioutils_mkdir.html index 6827b24cc6..e95873fd17 100644 --- a/dom/system/tests/ioutils/test_ioutils_mkdir.html +++ b/dom/system/tests/ioutils/test_ioutils_mkdir.html @@ -33,7 +33,7 @@ ); await Assert.rejects( IOUtils.makeDirectory(newDirectoryName, { ignoreExisting: false }), - /Could not create directory because it already exists at .*/, + /NoModificationAllowedError: Could not create directory `.*': directory already exists/, "IOUtils::makeDirectory can throw if the target dir exists" ) @@ -45,7 +45,7 @@ ); await Assert.rejects( IOUtils.makeDirectory(nestedDirName, { createAncestors: false }), - /Could not create directory at .*/, + /NotFoundError: Could not create directory `.*'/, "IOUtils::makeDirectory can fail if the target is missing parents" ); ok(!await IOUtils.exists(nestedDirName), `Expected ${nestedDirName} not to exist`); @@ -65,14 +65,14 @@ await Assert.rejects( IOUtils.makeDirectory(notADirFileName, { ignoreExisting: false }), - /Could not create directory because the target file\(.*\) exists and is not a directory/, + /InvalidAccessError: Could not create directory `.*': file exists and is not a directory/, "IOUtils::makeDirectory [ignoreExisting: false] throws when the target is an existing file" ); ok(await fileExists(notADirFileName), `Expected ${notADirFileName} to exist`); await Assert.rejects( IOUtils.makeDirectory(notADirFileName, { ignoreExisting: true }), - /Could not create directory because the target file\(.*\) exists and is not a directory/, + /InvalidAccessError: Could not create directory `.*': file exists and is not a directory/, "IOUtils::makeDirectory [ignoreExisting: true] throws when the target is an existing file" ); ok(await fileExists(notADirFileName), `Expected ${notADirFileName} to exist`); diff --git a/dom/system/tests/ioutils/test_ioutils_read_write.html b/dom/system/tests/ioutils/test_ioutils_read_write.html index 2243eb1eda..49232d464a 100644 --- a/dom/system/tests/ioutils/test_ioutils_read_write.html +++ b/dom/system/tests/ioutils/test_ioutils_read_write.html @@ -23,7 +23,7 @@ const doesNotExist = PathUtils.join(PathUtils.tempDir, "does_not_exist.tmp"); await Assert.rejects( IOUtils.read(doesNotExist), - /Could not open the file at .*/, + /NotFoundError: Could not open `.*': file does not exist/, "IOUtils::read rejects when file does not exist" ); }); @@ -46,7 +46,7 @@ IOUtils.write(tmpFileName, newContents, { mode: "create", }), - /Refusing to overwrite the file at */, + /NoModificationAllowedError: Could not write to `.*': refusing to overwrite file, `mode' is not "overwrite"/, "IOUtils::write rejects writing to existing file if overwrites are disabled" ); ok( @@ -285,7 +285,7 @@ info("Test writing a file at a relative destination"); await Assert.rejects( IOUtils.write(tmpFileName, bytes), - /Could not parse path/, + /OperationError: Could not write to `.*': could not parse path \(NS_ERROR_FILE_UNRECOGNIZED_PATH\)/, "IOUtils::write only works with absolute paths" ); }); @@ -296,8 +296,8 @@ info("Test reading a file at a relative destination"); await Assert.rejects( IOUtils.read(tmpFileName), - /Could not parse path/, - "IOUtils::write only works with absolute paths" + /OperationError: Could not read `.*': could not parse path \(NS_ERROR_FILE_UNRECOGNIZED_PATH\)/, + "IOUtils::read only works with absolute paths" ); }); @@ -348,7 +348,7 @@ is(bytesWritten, 64, "Expected to write 64 bytes"); await Assert.rejects( IOUtils.read(tmpFileName, { maxBytes: 4, decompress: true }), - /The `maxBytes` and `decompress` options are not compatible/, + /DataError: Could not read `.*': the `maxBytes' and `decompress' options are mutually exclusive/, "IOUtils::read rejects when maxBytes and decompress options are both used" ); @@ -364,17 +364,7 @@ await Assert.rejects( IOUtils.read(tmpFileName, { decompress: true }), - (actual) => { - is(actual.constructor, DOMException, - "rejection reason constructor for decompress with bad header"); - is(actual.name, "NotReadableError", - "rejection error name for decompress with bad header"); - ok(/Could not decompress file because it has an invalid LZ4 header \(wrong magic number: .*\)/ - .test(actual.message), - "rejection error message for decompress with bad header. Got " - + actual.message); - return true; - }, + /NotReadableError: Could not read `.*': could not decompress file: invalid LZ4 header: wrong magic number: `01 01 01 01 01 01 01 01 01 01 01 01' \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::read fails to decompress LZ4 data with a bad header" ); @@ -384,7 +374,7 @@ await Assert.rejects( IOUtils.read(tmpFileName, { decompress: true }), - /Could not decompress file because the buffer is too short/, + /NotReadableError: Could not read `.*': could not decompress file: buffer is too small \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::read fails to decompress LZ4 data with missing header" ); @@ -396,7 +386,7 @@ await Assert.rejects( IOUtils.read(tmpFileName, { decompress: true }), - /Could not decompress file contents, the file may be corrupt/, + /NotReadableError: Could not read `.*': could not decompress file: the file may be corrupt \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::read fails to read corrupt LZ4 contents with a correct header" ); @@ -411,11 +401,11 @@ await IOUtils.makeDirectory(fileName); await Assert.rejects( IOUtils.write(fileName, bytes), - /NotAllowedError: Could not open the file at .+ for writing/); + /NotAllowedError: Could not write to `.*': failed to open file for writing/); await Assert.rejects( IOUtils.write(fileName, bytes, { tmpPath }), - /NotAllowedError: Could not open the file at .+ for writing/); + /NotAllowedError: Could not write to `.*': file is a directory/); ok(!await IOUtils.exists(PathUtils.join(fileName, PathUtils.filename(tmpPath)))); }); @@ -509,7 +499,7 @@ await Assert.rejects( IOUtils.write(fileName, Uint8Array.of(5, 6, 7, 8, 9), { mode: "append" }), - /NotFoundError: Could not open the file at .*/ + /NotFoundError: Could not write to `.*': failed to open file for writing/ ); }); diff --git a/dom/system/tests/ioutils/test_ioutils_read_write_json.html b/dom/system/tests/ioutils/test_ioutils_read_write_json.html index 0acb191e1b..a85a0c19a1 100644 --- a/dom/system/tests/ioutils/test_ioutils_read_write_json.html +++ b/dom/system/tests/ioutils/test_ioutils_read_write_json.html @@ -77,7 +77,7 @@ ok(!await IOUtils.exists(notExistsFilename), `${notExistsFilename} should not exist`); await Assert.rejects( IOUtils.readJSON(notExistsFilename), - /NotFoundError: Could not open the file at/, + /NotFoundError: Could not open `.*'/, "IOUtils::readJSON rejects when file does not exist" ); @@ -149,7 +149,7 @@ await Assert.rejects( IOUtils.writeJSON(filename, OBJECT, {mode: "append"}), - /NotSupportedError: IOUtils.writeJSON does not support appending to files/, + /NotSupportedError: Could not write to `.*': IOUtils.writeJSON does not support appending to files/, "IOUtils.writeJSON() cannot append" ); diff --git a/dom/system/tests/ioutils/test_ioutils_read_write_utf8.html b/dom/system/tests/ioutils/test_ioutils_read_write_utf8.html index cdea016732..e1a1864656 100644 --- a/dom/system/tests/ioutils/test_ioutils_read_write_utf8.html +++ b/dom/system/tests/ioutils/test_ioutils_read_write_utf8.html @@ -26,7 +26,7 @@ const doesNotExist = PathUtils.join(PathUtils.tempDir, "does_not_exist.tmp"); await Assert.rejects( IOUtils.readUTF8(doesNotExist), - /Could not open the file at .*/, + /NotFoundError: Could not open `.*'/, "IOUtils::readUTF8 rejects when file does not exist" ); @@ -38,7 +38,7 @@ await Assert.rejects( IOUtils.readUTF8(invalidUTF8File), - /Could not read file\(.*\) because it is not UTF-8 encoded/, + /NotReadableError: Could not read `.*': file is not UTF-8 encoded/, "IOUtils::readUTF8 will reject when reading a file that is not valid UTF-8" ); @@ -56,7 +56,7 @@ IOUtils.writeUTF8(tmpFileName, newContents, { mode: "create", }), - /Refusing to overwrite the file at */, + /NoModificationAllowedError: Could not write to `.*': refusing to overwrite file, `mode' is not "overwrite"/, "IOUtils::writeUTF8 rejects writing to existing file if overwrites are disabled" ); ok( @@ -233,7 +233,7 @@ info("Test writing a file at a relative destination"); await Assert.rejects( IOUtils.writeUTF8(tmpFileName, "foo"), - /Could not parse path/, + /OperationError: Could not write to `.*': could not parse path \(NS_ERROR_FILE_UNRECOGNIZED_PATH\)/, "IOUtils::writeUTF8 only works with absolute paths" ); }); @@ -244,7 +244,7 @@ info("Test reading a file at a relative destination"); await Assert.rejects( IOUtils.readUTF8(tmpFileName), - /Could not parse path/, + /OperationError: Could not read `.*': could not parse path \(NS_ERROR_FILE_UNRECOGNIZED_PATH\)/, "IOUtils::readUTF8 only works with absolute paths" ); }); @@ -309,7 +309,7 @@ await Assert.rejects( IOUtils.readUTF8(tmpFileName, { decompress: true }), - /Could not decompress file because it has an invalid LZ4 header \(wrong magic number: .*\)/, + /NotReadableError: Could not read `.*': could not decompress file: invalid LZ4 header: wrong magic number: `01 01 01 01 01 01 01 01 01 01 01 01' \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::readUTF8 fails to decompress LZ4 data with a bad header" ); @@ -319,7 +319,7 @@ await Assert.rejects( IOUtils.readUTF8(tmpFileName, { decompress: true }), - /Could not decompress file because the buffer is too short/, + /NotReadableError: Could not read `.*': could not decompress file: buffer is too small \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::readUTF8 fails to decompress LZ4 data with missing header" ); @@ -331,7 +331,7 @@ await Assert.rejects( IOUtils.readUTF8(tmpFileName, { decompress: true }), - /Could not decompress file contents, the file may be corrupt/, + /NotReadableError: Could not read `.*': could not decompress file: the file may be corrupt \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::readUTF8 fails to read corrupt LZ4 contents with a correct header" ); @@ -342,7 +342,7 @@ } await Assert.rejects( IOUtils.readUTF8(tmpFileName, { decompress: true }), - /Could not decompress file because the buffer is too short/, + /NotReadableError: Could not read `.*': could not decompress file: buffer is too small \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::readUTF8 fails to decompress empty files" ); diff --git a/dom/system/tests/ioutils/test_ioutils_remove.html b/dom/system/tests/ioutils/test_ioutils_remove.html index f368fc09d3..1d860a7871 100644 --- a/dom/system/tests/ioutils/test_ioutils_remove.html +++ b/dom/system/tests/ioutils/test_ioutils_remove.html @@ -43,7 +43,7 @@ await Assert.rejects( IOUtils.remove(tmpFileName, { ignoreAbsent: false }), - /Could not remove the file at .* because it does not exist/, + /NotFoundError: Could not remove `.*': file does not exist/, "IOUtils::remove can throw an error when target file is missing" ); ok(!await fileExists(tmpFileName), `Expected file ${tmpFileName} not to exist`); @@ -69,7 +69,7 @@ await Assert.rejects( IOUtils.remove(tmpParentDir, { recursive: false }), - /Could not remove the non-empty directory at .*/, + /OperationError: Could not remove `.*': the directory is not empty/, "IOUtils::remove fails if non-recursively removing directory with contents" ); diff --git a/dom/system/tests/ioutils/test_ioutils_stat_set_modification_time.html b/dom/system/tests/ioutils/test_ioutils_stat_set_modification_time.html index e508817a41..8a5b521742 100644 --- a/dom/system/tests/ioutils/test_ioutils_stat_set_modification_time.html +++ b/dom/system/tests/ioutils/test_ioutils_stat_set_modification_time.html @@ -76,7 +76,7 @@ await Assert.rejects( IOUtils.stat(notExistsFile), - /Could not stat file\(.*\) because it does not exist/, + /NotFoundError: Could not stat `.*': file does not exist/, "IOUtils::stat throws if the target file does not exist" ); }); @@ -214,7 +214,7 @@ await Assert.rejects( IOUtils.setModificationTime(notExistsFile), - /Could not set modification time of file\(.*\) because it does not exist/, + /Could not set modification time of `.*': file does not exist/, "IOUtils::setModificationTime throws if the target file does not exist" ); @@ -224,7 +224,7 @@ await Assert.rejects( IOUtils.setModificationTime(tempFileName, 0), - /Refusing to set the modification time of file\(.*\) to 0/, + /DataError: Refusing to set modification time of `.*' to 0: to use the current system time, call `setModificationTime' with no arguments/, "IOUtils::setModificationTime cannot set the file modification time to Epoch" ); diff --git a/dom/system/tests/ioutils/test_ioutils_windows_file_attributes.html b/dom/system/tests/ioutils/test_ioutils_windows_file_attributes.html index a5b72bd078..00219fd6fb 100644 --- a/dom/system/tests/ioutils/test_ioutils_windows_file_attributes.html +++ b/dom/system/tests/ioutils/test_ioutils_windows_file_attributes.html @@ -48,7 +48,7 @@ await Assert.rejects( IOUtils.writeUTF8(filePath, "hello, world"), - /NotAllowedError: Could not open the file at .+ for writing/, + /NotAllowedError: Could not write to `.*': failed to open file for writing/, "IOUtils::writeUTF8 on a read-only file fails." ); diff --git a/dom/tests/browser/browser_ConsoleStorageAPITests.js b/dom/tests/browser/browser_ConsoleStorageAPITests.js index f28db48a91..ee3e9e3f52 100644 --- a/dom/tests/browser/browser_ConsoleStorageAPITests.js +++ b/dom/tests/browser/browser_ConsoleStorageAPITests.js @@ -28,14 +28,14 @@ add_task(async function () { var tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URI); var browser = gBrowser.selectedBrowser; - const windowId = await ContentTask.spawn(browser, null, async function (opt) { + const windowId = await ContentTask.spawn(browser, null, async function () { let ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService( Ci.nsIConsoleAPIStorage ); let observerPromise = new Promise(resolve => { let apiCallCount = 0; - function observe(aSubject) { + function observe() { apiCallCount++; info(`Received ${apiCallCount} console log events`); if (apiCallCount == 4) { diff --git a/dom/tests/browser/browser_ConsoleStoragePBTest_perwindowpb.js b/dom/tests/browser/browser_ConsoleStoragePBTest_perwindowpb.js index 38f85ef5b1..623e509702 100644 --- a/dom/tests/browser/browser_ConsoleStoragePBTest_perwindowpb.js +++ b/dom/tests/browser/browser_ConsoleStoragePBTest_perwindowpb.js @@ -33,7 +33,7 @@ function test() { function doTest(aIsPrivateMode, aWindow, aCallback) { BrowserTestUtils.browserLoaded(aWindow.gBrowser.selectedBrowser).then( () => { - function observe(aSubject) { + function observe() { afterEvents = ConsoleAPIStorage.getEvents(innerID); is( beforeEvents.length == afterEvents.length - 1, diff --git a/dom/tests/browser/browser_bug1004814.js b/dom/tests/browser/browser_bug1004814.js index 789709a8d7..eb2272285f 100644 --- a/dom/tests/browser/browser_bug1004814.js +++ b/dom/tests/browser/browser_bug1004814.js @@ -8,7 +8,7 @@ add_task(async function () { "http://example.com/browser/dom/tests/browser/test_bug1004814.html"; await BrowserTestUtils.withNewTab(TEST_URI, async aBrowser => { - let duration = await SpecialPowers.spawn(aBrowser, [], function (opts) { + let duration = await SpecialPowers.spawn(aBrowser, [], function () { const ConsoleAPIStorage = Cc[ "@mozilla.org/consoleAPI-storage;1" ].getService(Ci.nsIConsoleAPIStorage); diff --git a/dom/tests/browser/browser_bug1236512.js b/dom/tests/browser/browser_bug1236512.js index 66d58ab132..c7d9f14a66 100644 --- a/dom/tests/browser/browser_bug1236512.js +++ b/dom/tests/browser/browser_bug1236512.js @@ -42,7 +42,7 @@ async function waitContentVisibilityChange(aIsHidden, aBrowser) { content.document, "visibilitychange", true /* capture */, - aEvent => { + () => { info( `visibilitychange: ${content.document.hidden} ${content.document.visibilityState}` ); @@ -71,7 +71,7 @@ add_task(async function () { winTest, "resize", false, - e => { + () => { return winTest.innerHeight <= 500 && winTest.innerWidth <= 500; } ); diff --git a/dom/tests/browser/browser_bug1238427.js b/dom/tests/browser/browser_bug1238427.js index 60cb383e03..6e599b7b56 100644 --- a/dom/tests/browser/browser_bug1238427.js +++ b/dom/tests/browser/browser_bug1238427.js @@ -31,7 +31,7 @@ add_task(async function () { gBrowser, url: TEST_URI, }, - function (browser) { + function () { /* ... */ } ); diff --git a/dom/tests/browser/browser_bug1563629.js b/dom/tests/browser/browser_bug1563629.js index afbf5970d0..b5637ac84d 100644 --- a/dom/tests/browser/browser_bug1563629.js +++ b/dom/tests/browser/browser_bug1563629.js @@ -10,7 +10,7 @@ const URL1 = `https://example.com/${PATH}`; const URL2 = `https://example.org/${PATH}`; function listenForCrash(win) { - function listener(event) { + function listener() { ok(false, "a crash occurred"); } diff --git a/dom/tests/browser/browser_form_associated_custom_elements_validity.js b/dom/tests/browser/browser_form_associated_custom_elements_validity.js index 3765405735..da7c1ed263 100644 --- a/dom/tests/browser/browser_form_associated_custom_elements_validity.js +++ b/dom/tests/browser/browser_form_associated_custom_elements_validity.js @@ -109,3 +109,50 @@ add_task(async function form_report_validity() { } ); }); + +add_task(async function no_validation_anchor() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: `data:text/html,custom elements`, + }, + async function (aBrowser) { + let promisePopupShown = BrowserTestUtils.waitForEvent( + window, + "popupshown" + ); + + let message = "valueMissing message"; + await SpecialPowers.spawn(aBrowser, [message], function (aMessage) { + class MyControl extends content.HTMLElement { + static get formAssociated() { + return true; + } + constructor() { + super(); + let internals = this.attachInternals(); + internals.setValidity({ valueMissing: true }, aMessage); + internals.reportValidity(); + } + } + content.customElements.define("my-control", MyControl); + + let myControl = content.document.querySelector("my-control"); + content.customElements.upgrade(myControl); + }); + await promisePopupShown; + + let invalidFormPopup = + window.document.getElementById("invalid-form-popup"); + is(invalidFormPopup.state, "open", "invalid-form-popup should be opened"); + is(invalidFormPopup.firstChild.textContent, message, "check message"); + + let promisePopupHidden = BrowserTestUtils.waitForEvent( + invalidFormPopup, + "popuphidden" + ); + invalidFormPopup.hidePopup(); + await promisePopupHidden; + } + ); +}); diff --git a/dom/tests/browser/browser_localStorage_privatestorageevent.js b/dom/tests/browser/browser_localStorage_privatestorageevent.js index 7c81fadf2d..22b948a73d 100644 --- a/dom/tests/browser/browser_localStorage_privatestorageevent.js +++ b/dom/tests/browser/browser_localStorage_privatestorageevent.js @@ -37,43 +37,43 @@ add_task(async function () { var pubBrowser = gBrowser.getBrowserForTab(pubTab); // Check if pubWin can see privWin's storage events - await SpecialPowers.spawn(pubBrowser, [], function (opts) { + await SpecialPowers.spawn(pubBrowser, [], function () { content.window.gotStorageEvent = false; - content.window.addEventListener("storage", ev => { + content.window.addEventListener("storage", () => { content.window.gotStorageEvent = true; }); }); - await SpecialPowers.spawn(privBrowser, [], function (opts) { + await SpecialPowers.spawn(privBrowser, [], function () { content.window.localStorage.key = "ablooabloo"; }); - let pubSaw = await SpecialPowers.spawn(pubBrowser, [], function (opts) { + let pubSaw = await SpecialPowers.spawn(pubBrowser, [], function () { return content.window.gotStorageEvent; }); ok(!pubSaw, "pubWin shouldn't be able to see privWin's storage events"); - await SpecialPowers.spawn(privBrowser, [], function (opts) { + await SpecialPowers.spawn(privBrowser, [], function () { content.window.gotStorageEvent = false; - content.window.addEventListener("storage", ev => { + content.window.addEventListener("storage", () => { content.window.gotStorageEvent = true; }); }); // Check if privWin can see pubWin's storage events - await SpecialPowers.spawn(privBrowser, [], function (opts) { + await SpecialPowers.spawn(privBrowser, [], function () { content.window.gotStorageEvent = false; - content.window.addEventListener("storage", ev => { + content.window.addEventListener("storage", () => { content.window.gotStorageEvent = true; }); }); - await SpecialPowers.spawn(pubBrowser, [], function (opts) { + await SpecialPowers.spawn(pubBrowser, [], function () { content.window.localStorage.key = "ablooabloo"; }); - let privSaw = await SpecialPowers.spawn(privBrowser, [], function (opts) { + let privSaw = await SpecialPowers.spawn(privBrowser, [], function () { return content.window.gotStorageEvent; }); diff --git a/dom/tests/browser/browser_persist_cookies.js b/dom/tests/browser/browser_persist_cookies.js index 282ad22060..60a70d6e88 100644 --- a/dom/tests/browser/browser_persist_cookies.js +++ b/dom/tests/browser/browser_persist_cookies.js @@ -13,7 +13,7 @@ const TEST_PATH2 = getRootDirectory(gTestPath).replace( ); var MockFilePicker = SpecialPowers.MockFilePicker; -MockFilePicker.init(window); +MockFilePicker.init(window.browsingContext); registerCleanupFunction(async function () { info("Running the cleanup code"); diff --git a/dom/tests/browser/browser_persist_cross_origin_iframe.js b/dom/tests/browser/browser_persist_cross_origin_iframe.js index 94a9a74af7..46457b6051 100644 --- a/dom/tests/browser/browser_persist_cross_origin_iframe.js +++ b/dom/tests/browser/browser_persist_cross_origin_iframe.js @@ -13,7 +13,7 @@ const TEST_PATH2 = getRootDirectory(gTestPath).replace( ); var MockFilePicker = SpecialPowers.MockFilePicker; -MockFilePicker.init(window); +MockFilePicker.init(window.browsingContext); registerCleanupFunction(async function () { info("Running the cleanup code"); @@ -120,7 +120,7 @@ add_task(async function () { gTestDir = createTemporarySaveDirectory(); MockFilePicker.displayDirectory = gTestDir; - MockFilePicker.showCallback = function (fp) { + MockFilePicker.showCallback = function () { let destFile = gTestDir.clone(); destFile.append("first.html"); MockFilePicker.setFiles([destFile]); @@ -154,7 +154,7 @@ add_task(async function () { "second_files/image_data/dummy.png", ]); - MockFilePicker.showCallback = function (fp) { + MockFilePicker.showCallback = function () { let destFile = gTestDir.clone(); destFile.append("second.html"); MockFilePicker.setFiles([destFile]); @@ -176,7 +176,7 @@ add_task(async function () { "third_files/dummy.png", ]); - MockFilePicker.showCallback = function (fp) { + MockFilePicker.showCallback = function () { let destFile = gTestDir.clone(); destFile.append("third.html"); MockFilePicker.setFiles([destFile]); diff --git a/dom/tests/browser/browser_persist_image_accept.js b/dom/tests/browser/browser_persist_image_accept.js index b4648a51ec..21a2096b9d 100644 --- a/dom/tests/browser/browser_persist_image_accept.js +++ b/dom/tests/browser/browser_persist_image_accept.js @@ -9,7 +9,7 @@ const TEST_PATH = getRootDirectory(gTestPath).replace( ); var MockFilePicker = SpecialPowers.MockFilePicker; -MockFilePicker.init(window); +MockFilePicker.init(window.browsingContext); registerCleanupFunction(async function () { info("Running the cleanup code"); @@ -100,7 +100,7 @@ add_task(async function test_image_download() { }); let httpOnModifyPromise = TestUtils.topicObserved( "http-on-modify-request", - (s, t, d) => { + s => { let channel = s.QueryInterface(Ci.nsIChannel); let uri = channel.URI && channel.URI.spec; if (!uri.endsWith("dummy.png")) { diff --git a/dom/tests/browser/browser_persist_mixed_content_image.js b/dom/tests/browser/browser_persist_mixed_content_image.js index d84934376d..6612e61ef1 100644 --- a/dom/tests/browser/browser_persist_mixed_content_image.js +++ b/dom/tests/browser/browser_persist_mixed_content_image.js @@ -9,7 +9,7 @@ const TEST_PATH = getRootDirectory(gTestPath).replace( ); var MockFilePicker = SpecialPowers.MockFilePicker; -MockFilePicker.init(window); +MockFilePicker.init(window.browsingContext); registerCleanupFunction(async function () { info("Running the cleanup code"); diff --git a/dom/tests/browser/browser_sessionStorage_navigation.js b/dom/tests/browser/browser_sessionStorage_navigation.js index 8598969dc8..ffe75b13fe 100644 --- a/dom/tests/browser/browser_sessionStorage_navigation.js +++ b/dom/tests/browser/browser_sessionStorage_navigation.js @@ -66,7 +66,7 @@ add_task(async function () { await SpecialPowers.spawn( browser, [ORIGIN2, key, value], - async (ORIGIN, key, value) => { + async (ORIGIN, key) => { is(content.window.origin, ORIGIN, `Navigate to ${ORIGIN} as expected`); let value1 = content.window.sessionStorage.getItem(key); diff --git a/dom/tests/browser/browser_test_focus_after_modal_state.js b/dom/tests/browser/browser_test_focus_after_modal_state.js index 2193d8fdc4..9b3d989078 100644 --- a/dom/tests/browser/browser_test_focus_after_modal_state.js +++ b/dom/tests/browser/browser_test_focus_after_modal_state.js @@ -33,14 +33,14 @@ add_task(async function () { return new Promise(resolve => { let doc = content.document.getElementById("edit").contentDocument; - doc.addEventListener("focus", function (event) { + doc.addEventListener("focus", function () { focusOccurred = true; if (blurOccurred) { resolve(true); } }); - doc.addEventListener("blur", function (event) { + doc.addEventListener("blur", function () { blurOccurred = true; if (focusOccurred) { resolve(false); diff --git a/dom/tests/browser/browser_windowProxy_transplant.js b/dom/tests/browser/browser_windowProxy_transplant.js index 6b9e316968..8e6e0f8413 100644 --- a/dom/tests/browser/browser_windowProxy_transplant.js +++ b/dom/tests/browser/browser_windowProxy_transplant.js @@ -59,7 +59,7 @@ add_task(async function () { return new Promise(resolve => { iframe.addEventListener( "load", - event => { + () => { info("Got an iframe load event!"); resolve(); }, diff --git a/dom/tests/browser/create_webrtc_peer_connection.html b/dom/tests/browser/create_webrtc_peer_connection.html index ee993d4892..51ca043073 100644 --- a/dom/tests/browser/create_webrtc_peer_connection.html +++ b/dom/tests/browser/create_webrtc_peer_connection.html @@ -19,7 +19,7 @@ window.addEventListener("message", event => { } }); -window.addEventListener("DOMContentLoaded", function(ev) { +window.addEventListener("DOMContentLoaded", function() { document.getElementById("msg").innerText = location.host; }); diff --git a/dom/tests/browser/file_postMessage_parent.html b/dom/tests/browser/file_postMessage_parent.html index f9aa63a8c7..e9cb8a1d34 100644 --- a/dom/tests/browser/file_postMessage_parent.html +++ b/dom/tests/browser/file_postMessage_parent.html @@ -5,7 +5,7 @@ var winID = SpecialPowers.wrap(this).windowGlobalChild.innerWindowId; var observer = { - observe(subject, topic) { + observe(subject) { var currID = SpecialPowers.wrap(subject).QueryInterface(SpecialPowers.Ci.nsISupportsPRUint64).data; if (currID != winID) { return; diff --git a/dom/tests/browser/geo_leak_test.html b/dom/tests/browser/geo_leak_test.html index fb3fabac40..8273174581 100644 --- a/dom/tests/browser/geo_leak_test.html +++ b/dom/tests/browser/geo_leak_test.html @@ -4,7 +4,7 @@ Geolocation incomplete position leak test @@ -11,10 +11,18 @@ - - - - -Bug 887541 - - - diff --git a/dom/tests/unit/test_Fetch.js b/dom/tests/unit/test_Fetch.js index 768cf671dd..1449a23854 100644 --- a/dom/tests/unit/test_Fetch.js +++ b/dom/tests/unit/test_Fetch.js @@ -216,7 +216,7 @@ add_test(function test_getTestFailedConnect() { do_test_pending(); // try a server that's not there fetch("http://localhost:4/should/fail") - .then(response => { + .then(() => { do_throw("Request should not succeed"); }) .catch(err => { @@ -230,7 +230,7 @@ add_test(function test_mozError() { do_test_pending(); // try a server that's not there fetch("http://localhost:4/should/fail", { mozErrors: true }) - .then(response => { + .then(() => { do_throw("Request should not succeed"); }) .catch(err => { @@ -245,7 +245,7 @@ add_test(function test_request_mozError() { // try a server that's not there const r = new Request("http://localhost:4/should/fail", { mozErrors: true }); fetch(r) - .then(response => { + .then(() => { do_throw("Request should not succeed"); }) .catch(err => { diff --git a/dom/tests/unit/test_PromiseDebugging.js b/dom/tests/unit/test_PromiseDebugging.js index 2262d60d61..6148b65c75 100644 --- a/dom/tests/unit/test_PromiseDebugging.js +++ b/dom/tests/unit/test_PromiseDebugging.js @@ -2,7 +2,7 @@ function run_test() { // Hack around Promise.jsm being stuck on my global Assert.equal(false, PromiseDebugging === undefined); var res; - var p = new Promise(function (resolve, reject) { + var p = new Promise(function (resolve) { res = resolve; }); var state = PromiseDebugging.getState(p); diff --git a/dom/tests/unit/test_geolocation_monitor.js b/dom/tests/unit/test_geolocation_monitor.js index f0fc1ad74b..7b47463882 100644 --- a/dom/tests/unit/test_geolocation_monitor.js +++ b/dom/tests/unit/test_geolocation_monitor.js @@ -56,7 +56,7 @@ function watchPosition() { let observer = { QueryInterface: ChromeUtils.generateQI(["nsIObserver"]), - observe(subject, topic, data) { + observe(subject, topic) { Assert.equal(topic, "geolocation-position-events"); observer._countEvents++; observer._lastData = toJSON(subject); diff --git a/dom/tests/unit/test_geolocation_provider.js b/dom/tests/unit/test_geolocation_provider.js index 8c58cd39f5..e08887bfce 100644 --- a/dom/tests/unit/test_geolocation_provider.js +++ b/dom/tests/unit/test_geolocation_provider.js @@ -12,10 +12,10 @@ function terminate(succ) { geolocation.clearWatch(watchID); } -function successCallback(pos) { +function successCallback() { terminate(true); } -function errorCallback(pos) { +function errorCallback() { terminate(false); } diff --git a/dom/url/tests/browser_download_after_revoke.js b/dom/url/tests/browser_download_after_revoke.js index be8ad96e70..f145b36281 100644 --- a/dom/url/tests/browser_download_after_revoke.js +++ b/dom/url/tests/browser_download_after_revoke.js @@ -43,7 +43,7 @@ async function test() { domwindow.addEventListener("load", onModalLoad, true); }, - onCloseWindow(aXULWindow) {}, + onCloseWindow() {}, }; Services.wm.addListener(listener); diff --git a/dom/url/tests/protocol_worker.js b/dom/url/tests/protocol_worker.js index c038254a4c..81e761ee0e 100644 --- a/dom/url/tests/protocol_worker.js +++ b/dom/url/tests/protocol_worker.js @@ -1,3 +1,5 @@ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + function ok(a, msg) { postMessage({ type: "status", status: !!a, msg }); } diff --git a/dom/url/tests/urlSearchParams_commons.js b/dom/url/tests/urlSearchParams_commons.js index 3a1dcb2807..4a1308b94b 100644 --- a/dom/url/tests/urlSearchParams_commons.js +++ b/dom/url/tests/urlSearchParams_commons.js @@ -1,5 +1,9 @@ /* import-globals-from urlSearchParams_worker.js */ +// This file gets included into a worker which doesn't have any +// assertion methods besides `ok` and `is`. +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + function testSimpleURLSearchParams() { var u = new URLSearchParams(); ok(u, "URLSearchParams created"); diff --git a/dom/url/tests/url_exceptions_worker.js b/dom/url/tests/url_exceptions_worker.js index c8d8494ac9..8bbd641136 100644 --- a/dom/url/tests/url_exceptions_worker.js +++ b/dom/url/tests/url_exceptions_worker.js @@ -2,7 +2,7 @@ function ok(a, msg) { postMessage({ type: "status", status: !!a, msg }); } -onmessage = function (event) { +onmessage = function () { // URL.href throws var url = new URL("http://www.example.com"); ok(url, "URL created"); diff --git a/dom/vr/XRSystem.cpp b/dom/vr/XRSystem.cpp index 09b9e07476..2dd66e41f4 100644 --- a/dom/vr/XRSystem.cpp +++ b/dom/vr/XRSystem.cpp @@ -122,8 +122,8 @@ already_AddRefed XRSystem::IsSessionSupported(XRSessionMode aMode, } already_AddRefed XRSystem::RequestSession( - JSContext* aCx, XRSessionMode aMode, const XRSessionInit& aOptions, - CallerType aCallerType, ErrorResult& aRv) { + XRSessionMode aMode, const XRSessionInit& aOptions, CallerType aCallerType, + ErrorResult& aRv) { nsCOMPtr global = GetParentObject(); NS_ENSURE_TRUE(global, nullptr); @@ -166,49 +166,25 @@ already_AddRefed XRSystem::RequestSession( requiredReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Local); } - BindingCallContext callCx(aCx, "XRSystem.requestSession"); - if (aOptions.mRequiredFeatures.WasPassed()) { - const Sequence& arr = (aOptions.mRequiredFeatures.Value()); - for (const JS::Value& val : arr) { - if (!val.isNull() && !val.isUndefined()) { - bool bFound = false; - JS::Rooted v(aCx, val); - int index = 0; - if (FindEnumStringIndex( - callCx, v, XRReferenceSpaceTypeValues::strings, - "XRReferenceSpaceType", "Argument 2 of XR.requestSession", - &index)) { - if (index >= 0) { - requiredReferenceSpaceTypes.AppendElement( - static_cast(index)); - bFound = true; - } - } - if (!bFound) { - promise->MaybeRejectWithNotSupportedError( - "A required feature for the XRSession is not available."); - return promise.forget(); - } + for (const nsString& val : aOptions.mRequiredFeatures.Value()) { + Maybe type = + StringToEnum(val); + if (type.isNothing()) { + promise->MaybeRejectWithNotSupportedError( + "A required feature for the XRSession is not available."); + return promise.forget(); } + requiredReferenceSpaceTypes.AppendElement(type.value()); } } if (aOptions.mOptionalFeatures.WasPassed()) { - const Sequence& arr = (aOptions.mOptionalFeatures.Value()); - for (const JS::Value& val : arr) { - if (!val.isNull() && !val.isUndefined()) { - JS::Rooted v(aCx, val); - int index = 0; - if (FindEnumStringIndex( - callCx, v, XRReferenceSpaceTypeValues::strings, - "XRReferenceSpaceType", "Argument 2 of XR.requestSession", - &index)) { - if (index >= 0) { - optionalReferenceSpaceTypes.AppendElement( - static_cast(index)); - } - } + for (const nsString& val : aOptions.mOptionalFeatures.Value()) { + Maybe type = + StringToEnum(val); + if (type.isSome()) { + optionalReferenceSpaceTypes.AppendElement(type.value()); } } } diff --git a/dom/vr/XRSystem.h b/dom/vr/XRSystem.h index 2a49dfb68f..860098e30c 100644 --- a/dom/vr/XRSystem.h +++ b/dom/vr/XRSystem.h @@ -120,7 +120,7 @@ class XRSystem final : public DOMEventTargetHelper, // WebIDL Members already_AddRefed IsSessionSupported(XRSessionMode aMode, ErrorResult& aRv); - already_AddRefed RequestSession(JSContext* aCx, XRSessionMode aMode, + already_AddRefed RequestSession(XRSessionMode aMode, const XRSessionInit& aOptions, CallerType aCallerType, ErrorResult& aRv); diff --git a/dom/vr/test/reftest/reftest.list b/dom/vr/test/reftest/reftest.list index c1ca292c71..ac012495cb 100644 --- a/dom/vr/test/reftest/reftest.list +++ b/dom/vr/test/reftest/reftest.list @@ -2,9 +2,7 @@ # Please confirm there is no other VR display connected. Otherwise, VRPuppetDisplay can't be attached. defaults pref(dom.vr.enabled,true) pref(dom.vr.puppet.enabled,true) pref(dom.vr.test.enabled,true) pref(dom.vr.require-gesture,false) pref(dom.vr.puppet.submitframe,1) pref(dom.vr.display.rafMaxDuration,200) pref(dom.vr.display.enumerate.interval,0) pref(dom.vr.controller.enumerate.interval,0) # WebVR Tests have been disabled as refactoring of gfxVRPuppet is landing. Dependencies for re-enabling these are tracked by meta bug 1555185. -# VR SubmitFrame is only implemented for D3D11.1 and MacOSX now. -# Our Windows 7 test machines don't support D3D11.1, so we run these tests on Windows 8+ only. -# skip-if((!winWidget&&release_or_beta)||Android||gtkWidget||!layersGPUAccelerated) == draw_rect.html wrapper.html?draw_rect.png +# skip-if((!winWidget&&release_or_beta)||Android||gtkWidget) == draw_rect.html wrapper.html?draw_rect.png # On MacOSX platform, getting different color interpolation result. # For lower resolution Mac hardware, we need to adjust it to fuzzy-if(cocoaWidget,0-1,0-1200). -# fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||cocoaWidget,0-1,0-600) skip-if((!winWidget&&release_or_beta)||Android||gtkWidget||!layersGPUAccelerated) == change_size.html wrapper.html?change_size.png +# fuzzy-if(winWidget||cocoaWidget,0-1,0-600) skip-if((!winWidget&&release_or_beta)||Android||gtkWidget) == change_size.html wrapper.html?change_size.png diff --git a/dom/webauthn/MacOSWebAuthnService.mm b/dom/webauthn/MacOSWebAuthnService.mm index 79b9030541..cec9600e57 100644 --- a/dom/webauthn/MacOSWebAuthnService.mm +++ b/dom/webauthn/MacOSWebAuthnService.mm @@ -545,6 +545,19 @@ MacOSWebAuthnService::MakeCredential(uint64_t aTransactionId, "MacOSWebAuthnService::MakeCredential", [self = RefPtr{this}, browsingContextId(aBrowsingContextId), aArgs = nsCOMPtr{aArgs}, aPromise = nsCOMPtr{aPromise}]() { + // Bug 1884574 - The Reset() call above should have cancelled any + // transactions that were dispatched to the platform, the platform + // should have called didCompleteWithError, and didCompleteWithError + // should have rejected the pending promise. However, in some scenarios, + // the platform fails to call the callback, and this leads to a + // diagnostic assertion failure when we drop `mRegisterPromise`. Avoid + // this by aborting the transaction here. + if (self->mRegisterPromise) { + MOZ_LOG(gMacOSWebAuthnServiceLog, mozilla::LogLevel::Debug, + ("MacOSAuthenticatorRequestDelegate::MakeCredential: " + "platform failed to call callback")); + self->AbortTransaction(NS_ERROR_DOM_ABORT_ERR); + } self->mRegisterPromise = aPromise; nsAutoString rpId; @@ -847,6 +860,14 @@ void MacOSWebAuthnService::DoGetAssertion( [self = RefPtr{this}, browsingContextId(aBrowsingContextId), aArgs, aPromise, aSelectedCredentialId = std::move(aSelectedCredentialId)]() mutable { + // Bug 1884574 - This AbortTransaction call is necessary. + // See comment in MacOSWebAuthnService::MakeCredential. + if (self->mSignPromise) { + MOZ_LOG(gMacOSWebAuthnServiceLog, mozilla::LogLevel::Debug, + ("MacOSAuthenticatorRequestDelegate::DoGetAssertion: " + "platform failed to call callback")); + self->AbortTransaction(NS_ERROR_DOM_ABORT_ERR); + } self->mSignPromise = aPromise; nsAutoString rpId; diff --git a/dom/webauthn/moz.build b/dom/webauthn/moz.build index 5d84dc06e7..47309034c8 100644 --- a/dom/webauthn/moz.build +++ b/dom/webauthn/moz.build @@ -70,7 +70,7 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "android": "AndroidWebAuthnService.cpp", ] -if CONFIG["OS_ARCH"] == "Darwin": +if CONFIG["TARGET_OS"] == "OSX": UNIFIED_SOURCES += [ "MacOSWebAuthnService.mm", ] diff --git a/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp b/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp index dea0b98023..78641582ce 100644 --- a/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp +++ b/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp @@ -29,7 +29,6 @@ #include "mozilla/Unused.h" #include "nsComponentManagerUtils.h" #include "nsContentUtils.h" -#include "nsContentCID.h" #include "nsCycleCollectionParticipant.h" #include "nsDOMAttributeMap.h" #include "nsFrameLoader.h" diff --git a/dom/webgpu/Adapter.cpp b/dom/webgpu/Adapter.cpp index 434ba7c6fa..7c0e72eac4 100644 --- a/dom/webgpu/Adapter.cpp +++ b/dom/webgpu/Adapter.cpp @@ -128,9 +128,6 @@ static Maybe ToWGPUFeatures( case dom::GPUFeatureName::Float32_filterable: return Some(WGPUFeatures_FLOAT32_FILTERABLE); - - case dom::GPUFeatureName::EndGuard_: - break; } MOZ_CRASH("Bad GPUFeatureName."); } @@ -141,11 +138,11 @@ static Maybe MakeFeatureBits( for (const auto& feature : aFeatures) { const auto bit = ToWGPUFeatures(feature); if (!bit) { - const auto featureStr = dom::GPUFeatureNameValues::GetString(feature); + const auto featureStr = dom::GetEnumString(feature); (void)featureStr; NS_WARNING( nsPrintfCString("Requested feature bit for '%s' is not implemented.", - featureStr.data()) + featureStr.get()) .get()); return Nothing(); } @@ -169,7 +166,7 @@ Adapter::Adapter(Instance* const aParent, WebGPUChild* const aBridge, auto ret = std::unordered_map{}; for (const auto feature : - MakeEnumeratedRange(dom::GPUFeatureName::EndGuard_)) { + dom::MakeWebIDLEnumeratedRange()) { const auto bitForFeature = ToWGPUFeatures(feature); if (!bitForFeature) { // There are some features that don't have bits. @@ -363,12 +360,12 @@ already_AddRefed Adapter::RequestDevice( for (const auto requested : aDesc.mRequiredFeatures) { const bool supported = mFeatures->Features().count(requested); if (!supported) { - const auto fstr = dom::GPUFeatureNameValues::GetString(requested); + const auto fstr = dom::GetEnumString(requested); const auto astr = this->LabelOrId(); nsPrintfCString msg( "requestDevice: Feature '%s' requested must be supported by " "adapter %s", - fstr.data(), astr.get()); + fstr.get(), astr.get()); promise->MaybeRejectWithTypeError(msg); return; } diff --git a/dom/webgpu/CanvasContext.h b/dom/webgpu/CanvasContext.h index 58ef04e861..057287b26e 100644 --- a/dom/webgpu/CanvasContext.h +++ b/dom/webgpu/CanvasContext.h @@ -84,6 +84,8 @@ class CanvasContext final : public nsICanvasRenderingContextInternal, already_AddRefed UseCompositableForwarder( layers::CompositableForwarder* aForwarder) override; + bool IsOffscreenCanvas() { return !!mOffscreenCanvas; } + public: void GetCanvas(dom::OwningHTMLCanvasElementOrOffscreenCanvas&) const; diff --git a/dom/webgpu/CommandBuffer.cpp b/dom/webgpu/CommandBuffer.cpp index ff9bbd8d5d..59023018ef 100644 --- a/dom/webgpu/CommandBuffer.cpp +++ b/dom/webgpu/CommandBuffer.cpp @@ -16,10 +16,13 @@ namespace mozilla::webgpu { GPU_IMPL_CYCLE_COLLECTION(CommandBuffer, mParent) GPU_IMPL_JS_WRAP(CommandBuffer) -CommandBuffer::CommandBuffer(Device* const aParent, RawId aId, - nsTArray>&& aTargetContexts, - RefPtr&& aEncoder) - : ChildOf(aParent), mId(aId), mTargetContexts(std::move(aTargetContexts)) { +CommandBuffer::CommandBuffer( + Device* const aParent, RawId aId, + nsTArray>&& aPresentationContexts, + RefPtr&& aEncoder) + : ChildOf(aParent), + mId(aId), + mPresentationContexts(std::move(aPresentationContexts)) { mEncoder = std::move(aEncoder); MOZ_RELEASE_ASSERT(aId); } @@ -33,9 +36,9 @@ Maybe CommandBuffer::Commit() { return Nothing(); } mValid = false; - for (const auto& targetContext : mTargetContexts) { - if (targetContext) { - targetContext->MaybeQueueSwapChainPresent(); + for (const auto& presentationContext : mPresentationContexts) { + if (presentationContext) { + presentationContext->MaybeQueueSwapChainPresent(); } } return Some(mId); diff --git a/dom/webgpu/CommandBuffer.h b/dom/webgpu/CommandBuffer.h index b9c2495fb7..dff3e14d75 100644 --- a/dom/webgpu/CommandBuffer.h +++ b/dom/webgpu/CommandBuffer.h @@ -22,7 +22,7 @@ class CommandBuffer final : public ObjectBase, public ChildOf { GPU_DECL_JS_WRAP(CommandBuffer) CommandBuffer(Device* const aParent, RawId aId, - nsTArray>&& aTargetContexts, + nsTArray>&& aPresentationContexts, RefPtr&& aEncoder); Maybe Commit(); @@ -33,7 +33,7 @@ class CommandBuffer final : public ObjectBase, public ChildOf { void Cleanup(); const RawId mId; - const nsTArray> mTargetContexts; + const nsTArray> mPresentationContexts; // Command buffers and encoders share the same identity (this is a // simplifcation currently made by wgpu). To avoid dropping the same ID twice, // the wgpu resource lifetime is tied to the encoder which is held alive by diff --git a/dom/webgpu/CommandEncoder.cpp b/dom/webgpu/CommandEncoder.cpp index 15d95401d4..f254c9d8b9 100644 --- a/dom/webgpu/CommandEncoder.cpp +++ b/dom/webgpu/CommandEncoder.cpp @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "mozilla/dom/UnionTypes.h" #include "mozilla/dom/WebGPUBinding.h" #include "CommandEncoder.h" @@ -89,6 +90,14 @@ void CommandEncoder::Cleanup() { } } +void CommandEncoder::TrackPresentationContext(CanvasContext* aTargetContext) { + if (aTargetContext) { + if (!aTargetContext->IsOffscreenCanvas()) { + mPresentationContexts.AppendElement(aTargetContext); + } + } +} + void CommandEncoder::CopyBufferToBuffer(const Buffer& aSource, BufferAddress aSourceOffset, const Buffer& aDestination, @@ -121,10 +130,7 @@ void CommandEncoder::CopyBufferToTexture( ConvertExtent(aCopySize), ToFFI(&bb)); mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb)); - const auto& targetContext = aDestination.mTexture->mTargetContext; - if (targetContext) { - mTargetContexts.AppendElement(targetContext); - } + TrackPresentationContext(aDestination.mTexture->mTargetContext); } void CommandEncoder::CopyTextureToBuffer( const dom::GPUImageCopyTexture& aSource, @@ -156,10 +162,7 @@ void CommandEncoder::CopyTextureToTexture( ConvertExtent(aCopySize), ToFFI(&bb)); mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb)); - const auto& targetContext = aDestination.mTexture->mTargetContext; - if (targetContext) { - mTargetContexts.AppendElement(targetContext); - } + TrackPresentationContext(aDestination.mTexture->mTargetContext); } void CommandEncoder::ClearBuffer(const Buffer& aBuffer, const uint64_t aOffset, @@ -216,13 +219,9 @@ already_AddRefed CommandEncoder::BeginComputePass( already_AddRefed CommandEncoder::BeginRenderPass( const dom::GPURenderPassDescriptor& aDesc) { for (const auto& at : aDesc.mColorAttachments) { - auto* targetContext = at.mView->GetTargetContext(); - if (targetContext) { - mTargetContexts.AppendElement(targetContext); - } + TrackPresentationContext(at.mView->GetTargetContext()); if (at.mResolveTarget.WasPassed()) { - targetContext = at.mResolveTarget.Value().GetTargetContext(); - mTargetContexts.AppendElement(targetContext); + TrackPresentationContext(at.mResolveTarget.Value().GetTargetContext()); } } @@ -230,24 +229,24 @@ already_AddRefed CommandEncoder::BeginRenderPass( return pass.forget(); } -void CommandEncoder::EndComputePass(ffi::WGPUComputePass& aPass) { +void CommandEncoder::EndComputePass(ffi::WGPURecordedComputePass& aPass) { if (!mBridge->IsOpen()) { return; } ipc::ByteBuf byteBuf; ffi::wgpu_compute_pass_finish(&aPass, ToFFI(&byteBuf)); - mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(byteBuf)); + mBridge->SendComputePass(mId, mParent->mId, std::move(byteBuf)); } -void CommandEncoder::EndRenderPass(ffi::WGPURenderPass& aPass) { +void CommandEncoder::EndRenderPass(ffi::WGPURecordedRenderPass& aPass) { if (!mBridge->IsOpen()) { return; } ipc::ByteBuf byteBuf; ffi::wgpu_render_pass_finish(&aPass, ToFFI(&byteBuf)); - mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(byteBuf)); + mBridge->SendRenderPass(mId, mParent->mId, std::move(byteBuf)); } already_AddRefed CommandEncoder::Finish( @@ -263,7 +262,7 @@ already_AddRefed CommandEncoder::Finish( RefPtr me(this); RefPtr comb = new CommandBuffer( - mParent, mId, std::move(mTargetContexts), std::move(me)); + mParent, mId, std::move(mPresentationContexts), std::move(me)); return comb.forget(); } diff --git a/dom/webgpu/CommandEncoder.h b/dom/webgpu/CommandEncoder.h index 52b10a5b2e..99a2fb15b4 100644 --- a/dom/webgpu/CommandEncoder.h +++ b/dom/webgpu/CommandEncoder.h @@ -32,7 +32,7 @@ using GPUExtent3D = RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict; namespace webgpu { namespace ffi { struct WGPUComputePass; -struct WGPURenderPass; +struct WGPURecordedRenderPass; struct WGPUImageDataLayout; struct WGPUImageCopyTexture_TextureId; struct WGPUExtent3d; @@ -67,13 +67,15 @@ class CommandEncoder final : public ObjectBase, public ChildOf { void Cleanup(); RefPtr mBridge; - nsTArray> mTargetContexts; + nsTArray> mPresentationContexts; + + void TrackPresentationContext(CanvasContext* aTargetContext); public: const auto& GetDevice() const { return mParent; }; - void EndComputePass(ffi::WGPUComputePass& aPass); - void EndRenderPass(ffi::WGPURenderPass& aPass); + void EndComputePass(ffi::WGPURecordedComputePass& aPass); + void EndRenderPass(ffi::WGPURecordedRenderPass& aPass); void CopyBufferToBuffer(const Buffer& aSource, BufferAddress aSourceOffset, const Buffer& aDestination, diff --git a/dom/webgpu/ComputePassEncoder.cpp b/dom/webgpu/ComputePassEncoder.cpp index 2820a575e8..190bbf00a7 100644 --- a/dom/webgpu/ComputePassEncoder.cpp +++ b/dom/webgpu/ComputePassEncoder.cpp @@ -17,13 +17,13 @@ GPU_IMPL_CYCLE_COLLECTION(ComputePassEncoder, mParent, mUsedBindGroups, mUsedPipelines) GPU_IMPL_JS_WRAP(ComputePassEncoder) -void ffiWGPUComputePassDeleter::operator()(ffi::WGPUComputePass* raw) { +void ffiWGPUComputePassDeleter::operator()(ffi::WGPURecordedComputePass* raw) { if (raw) { ffi::wgpu_compute_pass_destroy(raw); } } -ffi::WGPUComputePass* BeginComputePass( +ffi::WGPURecordedComputePass* BeginComputePass( RawId aEncoderId, const dom::GPUComputePassDescriptor& aDesc) { MOZ_RELEASE_ASSERT(aEncoderId); ffi::WGPUComputePassDescriptor desc = {}; @@ -31,7 +31,7 @@ ffi::WGPUComputePass* BeginComputePass( webgpu::StringHelper label(aDesc.mLabel); desc.label = label.Get(); - return ffi::wgpu_command_encoder_begin_compute_pass(aEncoderId, &desc); + return ffi::wgpu_command_encoder_begin_compute_pass(&desc); } ComputePassEncoder::ComputePassEncoder( @@ -49,16 +49,16 @@ void ComputePassEncoder::SetBindGroup( const dom::Sequence& aDynamicOffsets) { if (mValid) { mUsedBindGroups.AppendElement(&aBindGroup); - ffi::wgpu_compute_pass_set_bind_group(mPass.get(), aSlot, aBindGroup.mId, - aDynamicOffsets.Elements(), - aDynamicOffsets.Length()); + ffi::wgpu_recorded_compute_pass_set_bind_group( + mPass.get(), aSlot, aBindGroup.mId, aDynamicOffsets.Elements(), + aDynamicOffsets.Length()); } } void ComputePassEncoder::SetPipeline(const ComputePipeline& aPipeline) { if (mValid) { mUsedPipelines.AppendElement(&aPipeline); - ffi::wgpu_compute_pass_set_pipeline(mPass.get(), aPipeline.mId); + ffi::wgpu_recorded_compute_pass_set_pipeline(mPass.get(), aPipeline.mId); } } @@ -66,7 +66,7 @@ void ComputePassEncoder::DispatchWorkgroups(uint32_t workgroupCountX, uint32_t workgroupCountY, uint32_t workgroupCountZ) { if (mValid) { - ffi::wgpu_compute_pass_dispatch_workgroups( + ffi::wgpu_recorded_compute_pass_dispatch_workgroups( mPass.get(), workgroupCountX, workgroupCountY, workgroupCountZ); } } @@ -74,7 +74,7 @@ void ComputePassEncoder::DispatchWorkgroups(uint32_t workgroupCountX, void ComputePassEncoder::DispatchWorkgroupsIndirect( const Buffer& aIndirectBuffer, uint64_t aIndirectOffset) { if (mValid) { - ffi::wgpu_compute_pass_dispatch_workgroups_indirect( + ffi::wgpu_recorded_compute_pass_dispatch_workgroups_indirect( mPass.get(), aIndirectBuffer.mId, aIndirectOffset); } } @@ -82,18 +82,20 @@ void ComputePassEncoder::DispatchWorkgroupsIndirect( void ComputePassEncoder::PushDebugGroup(const nsAString& aString) { if (mValid) { const NS_ConvertUTF16toUTF8 utf8(aString); - ffi::wgpu_compute_pass_push_debug_group(mPass.get(), utf8.get(), 0); + ffi::wgpu_recorded_compute_pass_push_debug_group(mPass.get(), utf8.get(), + 0); } } void ComputePassEncoder::PopDebugGroup() { if (mValid) { - ffi::wgpu_compute_pass_pop_debug_group(mPass.get()); + ffi::wgpu_recorded_compute_pass_pop_debug_group(mPass.get()); } } void ComputePassEncoder::InsertDebugMarker(const nsAString& aString) { if (mValid) { const NS_ConvertUTF16toUTF8 utf8(aString); - ffi::wgpu_compute_pass_insert_debug_marker(mPass.get(), utf8.get(), 0); + ffi::wgpu_recorded_compute_pass_insert_debug_marker(mPass.get(), utf8.get(), + 0); } } diff --git a/dom/webgpu/ComputePassEncoder.h b/dom/webgpu/ComputePassEncoder.h index 8160a09e2e..2455822f79 100644 --- a/dom/webgpu/ComputePassEncoder.h +++ b/dom/webgpu/ComputePassEncoder.h @@ -18,7 +18,7 @@ struct GPUComputePassDescriptor; namespace webgpu { namespace ffi { -struct WGPUComputePass; +struct WGPURecordedComputePass; } // namespace ffi class BindGroup; @@ -27,7 +27,7 @@ class CommandEncoder; class ComputePipeline; struct ffiWGPUComputePassDeleter { - void operator()(ffi::WGPUComputePass*); + void operator()(ffi::WGPURecordedComputePass*); }; class ComputePassEncoder final : public ObjectBase, @@ -43,7 +43,8 @@ class ComputePassEncoder final : public ObjectBase, virtual ~ComputePassEncoder(); void Cleanup() {} - std::unique_ptr mPass; + std::unique_ptr + mPass; // keep all the used objects alive while the pass is recorded nsTArray> mUsedBindGroups; nsTArray> mUsedPipelines; diff --git a/dom/webgpu/Device.cpp b/dom/webgpu/Device.cpp index a659047af1..a9fd5ee44c 100644 --- a/dom/webgpu/Device.cpp +++ b/dom/webgpu/Device.cpp @@ -247,6 +247,7 @@ already_AddRefed Device::CreateSampler( desc.mipmap_filter = ffi::WGPUFilterMode(aDesc.mMipmapFilter); desc.lod_min_clamp = aDesc.mLodMinClamp; desc.lod_max_clamp = aDesc.mLodMaxClamp; + desc.max_anisotropy = aDesc.mMaxAnisotropy; ffi::WGPUCompareFunction comparison = ffi::WGPUCompareFunction_Sentinel; if (aDesc.mCompare.WasPassed()) { @@ -320,8 +321,6 @@ already_AddRefed Device::CreateBindGroupLayout( case dom::GPUTextureSampleType::Depth: data.type = ffi::WGPURawTextureSampleType_Depth; break; - case dom::GPUTextureSampleType::EndGuard_: - MOZ_ASSERT_UNREACHABLE(); } } if (entry.mStorageTexture.WasPassed()) { @@ -349,8 +348,6 @@ already_AddRefed Device::CreateBindGroupLayout( case dom::GPUBufferBindingType::Read_only_storage: e.ty = ffi::WGPURawBindingType_ReadonlyStorageBuffer; break; - case dom::GPUBufferBindingType::EndGuard_: - MOZ_ASSERT_UNREACHABLE(); } e.has_dynamic_offset = entry.mBuffer.Value().mHasDynamicOffset; } @@ -361,10 +358,23 @@ already_AddRefed Device::CreateBindGroupLayout( e.multisampled = entry.mTexture.Value().mMultisampled; } if (entry.mStorageTexture.WasPassed()) { - e.ty = entry.mStorageTexture.Value().mAccess == - dom::GPUStorageTextureAccess::Write_only - ? ffi::WGPURawBindingType_WriteonlyStorageTexture - : ffi::WGPURawBindingType_ReadonlyStorageTexture; + switch (entry.mStorageTexture.Value().mAccess) { + case dom::GPUStorageTextureAccess::Write_only: { + e.ty = ffi::WGPURawBindingType_WriteonlyStorageTexture; + break; + } + case dom::GPUStorageTextureAccess::Read_only: { + e.ty = ffi::WGPURawBindingType_ReadonlyStorageTexture; + break; + } + case dom::GPUStorageTextureAccess::Read_write: { + e.ty = ffi::WGPURawBindingType_ReadWriteStorageTexture; + break; + } + default: { + MOZ_ASSERT_UNREACHABLE(); + } + } e.view_dimension = &optional[i].dim; e.storage_texture_format = &optional[i].format; } @@ -379,8 +389,6 @@ already_AddRefed Device::CreateBindGroupLayout( case dom::GPUSamplerBindingType::Comparison: e.sampler_compare = true; break; - case dom::GPUSamplerBindingType::EndGuard_: - MOZ_ASSERT_UNREACHABLE(); } } entries.AppendElement(e); @@ -671,8 +679,12 @@ RawId CreateComputePipelineImpl(PipelineCreationContext* const aContext, MOZ_ASSERT_UNREACHABLE(); } desc.stage.module = aDesc.mCompute.mModule->mId; - CopyUTF16toUTF8(aDesc.mCompute.mEntryPoint, entryPoint); - desc.stage.entry_point = entryPoint.get(); + if (aDesc.mCompute.mEntryPoint.WasPassed()) { + CopyUTF16toUTF8(aDesc.mCompute.mEntryPoint.Value(), entryPoint); + desc.stage.entry_point = entryPoint.get(); + } else { + desc.stage.entry_point = nullptr; + } RawId implicit_bgl_ids[WGPUMAX_BIND_GROUPS] = {}; RawId id = ffi::wgpu_client_create_compute_pipeline( @@ -717,8 +729,12 @@ RawId CreateRenderPipelineImpl(PipelineCreationContext* const aContext, { const auto& stage = aDesc.mVertex; vertexState.stage.module = stage.mModule->mId; - CopyUTF16toUTF8(stage.mEntryPoint, vsEntry); - vertexState.stage.entry_point = vsEntry.get(); + if (stage.mEntryPoint.WasPassed()) { + CopyUTF16toUTF8(stage.mEntryPoint.Value(), vsEntry); + vertexState.stage.entry_point = vsEntry.get(); + } else { + vertexState.stage.entry_point = nullptr; + } for (const auto& vertex_desc : stage.mBuffers) { ffi::WGPUVertexBufferLayout vb_desc = {}; @@ -753,8 +769,12 @@ RawId CreateRenderPipelineImpl(PipelineCreationContext* const aContext, if (aDesc.mFragment.WasPassed()) { const auto& stage = aDesc.mFragment.Value(); fragmentState.stage.module = stage.mModule->mId; - CopyUTF16toUTF8(stage.mEntryPoint, fsEntry); - fragmentState.stage.entry_point = fsEntry.get(); + if (stage.mEntryPoint.WasPassed()) { + CopyUTF16toUTF8(stage.mEntryPoint.Value(), fsEntry); + fragmentState.stage.entry_point = fsEntry.get(); + } else { + fragmentState.stage.entry_point = nullptr; + } // Note: we pre-collect the blend states into a different array // so that we can have non-stale pointers into it. diff --git a/dom/webgpu/Queue.cpp b/dom/webgpu/Queue.cpp index 26952ee173..ca25b2f290 100644 --- a/dom/webgpu/Queue.cpp +++ b/dom/webgpu/Queue.cpp @@ -69,18 +69,36 @@ void Queue::WriteBuffer(const Buffer& aBuffer, uint64_t aBufferOffset, return; } - dom::ProcessTypedArraysFixed(aData, [&](const Span& aData) { - uint64_t length = aData.Length(); - const auto checkedSize = aSize.WasPassed() - ? CheckedInt(aSize.Value()) - : CheckedInt(length) - aDataOffset; - if (!checkedSize.isValid()) { + size_t elementByteSize = 1; + if (aData.IsArrayBufferView()) { + auto type = aData.GetAsArrayBufferView().Type(); + if (type != JS::Scalar::MaxTypedArrayViewType) { + elementByteSize = byteSize(type); + } + } + dom::ProcessTypedArraysFixed(aData, [&, elementByteSize]( + const Span& aData) { + uint64_t byteLength = aData.Length(); + + auto checkedByteOffset = + CheckedInt(aDataOffset) * elementByteSize; + if (!checkedByteOffset.isValid()) { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return; + } + auto offset = checkedByteOffset.value(); + + const auto checkedByteSize = + aSize.WasPassed() ? CheckedInt(aSize.Value()) * elementByteSize + : CheckedInt(byteLength) - offset; + if (!checkedByteSize.isValid()) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } + auto size = checkedByteSize.value(); - const auto& size = checkedSize.value(); - if (aDataOffset + size > length) { + auto checkedByteEnd = CheckedInt(offset) + size; + if (!checkedByteEnd.isValid() || checkedByteEnd.value() > byteLength) { aRv.ThrowAbortError(nsPrintfCString("Wrong data size %" PRIuPTR, size)); return; } diff --git a/dom/webgpu/RenderPassEncoder.cpp b/dom/webgpu/RenderPassEncoder.cpp index c5cb19ce15..03c16ea3a4 100644 --- a/dom/webgpu/RenderPassEncoder.cpp +++ b/dom/webgpu/RenderPassEncoder.cpp @@ -18,7 +18,7 @@ GPU_IMPL_CYCLE_COLLECTION(RenderPassEncoder, mParent, mUsedBindGroups, mUsedRenderBundles) GPU_IMPL_JS_WRAP(RenderPassEncoder) -void ffiWGPURenderPassDeleter::operator()(ffi::WGPURenderPass* raw) { +void ffiWGPURenderPassDeleter::operator()(ffi::WGPURecordedRenderPass* raw) { if (raw) { ffi::wgpu_render_pass_destroy(raw); } @@ -30,8 +30,6 @@ static ffi::WGPULoadOp ConvertLoadOp(const dom::GPULoadOp& aOp) { return ffi::WGPULoadOp_Load; case dom::GPULoadOp::Clear: return ffi::WGPULoadOp_Clear; - case dom::GPULoadOp::EndGuard_: - break; } MOZ_CRASH("bad GPULoadOp"); } @@ -42,8 +40,6 @@ static ffi::WGPUStoreOp ConvertStoreOp(const dom::GPUStoreOp& aOp) { return ffi::WGPUStoreOp_Store; case dom::GPUStoreOp::Discard: return ffi::WGPUStoreOp_Discard; - case dom::GPUStoreOp::EndGuard_: - break; } MOZ_CRASH("bad GPUStoreOp"); } @@ -87,7 +83,7 @@ static ffi::WGPUColor ConvertColor( return ffi::WGPUColor(); } -ffi::WGPURenderPass* BeginRenderPass( +ffi::WGPURecordedRenderPass* BeginRenderPass( CommandEncoder* const aParent, const dom::GPURenderPassDescriptor& aDesc) { ffi::WGPURenderPassDescriptor desc = {}; @@ -155,7 +151,7 @@ ffi::WGPURenderPass* BeginRenderPass( } } - return ffi::wgpu_command_encoder_begin_render_pass(aParent->mId, &desc); + return ffi::wgpu_command_encoder_begin_render_pass(&desc); } RenderPassEncoder::RenderPassEncoder(CommandEncoder* const aParent, @@ -186,16 +182,16 @@ void RenderPassEncoder::SetBindGroup( const dom::Sequence& aDynamicOffsets) { if (mValid) { mUsedBindGroups.AppendElement(&aBindGroup); - ffi::wgpu_render_pass_set_bind_group(mPass.get(), aSlot, aBindGroup.mId, - aDynamicOffsets.Elements(), - aDynamicOffsets.Length()); + ffi::wgpu_recorded_render_pass_set_bind_group( + mPass.get(), aSlot, aBindGroup.mId, aDynamicOffsets.Elements(), + aDynamicOffsets.Length()); } } void RenderPassEncoder::SetPipeline(const RenderPipeline& aPipeline) { if (mValid) { mUsedPipelines.AppendElement(&aPipeline); - ffi::wgpu_render_pass_set_pipeline(mPass.get(), aPipeline.mId); + ffi::wgpu_recorded_render_pass_set_pipeline(mPass.get(), aPipeline.mId); } } @@ -207,8 +203,8 @@ void RenderPassEncoder::SetIndexBuffer(const Buffer& aBuffer, const auto iformat = aIndexFormat == dom::GPUIndexFormat::Uint32 ? ffi::WGPUIndexFormat_Uint32 : ffi::WGPUIndexFormat_Uint16; - ffi::wgpu_render_pass_set_index_buffer(mPass.get(), aBuffer.mId, iformat, - aOffset, aSize); + ffi::wgpu_recorded_render_pass_set_index_buffer(mPass.get(), aBuffer.mId, + iformat, aOffset, aSize); } } @@ -216,16 +212,17 @@ void RenderPassEncoder::SetVertexBuffer(uint32_t aSlot, const Buffer& aBuffer, uint64_t aOffset, uint64_t aSize) { if (mValid) { mUsedBuffers.AppendElement(&aBuffer); - ffi::wgpu_render_pass_set_vertex_buffer(mPass.get(), aSlot, aBuffer.mId, - aOffset, aSize); + ffi::wgpu_recorded_render_pass_set_vertex_buffer( + mPass.get(), aSlot, aBuffer.mId, aOffset, aSize); } } void RenderPassEncoder::Draw(uint32_t aVertexCount, uint32_t aInstanceCount, uint32_t aFirstVertex, uint32_t aFirstInstance) { if (mValid) { - ffi::wgpu_render_pass_draw(mPass.get(), aVertexCount, aInstanceCount, - aFirstVertex, aFirstInstance); + ffi::wgpu_recorded_render_pass_draw(mPass.get(), aVertexCount, + aInstanceCount, aFirstVertex, + aFirstInstance); } } @@ -234,24 +231,24 @@ void RenderPassEncoder::DrawIndexed(uint32_t aIndexCount, uint32_t aFirstIndex, int32_t aBaseVertex, uint32_t aFirstInstance) { if (mValid) { - ffi::wgpu_render_pass_draw_indexed(mPass.get(), aIndexCount, aInstanceCount, - aFirstIndex, aBaseVertex, - aFirstInstance); + ffi::wgpu_recorded_render_pass_draw_indexed(mPass.get(), aIndexCount, + aInstanceCount, aFirstIndex, + aBaseVertex, aFirstInstance); } } void RenderPassEncoder::DrawIndirect(const Buffer& aIndirectBuffer, uint64_t aIndirectOffset) { if (mValid) { - ffi::wgpu_render_pass_draw_indirect(mPass.get(), aIndirectBuffer.mId, - aIndirectOffset); + ffi::wgpu_recorded_render_pass_draw_indirect( + mPass.get(), aIndirectBuffer.mId, aIndirectOffset); } } void RenderPassEncoder::DrawIndexedIndirect(const Buffer& aIndirectBuffer, uint64_t aIndirectOffset) { if (mValid) { - ffi::wgpu_render_pass_draw_indexed_indirect( + ffi::wgpu_recorded_render_pass_draw_indexed_indirect( mPass.get(), aIndirectBuffer.mId, aIndirectOffset); } } @@ -259,15 +256,16 @@ void RenderPassEncoder::DrawIndexedIndirect(const Buffer& aIndirectBuffer, void RenderPassEncoder::SetViewport(float x, float y, float width, float height, float minDepth, float maxDepth) { if (mValid) { - ffi::wgpu_render_pass_set_viewport(mPass.get(), x, y, width, height, - minDepth, maxDepth); + ffi::wgpu_recorded_render_pass_set_viewport(mPass.get(), x, y, width, + height, minDepth, maxDepth); } } void RenderPassEncoder::SetScissorRect(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { if (mValid) { - ffi::wgpu_render_pass_set_scissor_rect(mPass.get(), x, y, width, height); + ffi::wgpu_recorded_render_pass_set_scissor_rect(mPass.get(), x, y, width, + height); } } @@ -275,13 +273,14 @@ void RenderPassEncoder::SetBlendConstant( const dom::DoubleSequenceOrGPUColorDict& color) { if (mValid) { ffi::WGPUColor aColor = ConvertColor(color); - ffi::wgpu_render_pass_set_blend_constant(mPass.get(), &aColor); + ffi::wgpu_recorded_render_pass_set_blend_constant(mPass.get(), &aColor); } } void RenderPassEncoder::SetStencilReference(uint32_t reference) { if (mValid) { - ffi::wgpu_render_pass_set_stencil_reference(mPass.get(), reference); + ffi::wgpu_recorded_render_pass_set_stencil_reference(mPass.get(), + reference); } } @@ -293,26 +292,27 @@ void RenderPassEncoder::ExecuteBundles( mUsedRenderBundles.AppendElement(bundle); renderBundles.AppendElement(bundle->mId); } - ffi::wgpu_render_pass_execute_bundles(mPass.get(), renderBundles.Elements(), - renderBundles.Length()); + ffi::wgpu_recorded_render_pass_execute_bundles( + mPass.get(), renderBundles.Elements(), renderBundles.Length()); } } void RenderPassEncoder::PushDebugGroup(const nsAString& aString) { if (mValid) { const NS_ConvertUTF16toUTF8 utf8(aString); - ffi::wgpu_render_pass_push_debug_group(mPass.get(), utf8.get(), 0); + ffi::wgpu_recorded_render_pass_push_debug_group(mPass.get(), utf8.get(), 0); } } void RenderPassEncoder::PopDebugGroup() { if (mValid) { - ffi::wgpu_render_pass_pop_debug_group(mPass.get()); + ffi::wgpu_recorded_render_pass_pop_debug_group(mPass.get()); } } void RenderPassEncoder::InsertDebugMarker(const nsAString& aString) { if (mValid) { const NS_ConvertUTF16toUTF8 utf8(aString); - ffi::wgpu_render_pass_insert_debug_marker(mPass.get(), utf8.get(), 0); + ffi::wgpu_recorded_render_pass_insert_debug_marker(mPass.get(), utf8.get(), + 0); } } diff --git a/dom/webgpu/RenderPassEncoder.h b/dom/webgpu/RenderPassEncoder.h index 5ca414b4ea..b6008bd013 100644 --- a/dom/webgpu/RenderPassEncoder.h +++ b/dom/webgpu/RenderPassEncoder.h @@ -24,7 +24,7 @@ class AutoSequence; } // namespace dom namespace webgpu { namespace ffi { -struct WGPURenderPass; +struct WGPURecordedRenderPass; } // namespace ffi class BindGroup; @@ -35,7 +35,7 @@ class RenderPipeline; class TextureView; struct ffiWGPURenderPassDeleter { - void operator()(ffi::WGPURenderPass*); + void operator()(ffi::WGPURecordedRenderPass*); }; class RenderPassEncoder final : public ObjectBase, @@ -51,7 +51,7 @@ class RenderPassEncoder final : public ObjectBase, virtual ~RenderPassEncoder(); void Cleanup() {} - std::unique_ptr mPass; + std::unique_ptr mPass; // keep all the used objects alive while the pass is recorded nsTArray> mUsedBindGroups; nsTArray> mUsedBuffers; diff --git a/dom/webgpu/SupportedFeatures.cpp b/dom/webgpu/SupportedFeatures.cpp index 294524bc81..a32879a2b0 100644 --- a/dom/webgpu/SupportedFeatures.cpp +++ b/dom/webgpu/SupportedFeatures.cpp @@ -5,6 +5,7 @@ #include "SupportedFeatures.h" #include "Adapter.h" +#include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/WebGPUBinding.h" namespace mozilla::webgpu { @@ -17,7 +18,7 @@ SupportedFeatures::SupportedFeatures(Adapter* const aParent) void SupportedFeatures::Add(const dom::GPUFeatureName aFeature, ErrorResult& aRv) { - const auto u8 = dom::GPUFeatureNameValues::GetString(aFeature); + const auto u8 = dom::GetEnumString(aFeature); const auto u16 = NS_ConvertUTF8toUTF16(u8); dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add(this, u16, aRv); diff --git a/dom/webgpu/Utility.cpp b/dom/webgpu/Utility.cpp index fdb5732e8a..111bac4416 100644 --- a/dom/webgpu/Utility.cpp +++ b/dom/webgpu/Utility.cpp @@ -228,8 +228,6 @@ ffi::WGPUTextureFormat ConvertTextureFormat( case dom::GPUTextureFormat::Depth32float_stencil8: result.tag = ffi::WGPUTextureFormat_Depth32FloatStencil8; break; - case dom::GPUTextureFormat::EndGuard_: - MOZ_ASSERT_UNREACHABLE(); } // Clang will check for us that the switch above is exhaustive, diff --git a/dom/webgpu/ipc/PWebGPU.ipdl b/dom/webgpu/ipc/PWebGPU.ipdl index 5146dd6826..451480a1c3 100644 --- a/dom/webgpu/ipc/PWebGPU.ipdl +++ b/dom/webgpu/ipc/PWebGPU.ipdl @@ -44,6 +44,8 @@ parent: async DeviceActionWithAck(RawId selfId, ByteBuf buf) returns (bool dummy); async TextureAction(RawId selfId, RawId aDeviceId, ByteBuf buf); async CommandEncoderAction(RawId selfId, RawId aDeviceId, ByteBuf buf); + async RenderPass(RawId selfId, RawId aDeviceId, ByteBuf buf); + async ComputePass(RawId selfId, RawId aDeviceId, ByteBuf buf); async BumpImplicitBindGroupLayout(RawId pipelineId, bool isCompute, uint32_t index, RawId assignId); async DeviceCreateBuffer(RawId deviceId, RawId bufferId, GPUBufferDescriptor desc, UnsafeSharedMemoryHandle shm); diff --git a/dom/webgpu/ipc/WebGPUChild.cpp b/dom/webgpu/ipc/WebGPUChild.cpp index 663dd5cb89..ab1a100736 100644 --- a/dom/webgpu/ipc/WebGPUChild.cpp +++ b/dom/webgpu/ipc/WebGPUChild.cpp @@ -40,10 +40,10 @@ void WebGPUChild::JsWarning(nsIGlobalObject* aGlobal, if (aGlobal) { dom::AutoJSAPI api; if (api.Init(aGlobal)) { - JS::WarnUTF8(api.cx(), "%s", flatString.get()); + JS::WarnUTF8(api.cx(), "Uncaptured WebGPU error: %s", flatString.get()); } } else { - printf_stderr("Validation error without device target: %s\n", + printf_stderr("Uncaptured WebGPU error without device target: %s\n", flatString.get()); } } diff --git a/dom/webgpu/ipc/WebGPUParent.cpp b/dom/webgpu/ipc/WebGPUParent.cpp index 9b79988245..1c0560d31e 100644 --- a/dom/webgpu/ipc/WebGPUParent.cpp +++ b/dom/webgpu/ipc/WebGPUParent.cpp @@ -154,6 +154,12 @@ class ErrorBuffer { } return Some(Error{*filterType, false, nsCString{mMessageUtf8}}); } + + void CoerceValidationToInternal() { + if (mType == ffi::WGPUErrorBufferType_Validation) { + mType = ffi::WGPUErrorBufferType_Internal; + } + } }; struct PendingSwapChainDrop { @@ -180,10 +186,9 @@ class PresentationData { Maybe mPendingSwapChainDrop; const uint32_t mSourcePitch; - std::vector mUnassignedBufferIds MOZ_GUARDED_BY(mBuffersLock); - std::vector mAvailableBufferIds MOZ_GUARDED_BY(mBuffersLock); - std::vector mQueuedBufferIds MOZ_GUARDED_BY(mBuffersLock); - Mutex mBuffersLock; + std::vector mUnassignedBufferIds; + std::vector mAvailableBufferIds; + std::vector mQueuedBufferIds; PresentationData(WebGPUParent* aParent, bool aUseExternalTextureInSwapChain, RawId aDeviceId, RawId aQueueId, @@ -194,8 +199,7 @@ class PresentationData { mDeviceId(aDeviceId), mQueueId(aQueueId), mDesc(aDesc), - mSourcePitch(aSourcePitch), - mBuffersLock("WebGPU presentation buffers") { + mSourcePitch(aSourcePitch) { MOZ_COUNT_CTOR(PresentationData); for (const RawId id : aBufferIds) { @@ -354,6 +358,11 @@ ipc::IPCResult WebGPUParent::RecvInstanceRequestAdapter( nsAutoCString message(aMessage); req->mParent->LoseDevice(deviceId, reason, message); + auto it = req->mParent->mDeviceFenceHandles.find(deviceId); + if (it != req->mParent->mDeviceFenceHandles.end()) { + req->mParent->mDeviceFenceHandles.erase(it); + } + // We're no longer tracking the memory for this callback, so erase // it to ensure we don't leak memory. req->mParent->mDeviceLostRequests.erase(deviceId); @@ -394,7 +403,9 @@ ipc::IPCResult WebGPUParent::RecvAdapterRequestDevice( HANDLE handle = wgpu_server_get_device_fence_handle(mContext.get(), aDeviceId); if (handle) { - mFenceHandle = new gfx::FileHandleWrapper(UniqueFileHandle(handle)); + RefPtr fenceHandle = + new gfx::FileHandleWrapper(UniqueFileHandle(handle)); + mDeviceFenceHandles.emplace(aDeviceId, std::move(fenceHandle)); } #endif @@ -970,20 +981,16 @@ static void ReadbackPresentCallback(ffi::WGPUBufferMapAsyncStatus status, return; } - PresentationData* data = req->mData.get(); + RefPtr data = req->mData; // get the buffer ID RawId bufferId; { - MutexAutoLock lock(data->mBuffersLock); bufferId = data->mQueuedBufferIds.back(); data->mQueuedBufferIds.pop_back(); } // Ensure we'll make the bufferId available for reuse - auto releaseBuffer = MakeScopeExit([data = RefPtr{data}, bufferId] { - MutexAutoLock lock(data->mBuffersLock); - data->mAvailableBufferIds.push_back(bufferId); - }); + data->mAvailableBufferIds.push_back(bufferId); MOZ_LOG(sLogger, LogLevel::Info, ("ReadbackPresentCallback for buffer %" PRIu64 " status=%d\n", @@ -994,15 +1001,16 @@ static void ReadbackPresentCallback(ffi::WGPUBufferMapAsyncStatus status, ErrorBuffer getRangeError; const auto mapped = ffi::wgpu_server_buffer_get_mapped_range( req->mContext, bufferId, 0, bufferSize, getRangeError.ToFFI()); + getRangeError.CoerceValidationToInternal(); if (req->mData->mParent) { req->mData->mParent->ForwardError(data->mDeviceId, getRangeError); - } else if (auto innerError = getRangeError.GetError()) { - // If an error occured in get_mapped_range, treat it as an internal error - // and crash. The error handling story for something unexpected happening - // during the present glue needs to befigured out in a more global way. + } + if (auto innerError = getRangeError.GetError()) { MOZ_LOG(sLogger, LogLevel::Info, - ("WebGPU present: buffer get_mapped_range failed: %s\n", + ("WebGPU present: buffer get_mapped_range for internal " + "presentation readback failed: %s\n", innerError->message.get())); + return; } MOZ_RELEASE_ASSERT(mapped.length >= bufferSize); @@ -1029,11 +1037,14 @@ static void ReadbackPresentCallback(ffi::WGPUBufferMapAsyncStatus status, } ErrorBuffer unmapError; wgpu_server_buffer_unmap(req->mContext, bufferId, unmapError.ToFFI()); + unmapError.CoerceValidationToInternal(); if (req->mData->mParent) { req->mData->mParent->ForwardError(data->mDeviceId, unmapError); - } else if (auto innerError = unmapError.GetError()) { + } + if (auto innerError = unmapError.GetError()) { MOZ_LOG(sLogger, LogLevel::Info, - ("WebGPU present: buffer unmap failed: %s\n", + ("WebGPU present: buffer unmap for internal presentation " + "readback failed: %s\n", innerError->message.get())); } } else { @@ -1083,9 +1094,12 @@ void WebGPUParent::PostExternalTexture( const auto index = aExternalTexture->GetSubmissionIndex(); MOZ_ASSERT(index != 0); + RefPtr data = lookup->second.get(); + Maybe fenceInfo; - if (mFenceHandle) { - fenceInfo = Some(gfx::FenceInfo(mFenceHandle, index)); + auto it = mDeviceFenceHandles.find(data->mDeviceId); + if (it != mDeviceFenceHandles.end()) { + fenceInfo = Some(gfx::FenceInfo(it->second, index)); } Maybe desc = @@ -1098,8 +1112,6 @@ void WebGPUParent::PostExternalTexture( mRemoteTextureOwner->PushTexture(aRemoteTextureId, aOwnerId, aExternalTexture, size, surfaceFormat, *desc); - RefPtr data = lookup->second.get(); - auto recycledTexture = mRemoteTextureOwner->GetRecycledExternalTexture( size, surfaceFormat, desc->type(), aOwnerId); if (recycledTexture) { @@ -1140,7 +1152,6 @@ ipc::IPCResult WebGPUParent::RecvSwapChainPresent( // step 1: find an available staging buffer, or create one { - MutexAutoLock lock(data->mBuffersLock); if (!data->mAvailableBufferIds.empty()) { bufferId = data->mAvailableBufferIds.back(); data->mAvailableBufferIds.pop_back(); @@ -1285,7 +1296,6 @@ ipc::IPCResult WebGPUParent::RecvSwapChainDrop( mPresentationDataMap.erase(lookup); - MutexAutoLock lock(data->mBuffersLock); ipc::ByteBuf dropByteBuf; for (const auto bid : data->mUnassignedBufferIds) { wgpu_server_buffer_free(bid, ToFFI(&dropByteBuf)); @@ -1351,6 +1361,24 @@ ipc::IPCResult WebGPUParent::RecvCommandEncoderAction( return IPC_OK(); } +ipc::IPCResult WebGPUParent::RecvRenderPass(RawId aEncoderId, RawId aDeviceId, + const ipc::ByteBuf& aByteBuf) { + ErrorBuffer error; + ffi::wgpu_server_render_pass(mContext.get(), aEncoderId, ToFFI(&aByteBuf), + error.ToFFI()); + ForwardError(aDeviceId, error); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvComputePass(RawId aEncoderId, RawId aDeviceId, + const ipc::ByteBuf& aByteBuf) { + ErrorBuffer error; + ffi::wgpu_server_compute_pass(mContext.get(), aEncoderId, ToFFI(&aByteBuf), + error.ToFFI()); + ForwardError(aDeviceId, error); + return IPC_OK(); +} + ipc::IPCResult WebGPUParent::RecvBumpImplicitBindGroupLayout(RawId aPipelineId, bool aIsCompute, uint32_t aIndex, @@ -1426,8 +1454,6 @@ ipc::IPCResult WebGPUParent::RecvDevicePopErrorScope( case dom::GPUErrorFilter::Internal: ret.resultType = PopErrorScopeResultType::InternalError; break; - case dom::GPUErrorFilter::EndGuard_: - MOZ_CRASH("Bad GPUErrorFilter"); } } return ret; diff --git a/dom/webgpu/ipc/WebGPUParent.h b/dom/webgpu/ipc/WebGPUParent.h index 6ad539c21e..a1eb36d723 100644 --- a/dom/webgpu/ipc/WebGPUParent.h +++ b/dom/webgpu/ipc/WebGPUParent.h @@ -118,6 +118,10 @@ class WebGPUParent final : public PWebGPUParent, public SupportsWeakPtr { const ipc::ByteBuf& aByteBuf); ipc::IPCResult RecvCommandEncoderAction(RawId aEncoderId, RawId aDeviceId, const ipc::ByteBuf& aByteBuf); + ipc::IPCResult RecvRenderPass(RawId aEncoderId, RawId aDeviceId, + const ipc::ByteBuf& aByteBuf); + ipc::IPCResult RecvComputePass(RawId aEncoderId, RawId aDeviceId, + const ipc::ByteBuf& aByteBuf); ipc::IPCResult RecvBumpImplicitBindGroupLayout(RawId aPipelineId, bool aIsCompute, uint32_t aIndex, @@ -219,7 +223,7 @@ class WebGPUParent final : public PWebGPUParent, public SupportsWeakPtr { nsTHashSet mLostDeviceIds; // Shared handle of wgpu device's fence. - RefPtr mFenceHandle; + std::unordered_map> mDeviceFenceHandles; // Store DeviceLostRequest structs for each device as unique_ptrs mapped // to their device ids. We keep these unique_ptrs alive as long as the diff --git a/dom/webgpu/ipc/WebGPUSerialize.h b/dom/webgpu/ipc/WebGPUSerialize.h index 8d78d784cb..03f9ee1676 100644 --- a/dom/webgpu/ipc/WebGPUSerialize.h +++ b/dom/webgpu/ipc/WebGPUSerialize.h @@ -9,6 +9,7 @@ #include "WebGPUTypes.h" #include "ipc/EnumSerializer.h" #include "ipc/IPCMessageUtils.h" +#include "mozilla/dom/BindingIPCUtils.h" #include "mozilla/dom/WebGPUBinding.h" #include "mozilla/webgpu/ffi/wgpu.h" @@ -20,7 +21,9 @@ namespace IPC { : public ContiguousEnumSerializer {} #define DEFINE_IPC_SERIALIZER_DOM_ENUM(something) \ - DEFINE_IPC_SERIALIZER_ENUM_GUARD(something, something::EndGuard_) + template <> \ + struct ParamTraits \ + : public mozilla::dom::WebIDLEnumSerializer {} #define DEFINE_IPC_SERIALIZER_FFI_ENUM(something) \ DEFINE_IPC_SERIALIZER_ENUM_GUARD(something, something##_Sentinel) diff --git a/dom/webidl/ARIAMixin.webidl b/dom/webidl/ARIAMixin.webidl new file mode 100644 index 0000000000..10d23af96e --- /dev/null +++ b/dom/webidl/ARIAMixin.webidl @@ -0,0 +1,148 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * https://w3c.github.io/aria/#ARIAMixin + * + * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C + * liability, trademark and document use rules apply. + */ + +interface mixin ARIAMixin { + [Pref="accessibility.ARIAElementReflection.enabled", CEReactions] + attribute Element? ariaActiveDescendantElement; + + [CEReactions, SetterThrows] + attribute DOMString? role; + + [CEReactions, SetterThrows] + attribute DOMString? ariaAtomic; + + [CEReactions, SetterThrows] + attribute DOMString? ariaAutoComplete; + + [CEReactions, SetterThrows] + attribute DOMString? ariaBrailleLabel; + + [CEReactions, SetterThrows] + attribute DOMString? ariaBrailleRoleDescription; + + [CEReactions, SetterThrows] + attribute DOMString? ariaBusy; + + [CEReactions, SetterThrows] + attribute DOMString? ariaChecked; + + [CEReactions, SetterThrows] + attribute DOMString? ariaColCount; + + [CEReactions, SetterThrows] + attribute DOMString? ariaColIndex; + + [CEReactions, SetterThrows] + attribute DOMString? ariaColIndexText; + + [CEReactions, SetterThrows] + attribute DOMString? ariaColSpan; + + [CEReactions, SetterThrows] + attribute DOMString? ariaCurrent; + + [CEReactions, SetterThrows] + attribute DOMString? ariaDescription; + + [CEReactions, SetterThrows] + attribute DOMString? ariaDisabled; + + [CEReactions, SetterThrows] + attribute DOMString? ariaExpanded; + + [CEReactions, SetterThrows] + attribute DOMString? ariaHasPopup; + + [CEReactions, SetterThrows] + attribute DOMString? ariaHidden; + + [CEReactions, SetterThrows] + attribute DOMString? ariaInvalid; + + [CEReactions, SetterThrows] + attribute DOMString? ariaKeyShortcuts; + + [CEReactions, SetterThrows] + attribute DOMString? ariaLabel; + + [CEReactions, SetterThrows] + attribute DOMString? ariaLevel; + + [CEReactions, SetterThrows] + attribute DOMString? ariaLive; + + [CEReactions, SetterThrows] + attribute DOMString? ariaModal; + + [CEReactions, SetterThrows] + attribute DOMString? ariaMultiLine; + + [CEReactions, SetterThrows] + attribute DOMString? ariaMultiSelectable; + + [CEReactions, SetterThrows] + attribute DOMString? ariaOrientation; + + [CEReactions, SetterThrows] + attribute DOMString? ariaPlaceholder; + + [CEReactions, SetterThrows] + attribute DOMString? ariaPosInSet; + + [CEReactions, SetterThrows] + attribute DOMString? ariaPressed; + + [CEReactions, SetterThrows] + attribute DOMString? ariaReadOnly; + + [CEReactions, SetterThrows] + attribute DOMString? ariaRelevant; + + [CEReactions, SetterThrows] + attribute DOMString? ariaRequired; + + [CEReactions, SetterThrows] + attribute DOMString? ariaRoleDescription; + + [CEReactions, SetterThrows] + attribute DOMString? ariaRowCount; + + [CEReactions, SetterThrows] + attribute DOMString? ariaRowIndex; + + [CEReactions, SetterThrows] + attribute DOMString? ariaRowIndexText; + + [CEReactions, SetterThrows] + attribute DOMString? ariaRowSpan; + + [CEReactions, SetterThrows] + attribute DOMString? ariaSelected; + + [CEReactions, SetterThrows] + attribute DOMString? ariaSetSize; + + [CEReactions, SetterThrows] + attribute DOMString? ariaSort; + + [CEReactions, SetterThrows] + attribute DOMString? ariaValueMax; + + [CEReactions, SetterThrows] + attribute DOMString? ariaValueMin; + + [CEReactions, SetterThrows] + attribute DOMString? ariaValueNow; + + [CEReactions, SetterThrows] + attribute DOMString? ariaValueText; +}; diff --git a/dom/webidl/AbortController.webidl b/dom/webidl/AbortController.webidl index 2b172b7718..1d35d192ca 100644 --- a/dom/webidl/AbortController.webidl +++ b/dom/webidl/AbortController.webidl @@ -7,7 +7,7 @@ * https://dom.spec.whatwg.org/#abortcontroller */ -[Exposed=(Window,Worker)] +[Exposed=*] interface AbortController { [Throws] constructor(); diff --git a/dom/webidl/AccessibilityRole.webidl b/dom/webidl/AccessibilityRole.webidl deleted file mode 100644 index 3e47e3180d..0000000000 --- a/dom/webidl/AccessibilityRole.webidl +++ /dev/null @@ -1,16 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - * - * The origin of this IDL file is - * https://rawgit.com/w3c/aria/master/#AccessibilityRole - * - * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C - * liability, trademark and document use rules apply. - */ - -interface mixin AccessibilityRole { - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? role; -}; diff --git a/dom/webidl/AddonManager.webidl b/dom/webidl/AddonManager.webidl index d392b90fb9..fc94228954 100644 --- a/dom/webidl/AddonManager.webidl +++ b/dom/webidl/AddonManager.webidl @@ -35,9 +35,9 @@ interface Addon { [ChromeOnly, JSImplementation="dummy", Exposed=Window] interface AddonInstall : EventTarget { - // One of the STATE_* symbols from AddonManager.jsm + // One of the STATE_* symbols from AddonManager.sys.mjs readonly attribute DOMString state; - // One of the ERROR_* symbols from AddonManager.jsm, or null + // One of the ERROR_* symbols from AddonManager.sys.mjs, or null readonly attribute DOMString? error; // How many bytes have been downloaded readonly attribute long long progress; diff --git a/dom/webidl/AriaAttributes.webidl b/dom/webidl/AriaAttributes.webidl deleted file mode 100644 index f6c34f01dc..0000000000 --- a/dom/webidl/AriaAttributes.webidl +++ /dev/null @@ -1,136 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - * - * The origin of this IDL file is - * https://rawgit.com/w3c/aria/master/#AriaAttributes - * - * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C - * liability, trademark and document use rules apply. - */ - -interface mixin AriaAttributes { - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaAtomic; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaAutoComplete; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaBusy; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaChecked; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaColCount; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaColIndex; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaColIndexText; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaColSpan; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaCurrent; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaDescription; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaDisabled; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaExpanded; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaHasPopup; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaHidden; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaInvalid; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaKeyShortcuts; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaLabel; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaLevel; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaLive; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaModal; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaMultiLine; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaMultiSelectable; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaOrientation; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaPlaceholder; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaPosInSet; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaPressed; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaReadOnly; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaRelevant; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaRequired; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaRoleDescription; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaRowCount; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaRowIndex; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaRowIndexText; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaRowSpan; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaSelected; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaSetSize; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaSort; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaValueMax; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaValueMin; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaValueNow; - - [Pref="accessibility.ARIAReflection.enabled", CEReactions, SetterThrows] - attribute DOMString? ariaValueText; -}; diff --git a/dom/webidl/AudioData.webidl b/dom/webidl/AudioData.webidl new file mode 100644 index 0000000000..e413e93971 --- /dev/null +++ b/dom/webidl/AudioData.webidl @@ -0,0 +1,63 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * https://w3c.github.io/webcodecs/#audiodata + */ + +// [Serializable, Transferable] are implemented without adding attributes here, +// but directly with {Read,Write}StructuredClone and Transfer/FromTransfered. +[Exposed=(Window,DedicatedWorker), Pref="dom.media.webcodecs.enabled"] +interface AudioData { + [Throws] + constructor(AudioDataInit init); + + readonly attribute AudioSampleFormat? format; + readonly attribute float sampleRate; + readonly attribute unsigned long numberOfFrames; + readonly attribute unsigned long numberOfChannels; + readonly attribute unsigned long long duration; // microseconds + readonly attribute long long timestamp; // microseconds + + [Throws] + unsigned long allocationSize(AudioDataCopyToOptions options); + [Throws] + undefined copyTo( + // bug 1696216: Should be `copyTo(AllowSharedBufferSource destination, ...)` + ([AllowShared] ArrayBufferView or [AllowShared] ArrayBuffer) destination, + AudioDataCopyToOptions options); + [Throws] + AudioData clone(); + undefined close(); +}; + +dictionary AudioDataInit { + required AudioSampleFormat format; + required float sampleRate; + required [EnforceRange] unsigned long numberOfFrames; + required [EnforceRange] unsigned long numberOfChannels; + required [EnforceRange] long long timestamp; // microseconds + // bug 1696216: Should be AllowSharedBufferSource + required ([AllowShared] ArrayBufferView or [AllowShared] ArrayBuffer) data; + sequence transfer = []; +}; + +enum AudioSampleFormat { + "u8", + "s16", + "s32", + "f32", + "u8-planar", + "s16-planar", + "s32-planar", + "f32-planar", +}; + +dictionary AudioDataCopyToOptions { + required [EnforceRange] unsigned long planeIndex; + [EnforceRange] unsigned long frameOffset = 0; + [EnforceRange] unsigned long frameCount; + AudioSampleFormat format; +}; diff --git a/dom/webidl/AudioDecoder.webidl b/dom/webidl/AudioDecoder.webidl new file mode 100644 index 0000000000..55cfe8e5e3 --- /dev/null +++ b/dom/webidl/AudioDecoder.webidl @@ -0,0 +1,53 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * https://w3c.github.io/webcodecs/#audiodecoder + */ + +[Exposed=(Window,DedicatedWorker), SecureContext, Pref="dom.media.webcodecs.enabled"] +interface AudioDecoder : EventTarget { + [Throws] + constructor(AudioDecoderInit init); + + readonly attribute CodecState state; + readonly attribute unsigned long decodeQueueSize; + attribute EventHandler ondequeue; + + [Throws] + undefined configure(AudioDecoderConfig config); + [Throws] + undefined decode(EncodedAudioChunk chunk); + [NewObject, Throws] + Promise flush(); + [Throws] + undefined reset(); + [Throws] + undefined close(); + + [NewObject, Throws] + static Promise isConfigSupported(AudioDecoderConfig config); +}; + +dictionary AudioDecoderInit { + required AudioDataOutputCallback output; + required WebCodecsErrorCallback error; +}; + +callback AudioDataOutputCallback = undefined(AudioData output); + +dictionary AudioDecoderSupport { + boolean supported; + AudioDecoderConfig config; +}; + +dictionary AudioDecoderConfig { + required DOMString codec; + required [EnforceRange] unsigned long sampleRate; + required [EnforceRange] unsigned long numberOfChannels; + + // Bug 1696216: Should be AllowSharedBufferSource + ([AllowShared] ArrayBufferView or [AllowShared] ArrayBuffer) description; +}; diff --git a/dom/webidl/CSSStyleDeclaration.webidl b/dom/webidl/CSSStyleDeclaration.webidl index 76050b75a0..8e38957412 100644 --- a/dom/webidl/CSSStyleDeclaration.webidl +++ b/dom/webidl/CSSStyleDeclaration.webidl @@ -21,6 +21,9 @@ interface CSSStyleDeclaration { [Throws, ChromeOnly] sequence getCSSImageURLs(UTF8String property); + [ChromeOnly] + readonly attribute float usedFontSize; + UTF8String getPropertyValue(UTF8String property); UTF8String getPropertyPriority(UTF8String property); [CEReactions, NeedsSubjectPrincipal=NonSystem, Throws] diff --git a/dom/webidl/CanvasRenderingContext2D.webidl b/dom/webidl/CanvasRenderingContext2D.webidl index c89c098928..d6c27d91b5 100644 --- a/dom/webidl/CanvasRenderingContext2D.webidl +++ b/dom/webidl/CanvasRenderingContext2D.webidl @@ -151,6 +151,7 @@ interface mixin CanvasState { undefined save(); // push state on state stack undefined restore(); // pop state stack and restore state undefined reset(); // reset the rendering context to its default state + boolean isContextLost(); // return whether context is lost }; interface mixin CanvasTransform { diff --git a/dom/webidl/Console.webidl b/dom/webidl/Console.webidl index 1f43ee19b6..68d86925d1 100644 --- a/dom/webidl/Console.webidl +++ b/dom/webidl/Console.webidl @@ -14,7 +14,7 @@ namespace console { // NOTE: if you touch this namespace, remember to update the ConsoleInstance - // interface as well! + // interface as well! - dom/chrome-webidl/ConsoleInstance.webidl // Logging [UseCounter] @@ -78,173 +78,3 @@ namespace console { [ChromeOnly, NewObject] ConsoleInstance createInstance(optional ConsoleInstanceOptions options = {}); }; - -// This is used to propagate console events to the observers. -[GenerateConversionToJS] -dictionary ConsoleEvent { - (unsigned long long or DOMString) ID; - (unsigned long long or DOMString) innerID; - DOMString consoleID = ""; - DOMString addonId = ""; - DOMString level = ""; - DOMString filename = ""; - // Unique identifier within the process for the script source this event is - // associated with, or zero. - unsigned long sourceId = 0; - unsigned long lineNumber = 0; - unsigned long columnNumber = 0; - DOMString functionName = ""; - double timeStamp = 0; - double microSecondTimeStamp = 0; - sequence arguments; - sequence styles; - boolean private = false; - // stacktrace is handled via a getter in some cases so we can construct it - // lazily. Note that we're not making this whole thing an interface because - // consumers expect to see own properties on it, which would mean making the - // props unforgeable, which means lots of JSFunction allocations. Maybe we - // should fix those consumers, of course.... - // sequence stacktrace; - DOMString groupName = ""; - any timer = null; - any counter = null; - DOMString prefix = ""; - boolean chromeContext = false; -}; - -// Event for profile operations -[GenerateConversionToJS] -dictionary ConsoleProfileEvent { - DOMString action = ""; - sequence arguments; - boolean chromeContext = false; -}; - -// This dictionary is used to manage stack trace data. -[GenerateConversionToJS] -dictionary ConsoleStackEntry { - DOMString filename = ""; - // Unique identifier within the process for the script source this entry is - // associated with, or zero. - unsigned long sourceId = 0; - unsigned long lineNumber = 0; - unsigned long columnNumber = 0; - DOMString functionName = ""; - DOMString? asyncCause; -}; - -[GenerateConversionToJS] -dictionary ConsoleTimerStart { - DOMString name = ""; -}; - -[GenerateConversionToJS] -dictionary ConsoleTimerLogOrEnd { - DOMString name = ""; - double duration = 0; -}; - -[GenerateConversionToJS] -dictionary ConsoleTimerError { - DOMString error = ""; - DOMString name = ""; -}; - -[GenerateConversionToJS] -dictionary ConsoleCounter { - DOMString label = ""; - unsigned long count = 0; -}; - -[GenerateConversionToJS] -dictionary ConsoleCounterError { - DOMString label = ""; - DOMString error = ""; -}; - -[ChromeOnly, - Exposed=(Window,Worker,WorkerDebugger,Worklet)] -// This is basically a copy of the console namespace. -interface ConsoleInstance { - // Logging - undefined assert(optional boolean condition = false, any... data); - undefined clear(); - undefined count(optional DOMString label = "default"); - undefined countReset(optional DOMString label = "default"); - undefined debug(any... data); - undefined error(any... data); - undefined info(any... data); - undefined log(any... data); - undefined table(any... data); // FIXME: The spec is still unclear about this. - undefined trace(any... data); - undefined warn(any... data); - undefined dir(any... data); // FIXME: This doesn't follow the spec yet. - undefined dirxml(any... data); - - // Grouping - undefined group(any... data); - undefined groupCollapsed(any... data); - undefined groupEnd(); - - // Timing - undefined time(optional DOMString label = "default"); - undefined timeLog(optional DOMString label = "default", any... data); - undefined timeEnd(optional DOMString label = "default"); - - // Mozilla only or Webcompat methods - - undefined _exception(any... data); - undefined timeStamp(optional any data); - - undefined profile(any... data); - undefined profileEnd(any... data); - - // Returns true if the given level would log a message. Used for avoiding - // long/significant processing when logging messages. - boolean shouldLog(ConsoleLogLevel level); -}; - -callback ConsoleInstanceDumpCallback = undefined (DOMString message); - -enum ConsoleLogLevel { - "All", "Debug", "Log", "Info", "Clear", "Trace", "TimeLog", "TimeEnd", "Time", - "Group", "GroupEnd", "Profile", "ProfileEnd", "Dir", "Dirxml", "Warn", "Error", - "Off" -}; - -dictionary ConsoleInstanceOptions { - // An optional function to intercept all strings written to stdout. - ConsoleInstanceDumpCallback dump; - - // An optional prefix string to be printed before the actual logged message. - DOMString prefix = ""; - - // An ID representing the source of the message. Normally the inner ID of a - // DOM window. - DOMString innerID = ""; - - // String identified for the console, this will be passed through the console - // notifications. - DOMString consoleID = ""; - - // Identifier that allows to filter which messages are logged based on their - // log level. - ConsoleLogLevel maxLogLevel; - - // String pref name which contains the level to use for maxLogLevel. If the - // pref doesn't exist, gets removed or it is used in workers, the maxLogLevel - // will default to the value passed to this constructor (or "all" if it wasn't - // specified). - DOMString maxLogLevelPref = ""; -}; - -enum ConsoleLevel { "log", "warning", "error" }; - -// this interface is just for testing -partial interface ConsoleInstance { - [ChromeOnly] - undefined reportForServiceWorkerScope(DOMString scope, DOMString message, - DOMString filename, unsigned long lineNumber, - unsigned long columnNumber, - ConsoleLevel level); -}; diff --git a/dom/webidl/DOMRequest.webidl b/dom/webidl/DOMRequest.webidl deleted file mode 100644 index 606b33b02f..0000000000 --- a/dom/webidl/DOMRequest.webidl +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -enum DOMRequestReadyState { "pending", "done" }; - -[Exposed=(Window,Worker)] -interface mixin DOMRequestShared { - readonly attribute DOMRequestReadyState readyState; - - readonly attribute any result; - readonly attribute DOMException? error; - - attribute EventHandler onsuccess; - attribute EventHandler onerror; -}; - -[Pref="dom.domrequest.enabled", Exposed=(Window,Worker)] -interface DOMRequest : EventTarget { - // The [TreatNonCallableAsNull] annotation is required since then() should do - // nothing instead of throwing errors when non-callable arguments are passed. - // See documentation for Promise.then to see why we return "any". - [NewObject, Throws] - any then([TreatNonCallableAsNull] optional AnyCallback? fulfillCallback = null, - [TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null); - - [ChromeOnly] - undefined fireDetailedError(DOMException aError); -}; - -DOMRequest includes DOMRequestShared; diff --git a/dom/webidl/Element.webidl b/dom/webidl/Element.webidl index 75d07995fb..32cb1dd30b 100644 --- a/dom/webidl/Element.webidl +++ b/dom/webidl/Element.webidl @@ -311,8 +311,7 @@ Element includes NonDocumentTypeChildNode; Element includes ParentNode; Element includes Animatable; Element includes GeometryUtils; -Element includes AccessibilityRole; -Element includes AriaAttributes; +Element includes ARIAMixin; // https://fullscreen.spec.whatwg.org/#api partial interface Element { diff --git a/dom/webidl/ElementInternals.webidl b/dom/webidl/ElementInternals.webidl index 175d0e4e1c..4b86e73060 100644 --- a/dom/webidl/ElementInternals.webidl +++ b/dom/webidl/ElementInternals.webidl @@ -63,8 +63,7 @@ partial interface ElementInternals { readonly attribute HTMLElement? validationAnchor; }; -ElementInternals includes AccessibilityRole; -ElementInternals includes AriaAttributes; +ElementInternals includes ARIAMixin; dictionary ValidityStateFlags { boolean valueMissing = false; diff --git a/dom/webidl/EncodedAudioChunk.webidl b/dom/webidl/EncodedAudioChunk.webidl new file mode 100644 index 0000000000..bf4c44e47d --- /dev/null +++ b/dom/webidl/EncodedAudioChunk.webidl @@ -0,0 +1,38 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * https://w3c.github.io/webcodecs/#encodedaudiochunk + */ + +// [Serializable] is implemented without adding attribute here. +[Exposed=(Window,DedicatedWorker), Pref="dom.media.webcodecs.enabled"] +interface EncodedAudioChunk { + [Throws] + constructor(EncodedAudioChunkInit init); + readonly attribute EncodedAudioChunkType type; + readonly attribute long long timestamp; // microseconds + readonly attribute unsigned long long? duration; // microseconds + readonly attribute unsigned long byteLength; + + [Throws] + undefined copyTo( + // bug 1696216: Should be `copyTo(AllowSharedBufferSource destination, ...)` + ([AllowShared] ArrayBufferView or [AllowShared] ArrayBuffer) destination); +}; + +dictionary EncodedAudioChunkInit { + required EncodedAudioChunkType type; + required [EnforceRange] long long timestamp; // microseconds + [EnforceRange] unsigned long long duration; // microseconds + // bug 1696216: Should be AllowSharedBufferSource + required ([AllowShared] ArrayBufferView or [AllowShared] ArrayBuffer) data; + sequence transfer = []; +}; + +enum EncodedAudioChunkType { + "key", + "delta" +}; diff --git a/dom/webidl/EventHandler.webidl b/dom/webidl/EventHandler.webidl index 439ac79e5d..c88e4f0422 100644 --- a/dom/webidl/EventHandler.webidl +++ b/dom/webidl/EventHandler.webidl @@ -39,7 +39,9 @@ interface mixin GlobalEventHandlers { attribute EventHandler onchange; attribute EventHandler onclick; attribute EventHandler onclose; + attribute EventHandler oncontextlost; attribute EventHandler oncontextmenu; + attribute EventHandler oncontextrestored; attribute EventHandler oncopy; attribute EventHandler oncuechange; attribute EventHandler oncut; diff --git a/dom/webidl/Gamepad.webidl b/dom/webidl/Gamepad.webidl index a8ec894441..e730d070ee 100644 --- a/dom/webidl/Gamepad.webidl +++ b/dom/webidl/Gamepad.webidl @@ -10,8 +10,7 @@ */ [Pref="dom.gamepad.enabled", - Exposed=Window, - SecureContext] + Exposed=Window] interface GamepadButton { readonly attribute boolean pressed; readonly attribute boolean touched; @@ -35,8 +34,7 @@ enum GamepadMappingType { }; [Pref="dom.gamepad.enabled", - Exposed=Window, - SecureContext] + Exposed=Window] interface Gamepad { /** * An identifier, unique per type of device. diff --git a/dom/webidl/GamepadAxisMoveEvent.webidl b/dom/webidl/GamepadAxisMoveEvent.webidl index 6ccdeabf71..24f16568f2 100644 --- a/dom/webidl/GamepadAxisMoveEvent.webidl +++ b/dom/webidl/GamepadAxisMoveEvent.webidl @@ -5,7 +5,7 @@ */ [Pref="dom.gamepad.non_standard_events.enabled", - Exposed=Window, SecureContext] + Exposed=Window] interface GamepadAxisMoveEvent : GamepadEvent { constructor(DOMString type, diff --git a/dom/webidl/GamepadButtonEvent.webidl b/dom/webidl/GamepadButtonEvent.webidl index 02bc4fb010..47d71107f0 100644 --- a/dom/webidl/GamepadButtonEvent.webidl +++ b/dom/webidl/GamepadButtonEvent.webidl @@ -5,8 +5,7 @@ */ [Pref="dom.gamepad.non_standard_events.enabled", - Exposed=Window, - SecureContext] + Exposed=Window] interface GamepadButtonEvent : GamepadEvent { constructor(DOMString type, diff --git a/dom/webidl/GamepadEvent.webidl b/dom/webidl/GamepadEvent.webidl index be2ad9ec10..0189050093 100644 --- a/dom/webidl/GamepadEvent.webidl +++ b/dom/webidl/GamepadEvent.webidl @@ -8,8 +8,7 @@ */ [Pref="dom.gamepad.enabled", - Exposed=Window, - SecureContext] + Exposed=Window] interface GamepadEvent : Event { constructor(DOMString type, optional GamepadEventInit eventInitDict = {}); diff --git a/dom/webidl/GamepadHapticActuator.webidl b/dom/webidl/GamepadHapticActuator.webidl index 9975b7ab85..0f3c8e0553 100644 --- a/dom/webidl/GamepadHapticActuator.webidl +++ b/dom/webidl/GamepadHapticActuator.webidl @@ -13,8 +13,7 @@ enum GamepadHapticActuatorType { [Pref="dom.gamepad.extensions.enabled", HeaderFile="mozilla/dom/GamepadHapticActuator.h", - Exposed=Window, - SecureContext] + Exposed=Window] interface GamepadHapticActuator { readonly attribute GamepadHapticActuatorType type; diff --git a/dom/webidl/GamepadLightIndicator.webidl b/dom/webidl/GamepadLightIndicator.webidl index 2c447439c8..c421c230bb 100644 --- a/dom/webidl/GamepadLightIndicator.webidl +++ b/dom/webidl/GamepadLightIndicator.webidl @@ -18,7 +18,7 @@ dictionary GamepadLightColor { required octet blue; }; -[SecureContext, Pref="dom.gamepad.extensions.lightindicator", +[Pref="dom.gamepad.extensions.lightindicator", Exposed=Window] interface GamepadLightIndicator { diff --git a/dom/webidl/GamepadPose.webidl b/dom/webidl/GamepadPose.webidl index 4de822e7a7..055df15930 100644 --- a/dom/webidl/GamepadPose.webidl +++ b/dom/webidl/GamepadPose.webidl @@ -8,8 +8,7 @@ */ [Pref="dom.gamepad.extensions.enabled", - Exposed=Window, - SecureContext] + Exposed=Window] interface GamepadPose { readonly attribute boolean hasOrientation; diff --git a/dom/webidl/GamepadTouch.webidl b/dom/webidl/GamepadTouch.webidl index a9c84edcbd..07e231d29d 100644 --- a/dom/webidl/GamepadTouch.webidl +++ b/dom/webidl/GamepadTouch.webidl @@ -7,7 +7,7 @@ * https://github.com/knyg/gamepad/blob/multitouch/extensions.html */ -[SecureContext, Pref="dom.gamepad.extensions.multitouch", +[Pref="dom.gamepad.extensions.multitouch", Exposed=Window] interface GamepadTouch { readonly attribute unsigned long touchId; diff --git a/dom/webidl/GleanMetrics.webidl b/dom/webidl/GleanMetrics.webidl index fc2697851d..47dc3262f1 100644 --- a/dom/webidl/GleanMetrics.webidl +++ b/dom/webidl/GleanMetrics.webidl @@ -111,6 +111,7 @@ interface GleanCounter : GleanMetric { dictionary GleanDistributionData { required unsigned long long sum; + required unsigned long long count; required record values; }; @@ -642,3 +643,35 @@ interface GleanText : GleanMetric { [Throws, ChromeOnly] UTF8String? testGetValue(optional UTF8String aPingName = ""); }; + +[Func="nsGlobalWindowInner::IsGleanNeeded", Exposed=Window] +interface GleanObject : GleanMetric { + /** + * Set to the specified object. + * + * The structure of the metric is validated against the predefined structure. + * + * @param object The object to set the metric to. + */ + undefined set(object value); + + /** + * **Test-only API** + * + * Gets the currently stored value as an object. + * + * This function will attempt to await the last parent-process task (if any) + * writing to the the metric's storage engine before returning a value. + * This function will not wait for data from child processes. + * + * This doesn't clear the stored value. + * Parent process only. Panics in child processes. + * + * @param aPingName The (optional) name of the ping to retrieve the metric + * for. Defaults to the first value in `send_in_pings`. + * + * @return value of the stored metric, or undefined if there is no value. + */ + [Throws, ChromeOnly] + object? testGetValue(optional UTF8String aPingName = ""); +}; diff --git a/dom/webidl/HTMLImageElement.webidl b/dom/webidl/HTMLImageElement.webidl index 1495d25f74..c57727bd51 100644 --- a/dom/webidl/HTMLImageElement.webidl +++ b/dom/webidl/HTMLImageElement.webidl @@ -43,6 +43,8 @@ interface HTMLImageElement : HTMLElement { attribute DOMString decoding; [CEReactions, SetterThrows] attribute DOMString loading; + [Pref="network.fetchpriority.enabled", CEReactions] + attribute DOMString fetchPriority; readonly attribute unsigned long naturalWidth; readonly attribute unsigned long naturalHeight; readonly attribute boolean complete; diff --git a/dom/webidl/HTMLTemplateElement.webidl b/dom/webidl/HTMLTemplateElement.webidl index ce71a51fe5..526a3427a8 100644 --- a/dom/webidl/HTMLTemplateElement.webidl +++ b/dom/webidl/HTMLTemplateElement.webidl @@ -16,6 +16,8 @@ interface HTMLTemplateElement : HTMLElement { readonly attribute DocumentFragment content; [CEReactions, Pref="dom.webcomponents.shadowdom.declarative.enabled"] attribute DOMString shadowRootMode; - [CEReactions, Pref="dom.webcomponents.shadowdom.declarative.enabled"] + [CEReactions, SetterThrows, Pref="dom.webcomponents.shadowdom.declarative.enabled"] attribute boolean shadowRootDelegatesFocus; + [CEReactions, SetterThrows, Pref="dom.webcomponents.shadowdom.declarative.enabled"] + attribute boolean shadowRootClonable; }; diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index 935ffdabec..3546a31bee 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -211,7 +211,7 @@ partial interface Navigator { // https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#navigator-interface-extension partial interface Navigator { - [Throws, Pref="dom.gamepad.enabled", SecureContext] + [Throws, Pref="dom.gamepad.enabled"] sequence getGamepads(); }; partial interface Navigator { diff --git a/dom/webidl/RTCDtlsTransport.webidl b/dom/webidl/RTCDtlsTransport.webidl index 0b2f095ab6..99b70af470 100644 --- a/dom/webidl/RTCDtlsTransport.webidl +++ b/dom/webidl/RTCDtlsTransport.webidl @@ -18,6 +18,7 @@ enum RTCDtlsTransportState { [Pref="media.peerconnection.enabled", Exposed=Window] interface RTCDtlsTransport : EventTarget { + [SameObject] readonly attribute RTCIceTransport iceTransport; readonly attribute RTCDtlsTransportState state; attribute EventHandler onstatechange; }; diff --git a/dom/webidl/RTCIceTransport.webidl b/dom/webidl/RTCIceTransport.webidl new file mode 100644 index 0000000000..35a1c74018 --- /dev/null +++ b/dom/webidl/RTCIceTransport.webidl @@ -0,0 +1,43 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * https://w3c.github.io/webrtc-pc/#dom-rtcicetransport + */ + +enum RTCIceTransportState { + "closed", + "failed", + "disconnected", + "new", + "checking", + "completed", + "connected" +}; + +enum RTCIceGathererState { + "new", + "gathering", + "complete" +}; + +[Exposed=Window] +interface RTCIceTransport : EventTarget { + // TODO(bug 1307994) + // readonly attribute RTCIceRole role; + // readonly attribute RTCIceComponent component; + readonly attribute RTCIceTransportState state; + readonly attribute RTCIceGathererState gatheringState; + // TODO(bug 1307994) + // sequence getLocalCandidates(); + // sequence getRemoteCandidates(); + // RTCIceCandidatePair? getSelectedCandidatePair(); + // RTCIceParameters? getLocalParameters(); + // RTCIceParameters? getRemoteParameters(); + attribute EventHandler onstatechange; + attribute EventHandler ongatheringstatechange; + // TODO(bug 1307994) + // attribute EventHandler onselectedcandidatepairchange; +}; diff --git a/dom/webidl/RTCPeerConnection.webidl b/dom/webidl/RTCPeerConnection.webidl index 8fb908788e..ac3093a848 100644 --- a/dom/webidl/RTCPeerConnection.webidl +++ b/dom/webidl/RTCPeerConnection.webidl @@ -27,13 +27,13 @@ enum RTCIceGatheringState { }; enum RTCIceConnectionState { - "new", - "checking", - "connected", - "completed", - "failed", - "disconnected", - "closed" + "closed", + "failed", + "disconnected", + "new", + "checking", + "completed", + "connected" }; enum RTCPeerConnectionState { @@ -90,8 +90,7 @@ dictionary RTCOfferOptions : RTCOfferAnswerOptions { Exposed=Window] interface RTCPeerConnection : EventTarget { [Throws] - constructor(optional RTCConfiguration configuration = {}, - optional object? constraints); + constructor(optional RTCConfiguration configuration = {}); [Throws, StaticClassOverride="mozilla::dom::RTCCertificate"] static Promise generateCertificate (AlgorithmIdentifier keygenAlgorithm); @@ -99,13 +98,13 @@ interface RTCPeerConnection : EventTarget { undefined setIdentityProvider (DOMString provider, optional RTCIdentityProviderOptions options = {}); Promise getIdentityAssertion(); - Promise createOffer (optional RTCOfferOptions options = {}); - Promise createAnswer (optional RTCAnswerOptions options = {}); - Promise setLocalDescription (optional RTCSessionDescriptionInit description = {}); - Promise setRemoteDescription (optional RTCSessionDescriptionInit description = {}); + Promise createOffer(optional RTCOfferOptions options = {}); + Promise createAnswer(optional RTCAnswerOptions options = {}); + Promise setLocalDescription(optional RTCLocalSessionDescriptionInit description = {}); readonly attribute RTCSessionDescription? localDescription; readonly attribute RTCSessionDescription? currentLocalDescription; readonly attribute RTCSessionDescription? pendingLocalDescription; + Promise setRemoteDescription(RTCSessionDescriptionInit description); readonly attribute RTCSessionDescription? remoteDescription; readonly attribute RTCSessionDescription? currentRemoteDescription; readonly attribute RTCSessionDescription? pendingRemoteDescription; @@ -181,21 +180,23 @@ interface RTCPeerConnection : EventTarget { partial interface RTCPeerConnection { - // Dummy Promise return values avoid "WebIDL.WebIDLError: error: - // We have overloads with both Promise and non-Promise return types" - - Promise createOffer (RTCSessionDescriptionCallback successCallback, - RTCPeerConnectionErrorCallback failureCallback, - optional RTCOfferOptions options = {}); - Promise createAnswer (RTCSessionDescriptionCallback successCallback, - RTCPeerConnectionErrorCallback failureCallback); - Promise setLocalDescription (RTCSessionDescriptionInit description, + // Legacy Interface Extensions + // Supporting the methods in this section is optional. + // If these methods are supported + // they must be implemented as defined + // in section "Legacy Interface Extensions" + Promise createOffer(RTCSessionDescriptionCallback successCallback, + RTCPeerConnectionErrorCallback failureCallback, + optional RTCOfferOptions options = {}); + Promise setLocalDescription(RTCLocalSessionDescriptionInit description, + VoidFunction successCallback, + RTCPeerConnectionErrorCallback failureCallback); + Promise createAnswer(RTCSessionDescriptionCallback successCallback, + RTCPeerConnectionErrorCallback failureCallback); + Promise setRemoteDescription(RTCSessionDescriptionInit description, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback); - Promise setRemoteDescription (RTCSessionDescriptionInit description, - VoidFunction successCallback, - RTCPeerConnectionErrorCallback failureCallback); - Promise addIceCandidate (RTCIceCandidate candidate, - VoidFunction successCallback, - RTCPeerConnectionErrorCallback failureCallback); + Promise addIceCandidate(RTCIceCandidateInit candidate, + VoidFunction successCallback, + RTCPeerConnectionErrorCallback failureCallback); }; diff --git a/dom/webidl/RTCSessionDescription.webidl b/dom/webidl/RTCSessionDescription.webidl index 6cf116ff6e..236d1e147c 100644 --- a/dom/webidl/RTCSessionDescription.webidl +++ b/dom/webidl/RTCSessionDescription.webidl @@ -4,7 +4,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is - * http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCSessionDescription + * https://www.w3.org/TR/webrtc/#rtcsessiondescription-class */ enum RTCSdpType { @@ -15,6 +15,11 @@ enum RTCSdpType { }; dictionary RTCSessionDescriptionInit { + required RTCSdpType type; + DOMString sdp = ""; +}; + +dictionary RTCLocalSessionDescriptionInit { RTCSdpType type; DOMString sdp = ""; }; @@ -24,7 +29,7 @@ dictionary RTCSessionDescriptionInit { Exposed=Window] interface RTCSessionDescription { [Throws] - constructor(optional RTCSessionDescriptionInit descriptionInitDict = {}); + constructor(RTCSessionDescriptionInit descriptionInitDict); // These should be readonly, but writing causes deprecation warnings for a bit attribute RTCSdpType type; diff --git a/dom/webidl/Request.webidl b/dom/webidl/Request.webidl index 1aa6be963f..54e4e5ec95 100644 --- a/dom/webidl/Request.webidl +++ b/dom/webidl/Request.webidl @@ -64,6 +64,9 @@ dictionary RequestInit { AbortSignal? signal; + [Pref="network.fetchpriority.enabled"] + RequestPriority priority; + [Pref="dom.fetchObserver.enabled"] ObserverCallback observe; }; diff --git a/dom/webidl/SVGAElement.webidl b/dom/webidl/SVGAElement.webidl index 94363513ea..f2621e9e79 100644 --- a/dom/webidl/SVGAElement.webidl +++ b/dom/webidl/SVGAElement.webidl @@ -29,7 +29,7 @@ interface SVGAElement : SVGGraphicsElement { [SetterThrows] attribute DOMString type; - [Throws] + [Throws, Pref="svg.SVGAElement.text.enabled"] attribute DOMString text; }; diff --git a/dom/webidl/SecurityPolicyViolationEvent.webidl b/dom/webidl/SecurityPolicyViolationEvent.webidl index 5578238347..4366347e14 100644 --- a/dom/webidl/SecurityPolicyViolationEvent.webidl +++ b/dom/webidl/SecurityPolicyViolationEvent.webidl @@ -1,6 +1,10 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * https://w3c.github.io/webappsec-csp/#violation-events + */ enum SecurityPolicyViolationEventDisposition { @@ -16,15 +20,15 @@ interface SecurityPolicyViolationEvent : Event readonly attribute DOMString documentURI; readonly attribute DOMString referrer; readonly attribute DOMString blockedURI; - readonly attribute DOMString violatedDirective; + readonly attribute DOMString violatedDirective; // historical alias of effectiveDirective readonly attribute DOMString effectiveDirective; readonly attribute DOMString originalPolicy; readonly attribute DOMString sourceFile; readonly attribute DOMString sample; readonly attribute SecurityPolicyViolationEventDisposition disposition; readonly attribute unsigned short statusCode; - readonly attribute long lineNumber; - readonly attribute long columnNumber; + readonly attribute unsigned long lineNumber; + readonly attribute unsigned long columnNumber; }; [GenerateInitFromJSON, GenerateToJSON] @@ -38,8 +42,8 @@ dictionary SecurityPolicyViolationEventInit : EventInit DOMString originalPolicy = ""; DOMString sourceFile = ""; DOMString sample = ""; - SecurityPolicyViolationEventDisposition disposition = "report"; + SecurityPolicyViolationEventDisposition disposition = "enforce"; unsigned short statusCode = 0; - long lineNumber = 0; - long columnNumber = 0; + unsigned long lineNumber = 0; + unsigned long columnNumber = 0; }; diff --git a/dom/webidl/TrustedTypes.webidl b/dom/webidl/TrustedTypes.webidl new file mode 100644 index 0000000000..3b7e35534f --- /dev/null +++ b/dom/webidl/TrustedTypes.webidl @@ -0,0 +1,64 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * . + */ + +[Exposed=(Window,Worker), Pref="dom.security.trusted_types.enabled"] +interface TrustedHTML { + stringifier; + DOMString toJSON(); +}; + +[Exposed=(Window,Worker), Pref="dom.security.trusted_types.enabled"] +interface TrustedScript { + stringifier; + DOMString toJSON(); +}; + +[Exposed=(Window,Worker), Pref="dom.security.trusted_types.enabled"] +interface TrustedScriptURL { + stringifier; + USVString toJSON(); +}; + +[Exposed=(Window,Worker), Pref="dom.security.trusted_types.enabled"] +interface TrustedTypePolicy { + readonly attribute DOMString name; + [NewObject] TrustedHTML createHTML(DOMString input, any... arguments); + [NewObject] TrustedScript createScript(DOMString input, any... arguments); + [NewObject] TrustedScriptURL createScriptURL(DOMString input, any... arguments); +}; + +dictionary TrustedTypePolicyOptions { + CreateHTMLCallback createHTML; + CreateScriptCallback createScript; + CreateScriptURLCallback createScriptURL; +}; + +callback CreateHTMLCallback = DOMString? (DOMString input, any... arguments); +callback CreateScriptCallback = DOMString? (DOMString input, any... arguments); +callback CreateScriptURLCallback = USVString? (DOMString input, any... arguments); + +[Exposed=(Window,Worker), Pref="dom.security.trusted_types.enabled"] +interface TrustedTypePolicyFactory { + TrustedTypePolicy createPolicy(DOMString policyName , optional TrustedTypePolicyOptions policyOptions = {}); + boolean isHTML(any value); + boolean isScript(any value); + boolean isScriptURL(any value); + [Pure, StoreInSlot] readonly attribute TrustedHTML emptyHTML; + [Pure, StoreInSlot] readonly attribute TrustedScript emptyScript; + DOMString? getAttributeType( + DOMString tagName, + DOMString attribute, + optional DOMString elementNs = "", + optional DOMString attrNs = ""); + DOMString? getPropertyType( + DOMString tagName, + DOMString property, + optional DOMString elementNs = ""); + readonly attribute TrustedTypePolicy? defaultPolicy; +}; diff --git a/dom/webidl/VideoDecoder.webidl b/dom/webidl/VideoDecoder.webidl index 0c8f5c9b5e..e8abb753dc 100644 --- a/dom/webidl/VideoDecoder.webidl +++ b/dom/webidl/VideoDecoder.webidl @@ -45,7 +45,7 @@ dictionary VideoDecoderSupport { dictionary VideoDecoderConfig { required DOMString codec; - // Bug 1696216: Should be 1696216 [AllowShared] BufferSource description; + // Bug 1696216: Should be [AllowShared] BufferSource description; ([AllowShared] ArrayBufferView or [AllowShared] ArrayBuffer) description; [EnforceRange] unsigned long codedWidth; [EnforceRange] unsigned long codedHeight; diff --git a/dom/webidl/WebGPU.webidl b/dom/webidl/WebGPU.webidl index 58e259258d..c01d501542 100644 --- a/dom/webidl/WebGPU.webidl +++ b/dom/webidl/WebGPU.webidl @@ -499,6 +499,8 @@ dictionary GPUTextureBindingLayout { enum GPUStorageTextureAccess { "write-only", + "read-only", + "read-write", }; dictionary GPUStorageTextureBindingLayout { @@ -599,7 +601,7 @@ interface mixin GPUPipelineBase { dictionary GPUProgrammableStage { required GPUShaderModule module; - required USVString entryPoint; + USVString entryPoint; }; //TODO: Serializable diff --git a/dom/webidl/WebXR.webidl b/dom/webidl/WebXR.webidl index 302c82156a..7545ffe728 100644 --- a/dom/webidl/WebXR.webidl +++ b/dom/webidl/WebXR.webidl @@ -27,8 +27,8 @@ enum XRSessionMode { }; dictionary XRSessionInit { - sequence requiredFeatures; - sequence optionalFeatures; + sequence requiredFeatures; + sequence optionalFeatures; }; enum XRVisibilityState { diff --git a/dom/webidl/WindowOrWorkerGlobalScope.webidl b/dom/webidl/WindowOrWorkerGlobalScope.webidl index 5b5f5c61f6..5e3ff86e88 100644 --- a/dom/webidl/WindowOrWorkerGlobalScope.webidl +++ b/dom/webidl/WindowOrWorkerGlobalScope.webidl @@ -85,3 +85,10 @@ partial interface mixin WindowOrWorkerGlobalScope { [Replaceable, Pref="dom.enable_web_task_scheduling", SameObject] readonly attribute Scheduler scheduler; }; + + +// https://w3c.github.io/trusted-types/dist/spec/#extensions-to-the-windoworworkerglobalscope-interface +partial interface mixin WindowOrWorkerGlobalScope { + [Pref="dom.security.trusted_types.enabled"] + readonly attribute TrustedTypePolicyFactory trustedTypes; +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 68b42a9c54..3880b727e7 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -13,10 +13,7 @@ with Files("APZTestData.webidl"): with Files("AccessibleNode.webidl"): BUG_COMPONENT = ("Core", "Disability Access APIs") -with Files("AccessibilityRole.webidl"): - BUG_COMPONENT = ("Core", "Disability Access APIs") - -with Files("AriaAttributes.webidl"): +with Files("ARIAMixin.webidl"): BUG_COMPONENT = ("Core", "Disability Access APIs") with Files("Addon*"): @@ -402,7 +399,6 @@ WEBIDL_FILES = [ "AbortSignal.webidl", "AbstractRange.webidl", "AbstractWorker.webidl", - "AccessibilityRole.webidl", "AddonManager.webidl", "AnalyserNode.webidl", "Animatable.webidl", @@ -415,11 +411,13 @@ WEBIDL_FILES = [ "AppInfo.webidl", "AppNotificationServiceOptions.webidl", "APZTestData.webidl", - "AriaAttributes.webidl", + "ARIAMixin.webidl", "Attr.webidl", "AudioBuffer.webidl", "AudioBufferSourceNode.webidl", "AudioContext.webidl", + "AudioData.webidl", + "AudioDecoder.webidl", "AudioDestinationNode.webidl", "AudioListener.webidl", "AudioNode.webidl", @@ -523,7 +521,6 @@ WEBIDL_FILES = [ "DOMQuad.webidl", "DOMRect.webidl", "DOMRectList.webidl", - "DOMRequest.webidl", "DOMStringList.webidl", "DOMStringMap.webidl", "DOMTokenList.webidl", @@ -531,6 +528,7 @@ WEBIDL_FILES = [ "DynamicsCompressorNode.webidl", "Element.webidl", "ElementInternals.webidl", + "EncodedAudioChunk.webidl", "EncodedVideoChunk.webidl", "Event.webidl", "EventHandler.webidl", @@ -978,6 +976,7 @@ WEBIDL_FILES = [ "TransformStreamDefaultController.webidl", "TransitionEvent.webidl", "TreeWalker.webidl", + "TrustedTypes.webidl", "UDPMessageEvent.webidl", "UDPSocket.webidl", "UIEvent.webidl", @@ -1052,6 +1051,7 @@ if CONFIG["MOZ_WEBRTC"]: "RTCEncodedAudioFrame.webidl", "RTCEncodedVideoFrame.webidl", "RTCIceCandidate.webidl", + "RTCIceTransport.webidl", "RTCIdentityAssertion.webidl", "RTCIdentityProvider.webidl", "RTCPeerConnection.webidl", diff --git a/dom/webscheduling/WebTaskScheduler.cpp b/dom/webscheduling/WebTaskScheduler.cpp index b6fa749095..46ece9793c 100644 --- a/dom/webscheduling/WebTaskScheduler.cpp +++ b/dom/webscheduling/WebTaskScheduler.cpp @@ -291,9 +291,8 @@ WebTask* WebTaskScheduler::GetNextTask() const { return nullptr; } - for (uint32_t priority = static_cast(TaskPriority::User_blocking); - priority < static_cast(TaskPriority::EndGuard_); ++priority) { - if (auto queues = allQueues.Lookup(priority)) { + for (TaskPriority priority : MakeWebIDLEnumeratedRange()) { + if (auto queues = allQueues.Lookup(UnderlyingValue(priority))) { WebTaskQueue* oldestQueue = nullptr; MOZ_ASSERT(!queues.Data().IsEmpty()); for (auto& webTaskQueue : queues.Data()) { diff --git a/dom/webtransport/parent/WebTransportParent.cpp b/dom/webtransport/parent/WebTransportParent.cpp index c9f7943cc3..236c9a945a 100644 --- a/dom/webtransport/parent/WebTransportParent.cpp +++ b/dom/webtransport/parent/WebTransportParent.cpp @@ -97,14 +97,15 @@ void WebTransportParent::Create( nsCOMPtr r = NS_NewRunnableFunction( "WebTransport AsyncConnect", [self = RefPtr{this}, uri = std::move(uri), + dedicated = true /* aDedicated, see BUG 1915735.*/, nsServerCertHashes = std::move(nsServerCertHashes), principal = RefPtr{aPrincipal}, flags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, clientInfo = aClientInfo] { LOG(("WebTransport %p AsyncConnect", self.get())); if (NS_FAILED(self->mWebTransport->AsyncConnectWithClient( - uri, std::move(nsServerCertHashes), principal, flags, self, - clientInfo))) { + uri, dedicated, std::move(nsServerCertHashes), principal, flags, + self, clientInfo))) { LOG(("AsyncConnect failure; we should get OnSessionClosed")); } }); diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 3d6a883867..02efb12053 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -369,6 +369,14 @@ void LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */) { PREF("gc_min_empty_chunk_count", JSGC_MIN_EMPTY_CHUNK_COUNT), PREF("gc_max_empty_chunk_count", JSGC_MAX_EMPTY_CHUNK_COUNT), PREF("gc_compacting", JSGC_COMPACTING_ENABLED), + PREF("gc_parallel_marking", JSGC_PARALLEL_MARKING_ENABLED), + PREF("gc_parallel_marking_threshold_mb", + JSGC_PARALLEL_MARKING_THRESHOLD_MB), + // Note: Workers do not currently trigger eager minor GC, but if that is + // desired the following parameters should be added: + // javascript.options.mem.nursery_eager_collection_threshold_kb + // javascript.options.mem.nursery_eager_collection_threshold_percent + // javascript.options.mem.nursery_eager_collection_timeout_ms }; #undef PREF @@ -439,6 +447,7 @@ void LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */) { case JSGC_MIN_EMPTY_CHUNK_COUNT: case JSGC_MAX_EMPTY_CHUNK_COUNT: case JSGC_HEAP_GROWTH_FACTOR: + case JSGC_PARALLEL_MARKING_THRESHOLD_MB: UpdateCommonJSGCMemoryOption(rts, pref->fullName, pref->key); break; default: @@ -1410,10 +1419,16 @@ nsresult RuntimeService::Init() { Preferences::GetInt(PREF_WORKERS_MAX_PER_DOMAIN, MAX_WORKERS_PER_DOMAIN); gMaxWorkersPerDomain = std::max(0, maxPerDomain); - if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) { + IndexedDatabaseManager* idm = IndexedDatabaseManager::GetOrCreate(); + if (NS_WARN_IF(!idm)) { return NS_ERROR_UNEXPECTED; } + rv = idm->EnsureLocale(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + // PerformanceService must be initialized on the main-thread. PerformanceService::GetOrCreate(); diff --git a/dom/workers/WorkerIPCUtils.h b/dom/workers/WorkerIPCUtils.h index 0be45b307f..a93fad5b02 100644 --- a/dom/workers/WorkerIPCUtils.h +++ b/dom/workers/WorkerIPCUtils.h @@ -6,7 +6,7 @@ #ifndef _mozilla_dom_WorkerIPCUtils_h #define _mozilla_dom_WorkerIPCUtils_h -#include "ipc/EnumSerializer.h" +#include "mozilla/dom/BindingIPCUtils.h" // Undo X11/X.h's definition of None #undef None @@ -17,9 +17,7 @@ namespace IPC { template <> struct ParamTraits - : public ContiguousEnumSerializer {}; + : public mozilla::dom::WebIDLEnumSerializer {}; } // namespace IPC diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 78de4adc3a..a8643981aa 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -2804,7 +2804,12 @@ nsresult WorkerPrivate::GetLoadInfo( AssertIsOnMainThread(); // Make sure that the IndexedDatabaseManager is set up - Unused << NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate()); + IndexedDatabaseManager* idm = IndexedDatabaseManager::GetOrCreate(); + if (idm) { + Unused << NS_WARN_IF(NS_FAILED(idm->EnsureLocale())); + } else { + NS_WARNING("Failed to get IndexedDatabaseManager!"); + } nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); MOZ_ASSERT(ssm); diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp index 159829f4a8..92d6c89dca 100644 --- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -404,6 +404,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScope, NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebTaskScheduler) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTrustedTypePolicyFactory) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet) @@ -420,6 +421,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope, tmp->mWebTaskScheduler->Disconnect(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebTaskScheduler) } + NS_IMPL_CYCLE_COLLECTION_UNLINK(mTrustedTypePolicyFactory) NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation) NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator) NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet) @@ -868,6 +870,14 @@ void WorkerGlobalScope::StorageAccessPermissionGranted() { mCacheStorage = nullptr; } +TrustedTypePolicyFactory* WorkerGlobalScope::TrustedTypes() { + if (!mTrustedTypePolicyFactory) { + mTrustedTypePolicyFactory = MakeRefPtr(this); + } + + return mTrustedTypePolicyFactory; +} + bool WorkerGlobalScope::WindowInteractionAllowed() const { AssertIsOnWorkerThread(); return mWindowInteractionsAllowed > 0; diff --git a/dom/workers/WorkerScope.h b/dom/workers/WorkerScope.h index 7e00f9b59b..12a97e12c3 100644 --- a/dom/workers/WorkerScope.h +++ b/dom/workers/WorkerScope.h @@ -22,6 +22,7 @@ #include "mozilla/dom/ImageBitmapSource.h" #include "mozilla/dom/PerformanceWorker.h" #include "mozilla/dom/SafeRefPtr.h" +#include "mozilla/dom/TrustedTypePolicyFactory.h" #include "mozilla/dom/WorkerPrivate.h" #include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" @@ -352,6 +353,8 @@ class WorkerGlobalScope : public WorkerGlobalScopeBase { MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void OnVsync(const VsyncEvent& aVsync) {} + TrustedTypePolicyFactory* TrustedTypes(); + protected: ~WorkerGlobalScope(); @@ -376,6 +379,7 @@ class WorkerGlobalScope : public WorkerGlobalScopeBase { RefPtr mCacheStorage; RefPtr mDebuggerNotificationManager; RefPtr mWebTaskScheduler; + RefPtr mTrustedTypePolicyFactory; uint32_t mWindowInteractionsAllowed = 0; bool mIsEligibleForMessaging{true}; }; diff --git a/dom/workers/remoteworkers/RemoteWorkerChild.cpp b/dom/workers/remoteworkers/RemoteWorkerChild.cpp index a644439a8d..feb294f3fc 100644 --- a/dom/workers/remoteworkers/RemoteWorkerChild.cpp +++ b/dom/workers/remoteworkers/RemoteWorkerChild.cpp @@ -232,7 +232,12 @@ nsresult RemoteWorkerChild::ExecWorkerOnMainThread(RemoteWorkerData&& aData) { // Ensure that the IndexedDatabaseManager is initialized so that if any // workers do any IndexedDB calls that all of IDB's prefs/etc. are // initialized. - Unused << NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate()); + IndexedDatabaseManager* idm = IndexedDatabaseManager::GetOrCreate(); + if (idm) { + Unused << NS_WARN_IF(NS_FAILED(idm->EnsureLocale())); + } else { + NS_WARNING("Failed to get IndexedDatabaseManager!"); + } auto scopeExit = MakeScopeExit([&] { ExceptionalErrorTransitionDuringExecWorker(); }); diff --git a/dom/workers/test/WorkerDebugger.console_debugger.js b/dom/workers/test/WorkerDebugger.console_debugger.js index a8b2493200..805b7fb387 100644 --- a/dom/workers/test/WorkerDebugger.console_debugger.js +++ b/dom/workers/test/WorkerDebugger.console_debugger.js @@ -1,5 +1,7 @@ "use strict"; +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + function ok(a, msg) { postMessage(JSON.stringify({ type: "status", what: !!a, msg })); } diff --git a/dom/workers/test/bug1014466_worker.js b/dom/workers/test/bug1014466_worker.js index 2161954d2b..e06979d7b3 100644 --- a/dom/workers/test/bug1014466_worker.js +++ b/dom/workers/test/bug1014466_worker.js @@ -3,6 +3,8 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + function ok(a, msg) { postMessage({ type: "status", status: !!a, msg }); } diff --git a/dom/workers/test/notification_permission_worker.js b/dom/workers/test/notification_permission_worker.js index 0e6b96d975..0551247d07 100644 --- a/dom/workers/test/notification_permission_worker.js +++ b/dom/workers/test/notification_permission_worker.js @@ -1,3 +1,5 @@ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + function info(message) { dump("INFO: " + message + "\n"); } diff --git a/dom/workers/test/notification_worker.js b/dom/workers/test/notification_worker.js index 87aa02ac05..b97a4eb505 100644 --- a/dom/workers/test/notification_worker.js +++ b/dom/workers/test/notification_worker.js @@ -1,3 +1,5 @@ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + function ok(test, message) { postMessage({ type: "ok", test, message }); } diff --git a/dom/workers/test/notification_worker_child-child.js b/dom/workers/test/notification_worker_child-child.js index 236e314e47..9356f1be7a 100644 --- a/dom/workers/test/notification_worker_child-child.js +++ b/dom/workers/test/notification_worker_child-child.js @@ -1,3 +1,5 @@ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + function ok(test, message) { postMessage({ type: "ok", test, message }); } diff --git a/dom/workers/test/onLine_worker_child.js b/dom/workers/test/onLine_worker_child.js index 92542c018f..cee3052c90 100644 --- a/dom/workers/test/onLine_worker_child.js +++ b/dom/workers/test/onLine_worker_child.js @@ -3,10 +3,7 @@ * http://creativecommons.org/licenses/publicdomain/ */ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - */ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ function info(text) { dump("Test for Bug 925437: worker: " + text + "\n"); diff --git a/dom/workers/test/onLine_worker_head.js b/dom/workers/test/onLine_worker_head.js index 632821b1f4..8c6d601aa5 100644 --- a/dom/workers/test/onLine_worker_head.js +++ b/dom/workers/test/onLine_worker_head.js @@ -3,6 +3,8 @@ * http://creativecommons.org/licenses/publicdomain/ */ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + function info(text) { dump("Test for Bug 925437: worker: " + text + "\n"); } diff --git a/dom/workers/test/promise_worker.js b/dom/workers/test/promise_worker.js index fd4a9177d6..1c2d080e5b 100644 --- a/dom/workers/test/promise_worker.js +++ b/dom/workers/test/promise_worker.js @@ -1,5 +1,7 @@ "use strict"; +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + function ok(a, msg) { dump("OK: " + !!a + " => " + a + " " + msg + "\n"); postMessage({ type: "status", status: !!a, msg: a + ": " + msg }); diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js index 3ea89ad6b5..efd108f85c 100644 --- a/dom/workers/test/test_worker_interfaces.js +++ b/dom/workers/test/test_worker_interfaces.js @@ -1,3 +1,5 @@ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + // This is a list of all interfaces that are exposed to workers. // Please only add things to this list with great care and proper review // from the associated module peers. @@ -132,6 +134,10 @@ let interfaceNamesInGlobalScope = [ // IMPORTANT: Do not change this list without review from a DOM peer! { name: "AbortSignal", insecureContext: true }, // IMPORTANT: Do not change this list without review from a DOM peer! + { name: "AudioData", insecureContext: true, nightly: true }, + // IMPORTANT: Do not change this list without review from a DOM peer! + { name: "AudioDecoder", nightly: true }, + // IMPORTANT: Do not change this list without review from a DOM peer! { name: "Blob", insecureContext: true }, // IMPORTANT: Do not change this list without review from a DOM peer! { name: "BroadcastChannel", insecureContext: true }, @@ -180,10 +186,10 @@ let interfaceNamesInGlobalScope = [ // IMPORTANT: Do not change this list without review from a DOM peer! { name: "DOMRectReadOnly", insecureContext: true }, // IMPORTANT: Do not change this list without review from a DOM peer! - { name: "DOMRequest", insecureContext: true, disabled: true }, - // IMPORTANT: Do not change this list without review from a DOM peer! { name: "DOMStringList", insecureContext: true }, // IMPORTANT: Do not change this list without review from a DOM peer! + { name: "EncodedAudioChunk", insecureContext: true, nightly: true }, + // IMPORTANT: Do not change this list without review from a DOM peer! { name: "EncodedVideoChunk", insecureContext: true, nightly: true }, // IMPORTANT: Do not change this list without review from a DOM peer! { name: "ErrorEvent", insecureContext: true }, diff --git a/dom/xhr/XMLHttpRequest.h b/dom/xhr/XMLHttpRequest.h index 0d82f8c035..a7c4c0550c 100644 --- a/dom/xhr/XMLHttpRequest.h +++ b/dom/xhr/XMLHttpRequest.h @@ -29,9 +29,12 @@ class XMLHttpRequest : public XMLHttpRequestEventTarget { const char* cStr; const char16_t* str; - EventType(const char* name, const char16_t* uname) + constexpr EventType(const char* name, const char16_t* uname) : cStr(name), str(uname) {} + constexpr EventType(const EventType& other) + : cStr(other.cStr), str(other.str) {} + operator const nsDependentString() const { return nsDependentString(str); } friend bool operator==(const EventType& a, const EventType& b) { @@ -56,55 +59,26 @@ class XMLHttpRequest : public XMLHttpRequestEventTarget { }; struct ProgressEventType : public EventType { - ProgressEventType(const char* name, const char16_t* uname) + constexpr ProgressEventType(const char* name, const char16_t* uname) : EventType(name, uname) {} }; struct ErrorProgressEventType : public ProgressEventType { const nsresult errorCode; - - ErrorProgressEventType(const char* name, const char16_t* uname, - const nsresult code) + constexpr ErrorProgressEventType(const char* name, const char16_t* uname, + const nsresult code) : ProgressEventType(name, uname), errorCode(code) {} }; -#define DECL_EVENT(NAME) \ - static inline const EventType NAME = EventType(#NAME, u## #NAME); - -#define DECL_PROGRESSEVENT(NAME) \ - static inline const ProgressEventType NAME = \ - ProgressEventType(#NAME, u## #NAME); - -#define DECL_ERRORPROGRESSEVENT(NAME, ERR) \ - static inline const ErrorProgressEventType NAME = \ - ErrorProgressEventType(#NAME, u## #NAME, ERR); - - struct Events { - DECL_EVENT(readystatechange); - DECL_PROGRESSEVENT(loadstart); - DECL_PROGRESSEVENT(progress); - DECL_ERRORPROGRESSEVENT(error, NS_ERROR_DOM_NETWORK_ERR); - DECL_ERRORPROGRESSEVENT(abort, NS_ERROR_DOM_ABORT_ERR); - DECL_ERRORPROGRESSEVENT(timeout, NS_ERROR_DOM_TIMEOUT_ERR); - DECL_PROGRESSEVENT(load); - DECL_PROGRESSEVENT(loadend); - - static inline const EventType* All[]{ - &readystatechange, &loadstart, &progress, &error, &abort, - &timeout, &load, &loadend}; - - static inline const EventType* ProgressEvents[]{ - &loadstart, &progress, &error, &abort, &timeout, &load, &loadend}; - - static inline const EventType* Find(const nsString& name) { - for (const EventType* type : Events::All) { - if (*type == name) { - return type; - } - } - return nullptr; - } - }; +#define DECL_EVENT(NAME) static constexpr EventType NAME{#NAME, u## #NAME}; + +#define DECL_PROGRESSEVENT(NAME) \ + static constexpr ProgressEventType NAME { #NAME, u## #NAME } + +#define DECL_ERRORPROGRESSEVENT(NAME, ERR) \ + static constexpr ErrorProgressEventType NAME{#NAME, u## #NAME, ERR}; + + struct Events; static already_AddRefed Constructor( const GlobalObject& aGlobal, const MozXMLHttpRequestParameters& aParams, @@ -216,6 +190,33 @@ class XMLHttpRequest : public XMLHttpRequestEventTarget { : XMLHttpRequestEventTarget(aGlobalObject) {} }; +struct XMLHttpRequest::Events { + DECL_EVENT(readystatechange); + DECL_PROGRESSEVENT(loadstart); + DECL_PROGRESSEVENT(progress); + DECL_ERRORPROGRESSEVENT(error, NS_ERROR_DOM_NETWORK_ERR); + DECL_ERRORPROGRESSEVENT(abort, NS_ERROR_DOM_ABORT_ERR); + DECL_ERRORPROGRESSEVENT(timeout, NS_ERROR_DOM_TIMEOUT_ERR); + DECL_PROGRESSEVENT(load); + DECL_PROGRESSEVENT(loadend); + + static inline const EventType* All[]{ + &readystatechange, &loadstart, &progress, &error, &abort, + &timeout, &load, &loadend}; + + static inline const EventType* ProgressEvents[]{ + &loadstart, &progress, &error, &abort, &timeout, &load, &loadend}; + + static inline const EventType* Find(const nsString& name) { + for (const EventType* type : Events::All) { + if (*type == name) { + return type; + } + } + return nullptr; + } +}; + } // namespace mozilla::dom #endif // mozilla_dom_XMLHttpRequest_h diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index dc256b10c2..ace26f296f 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -40,6 +40,7 @@ #include "mozilla/LoadInfo.h" #include "mozilla/LoadContext.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/net/ContentRange.h" #include "mozilla/PreloaderBase.h" #include "mozilla/ScopeExit.h" #include "mozilla/SpinEventLoopUntil.h" @@ -48,9 +49,9 @@ #include "mozilla/StaticPrefs_privacy.h" #include "mozilla/dom/ProgressEvent.h" #include "nsDataChannel.h" +#include "nsIBaseChannel.h" #include "nsIJARChannel.h" #include "nsIJARURI.h" -#include "nsLayoutCID.h" #include "nsReadableUtils.h" #include "nsSandboxFlags.h" @@ -186,15 +187,17 @@ static void AddLoadFlags(nsIRequest* request, nsLoadFlags newFlags) { // invoked for increased scrutability. Save the previous value on the stack. namespace { struct DebugWorkerRefs { - RefPtr& mTSWorkerRef; + Mutex& mMutex; + RefPtr mTSWorkerRef; nsCString mPrev; - DebugWorkerRefs(RefPtr& aTSWorkerRef, - const std::string& aStatus) - : mTSWorkerRef(aTSWorkerRef) { + DebugWorkerRefs(XMLHttpRequestMainThread& aXHR, const std::string& aStatus) + : mMutex(aXHR.mTSWorkerRefMutex) { + MutexAutoLock lock(mMutex); + + mTSWorkerRef = aXHR.mTSWorkerRef; + if (!mTSWorkerRef) { - MOZ_LOG(gXMLHttpRequestLog, LogLevel::Info, - ("No WorkerRef during: %s", aStatus.c_str())); return; } @@ -206,6 +209,8 @@ struct DebugWorkerRefs { } ~DebugWorkerRefs() { + MutexAutoLock lock(mMutex); + if (!mTSWorkerRef) { return; } @@ -213,6 +218,8 @@ struct DebugWorkerRefs { MOZ_ASSERT(mTSWorkerRef->Private()); SET_WORKERREF_DEBUG_STATUS(mTSWorkerRef->Ref(), mPrev); + + mTSWorkerRef = nullptr; } }; } // namespace @@ -220,11 +227,13 @@ struct DebugWorkerRefs { # define STREAM_STRING(stuff) \ (((const std::ostringstream&)(std::ostringstream() << stuff)) \ .str()) // NOLINT + # define DEBUG_WORKERREFS \ - DebugWorkerRefs MOZ_UNIQUE_VAR(debugWR__)(mTSWorkerRef, __func__) + DebugWorkerRefs MOZ_UNIQUE_VAR(debugWR__)(*this, __func__) + # define DEBUG_WORKERREFS1(x) \ DebugWorkerRefs MOZ_UNIQUE_VAR(debugWR__)( \ - mTSWorkerRef, STREAM_STRING(__func__ << ": " << x)) // NOLINT + *this, STREAM_STRING(__func__ << ": " << x)) // NOLINT #else # define DEBUG_WORKERREFS void() @@ -236,6 +245,9 @@ bool XMLHttpRequestMainThread::sDontWarnAboutSyncXHR = false; XMLHttpRequestMainThread::XMLHttpRequestMainThread( nsIGlobalObject* aGlobalObject) : XMLHttpRequest(aGlobalObject), +#ifdef DEBUG + mTSWorkerRefMutex("Debug WorkerRefs"), +#endif mResponseBodyDecodedPos(0), mResponseType(XMLHttpRequestResponseType::_empty), mState(XMLHttpRequest_Binding::UNSENT), @@ -864,14 +876,28 @@ bool XMLHttpRequestMainThread::IsDeniedCrossSiteCORSRequest() { return false; } -Maybe +bool XMLHttpRequestMainThread::BadContentRangeRequested() { + if (!mChannel) { + return false; + } + // Only nsIBaseChannel supports this + nsCOMPtr baseChan = do_QueryInterface(mChannel); + if (!baseChan) { + return false; + } + // A bad range was requested if the channel has no content range + // despite the request specifying a range header. + return !baseChan->ContentRange() && mAuthorRequestHeaders.Has("range"); +} + +RefPtr XMLHttpRequestMainThread::GetRequestedContentRange() const { MOZ_ASSERT(mChannel); - nsBaseChannel* baseChan = static_cast(mChannel.get()); + nsCOMPtr baseChan = do_QueryInterface(mChannel); if (!baseChan) { - return mozilla::Nothing(); + return nullptr; } - return baseChan->GetContentRange(); + return baseChan->ContentRange(); } void XMLHttpRequestMainThread::GetContentRangeHeader(nsACString& out) const { @@ -879,8 +905,8 @@ void XMLHttpRequestMainThread::GetContentRangeHeader(nsACString& out) const { out.SetIsVoid(true); return; } - Maybe range = GetRequestedContentRange(); - if (range.isSome()) { + RefPtr range = GetRequestedContentRange(); + if (range) { range->AsHeader(out); } else { out.SetIsVoid(true); @@ -944,8 +970,7 @@ uint32_t XMLHttpRequestMainThread::GetStatus(ErrorResult& aRv) { nsCOMPtr httpChannel = GetCurrentHttpChannel(); if (!httpChannel) { // Pretend like we got a 200/206 response, since our load was successful - return IsBlobURI(mRequestURL) && GetRequestedContentRange().isSome() ? 206 - : 200; + return GetRequestedContentRange() ? 206 : 200; } uint32_t status; @@ -1194,13 +1219,13 @@ bool XMLHttpRequestMainThread::IsSafeHeader( bool XMLHttpRequestMainThread::GetContentType(nsACString& aValue) const { MOZ_ASSERT(mChannel); - nsCOMPtr uri; - if (NS_SUCCEEDED(mChannel->GetURI(getter_AddRefs(uri))) && - uri->SchemeIs("data")) { - nsDataChannel* dchan = static_cast(mChannel.get()); - MOZ_ASSERT(dchan); - aValue.Assign(dchan->MimeType()); - return true; + nsCOMPtr baseChan = do_QueryInterface(mChannel); + if (baseChan) { + RefPtr fullMimeType(baseChan->FullMimeType()); + if (fullMimeType) { + fullMimeType->Serialize(aValue); + return true; + } } if (NS_SUCCEEDED(mChannel->GetContentType(aValue))) { nsCString value; @@ -1956,8 +1981,7 @@ XMLHttpRequestMainThread::OnStartRequest(nsIRequest* request) { // If we were asked for a bad range on a blob URL, but we're async, // we should throw now in order to fire an error progress event. - if (IsBlobURI(mRequestURL) && GetRequestedContentRange().isNothing() && - mAuthorRequestHeaders.Has("range")) { + if (BadContentRangeRequested()) { return NS_ERROR_NET_PARTIAL_TRANSFER; } @@ -3128,7 +3152,7 @@ void XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody, if (uploadContentType.IsVoid()) { uploadContentType = defaultContentType; } else if (aBodyIsDocumentOrString) { - UniquePtr contentTypeRecord = + RefPtr contentTypeRecord = CMimeType::Parse(uploadContentType); nsAutoCString charset; if (contentTypeRecord && @@ -3391,7 +3415,7 @@ void XMLHttpRequestMainThread::OverrideMimeType(const nsAString& aMimeType, return; } - UniquePtr parsed = MimeType::Parse(aMimeType); + RefPtr parsed = MimeType::Parse(aMimeType); if (parsed) { parsed->Serialize(mOverrideMimeType); } else { diff --git a/dom/xhr/XMLHttpRequestMainThread.h b/dom/xhr/XMLHttpRequestMainThread.h index 3f2d395991..b860f041fb 100644 --- a/dom/xhr/XMLHttpRequestMainThread.h +++ b/dom/xhr/XMLHttpRequestMainThread.h @@ -48,7 +48,6 @@ #include "mozilla/dom/XMLHttpRequestEventTarget.h" #include "mozilla/dom/XMLHttpRequestString.h" #include "mozilla/Encoding.h" -#include "nsBaseChannel.h" #ifdef Status /* Xlib headers insist on this for some reason... Nuke it because @@ -65,6 +64,10 @@ class nsILoadGroup; namespace mozilla { class ProfileChunkedBuffer; +namespace net { +class ContentRange; +} + namespace dom { class DOMString; @@ -447,7 +450,8 @@ class XMLHttpRequestMainThread final : public XMLHttpRequest, #ifdef DEBUG // For logging when there's trouble - RefPtr mTSWorkerRef = nullptr; + RefPtr mTSWorkerRef MOZ_GUARDED_BY(mTSWorkerRefMutex); + Mutex mTSWorkerRefMutex; #endif protected: @@ -507,7 +511,8 @@ class XMLHttpRequestMainThread final : public XMLHttpRequest, void AbortInternal(ErrorResult& aRv); - Maybe GetRequestedContentRange() const; + bool BadContentRangeRequested(); + RefPtr GetRequestedContentRange() const; void GetContentRangeHeader(nsACString&) const; struct PendingEvent { diff --git a/dom/xhr/XMLHttpRequestWorker.cpp b/dom/xhr/XMLHttpRequestWorker.cpp index 371f444ee9..7fdfa8fee9 100644 --- a/dom/xhr/XMLHttpRequestWorker.cpp +++ b/dom/xhr/XMLHttpRequestWorker.cpp @@ -198,11 +198,13 @@ class Proxy final : public nsIDOMEventListener { #ifdef DEBUG void DebugStoreWorkerRef(RefPtr& aWorkerRef) { MOZ_ASSERT(!NS_IsMainThread()); + MutexAutoLock lock(mXHR->mTSWorkerRefMutex); mXHR->mTSWorkerRef = new ThreadSafeWorkerRef(aWorkerRef); } void DebugForgetWorkerRef() { MOZ_ASSERT(!NS_IsMainThread()); + MutexAutoLock lock(mXHR->mTSWorkerRefMutex); mXHR->mTSWorkerRef = nullptr; } #endif @@ -325,7 +327,6 @@ class LoadStartDetectionRunnable final : public Runnable, WorkerPrivate* mWorkerPrivate; RefPtr mProxy; RefPtr mXHR; - nsString mEventType; uint32_t mChannelId; bool mReceivedLoadStart; diff --git a/dom/xhr/tests/file_XHRResponseURL.js b/dom/xhr/tests/file_XHRResponseURL.js index 1ab1694bfa..29e6ddea69 100644 --- a/dom/xhr/tests/file_XHRResponseURL.js +++ b/dom/xhr/tests/file_XHRResponseURL.js @@ -51,7 +51,7 @@ function info(aMessage) { } function request(aURL) { - return new Promise(function (aResolve, aReject) { + return new Promise(function (aResolve) { var xhr = new XMLHttpRequest(); xhr.open("GET", aURL); xhr.addEventListener("load", function () { @@ -272,7 +272,7 @@ function testNotToLeakResponseURLWhileDoingRedirects() { function testNotToLeakResponseURLWhileDoingRedirectsInWindow() { var xhr = new XMLHttpRequest(); var requestObserver = { - observe(aSubject, aTopic, aData) { + observe() { is(xhr.readyState, XMLHttpRequest.OPENED, "assert for XHR state"); is( xhr.responseURL, @@ -286,7 +286,7 @@ function testNotToLeakResponseURLWhileDoingRedirectsInWindow() { "specialpowers-http-notify-request" ); - return new Promise(function (aResolve, aReject) { + return new Promise(function (aResolve) { xhr.open( "GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text" @@ -322,7 +322,7 @@ function testNotToLeakResponseURLWhileDoingRedirectsInWorker() { } }; - return new Promise(function (aResolve, aReject) { + return new Promise(function (aResolve) { self.addEventListener("message", testRedirect); message({ type: "redirect_test", status: "start" }); xhr.open( @@ -334,7 +334,7 @@ function testNotToLeakResponseURLWhileDoingRedirectsInWorker() { message({ type: "redirect_test", status: "end" }); aResolve(); }); - xhr.addEventListener("error", function (e) { + xhr.addEventListener("error", function () { ok(false, "unexpected request falilure"); self.removeEventListener("message", testRedirect); message({ type: "redirect_test", status: "end" }); @@ -345,7 +345,7 @@ function testNotToLeakResponseURLWhileDoingRedirectsInWorker() { } function waitForAllMessagesProcessed() { - return new Promise(function (aResolve, aReject) { + return new Promise(function (aResolve) { var id = setInterval(function () { if (message.ping === message.pong) { clearInterval(id); diff --git a/dom/xhr/tests/file_sync_xhr_document_write_with_iframe.html b/dom/xhr/tests/file_sync_xhr_document_write_with_iframe.html index 2135011d9c..895fbc4e4b 100644 --- a/dom/xhr/tests/file_sync_xhr_document_write_with_iframe.html +++ b/dom/xhr/tests/file_sync_xhr_document_write_with_iframe.html @@ -7,7 +7,7 @@ function syncXHR() { xhr.send(null); } -addEventListener('load', evt => { +addEventListener('load', () => { syncXHR(); document.open(); document.write( diff --git a/dom/xhr/tests/relativeLoad_worker.js b/dom/xhr/tests/relativeLoad_worker.js index b600b592be..6d281244c2 100644 --- a/dom/xhr/tests/relativeLoad_worker.js +++ b/dom/xhr/tests/relativeLoad_worker.js @@ -6,7 +6,7 @@ /* global workerURL */ const importURL = "relativeLoad_import.js"; -onmessage = function (event) { +onmessage = function () { var xhr = new XMLHttpRequest(); xhr.open("GET", "worker_testXHR.txt", false); xhr.send(null); diff --git a/dom/xhr/tests/temporaryFileBlob.sjs b/dom/xhr/tests/temporaryFileBlob.sjs index d952b325ce..151c05a231 100644 --- a/dom/xhr/tests/temporaryFileBlob.sjs +++ b/dom/xhr/tests/temporaryFileBlob.sjs @@ -28,7 +28,7 @@ function handleRequest(request, response) { bos.writeByteArray(part); response.timer1 = new Timer( - function (timer) { + function () { bos.writeByteArray(bodyBytes); }, 1000, @@ -36,7 +36,7 @@ function handleRequest(request, response) { ); response.timer2 = new Timer( - function (timer) { + function () { response.finish(); }, 2000, diff --git a/dom/xhr/tests/terminateSyncXHR_worker.js b/dom/xhr/tests/terminateSyncXHR_worker.js index 7a2509af3d..29a5a8a369 100644 --- a/dom/xhr/tests/terminateSyncXHR_worker.js +++ b/dom/xhr/tests/terminateSyncXHR_worker.js @@ -3,7 +3,7 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ -onmessage = function (event) { +onmessage = function () { throw new Error("No messages should reach me!"); }; diff --git a/dom/xhr/tests/test_XHR.js b/dom/xhr/tests/test_XHR.js index 12eb06e4f6..0034f8a0eb 100644 --- a/dom/xhr/tests/test_XHR.js +++ b/dom/xhr/tests/test_XHR.js @@ -1,4 +1,7 @@ "use strict"; + +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + SimpleTest.waitForExplicitFinish(); var gen = runTests(); diff --git a/dom/xhr/tests/test_XHRDocURI.html b/dom/xhr/tests/test_XHRDocURI.html index 1062be13a6..61be580ddd 100644 --- a/dom/xhr/tests/test_XHRDocURI.html +++ b/dom/xhr/tests/test_XHRDocURI.html @@ -89,7 +89,7 @@ function* runTest() { // use content XHR and access URI properties from content privileged script var xhr = new XMLHttpRequest; xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRDocURI.xml"); - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.responseXML) { return; } @@ -108,7 +108,7 @@ function* runTest() { xhr = new XMLHttpRequest; xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRDocURI.html"); xhr.responseType = "document"; - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.response) { return; } @@ -126,7 +126,7 @@ function* runTest() { xhr = new XMLHttpRequest; xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRDocURI.text"); - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { is(xhr.responseXML, null, "should not have document"); if (xhr.readyState == 4) { gen.next(); @@ -137,7 +137,7 @@ function* runTest() { xhr = new XMLHttpRequest; xhr.open("GET", "http://example.com/tests/dom/xhr/tests/file_XHRDocURI.xml"); - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.responseXML) { return; } @@ -156,7 +156,7 @@ function* runTest() { xhr = new XMLHttpRequest; xhr.open("GET", "http://example.com/tests/dom/xhr/tests/file_XHRDocURI.html"); xhr.responseType = "document"; - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.response) { return; } @@ -174,7 +174,7 @@ function* runTest() { xhr = new XMLHttpRequest; xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRDocURI.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRDocURI.xml"); - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.responseXML) { return; } @@ -193,7 +193,7 @@ function* runTest() { xhr = new XMLHttpRequest; xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRDocURI.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRDocURI.html"); xhr.responseType = "document"; - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.response) { return; } @@ -211,7 +211,7 @@ function* runTest() { xhr = new XMLHttpRequest; xhr.open("GET", "http://example.com/tests/dom/xhr/tests/file_XHRDocURI.text"); - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { is(xhr.responseXML, null, "should not have document"); if (xhr.readyState == 4) { gen.next(); @@ -225,7 +225,7 @@ function* runTest() { xhr = new XMLHttpRequest; xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRDocURI.xml"); - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.responseXML) { return; } @@ -246,7 +246,7 @@ function* runTest() { xhr = new XMLHttpRequest; xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRDocURI.html"); xhr.responseType = "document"; - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.response) { return; } @@ -266,7 +266,7 @@ function* runTest() { xhr = new XMLHttpRequest; xhr.open("GET", "http://example.com/tests/dom/xhr/tests/file_XHRDocURI.xml"); - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.responseXML) { return; } @@ -287,7 +287,7 @@ function* runTest() { xhr = new XMLHttpRequest; xhr.open("GET", "http://example.com/tests/dom/xhr/tests/file_XHRDocURI.html"); xhr.responseType = "document"; - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.response) { return; } @@ -307,7 +307,7 @@ function* runTest() { xhr = new XMLHttpRequest; xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRDocURI.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRDocURI.xml"); - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.responseXML) { return; } @@ -328,7 +328,7 @@ function* runTest() { xhr = new XMLHttpRequest; xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRDocURI.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRDocURI.html"); xhr.responseType = "document"; - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.response) { return; } @@ -351,7 +351,7 @@ function* runTest() { SpecialPowers.addPermission("systemXHR", true, document); xhr = new XMLHttpRequest({mozAnon: false, mozSystem: true}); xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRDocURI.xml"); - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.responseXML) { return; } @@ -370,7 +370,7 @@ function* runTest() { xhr = new XMLHttpRequest({mozAnon: false, mozSystem: true}); xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRDocURI.html"); xhr.responseType = "document"; - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.response) { return; } @@ -388,7 +388,7 @@ function* runTest() { xhr = new XMLHttpRequest({mozAnon: false, mozSystem: true}); xhr.open("GET", "http://example.com/tests/dom/xhr/tests/file_XHRDocURI.xml"); - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.responseXML) { return; } @@ -407,7 +407,7 @@ function* runTest() { xhr = new XMLHttpRequest({mozAnon: false, mozSystem: true}); xhr.open("GET", "http://example.com/tests/dom/xhr/tests/file_XHRDocURI.html"); xhr.responseType = "document"; - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.response) { return; } @@ -425,7 +425,7 @@ function* runTest() { xhr = new XMLHttpRequest({mozAnon: false, mozSystem: true}); xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRDocURI.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRDocURI.xml"); - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.responseXML) { return; } @@ -444,7 +444,7 @@ function* runTest() { xhr = new XMLHttpRequest({mozAnon: false, mozSystem: true}); xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRDocURI.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRDocURI.html"); xhr.responseType = "document"; - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if (!xhr.response) { return; } diff --git a/dom/xhr/tests/test_XHR_timeout.js b/dom/xhr/tests/test_XHR_timeout.js index 1e75c1c174..69986770e1 100644 --- a/dom/xhr/tests/test_XHR_timeout.js +++ b/dom/xhr/tests/test_XHR_timeout.js @@ -1,3 +1,5 @@ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + /* Notes: - All times are expressed in milliseconds in this test suite. - Test harness code is at the end of this file. diff --git a/dom/xhr/tests/test_bug1752863_worker.js b/dom/xhr/tests/test_bug1752863_worker.js index 196b825c0c..929b005939 100644 --- a/dom/xhr/tests/test_bug1752863_worker.js +++ b/dom/xhr/tests/test_bug1752863_worker.js @@ -24,7 +24,7 @@ async function handleLoadstart() { } } -self.onmessage = async function (ev) { +self.onmessage = async function () { xhr = new XMLHttpRequest({ mozAnon: false }); myself = self; xhr.addEventListener("loadstart", handleLoadstart, true); diff --git a/dom/xhr/tests/test_worker_xhr_responseURL.html b/dom/xhr/tests/test_worker_xhr_responseURL.html index 89924e9815..b33cc880c6 100644 --- a/dom/xhr/tests/test_worker_xhr_responseURL.html +++ b/dom/xhr/tests/test_worker_xhr_responseURL.html @@ -16,7 +16,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=998076 var worker = new Worker("../../../dom/xhr/tests/file_XHRResponseURL.js"); var requestObserver = { - observe (aSubject, aTopic, aData) { + observe () { worker.postMessage("request"); } }; diff --git a/dom/xhr/tests/test_worker_xhr_system.js b/dom/xhr/tests/test_worker_xhr_system.js index 23137801a0..ee5934363d 100644 --- a/dom/xhr/tests/test_worker_xhr_system.js +++ b/dom/xhr/tests/test_worker_xhr_system.js @@ -1,3 +1,5 @@ +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + function ok(what, msg) { postMessage({ event: msg, test: "ok", a: what }); } @@ -6,7 +8,7 @@ function is(a, b, msg) { postMessage({ event: msg, test: "is", a, b }); } -self.onmessage = function onmessage(event) { +self.onmessage = function onmessage() { // An XHR with system privileges will be able to do cross-site calls. const TEST_URL = diff --git a/dom/xhr/tests/test_xhr_progressevents.html b/dom/xhr/tests/test_xhr_progressevents.html index ebfc06fd5b..69f549f7a8 100644 --- a/dom/xhr/tests/test_xhr_progressevents.html +++ b/dom/xhr/tests/test_xhr_progressevents.html @@ -12,7 +12,7 @@ SimpleTest.waitForExplicitFinish(); var gen = runTests(); -function log(s) { +function log() { // Uncomment these to get debugging information /* document.getElementById("l").textContent += s + "\n"; diff --git a/dom/xhr/tests/worker_temporaryFileBlob.js b/dom/xhr/tests/worker_temporaryFileBlob.js index 50f071bab7..056b826e00 100644 --- a/dom/xhr/tests/worker_temporaryFileBlob.js +++ b/dom/xhr/tests/worker_temporaryFileBlob.js @@ -1,4 +1,7 @@ /* eslint-env worker */ + +/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */ + importScripts("common_temporaryFileBlob.js"); function info(msg) { diff --git a/dom/xhr/tests/worker_terminateSyncXHR_frame.html b/dom/xhr/tests/worker_terminateSyncXHR_frame.html index 04bd53ff1d..720cf9551d 100644 --- a/dom/xhr/tests/worker_terminateSyncXHR_frame.html +++ b/dom/xhr/tests/worker_terminateSyncXHR_frame.html @@ -16,7 +16,7 @@ parent.postMessage(event.data, "*"); }; - worker.onerror = function(event) { + worker.onerror = function() { parent.postMessage("ERROR!", "*"); } } diff --git a/dom/xhr/tests/xhrAbort_worker.js b/dom/xhr/tests/xhrAbort_worker.js index 6b82241d68..e922f8259f 100644 --- a/dom/xhr/tests/xhrAbort_worker.js +++ b/dom/xhr/tests/xhrAbort_worker.js @@ -57,11 +57,11 @@ function runTest() { events.push(str); } - xhr.onerror = function (event) { + xhr.onerror = function () { throw new Error("Error: " + xhr.statusText); }; - xhr.onload = function (event) { + xhr.onload = function () { throw new Error("Shouldn't have gotten load event!"); }; diff --git a/dom/xhr/tests/xhr_worker.js b/dom/xhr/tests/xhr_worker.js index 46edd700db..4361b347e5 100644 --- a/dom/xhr/tests/xhr_worker.js +++ b/dom/xhr/tests/xhr_worker.js @@ -53,21 +53,21 @@ function onprogress(event) { } xhr.addEventListener("progress", onprogress); -xhr.addEventListener("foopety", function (event) {}); -xhr.removeEventListener("doopety", function (event) {}); +xhr.addEventListener("foopety", function () {}); +xhr.removeEventListener("doopety", function () {}); -xhr.onloadend = function (event) { +xhr.onloadend = function () { const message = { type: "loadend" }; postMessage(message); }; var upload = xhr.upload; -upload.onprogress = function (event) {}; -upload.addEventListener("foo", function (event) {}); -upload.removeEventListener("foo", function (event) {}); -upload.addEventListener("load", function (event) {}); -upload.removeEventListener("foo", function (event) {}); -upload.onload = function (event) { +upload.onprogress = function () {}; +upload.addEventListener("foo", function () {}); +upload.removeEventListener("foo", function () {}); +upload.addEventListener("load", function () {}); +upload.removeEventListener("foo", function () {}); +upload.onload = function () { const message = { type: "upload.load" }; postMessage(message); }; diff --git a/dom/xml/XMLDocument.cpp b/dom/xml/XMLDocument.cpp index e62269b9a6..e9136bbe46 100644 --- a/dom/xml/XMLDocument.cpp +++ b/dom/xml/XMLDocument.cpp @@ -17,7 +17,6 @@ #include "nsNetUtil.h" #include "nsError.h" #include "nsIPrincipal.h" -#include "nsLayoutCID.h" #include "mozilla/dom/Attr.h" #include "nsCExternalHandlerService.h" #include "nsMimeTypes.h" diff --git a/dom/xml/XMLStylesheetProcessingInstruction.cpp b/dom/xml/XMLStylesheetProcessingInstruction.cpp index 9f0d3f6156..a022ed4272 100644 --- a/dom/xml/XMLStylesheetProcessingInstruction.cpp +++ b/dom/xml/XMLStylesheetProcessingInstruction.cpp @@ -49,10 +49,11 @@ nsresult XMLStylesheetProcessingInstruction::BindToTree(BindContext& aContext, return rv; } -void XMLStylesheetProcessingInstruction::UnbindFromTree(bool aNullParent) { +void XMLStylesheetProcessingInstruction::UnbindFromTree( + UnbindContext& aContext) { nsCOMPtr oldDoc = GetUncomposedDoc(); - ProcessingInstruction::UnbindFromTree(aNullParent); + ProcessingInstruction::UnbindFromTree(aContext); Unused << UpdateStyleSheetInternal(oldDoc, nullptr); } diff --git a/dom/xml/XMLStylesheetProcessingInstruction.h b/dom/xml/XMLStylesheetProcessingInstruction.h index a6b3aa6978..cacc0aa932 100644 --- a/dom/xml/XMLStylesheetProcessingInstruction.h +++ b/dom/xml/XMLStylesheetProcessingInstruction.h @@ -43,7 +43,7 @@ class XMLStylesheetProcessingInstruction final : public ProcessingInstruction, // nsIContent virtual nsresult BindToTree(BindContext&, nsINode& aParent) override; - virtual void UnbindFromTree(bool aNullParent = true) override; + virtual void UnbindFromTree(UnbindContext&) override; /** * Tells this processing instruction to use a different base URI. This is used diff --git a/dom/xml/nsXMLElement.cpp b/dom/xml/nsXMLElement.cpp index ef51715d1b..124d4f5873 100644 --- a/dom/xml/nsXMLElement.cpp +++ b/dom/xml/nsXMLElement.cpp @@ -28,7 +28,7 @@ JSObject* nsXMLElement::WrapNode(JSContext* aCx, return Element_Binding::Wrap(aCx, this, aGivenProto); } -void nsXMLElement::UnbindFromTree(bool aNullParent) { +void nsXMLElement::UnbindFromTree(UnbindContext& aContext) { nsAtom* property; switch (GetPseudoElementType()) { case PseudoStyleType::marker: @@ -48,7 +48,7 @@ void nsXMLElement::UnbindFromTree(bool aNullParent) { MOZ_ASSERT(GetParent()->IsElement()); GetParent()->RemoveProperty(property); } - Element::UnbindFromTree(aNullParent); + Element::UnbindFromTree(aContext); } NS_IMPL_ELEMENT_CLONE(nsXMLElement) diff --git a/dom/xml/nsXMLElement.h b/dom/xml/nsXMLElement.h index e401965fff..01b526f451 100644 --- a/dom/xml/nsXMLElement.h +++ b/dom/xml/nsXMLElement.h @@ -23,7 +23,7 @@ class nsXMLElement : public mozilla::dom::Element { virtual nsresult Clone(mozilla::dom::NodeInfo*, nsINode** aResult) const override; - virtual void UnbindFromTree(bool aNullParent = true) override; + virtual void UnbindFromTree(UnbindContext&) override; protected: virtual ~nsXMLElement() = default; diff --git a/dom/xslt/tests/mochitest/mochitest.toml b/dom/xslt/tests/mochitest/mochitest.toml index 70d313758c..e22783231a 100644 --- a/dom/xslt/tests/mochitest/mochitest.toml +++ b/dom/xslt/tests/mochitest/mochitest.toml @@ -54,4 +54,6 @@ support-files = ["file_metaRefresh.xml"] ["test_parameter.html"] +["test_parameter_conversion.html"] + ["test_sorting_invalid_lang.html"] diff --git a/dom/xslt/tests/mochitest/test_parameter_conversion.html b/dom/xslt/tests/mochitest/test_parameter_conversion.html new file mode 100644 index 0000000000..a0ea6acce2 --- /dev/null +++ b/dom/xslt/tests/mochitest/test_parameter_conversion.html @@ -0,0 +1,49 @@ + + + + Test for setParameter conversion to XSLT type + + + + +

+ +
+
+
+ + diff --git a/dom/xslt/xpath/XPathEvaluator.cpp b/dom/xslt/xpath/XPathEvaluator.cpp index 269ea98ff6..14889462fb 100644 --- a/dom/xslt/xpath/XPathEvaluator.cpp +++ b/dom/xslt/xpath/XPathEvaluator.cpp @@ -16,7 +16,6 @@ #include "mozilla/dom/XPathNSResolverBinding.h" #include "nsAtom.h" #include "nsCOMPtr.h" -#include "nsContentCID.h" #include "nsContentUtils.h" #include "nsDOMString.h" #include "nsError.h" diff --git a/dom/xslt/xslt/txEXSLTFunctions.cpp b/dom/xslt/xslt/txEXSLTFunctions.cpp index d4882d0b13..cb4f204019 100644 --- a/dom/xslt/xslt/txEXSLTFunctions.cpp +++ b/dom/xslt/xslt/txEXSLTFunctions.cpp @@ -23,7 +23,6 @@ #include "nsImportModule.h" #include "nsPrintfCString.h" #include "nsComponentManagerUtils.h" -#include "nsContentCID.h" #include "nsContentCreatorFunctions.h" #include "nsIContent.h" #include "txMozillaXMLOutput.h" @@ -189,8 +188,8 @@ struct txEXSLTFunctionDescriptor { int32_t mNamespaceID; }; -static EnumeratedArray +static EnumeratedArray descriptTable; class txEXSLTFunctionCall : public FunctionCall { diff --git a/dom/xslt/xslt/txMozillaTextOutput.cpp b/dom/xslt/xslt/txMozillaTextOutput.cpp index 2104a0fd6b..01974bb17e 100644 --- a/dom/xslt/xslt/txMozillaTextOutput.cpp +++ b/dom/xslt/xslt/txMozillaTextOutput.cpp @@ -4,7 +4,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "txMozillaTextOutput.h" -#include "nsContentCID.h" #include "nsIContent.h" #include "mozilla/dom/Document.h" #include "nsIDocumentTransformer.h" diff --git a/dom/xslt/xslt/txMozillaXMLOutput.cpp b/dom/xslt/xslt/txMozillaXMLOutput.cpp index 4aa51d9928..3ef89d31a4 100644 --- a/dom/xslt/xslt/txMozillaXMLOutput.cpp +++ b/dom/xslt/xslt/txMozillaXMLOutput.cpp @@ -12,7 +12,6 @@ #include "nsIRefreshURI.h" #include "nsPIDOMWindow.h" #include "nsIContent.h" -#include "nsContentCID.h" #include "nsUnicharUtils.h" #include "nsGkAtoms.h" #include "txLog.h" diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp index db4de439ef..c26aea1bb9 100644 --- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp +++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp @@ -4,7 +4,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "txMozillaXSLTProcessor.h" -#include "nsContentCID.h" #include "nsError.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/Document.h" diff --git a/dom/xul/XULButtonElement.cpp b/dom/xul/XULButtonElement.cpp index fa9ee28628..6c76488db4 100644 --- a/dom/xul/XULButtonElement.cpp +++ b/dom/xul/XULButtonElement.cpp @@ -317,9 +317,9 @@ void XULButtonElement::StartBlinking() { "XULButtonElement::StartBlinking", GetMainThreadSerialEventTarget()); } -void XULButtonElement::UnbindFromTree(bool aNullParent) { +void XULButtonElement::UnbindFromTree(UnbindContext& aContext) { StopBlinking(); - nsXULElement::UnbindFromTree(aNullParent); + nsXULElement::UnbindFromTree(aContext); } void XULButtonElement::ExecuteMenu(WidgetEvent& aEvent) { diff --git a/dom/xul/XULButtonElement.h b/dom/xul/XULButtonElement.h index fc880210a2..b79b8c2186 100644 --- a/dom/xul/XULButtonElement.h +++ b/dom/xul/XULButtonElement.h @@ -55,7 +55,7 @@ class XULButtonElement : public nsXULElement { XULMenuParentElement* GetMenuParent() const; - void UnbindFromTree(bool aNullParent) override; + void UnbindFromTree(UnbindContext&) override; MOZ_CAN_RUN_SCRIPT bool HandleKeyPress(KeyboardEvent& keyEvent); bool OpenedWithKey() const; diff --git a/dom/xul/XULFrameElement.cpp b/dom/xul/XULFrameElement.cpp index efbeb15829..87f1ecf71f 100644 --- a/dom/xul/XULFrameElement.cpp +++ b/dom/xul/XULFrameElement.cpp @@ -159,13 +159,13 @@ nsresult XULFrameElement::BindToTree(BindContext& aContext, nsINode& aParent) { return NS_OK; } -void XULFrameElement::UnbindFromTree(bool aNullParent) { +void XULFrameElement::UnbindFromTree(UnbindContext& aContext) { if (RefPtr frameLoader = GetFrameLoader()) { frameLoader->Destroy(); } mFrameLoader = nullptr; - nsXULElement::UnbindFromTree(aNullParent); + nsXULElement::UnbindFromTree(aContext); } void XULFrameElement::DestroyContent() { diff --git a/dom/xul/XULFrameElement.h b/dom/xul/XULFrameElement.h index 13a65f42e8..20b467f66a 100644 --- a/dom/xul/XULFrameElement.h +++ b/dom/xul/XULFrameElement.h @@ -54,7 +54,7 @@ class XULFrameElement final : public nsXULElement, public nsFrameLoaderOwner { // nsIContent nsresult BindToTree(BindContext&, nsINode& aParent) override; - void UnbindFromTree(bool aNullParent) override; + void UnbindFromTree(UnbindContext&) override; void DestroyContent() override; void AfterSetAttr(int32_t aNamespaceID, nsAtom* aName, diff --git a/dom/xul/XULMenuBarElement.cpp b/dom/xul/XULMenuBarElement.cpp index f32698b3cd..1ec36d3859 100644 --- a/dom/xul/XULMenuBarElement.cpp +++ b/dom/xul/XULMenuBarElement.cpp @@ -85,7 +85,7 @@ nsresult XULMenuBarElement::BindToTree(BindContext& aContext, return NS_OK; } -void XULMenuBarElement::UnbindFromTree(bool aNullParent) { +void XULMenuBarElement::UnbindFromTree(UnbindContext& aContext) { if (mListener) { mListener->Detach(); mListener = nullptr; @@ -97,7 +97,7 @@ void XULMenuBarElement::UnbindFromTree(bool aNullParent) { pm->SetActiveMenuBar(this, false); } } - return XULMenuParentElement::UnbindFromTree(aNullParent); + return XULMenuParentElement::UnbindFromTree(aContext); } } // namespace mozilla::dom diff --git a/dom/xul/XULMenuBarElement.h b/dom/xul/XULMenuBarElement.h index 117682642d..1d91fee660 100644 --- a/dom/xul/XULMenuBarElement.h +++ b/dom/xul/XULMenuBarElement.h @@ -38,7 +38,7 @@ class XULMenuBarElement final : public XULMenuParentElement { bool IsActiveByKeyboard() const { return mActiveByKeyboard; } nsresult BindToTree(BindContext&, nsINode& aParent) override; - void UnbindFromTree(bool aNullParent) override; + void UnbindFromTree(UnbindContext&) override; protected: ~XULMenuBarElement() override; diff --git a/dom/xul/XULTreeElement.cpp b/dom/xul/XULTreeElement.cpp index e190b22556..cd68d7e664 100644 --- a/dom/xul/XULTreeElement.cpp +++ b/dom/xul/XULTreeElement.cpp @@ -27,7 +27,7 @@ JSObject* XULTreeElement::WrapNode(JSContext* aCx, return XULTreeElement_Binding::Wrap(aCx, this, aGivenProto); } -void XULTreeElement::UnbindFromTree(bool aNullParent) { +void XULTreeElement::UnbindFromTree(UnbindContext& aContext) { // Drop the view's ref to us. if (mView) { nsCOMPtr sel; @@ -39,7 +39,7 @@ void XULTreeElement::UnbindFromTree(bool aNullParent) { } mView = nullptr; - nsXULElement::UnbindFromTree(aNullParent); + nsXULElement::UnbindFromTree(aContext); } void XULTreeElement::DestroyContent() { diff --git a/dom/xul/XULTreeElement.h b/dom/xul/XULTreeElement.h index 381ae88f41..8d6cc383db 100644 --- a/dom/xul/XULTreeElement.h +++ b/dom/xul/XULTreeElement.h @@ -101,7 +101,7 @@ class XULTreeElement final : public nsXULElement { void EndUpdateBatch(void); void ClearStyleAndImageCaches(void); - virtual void UnbindFromTree(bool aNullParent) override; + virtual void UnbindFromTree(UnbindContext&) override; virtual void DestroyContent() override; void BodyDestroyed(int32_t aFirstVisibleRow) { diff --git a/dom/xul/nsXULContentSink.cpp b/dom/xul/nsXULContentSink.cpp index 197c5c2b3b..9a4f2deb23 100644 --- a/dom/xul/nsXULContentSink.cpp +++ b/dom/xul/nsXULContentSink.cpp @@ -27,7 +27,6 @@ #include "nsParserBase.h" #include "nsViewManager.h" #include "nsIScriptSecurityManager.h" -#include "nsLayoutCID.h" #include "nsNetUtil.h" #include "nsString.h" #include "nsReadableUtils.h" diff --git a/dom/xul/nsXULContentUtils.cpp b/dom/xul/nsXULContentUtils.cpp index 109aa1975a..07de8f6cdb 100644 --- a/dom/xul/nsXULContentUtils.cpp +++ b/dom/xul/nsXULContentUtils.cpp @@ -20,7 +20,6 @@ #include "mozilla/dom/Document.h" #include "mozilla/dom/Element.h" #include "nsXULContentUtils.h" -#include "nsLayoutCID.h" #include "nsString.h" #include "nsGkAtoms.h" diff --git a/dom/xul/nsXULElement.cpp b/dom/xul/nsXULElement.cpp index 78c29fb315..5bccc15f69 100644 --- a/dom/xul/nsXULElement.cpp +++ b/dom/xul/nsXULElement.cpp @@ -654,7 +654,7 @@ nsresult nsXULElement::BindToTree(BindContext& aContext, nsINode& aParent) { return rv; } -void nsXULElement::UnbindFromTree(bool aNullParent) { +void nsXULElement::UnbindFromTree(UnbindContext& aContext) { if (NodeInfo()->Equals(nsGkAtoms::keyset, kNameSpaceID_XUL)) { XULKeySetGlobalKeyListener::DetachKeyHandler(this); } @@ -689,7 +689,7 @@ void nsXULElement::UnbindFromTree(bool aNullParent) { slots->mControllers = nullptr; } - nsStyledElement::UnbindFromTree(aNullParent); + nsStyledElement::UnbindFromTree(aContext); } void nsXULElement::DoneAddingChildren(bool aHaveNotified) { @@ -1425,6 +1425,10 @@ nsresult nsXULPrototypeElement::SetAttrAt(uint32_t aPos, // emptystring as id. mAttributes[aPos].mValue.ParseAtom(aValue); + return NS_OK; + } else if (mAttributes[aPos].mName.Equals(nsGkAtoms::aria_activedescendant)) { + mAttributes[aPos].mValue.ParseAtom(aValue); + return NS_OK; } else if (mAttributes[aPos].mName.Equals(nsGkAtoms::is)) { // Store is as atom. @@ -1839,9 +1843,8 @@ class ScriptCompileTask final : public Task { return; } - JS::CompilationStorage compileStorage; - mStencil = JS::CompileGlobalScriptToStencil(mFrontendContext, mOptions, - srcBuf, compileStorage); + mStencil = + JS::CompileGlobalScriptToStencil(mFrontendContext, mOptions, srcBuf); #ifdef DEBUG // Chrome-privileged code shouldn't have any compilation error. CheckErrorsAndWarnings(mFrontendContext, mOptions); diff --git a/dom/xul/nsXULElement.h b/dom/xul/nsXULElement.h index 4002ec63dc..2681a14a9a 100644 --- a/dom/xul/nsXULElement.h +++ b/dom/xul/nsXULElement.h @@ -374,7 +374,7 @@ class nsXULElement : public nsStyledElement { mozilla::EventChainVisitor& aVisitor) override; // nsIContent virtual nsresult BindToTree(BindContext&, nsINode& aParent) override; - virtual void UnbindFromTree(bool aNullParent) override; + virtual void UnbindFromTree(UnbindContext&) override; virtual void DestroyContent() override; virtual void DoneAddingChildren(bool aHaveNotified) override; diff --git a/dom/xul/nsXULPopupListener.cpp b/dom/xul/nsXULPopupListener.cpp index 9f2ee88e8d..35445d6d3e 100644 --- a/dom/xul/nsXULPopupListener.cpp +++ b/dom/xul/nsXULPopupListener.cpp @@ -12,7 +12,6 @@ #include "XULButtonElement.h" #include "nsCOMPtr.h" #include "nsGkAtoms.h" -#include "nsContentCID.h" #include "nsContentUtils.h" #include "nsXULPopupManager.h" #include "nsIScriptContext.h" diff --git a/dom/xul/test/test_bug468176.xhtml b/dom/xul/test/test_bug468176.xhtml index f21c1bcde3..3f4c690b6f 100644 --- a/dom/xul/test/test_bug468176.xhtml +++ b/dom/xul/test/test_bug468176.xhtml @@ -27,7 +27,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=468176 SimpleTest.waitForExplicitFinish(); var broadcastCount = 0; - function b_listener(evt) { + function b_listener() { ++broadcastCount; } -- cgit v1.2.3