From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- dom/events/AnimationEvent.cpp | 66 + dom/events/AnimationEvent.h | 48 + dom/events/AsyncEventDispatcher.cpp | 180 + dom/events/AsyncEventDispatcher.h | 209 + dom/events/BeforeUnloadEvent.cpp | 29 + dom/events/BeforeUnloadEvent.h | 45 + dom/events/Clipboard.cpp | 820 +++ dom/events/Clipboard.h | 133 + dom/events/ClipboardEvent.cpp | 90 + dom/events/ClipboardEvent.h | 48 + dom/events/ClipboardItem.cpp | 331 + dom/events/ClipboardItem.h | 132 + dom/events/CommandEvent.cpp | 42 + dom/events/CommandEvent.h | 40 + dom/events/CompositionEvent.cpp | 108 + dom/events/CompositionEvent.h | 58 + dom/events/ConstructibleEventTarget.cpp | 17 + dom/events/ConstructibleEventTarget.h | 30 + dom/events/ContentEventHandler.cpp | 3307 ++++++++++ dom/events/ContentEventHandler.h | 444 ++ dom/events/CustomEvent.cpp | 83 + dom/events/CustomEvent.h | 52 + dom/events/DOMEventTargetHelper.cpp | 265 + dom/events/DOMEventTargetHelper.h | 167 + dom/events/DataTransfer.cpp | 1488 +++++ dom/events/DataTransfer.h | 529 ++ dom/events/DataTransferItem.cpp | 615 ++ dom/events/DataTransferItem.h | 137 + dom/events/DataTransferItemList.cpp | 642 ++ dom/events/DataTransferItemList.h | 125 + dom/events/DeviceMotionEvent.cpp | 130 + dom/events/DeviceMotionEvent.h | 129 + dom/events/DragEvent.cpp | 98 + dom/events/DragEvent.h | 55 + dom/events/Event.cpp | 889 +++ dom/events/Event.h | 409 ++ dom/events/EventDispatcher.cpp | 1539 +++++ dom/events/EventDispatcher.h | 385 ++ dom/events/EventListenerManager.cpp | 2088 ++++++ dom/events/EventListenerManager.h | 704 ++ dom/events/EventListenerService.cpp | 409 ++ dom/events/EventListenerService.h | 108 + dom/events/EventNameList.h | 594 ++ dom/events/EventStateManager.cpp | 6695 ++++++++++++++++++++ dom/events/EventStateManager.h | 1256 ++++ dom/events/EventTarget.cpp | 236 + dom/events/EventTarget.h | 412 ++ dom/events/FocusEvent.cpp | 61 + dom/events/FocusEvent.h | 47 + dom/events/GlobalKeyListener.cpp | 751 +++ dom/events/GlobalKeyListener.h | 186 + dom/events/IMEContentObserver.cpp | 2173 +++++++ dom/events/IMEContentObserver.h | 538 ++ dom/events/IMEStateManager.cpp | 2363 +++++++ dom/events/IMEStateManager.h | 494 ++ dom/events/ImageCaptureError.cpp | 39 + dom/events/ImageCaptureError.h | 56 + dom/events/InputEvent.cpp | 118 + dom/events/InputEvent.h | 58 + dom/events/InputEventOptions.h | 75 + dom/events/InputTypeList.h | 73 + dom/events/InternalMutationEvent.h | 66 + dom/events/JSEventHandler.cpp | 229 + dom/events/JSEventHandler.h | 231 + dom/events/KeyEventHandler.cpp | 741 +++ dom/events/KeyEventHandler.h | 176 + dom/events/KeyNameList.h | 438 ++ dom/events/KeyboardEvent.cpp | 424 ++ dom/events/KeyboardEvent.h | 135 + dom/events/MessageEvent.cpp | 162 + dom/events/MessageEvent.h | 102 + dom/events/MouseEvent.cpp | 320 + dom/events/MouseEvent.h | 115 + dom/events/MouseScrollEvent.cpp | 66 + dom/events/MouseScrollEvent.h | 47 + dom/events/MutationEvent.cpp | 75 + dom/events/MutationEvent.h | 53 + dom/events/NotifyPaintEvent.cpp | 133 + dom/events/NotifyPaintEvent.h | 73 + dom/events/PaintRequest.cpp | 60 + dom/events/PaintRequest.h | 77 + dom/events/PendingFullscreenEvent.h | 71 + dom/events/PhysicalKeyCodeNameList.h | 235 + dom/events/PointerEvent.cpp | 298 + dom/events/PointerEvent.h | 78 + dom/events/PointerEventHandler.cpp | 800 +++ dom/events/PointerEventHandler.h | 237 + dom/events/RemoteDragStartData.cpp | 83 + dom/events/RemoteDragStartData.h | 74 + dom/events/ScrollAreaEvent.cpp | 80 + dom/events/ScrollAreaEvent.h | 60 + dom/events/ShortcutKeyDefinitions.cpp | 780 +++ dom/events/ShortcutKeys.cpp | 120 + dom/events/ShortcutKeys.h | 70 + dom/events/SimpleGestureEvent.cpp | 86 + dom/events/SimpleGestureEvent.h | 56 + dom/events/SpeechRecognitionError.cpp | 46 + dom/events/SpeechRecognitionError.h | 48 + dom/events/StorageEvent.cpp | 84 + dom/events/StorageEvent.h | 85 + dom/events/TextClause.cpp | 45 + dom/events/TextClause.h | 53 + dom/events/TextComposition.cpp | 1045 +++ dom/events/TextComposition.h | 631 ++ dom/events/Touch.cpp | 233 + dom/events/Touch.h | 105 + dom/events/TouchEvent.cpp | 338 + dom/events/TouchEvent.h | 121 + dom/events/TransitionEvent.cpp | 68 + dom/events/TransitionEvent.h | 47 + dom/events/UIEvent.cpp | 336 + dom/events/UIEvent.h | 124 + dom/events/VirtualKeyCodeList.h | 245 + dom/events/WheelEvent.cpp | 178 + dom/events/WheelEvent.h | 82 + dom/events/WheelHandlingHelper.cpp | 872 +++ dom/events/WheelHandlingHelper.h | 440 ++ dom/events/XULCommandEvent.cpp | 73 + dom/events/XULCommandEvent.h | 66 + dom/events/crashtests/1033343.html | 5 + dom/events/crashtests/1035654-1.html | 21 + dom/events/crashtests/1035654-2.html | 20 + dom/events/crashtests/104310-1.html | 22 + dom/events/crashtests/1072137-1.html | 18 + dom/events/crashtests/1143972-1.html | 12 + dom/events/crashtests/116206-1.html | 23 + dom/events/crashtests/1190036-1.html | 15 + dom/events/crashtests/135345-1.html | 14 + dom/events/crashtests/1397711.html | 11 + dom/events/crashtests/457776-1.html | 9 + dom/events/crashtests/496308-1.html | 3 + dom/events/crashtests/682637-1.html | 22 + dom/events/crashtests/938341.html | 7 + dom/events/crashtests/crashtests.list | 18 + .../crashtests/eventctor-nulldictionary.html | 4 + dom/events/crashtests/eventctor-nullstorage.html | 4 + .../crashtests/recursive-DOMNodeInserted.html | 17 + dom/events/crashtests/recursive-onload.html | 1 + dom/events/moz.build | 186 + dom/events/nsIEventListenerService.idl | 128 + dom/events/test/browser.ini | 30 + dom/events/test/browser_alt_keyup_in_content.js | 333 + ..._beforeinput_by_execCommand_in_contentscript.js | 106 + dom/events/test/browser_bug1539497.js | 25 + dom/events/test/browser_dragimage.js | 65 + ...vent_init_key_event_enabled_in_contentscript.js | 80 + .../test/browser_mouse_enterleave_switch_tab.js | 158 + ...er_conflicts_with_content_accesskey_modifier.js | 102 + dom/events/test/bug1017086_inner.html | 39 + dom/events/test/bug226361_iframe.xhtml | 47 + dom/events/test/bug299673.js | 150 + dom/events/test/bug322588-popup.html | 1 + dom/events/test/bug415498-doc1.html | 15 + dom/events/test/bug415498-doc2.html | 15 + dom/events/test/bug418986-3.js | 85 + dom/events/test/bug426082.html | 116 + dom/events/test/bug545268.html | 1 + dom/events/test/bug574663.html | 3 + dom/events/test/bug591249_iframe.xhtml | 33 + dom/events/test/bug602962.xhtml | 8 + dom/events/test/bug607464.html | 3 + dom/events/test/bug656379-1.html | 186 + dom/events/test/chrome.ini | 31 + dom/events/test/clipboard/browser.ini | 21 + .../browser_navigator_clipboard_clickjacking.js | 69 + .../clipboard/browser_navigator_clipboard_read.js | 198 + .../browser_navigator_clipboard_readText.js | 201 + .../clipboard/browser_navigator_clipboard_touch.js | 114 + dom/events/test/clipboard/chrome.ini | 3 + dom/events/test/clipboard/head.js | 169 + .../simple_navigator_clipboard_keydown.html | 15 + .../clipboard/simple_navigator_clipboard_read.html | 65 + .../simple_navigator_clipboard_readText.html | 47 + .../test/clipboard/test_async_clipboard.xhtml | 130 + dom/events/test/dragimage.html | 10 + dom/events/test/empty.js | 0 dom/events/test/error_event_worker.js | 19 + dom/events/test/event_leak_utils.js | 84 + ...eforeinput_by_execCommand_in_contentscript.html | 2 + dom/events/test/file_bug1446834.html | 96 + dom/events/test/file_bug1484371.html | 94 + dom/events/test/file_bug1692052.html | 25 + dom/events/test/file_bug679494.html | 8 + .../test/file_coalesce_touchmove_browserchild.html | 117 + .../file_coalesce_touchmove_browserchild2.html | 193 + dom/events/test/file_coalesce_touchmove_ipc.html | 193 + dom/events/test/file_empty.html | 15 + dom/events/test/file_event_screenXY.html | 23 + ...focus_blur_on_click_in_cross_origin_iframe.html | 28 + ...on_click_in_deep_cross_origin_iframe_inner.html | 28 + ...n_click_in_deep_cross_origin_iframe_middle.html | 37 + ...nt_init_key_event_enabled_in_contentscript.html | 21 + dom/events/test/file_mouse_enterleave.html | 40 + dom/events/test/green.png | Bin 0 -> 255 bytes .../test/gtest/TestShortcutKeyDefinitions.cpp | 634 ++ dom/events/test/gtest/moz.build | 18 + dom/events/test/mochitest.ini | 333 + ...93174_implicit_pointer_capture_for_touch_1.html | 63 + ...93174_implicit_pointer_capture_for_touch_2.html | 64 + dom/events/test/pointerevents/bug968148_inner.html | 316 + .../test/pointerevents/bug968148_inner2.html | 315 + .../test/pointerevents/bug_1420589_iframe1.html | 17 + .../test/pointerevents/bug_1420589_iframe2.html | 17 + dom/events/test/pointerevents/chrome.ini | 1 + .../file_pointercapture_xorigin_iframe.html | 62 + ..._pointercapture_xorigin_iframe_pointerlock.html | 111 + .../file_pointercapture_xorigin_iframe_touch.html | 69 + .../file_test_trigger_fullscreen.html | 1 + dom/events/test/pointerevents/iframe.html | 7 + dom/events/test/pointerevents/mochitest.ini | 168 + .../pointerevents/mochitest_support_external.js | 270 + .../pointerevents/mochitest_support_internal.js | 125 + .../test/pointerevents/pointerevent_utils.js | 60 + dom/events/test/pointerevents/readme.md | 9 + dom/events/test/pointerevents/test_bug1285128.html | 51 + ...93174_implicit_pointer_capture_for_touch_1.html | 30 + ...93174_implicit_pointer_capture_for_touch_2.html | 30 + dom/events/test/pointerevents/test_bug1303704.html | 135 + dom/events/test/pointerevents/test_bug1315862.html | 66 + dom/events/test/pointerevents/test_bug1323158.html | 91 + dom/events/test/pointerevents/test_bug1403055.html | 90 + .../test/pointerevents/test_bug1420589_1.html | 105 + .../test/pointerevents/test_bug1420589_2.html | 122 + .../test/pointerevents/test_bug1420589_3.html | 115 + .../test/pointerevents/test_bug1697769.xhtml | 74 + dom/events/test/pointerevents/test_bug1725416.html | 37 + dom/events/test/pointerevents/test_bug968148.html | 46 + .../pointerevents/test_getCoalescedEvents.html | 88 + .../test_getCoalescedEvents_touch.html | 111 + .../test/pointerevents/test_multiple_touches.html | 196 + .../test_pointercapture_remove_iframe.html | 80 + .../test_pointercapture_xorigin_iframe.html | 55 + .../test_pointermove_drag_scrollbar.html | 77 + ...test_remove_frame_when_got_pointer_capture.html | 166 + .../test/pointerevents/test_synthesized_touch.html | 47 + .../test_trigger_fullscreen_by_pointer_events.html | 54 + ...event_attributes_hoverable_pointers-manual.html | 53 + ...erevent_attributes_nohover_pointers-manual.html | 26 + ...revent_boundary_events_in_capturing-manual.html | 46 + ...ge-touch-action-onpointerdown_touch-manual.html | 39 + .../test_wpt_pointerevent_constructor.html | 26 + ...t_wpt_pointerevent_drag_interaction-manual.html | 38 + .../test_wpt_pointerevent_movementxy-manual.html | 53 + ...le_primary_pointers_boundary_events-manual.html | 31 + ...st_wpt_pointerevent_pointerId_scope-manual.html | 27 + ...pt_pointerevent_pointercancel_touch-manual.html | 30 + ...nterleave_after_pointercancel_touch-manual.html | 30 + ...t_wpt_pointerevent_pointerleave_pen-manual.html | 28 + ...ointerout_after_pointercancel_touch-manual.html | 30 + ...est_wpt_pointerevent_pointerout_pen-manual.html | 28 + ...ercapture_events_to_original_target-manual.html | 49 + ...ointercapture_onpointercancel_touch-manual.html | 30 + ...equence_at_implicit_release_on_drag-manual.html | 27 + .../test/pointerevents/test_wpt_touch_action.html | 98 + .../test/pointerevents/touch_action_helpers.js | 242 + ...touch-action_two-finger_interaction-manual.html | 102 + .../html/pointerevent_drag_interaction-manual.html | 103 + dom/events/test/pointerevents/wpt/idlharness.html | 104 + ...event_attributes_hoverable_pointers-manual.html | 143 + ...erevent_attributes_nohover_pointers-manual.html | 126 + ...revent_boundary_events_in_capturing-manual.html | 97 + ...ge-touch-action-onpointerdown_touch-manual.html | 135 + .../wpt/pointerevent_constructor.html | 106 + ...le_primary_pointers_boundary_events-manual.html | 145 + .../wpt/pointerevent_pointerId_scope-manual.html | 82 + .../pointerevent_pointercancel_touch-manual.html | 77 + ...nterleave_after_pointercancel_touch-manual.html | 66 + .../wpt/pointerevent_pointerleave_pen-manual.html | 58 + ...ointerout_after_pointercancel_touch-manual.html | 67 + .../wpt/pointerevent_pointerout_pen-manual.html | 57 + ...ercapture_events_to_original_target-manual.html | 137 + ...ointercapture_onpointercancel_touch-manual.html | 71 + ...quence_at_implicit_release_on_click-manual.html | 83 + ...equence_at_implicit_release_on_drag-manual.html | 84 + .../test/pointerevents/wpt/pointerevent_styles.css | 112 + .../test/pointerevents/wpt/pointerevent_support.js | 333 + ...erevent_touch-action-auto-css_touch-manual.html | 129 + ...vent_touch-action-button-test_touch-manual.html | 110 + .../wpt/pointerevent_touch-action-illegal.html | 67 + ...inherit_child-auto-child-none_touch-manual.html | 117 + ...uch-action-inherit_child-none_touch-manual.html | 112 + ...herit_child-pan-x-child-pan-x_touch-manual.html | 112 + ...herit_child-pan-x-child-pan-y_touch-manual.html | 117 + ...n-inherit_highest-parent-none_touch-manual.html | 133 + ...ch-action-inherit_parent-none_touch-manual.html | 112 + .../pointerevent_touch-action-keyboard-manual.html | 124 + .../pointerevent_touch-action-mouse-manual.html | 130 + ...erevent_touch-action-none-css_touch-manual.html | 111 + ...ent_touch-action-pan-down-css_touch-manual.html | 114 + ...ent_touch-action-pan-left-css_touch-manual.html | 114 + ...nt_touch-action-pan-right-css_touch-manual.html | 114 + ...event_touch-action-pan-up-css_touch-manual.html | 114 + ...revent_touch-action-pan-x-css_touch-manual.html | 106 + ...ouch-action-pan-x-pan-y-pan-y_touch-manual.html | 111 + ...vent_touch-action-pan-x-pan-y_touch-manual.html | 126 + ...revent_touch-action-pan-y-css_touch-manual.html | 106 + ...revent_touch-action-span-test_touch-manual.html | 114 + ...erevent_touch-action-svg-test_touch-manual.html | 122 + ...event_touch-action-table-test_touch-manual.html | 145 + .../pointerevent_touch-action-verification.html | 91 + .../pointerevent_movementxy-manual.html | 99 + .../resources/pointerevent_movementxy-iframe.html | 8 + ...event_attributes_hoverable_pointers-iframe.html | 10 + .../pointerevent_pointerId_scope-iframe.html | 35 + dom/events/test/test_DataTransferItemList.html | 233 + dom/events/test/test_accel_virtual_modifier.html | 90 + dom/events/test/test_accesskey.html | 160 + dom/events/test/test_addEventListenerExtraArg.html | 31 + dom/events/test/test_all_synthetic_events.html | 479 ++ dom/events/test/test_bug1003432.html | 45 + dom/events/test/test_bug1003432.js | 31 + dom/events/test/test_bug1013412.html | 116 + dom/events/test/test_bug1017086_enable.html | 35 + dom/events/test/test_bug1037990.html | 61 + dom/events/test/test_bug1079236.html | 66 + dom/events/test/test_bug1127588.html | 61 + dom/events/test/test_bug1128787-1.html | 52 + dom/events/test/test_bug1128787-2.html | 54 + dom/events/test/test_bug1128787-3.html | 53 + dom/events/test/test_bug1145910.html | 54 + dom/events/test/test_bug1150308.html | 49 + dom/events/test/test_bug1248459.html | 58 + dom/events/test/test_bug1264380.html | 82 + dom/events/test/test_bug1298970.html | 33 + dom/events/test/test_bug1304044.html | 133 + dom/events/test/test_bug1305458.html | 50 + dom/events/test/test_bug1327798.html | 47 + dom/events/test/test_bug1332699.html | 37 + dom/events/test/test_bug1339758.html | 80 + dom/events/test/test_bug1369072.html | 37 + dom/events/test/test_bug1412775.xhtml | 66 + dom/events/test/test_bug1429572.html | 43 + dom/events/test/test_bug1446834.html | 33 + dom/events/test/test_bug1447993.html | 41 + dom/events/test/test_bug1484371.html | 27 + dom/events/test/test_bug1534562.html | 51 + dom/events/test/test_bug1539497.html | 29 + dom/events/test/test_bug1581192.html | 73 + dom/events/test/test_bug1635018.html | 27 + dom/events/test/test_bug1637259.html | 71 + dom/events/test/test_bug1673434.html | 75 + dom/events/test/test_bug1681800.html | 26 + dom/events/test/test_bug1686716.html | 28 + dom/events/test/test_bug1692052.html | 36 + dom/events/test/test_bug1692277.html | 43 + dom/events/test/test_bug1709832.html | 46 + dom/events/test/test_bug1710509.html | 49 + dom/events/test/test_bug1728171.html | 70 + dom/events/test/test_bug226361.xhtml | 82 + dom/events/test/test_bug238987.html | 279 + dom/events/test/test_bug288392.html | 103 + dom/events/test/test_bug299673-1.html | 61 + dom/events/test/test_bug299673-2.html | 60 + dom/events/test/test_bug322588.html | 66 + dom/events/test/test_bug328885.html | 135 + dom/events/test/test_bug336682.js | 96 + dom/events/test/test_bug336682_1.html | 55 + dom/events/test/test_bug336682_2.xhtml | 59 + dom/events/test/test_bug367781.html | 53 + dom/events/test/test_bug379120.html | 55 + dom/events/test/test_bug402089.html | 67 + dom/events/test/test_bug405632.html | 34 + dom/events/test/test_bug409604.html | 379 ++ dom/events/test/test_bug412567.html | 47 + dom/events/test/test_bug415498.xhtml | 95 + dom/events/test/test_bug418986-3.html | 25 + dom/events/test/test_bug418986-3.xhtml | 27 + dom/events/test/test_bug422132.html | 125 + dom/events/test/test_bug426082.html | 30 + dom/events/test/test_bug427537.html | 61 + dom/events/test/test_bug428988.html | 44 + dom/events/test/test_bug432698.html | 223 + dom/events/test/test_bug443985.html | 76 + dom/events/test/test_bug447736.html | 47 + dom/events/test/test_bug448602.html | 294 + dom/events/test/test_bug450876.html | 47 + dom/events/test/test_bug456273.html | 46 + dom/events/test/test_bug457672.html | 55 + dom/events/test/test_bug489671.html | 55 + dom/events/test/test_bug493251.html | 181 + dom/events/test/test_bug508479.html | 110 + dom/events/test/test_bug517851.html | 122 + dom/events/test/test_bug524674.xhtml | 130 + dom/events/test/test_bug534833.html | 156 + dom/events/test/test_bug545268.html | 129 + dom/events/test/test_bug547996-1.html | 87 + dom/events/test/test_bug547996-2.xhtml | 120 + dom/events/test/test_bug547996-3.xhtml | 65 + dom/events/test/test_bug556493.html | 74 + dom/events/test/test_bug563329.html | 82 + dom/events/test/test_bug574663.html | 194 + dom/events/test/test_bug586961.xhtml | 46 + dom/events/test/test_bug591249.xhtml | 73 + dom/events/test/test_bug591815.html | 68 + dom/events/test/test_bug593959.html | 60 + dom/events/test/test_bug602962.xhtml | 87 + dom/events/test/test_bug603008.html | 559 ++ dom/events/test/test_bug605242.html | 58 + dom/events/test/test_bug607464.html | 84 + dom/events/test/test_bug613634.html | 90 + dom/events/test/test_bug615597.html | 39 + dom/events/test/test_bug617528.xhtml | 94 + dom/events/test/test_bug624127.html | 35 + dom/events/test/test_bug635465.html | 90 + dom/events/test/test_bug641477.html | 37 + dom/events/test/test_bug648573.html | 120 + dom/events/test/test_bug650493.html | 215 + dom/events/test/test_bug656379-1.html | 30 + dom/events/test/test_bug656379-2.html | 115 + dom/events/test/test_bug656954.html | 42 + dom/events/test/test_bug659071.html | 39 + dom/events/test/test_bug659350.html | 111 + dom/events/test/test_bug662678.html | 153 + dom/events/test/test_bug667612.html | 38 + dom/events/test/test_bug667919-1.html | 41 + dom/events/test/test_bug679494.xhtml | 36 + dom/events/test/test_bug684208.html | 80 + dom/events/test/test_bug687787.html | 610 ++ dom/events/test/test_bug689564.html | 65 + dom/events/test/test_bug698929.html | 47 + dom/events/test/test_bug704423.html | 40 + dom/events/test/test_bug741666.html | 185 + dom/events/test/test_bug812744.html | 37 + dom/events/test/test_bug822898.html | 343 + dom/events/test/test_bug855741.html | 90 + dom/events/test/test_bug864040.html | 87 + dom/events/test/test_bug924087.html | 45 + dom/events/test/test_bug930374-chrome.html | 57 + dom/events/test/test_bug930374-content.html | 70 + dom/events/test/test_bug944011.html | 52 + dom/events/test/test_bug944847.html | 42 + dom/events/test/test_bug946632.html | 156 + dom/events/test/test_bug967796.html | 236 + dom/events/test/test_bug985988.html | 89 + dom/events/test/test_bug998809.html | 35 + .../test_click_on_reframed_generated_text.html | 32 + .../test/test_click_on_restyled_element.html | 51 + dom/events/test/test_clickevent_on_input.html | 108 + dom/events/test/test_coalesce_mousewheel.html | 241 + dom/events/test/test_coalesce_touchmove.html | 34 + dom/events/test/test_continuous_wheel_events.html | 3294 ++++++++++ .../test_dblclick_explicit_original_target.html | 52 + .../test/test_deltaMode_lines_always_enabled.html | 40 + dom/events/test/test_deviceSensor.html | 136 + dom/events/test/test_disabled_events.html | 40 + dom/events/test/test_dnd_with_modifiers.html | 78 + dom/events/test/test_dom_activate_event.html | 91 + dom/events/test/test_dom_keyboard_event.html | 541 ++ dom/events/test/test_dom_mouse_event.html | 143 + dom/events/test/test_dom_storage_event.html | 62 + dom/events/test/test_dom_wheel_event.html | 850 +++ dom/events/test/test_drag_coords.html | 52 + dom/events/test/test_drag_image_file.html | 56 + dom/events/test/test_draggableprop.html | 93 + dom/events/test/test_dragstart.html | 716 +++ dom/events/test/test_error_events.html | 71 + dom/events/test/test_eventTimeStamp.html | 116 + dom/events/test/test_event_handler_cc.html | 90 + ...test_event_screenXY_in_cross_origin_iframe.html | 101 + dom/events/test/test_event_screenXY_with_zoom.html | 63 + dom/events/test/test_eventctors.html | 936 +++ dom/events/test/test_eventctors.xhtml | 49 + dom/events/test/test_eventctors_sensors.html | 97 + dom/events/test/test_eventhandler_scoping.html | 17 + dom/events/test/test_focus_abspos.html | 32 + ...focus_blur_on_click_in_cross_origin_iframe.html | 118 + ..._blur_on_click_in_deep_cross_origin_iframe.html | 146 + dom/events/test/test_hover_mouseleave.html | 47 + dom/events/test/test_legacy_event.html | 297 + dom/events/test/test_legacy_non-primary_click.html | 53 + dom/events/test/test_legacy_touch_api.html | 65 + dom/events/test/test_marquee_events.html | 31 + dom/events/test/test_messageEvent.html | 79 + dom/events/test/test_messageEvent_init.html | 25 + dom/events/test/test_mouse_capture_iframe.html | 70 + dom/events/test/test_mouse_enterleave_iframe.html | 305 + ...st_moving_and_expanding_selection_per_page.html | 353 ++ .../test/test_moz_mouse_pixel_scroll_event.html | 481 ++ dom/events/test/test_offsetxy.html | 98 + dom/events/test/test_onerror_handler_args.html | 36 + dom/events/test/test_passive_listeners.html | 118 + dom/events/test/test_paste_image.html | 191 + dom/events/test/test_scroll_per_page.html | 259 + dom/events/test/test_slotted_mouse_event.html | 97 + dom/events/test/test_slotted_text_click.html | 72 + dom/events/test/test_submitevent_on_form.html | 67 + dom/events/test/test_text_event_in_content.html | 68 + .../test/test_unbound_before_in_active_chain.html | 38 + ..._event_model_on_newer_Office_Online_Server.html | 59 + ...lit_keypress_event_model_on_old_Confluence.html | 82 + ...ss_event_model_on_old_Office_Online_Server.html | 69 + dom/events/test/test_wheel_default_action.html | 39 + .../test/test_wheel_zoom_on_form_controls.html | 69 + dom/events/test/window_bug1369072.html | 170 + dom/events/test/window_bug1412775.xhtml | 8 + dom/events/test/window_bug1429572.html | 351 + dom/events/test/window_bug1447993.html | 239 + dom/events/test/window_bug493251.html | 13 + dom/events/test/window_bug617528.xhtml | 9 + dom/events/test/window_bug659071.html | 72 + dom/events/test/window_empty_document.html | 7 + dom/events/test/window_wheel_default_action.html | 3621 +++++++++++ 502 files changed, 88891 insertions(+) create mode 100644 dom/events/AnimationEvent.cpp create mode 100644 dom/events/AnimationEvent.h create mode 100644 dom/events/AsyncEventDispatcher.cpp create mode 100644 dom/events/AsyncEventDispatcher.h create mode 100644 dom/events/BeforeUnloadEvent.cpp create mode 100644 dom/events/BeforeUnloadEvent.h create mode 100644 dom/events/Clipboard.cpp create mode 100644 dom/events/Clipboard.h create mode 100644 dom/events/ClipboardEvent.cpp create mode 100644 dom/events/ClipboardEvent.h create mode 100644 dom/events/ClipboardItem.cpp create mode 100644 dom/events/ClipboardItem.h create mode 100644 dom/events/CommandEvent.cpp create mode 100644 dom/events/CommandEvent.h create mode 100644 dom/events/CompositionEvent.cpp create mode 100644 dom/events/CompositionEvent.h create mode 100644 dom/events/ConstructibleEventTarget.cpp create mode 100644 dom/events/ConstructibleEventTarget.h create mode 100644 dom/events/ContentEventHandler.cpp create mode 100644 dom/events/ContentEventHandler.h create mode 100644 dom/events/CustomEvent.cpp create mode 100644 dom/events/CustomEvent.h create mode 100644 dom/events/DOMEventTargetHelper.cpp create mode 100644 dom/events/DOMEventTargetHelper.h create mode 100644 dom/events/DataTransfer.cpp create mode 100644 dom/events/DataTransfer.h create mode 100644 dom/events/DataTransferItem.cpp create mode 100644 dom/events/DataTransferItem.h create mode 100644 dom/events/DataTransferItemList.cpp create mode 100644 dom/events/DataTransferItemList.h create mode 100644 dom/events/DeviceMotionEvent.cpp create mode 100644 dom/events/DeviceMotionEvent.h create mode 100644 dom/events/DragEvent.cpp create mode 100644 dom/events/DragEvent.h create mode 100644 dom/events/Event.cpp create mode 100644 dom/events/Event.h create mode 100644 dom/events/EventDispatcher.cpp create mode 100644 dom/events/EventDispatcher.h create mode 100644 dom/events/EventListenerManager.cpp create mode 100644 dom/events/EventListenerManager.h create mode 100644 dom/events/EventListenerService.cpp create mode 100644 dom/events/EventListenerService.h create mode 100644 dom/events/EventNameList.h create mode 100644 dom/events/EventStateManager.cpp create mode 100644 dom/events/EventStateManager.h create mode 100644 dom/events/EventTarget.cpp create mode 100644 dom/events/EventTarget.h create mode 100644 dom/events/FocusEvent.cpp create mode 100644 dom/events/FocusEvent.h create mode 100644 dom/events/GlobalKeyListener.cpp create mode 100644 dom/events/GlobalKeyListener.h create mode 100644 dom/events/IMEContentObserver.cpp create mode 100644 dom/events/IMEContentObserver.h create mode 100644 dom/events/IMEStateManager.cpp create mode 100644 dom/events/IMEStateManager.h create mode 100644 dom/events/ImageCaptureError.cpp create mode 100644 dom/events/ImageCaptureError.h create mode 100644 dom/events/InputEvent.cpp create mode 100644 dom/events/InputEvent.h create mode 100644 dom/events/InputEventOptions.h create mode 100644 dom/events/InputTypeList.h create mode 100644 dom/events/InternalMutationEvent.h create mode 100644 dom/events/JSEventHandler.cpp create mode 100644 dom/events/JSEventHandler.h create mode 100644 dom/events/KeyEventHandler.cpp create mode 100644 dom/events/KeyEventHandler.h create mode 100644 dom/events/KeyNameList.h create mode 100644 dom/events/KeyboardEvent.cpp create mode 100644 dom/events/KeyboardEvent.h create mode 100644 dom/events/MessageEvent.cpp create mode 100644 dom/events/MessageEvent.h create mode 100644 dom/events/MouseEvent.cpp create mode 100644 dom/events/MouseEvent.h create mode 100644 dom/events/MouseScrollEvent.cpp create mode 100644 dom/events/MouseScrollEvent.h create mode 100644 dom/events/MutationEvent.cpp create mode 100644 dom/events/MutationEvent.h create mode 100644 dom/events/NotifyPaintEvent.cpp create mode 100644 dom/events/NotifyPaintEvent.h create mode 100644 dom/events/PaintRequest.cpp create mode 100644 dom/events/PaintRequest.h create mode 100644 dom/events/PendingFullscreenEvent.h create mode 100644 dom/events/PhysicalKeyCodeNameList.h create mode 100644 dom/events/PointerEvent.cpp create mode 100644 dom/events/PointerEvent.h create mode 100644 dom/events/PointerEventHandler.cpp create mode 100644 dom/events/PointerEventHandler.h create mode 100644 dom/events/RemoteDragStartData.cpp create mode 100644 dom/events/RemoteDragStartData.h create mode 100644 dom/events/ScrollAreaEvent.cpp create mode 100644 dom/events/ScrollAreaEvent.h create mode 100644 dom/events/ShortcutKeyDefinitions.cpp create mode 100644 dom/events/ShortcutKeys.cpp create mode 100644 dom/events/ShortcutKeys.h create mode 100644 dom/events/SimpleGestureEvent.cpp create mode 100644 dom/events/SimpleGestureEvent.h create mode 100644 dom/events/SpeechRecognitionError.cpp create mode 100644 dom/events/SpeechRecognitionError.h create mode 100644 dom/events/StorageEvent.cpp create mode 100644 dom/events/StorageEvent.h create mode 100644 dom/events/TextClause.cpp create mode 100644 dom/events/TextClause.h create mode 100644 dom/events/TextComposition.cpp create mode 100644 dom/events/TextComposition.h create mode 100644 dom/events/Touch.cpp create mode 100644 dom/events/Touch.h create mode 100644 dom/events/TouchEvent.cpp create mode 100644 dom/events/TouchEvent.h create mode 100644 dom/events/TransitionEvent.cpp create mode 100644 dom/events/TransitionEvent.h create mode 100644 dom/events/UIEvent.cpp create mode 100644 dom/events/UIEvent.h create mode 100644 dom/events/VirtualKeyCodeList.h create mode 100644 dom/events/WheelEvent.cpp create mode 100644 dom/events/WheelEvent.h create mode 100644 dom/events/WheelHandlingHelper.cpp create mode 100644 dom/events/WheelHandlingHelper.h create mode 100644 dom/events/XULCommandEvent.cpp create mode 100644 dom/events/XULCommandEvent.h create mode 100644 dom/events/crashtests/1033343.html create mode 100644 dom/events/crashtests/1035654-1.html create mode 100644 dom/events/crashtests/1035654-2.html create mode 100644 dom/events/crashtests/104310-1.html create mode 100644 dom/events/crashtests/1072137-1.html create mode 100644 dom/events/crashtests/1143972-1.html create mode 100644 dom/events/crashtests/116206-1.html create mode 100644 dom/events/crashtests/1190036-1.html create mode 100644 dom/events/crashtests/135345-1.html create mode 100644 dom/events/crashtests/1397711.html create mode 100644 dom/events/crashtests/457776-1.html create mode 100644 dom/events/crashtests/496308-1.html create mode 100644 dom/events/crashtests/682637-1.html create mode 100644 dom/events/crashtests/938341.html create mode 100644 dom/events/crashtests/crashtests.list create mode 100644 dom/events/crashtests/eventctor-nulldictionary.html create mode 100644 dom/events/crashtests/eventctor-nullstorage.html create mode 100644 dom/events/crashtests/recursive-DOMNodeInserted.html create mode 100644 dom/events/crashtests/recursive-onload.html create mode 100644 dom/events/moz.build create mode 100644 dom/events/nsIEventListenerService.idl create mode 100644 dom/events/test/browser.ini create mode 100644 dom/events/test/browser_alt_keyup_in_content.js create mode 100644 dom/events/test/browser_beforeinput_by_execCommand_in_contentscript.js create mode 100644 dom/events/test/browser_bug1539497.js create mode 100644 dom/events/test/browser_dragimage.js create mode 100644 dom/events/test/browser_keyboard_event_init_key_event_enabled_in_contentscript.js create mode 100644 dom/events/test/browser_mouse_enterleave_switch_tab.js create mode 100644 dom/events/test/browser_shortcutkey_modifier_conflicts_with_content_accesskey_modifier.js create mode 100644 dom/events/test/bug1017086_inner.html create mode 100644 dom/events/test/bug226361_iframe.xhtml create mode 100644 dom/events/test/bug299673.js create mode 100644 dom/events/test/bug322588-popup.html create mode 100644 dom/events/test/bug415498-doc1.html create mode 100644 dom/events/test/bug415498-doc2.html create mode 100644 dom/events/test/bug418986-3.js create mode 100644 dom/events/test/bug426082.html create mode 100644 dom/events/test/bug545268.html create mode 100644 dom/events/test/bug574663.html create mode 100644 dom/events/test/bug591249_iframe.xhtml create mode 100644 dom/events/test/bug602962.xhtml create mode 100644 dom/events/test/bug607464.html create mode 100644 dom/events/test/bug656379-1.html create mode 100644 dom/events/test/chrome.ini create mode 100644 dom/events/test/clipboard/browser.ini create mode 100644 dom/events/test/clipboard/browser_navigator_clipboard_clickjacking.js create mode 100644 dom/events/test/clipboard/browser_navigator_clipboard_read.js create mode 100644 dom/events/test/clipboard/browser_navigator_clipboard_readText.js create mode 100644 dom/events/test/clipboard/browser_navigator_clipboard_touch.js create mode 100644 dom/events/test/clipboard/chrome.ini create mode 100644 dom/events/test/clipboard/head.js create mode 100644 dom/events/test/clipboard/simple_navigator_clipboard_keydown.html create mode 100644 dom/events/test/clipboard/simple_navigator_clipboard_read.html create mode 100644 dom/events/test/clipboard/simple_navigator_clipboard_readText.html create mode 100644 dom/events/test/clipboard/test_async_clipboard.xhtml create mode 100644 dom/events/test/dragimage.html create mode 100644 dom/events/test/empty.js create mode 100644 dom/events/test/error_event_worker.js create mode 100644 dom/events/test/event_leak_utils.js create mode 100644 dom/events/test/file_beforeinput_by_execCommand_in_contentscript.html create mode 100644 dom/events/test/file_bug1446834.html create mode 100644 dom/events/test/file_bug1484371.html create mode 100644 dom/events/test/file_bug1692052.html create mode 100644 dom/events/test/file_bug679494.html create mode 100644 dom/events/test/file_coalesce_touchmove_browserchild.html create mode 100644 dom/events/test/file_coalesce_touchmove_browserchild2.html create mode 100644 dom/events/test/file_coalesce_touchmove_ipc.html create mode 100644 dom/events/test/file_empty.html create mode 100644 dom/events/test/file_event_screenXY.html create mode 100644 dom/events/test/file_focus_blur_on_click_in_cross_origin_iframe.html create mode 100644 dom/events/test/file_focus_blur_on_click_in_deep_cross_origin_iframe_inner.html create mode 100644 dom/events/test/file_focus_blur_on_click_in_deep_cross_origin_iframe_middle.html create mode 100644 dom/events/test/file_keyboard_event_init_key_event_enabled_in_contentscript.html create mode 100644 dom/events/test/file_mouse_enterleave.html create mode 100644 dom/events/test/green.png create mode 100644 dom/events/test/gtest/TestShortcutKeyDefinitions.cpp create mode 100644 dom/events/test/gtest/moz.build create mode 100644 dom/events/test/mochitest.ini create mode 100644 dom/events/test/pointerevents/bug1293174_implicit_pointer_capture_for_touch_1.html create mode 100644 dom/events/test/pointerevents/bug1293174_implicit_pointer_capture_for_touch_2.html create mode 100644 dom/events/test/pointerevents/bug968148_inner.html create mode 100644 dom/events/test/pointerevents/bug968148_inner2.html create mode 100644 dom/events/test/pointerevents/bug_1420589_iframe1.html create mode 100644 dom/events/test/pointerevents/bug_1420589_iframe2.html create mode 100644 dom/events/test/pointerevents/chrome.ini create mode 100644 dom/events/test/pointerevents/file_pointercapture_xorigin_iframe.html create mode 100644 dom/events/test/pointerevents/file_pointercapture_xorigin_iframe_pointerlock.html create mode 100644 dom/events/test/pointerevents/file_pointercapture_xorigin_iframe_touch.html create mode 100644 dom/events/test/pointerevents/file_test_trigger_fullscreen.html create mode 100644 dom/events/test/pointerevents/iframe.html create mode 100644 dom/events/test/pointerevents/mochitest.ini create mode 100644 dom/events/test/pointerevents/mochitest_support_external.js create mode 100644 dom/events/test/pointerevents/mochitest_support_internal.js create mode 100644 dom/events/test/pointerevents/pointerevent_utils.js create mode 100644 dom/events/test/pointerevents/readme.md create mode 100644 dom/events/test/pointerevents/test_bug1285128.html create mode 100644 dom/events/test/pointerevents/test_bug1293174_implicit_pointer_capture_for_touch_1.html create mode 100644 dom/events/test/pointerevents/test_bug1293174_implicit_pointer_capture_for_touch_2.html create mode 100644 dom/events/test/pointerevents/test_bug1303704.html create mode 100644 dom/events/test/pointerevents/test_bug1315862.html create mode 100644 dom/events/test/pointerevents/test_bug1323158.html create mode 100644 dom/events/test/pointerevents/test_bug1403055.html create mode 100644 dom/events/test/pointerevents/test_bug1420589_1.html create mode 100644 dom/events/test/pointerevents/test_bug1420589_2.html create mode 100644 dom/events/test/pointerevents/test_bug1420589_3.html create mode 100644 dom/events/test/pointerevents/test_bug1697769.xhtml create mode 100644 dom/events/test/pointerevents/test_bug1725416.html create mode 100644 dom/events/test/pointerevents/test_bug968148.html create mode 100644 dom/events/test/pointerevents/test_getCoalescedEvents.html create mode 100644 dom/events/test/pointerevents/test_getCoalescedEvents_touch.html create mode 100644 dom/events/test/pointerevents/test_multiple_touches.html create mode 100644 dom/events/test/pointerevents/test_pointercapture_remove_iframe.html create mode 100644 dom/events/test/pointerevents/test_pointercapture_xorigin_iframe.html create mode 100644 dom/events/test/pointerevents/test_pointermove_drag_scrollbar.html create mode 100644 dom/events/test/pointerevents/test_remove_frame_when_got_pointer_capture.html create mode 100644 dom/events/test/pointerevents/test_synthesized_touch.html create mode 100644 dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_attributes_hoverable_pointers-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_attributes_nohover_pointers-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_boundary_events_in_capturing-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_change-touch-action-onpointerdown_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_constructor.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_drag_interaction-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_movementxy-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_multiple_primary_pointers_boundary_events-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_pointerId_scope-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_pointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_pointerleave_after_pointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_pointerleave_pen-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_pointerout_after_pointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_pointerout_pen-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_events_to_original_target-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_onpointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_pointerevent_sequence_at_implicit_release_on_drag-manual.html create mode 100644 dom/events/test/pointerevents/test_wpt_touch_action.html create mode 100644 dom/events/test/pointerevents/touch_action_helpers.js create mode 100644 dom/events/test/pointerevents/wpt/compat/pointerevent_touch-action_two-finger_interaction-manual.html create mode 100644 dom/events/test/pointerevents/wpt/html/pointerevent_drag_interaction-manual.html create mode 100644 dom/events/test/pointerevents/wpt/idlharness.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_attributes_hoverable_pointers-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_attributes_nohover_pointers-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_boundary_events_in_capturing-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_change-touch-action-onpointerdown_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_constructor.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_multiple_primary_pointers_boundary_events-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_pointerId_scope-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_pointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_pointerleave_after_pointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_pointerleave_pen-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_pointerout_after_pointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_pointerout_pen-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_events_to_original_target-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_onpointercancel_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_sequence_at_implicit_release_on_click-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_sequence_at_implicit_release_on_drag-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_styles.css create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_support.js create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-auto-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-button-test_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-illegal.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-none_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_parent-none_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-keyboard-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-mouse-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-none-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-down-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-left-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-right-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-up-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-pan-y_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-y-css_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-span-test_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-svg-test_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-table-test_touch-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerevent_touch-action-verification.html create mode 100644 dom/events/test/pointerevents/wpt/pointerlock/pointerevent_movementxy-manual.html create mode 100644 dom/events/test/pointerevents/wpt/pointerlock/resources/pointerevent_movementxy-iframe.html create mode 100644 dom/events/test/pointerevents/wpt/resources/pointerevent_attributes_hoverable_pointers-iframe.html create mode 100644 dom/events/test/pointerevents/wpt/resources/pointerevent_pointerId_scope-iframe.html create mode 100644 dom/events/test/test_DataTransferItemList.html create mode 100644 dom/events/test/test_accel_virtual_modifier.html create mode 100644 dom/events/test/test_accesskey.html create mode 100644 dom/events/test/test_addEventListenerExtraArg.html create mode 100644 dom/events/test/test_all_synthetic_events.html create mode 100644 dom/events/test/test_bug1003432.html create mode 100644 dom/events/test/test_bug1003432.js create mode 100644 dom/events/test/test_bug1013412.html create mode 100644 dom/events/test/test_bug1017086_enable.html create mode 100644 dom/events/test/test_bug1037990.html create mode 100644 dom/events/test/test_bug1079236.html create mode 100644 dom/events/test/test_bug1127588.html create mode 100644 dom/events/test/test_bug1128787-1.html create mode 100644 dom/events/test/test_bug1128787-2.html create mode 100644 dom/events/test/test_bug1128787-3.html create mode 100644 dom/events/test/test_bug1145910.html create mode 100644 dom/events/test/test_bug1150308.html create mode 100644 dom/events/test/test_bug1248459.html create mode 100644 dom/events/test/test_bug1264380.html create mode 100644 dom/events/test/test_bug1298970.html create mode 100644 dom/events/test/test_bug1304044.html create mode 100644 dom/events/test/test_bug1305458.html create mode 100644 dom/events/test/test_bug1327798.html create mode 100644 dom/events/test/test_bug1332699.html create mode 100644 dom/events/test/test_bug1339758.html create mode 100644 dom/events/test/test_bug1369072.html create mode 100644 dom/events/test/test_bug1412775.xhtml create mode 100644 dom/events/test/test_bug1429572.html create mode 100644 dom/events/test/test_bug1446834.html create mode 100644 dom/events/test/test_bug1447993.html create mode 100644 dom/events/test/test_bug1484371.html create mode 100644 dom/events/test/test_bug1534562.html create mode 100644 dom/events/test/test_bug1539497.html create mode 100644 dom/events/test/test_bug1581192.html create mode 100644 dom/events/test/test_bug1635018.html create mode 100644 dom/events/test/test_bug1637259.html create mode 100644 dom/events/test/test_bug1673434.html create mode 100644 dom/events/test/test_bug1681800.html create mode 100644 dom/events/test/test_bug1686716.html create mode 100644 dom/events/test/test_bug1692052.html create mode 100644 dom/events/test/test_bug1692277.html create mode 100644 dom/events/test/test_bug1709832.html create mode 100644 dom/events/test/test_bug1710509.html create mode 100644 dom/events/test/test_bug1728171.html create mode 100644 dom/events/test/test_bug226361.xhtml create mode 100644 dom/events/test/test_bug238987.html create mode 100644 dom/events/test/test_bug288392.html create mode 100644 dom/events/test/test_bug299673-1.html create mode 100644 dom/events/test/test_bug299673-2.html create mode 100644 dom/events/test/test_bug322588.html create mode 100644 dom/events/test/test_bug328885.html create mode 100644 dom/events/test/test_bug336682.js create mode 100644 dom/events/test/test_bug336682_1.html create mode 100644 dom/events/test/test_bug336682_2.xhtml create mode 100644 dom/events/test/test_bug367781.html create mode 100644 dom/events/test/test_bug379120.html create mode 100644 dom/events/test/test_bug402089.html create mode 100644 dom/events/test/test_bug405632.html create mode 100644 dom/events/test/test_bug409604.html create mode 100644 dom/events/test/test_bug412567.html create mode 100644 dom/events/test/test_bug415498.xhtml create mode 100644 dom/events/test/test_bug418986-3.html create mode 100644 dom/events/test/test_bug418986-3.xhtml create mode 100644 dom/events/test/test_bug422132.html create mode 100644 dom/events/test/test_bug426082.html create mode 100644 dom/events/test/test_bug427537.html create mode 100644 dom/events/test/test_bug428988.html create mode 100644 dom/events/test/test_bug432698.html create mode 100644 dom/events/test/test_bug443985.html create mode 100644 dom/events/test/test_bug447736.html create mode 100644 dom/events/test/test_bug448602.html create mode 100644 dom/events/test/test_bug450876.html create mode 100644 dom/events/test/test_bug456273.html create mode 100644 dom/events/test/test_bug457672.html create mode 100644 dom/events/test/test_bug489671.html create mode 100644 dom/events/test/test_bug493251.html create mode 100644 dom/events/test/test_bug508479.html create mode 100644 dom/events/test/test_bug517851.html create mode 100644 dom/events/test/test_bug524674.xhtml create mode 100644 dom/events/test/test_bug534833.html create mode 100644 dom/events/test/test_bug545268.html create mode 100644 dom/events/test/test_bug547996-1.html create mode 100644 dom/events/test/test_bug547996-2.xhtml create mode 100644 dom/events/test/test_bug547996-3.xhtml create mode 100644 dom/events/test/test_bug556493.html create mode 100644 dom/events/test/test_bug563329.html create mode 100644 dom/events/test/test_bug574663.html create mode 100644 dom/events/test/test_bug586961.xhtml create mode 100644 dom/events/test/test_bug591249.xhtml create mode 100644 dom/events/test/test_bug591815.html create mode 100644 dom/events/test/test_bug593959.html create mode 100644 dom/events/test/test_bug602962.xhtml create mode 100644 dom/events/test/test_bug603008.html create mode 100644 dom/events/test/test_bug605242.html create mode 100644 dom/events/test/test_bug607464.html create mode 100644 dom/events/test/test_bug613634.html create mode 100644 dom/events/test/test_bug615597.html create mode 100644 dom/events/test/test_bug617528.xhtml create mode 100644 dom/events/test/test_bug624127.html create mode 100644 dom/events/test/test_bug635465.html create mode 100644 dom/events/test/test_bug641477.html create mode 100644 dom/events/test/test_bug648573.html create mode 100644 dom/events/test/test_bug650493.html create mode 100644 dom/events/test/test_bug656379-1.html create mode 100644 dom/events/test/test_bug656379-2.html create mode 100644 dom/events/test/test_bug656954.html create mode 100644 dom/events/test/test_bug659071.html create mode 100644 dom/events/test/test_bug659350.html create mode 100644 dom/events/test/test_bug662678.html create mode 100644 dom/events/test/test_bug667612.html create mode 100644 dom/events/test/test_bug667919-1.html create mode 100644 dom/events/test/test_bug679494.xhtml create mode 100644 dom/events/test/test_bug684208.html create mode 100644 dom/events/test/test_bug687787.html create mode 100644 dom/events/test/test_bug689564.html create mode 100644 dom/events/test/test_bug698929.html create mode 100644 dom/events/test/test_bug704423.html create mode 100644 dom/events/test/test_bug741666.html create mode 100644 dom/events/test/test_bug812744.html create mode 100644 dom/events/test/test_bug822898.html create mode 100644 dom/events/test/test_bug855741.html create mode 100644 dom/events/test/test_bug864040.html create mode 100644 dom/events/test/test_bug924087.html create mode 100644 dom/events/test/test_bug930374-chrome.html create mode 100644 dom/events/test/test_bug930374-content.html create mode 100644 dom/events/test/test_bug944011.html create mode 100644 dom/events/test/test_bug944847.html create mode 100644 dom/events/test/test_bug946632.html create mode 100644 dom/events/test/test_bug967796.html create mode 100644 dom/events/test/test_bug985988.html create mode 100644 dom/events/test/test_bug998809.html create mode 100644 dom/events/test/test_click_on_reframed_generated_text.html create mode 100644 dom/events/test/test_click_on_restyled_element.html create mode 100644 dom/events/test/test_clickevent_on_input.html create mode 100644 dom/events/test/test_coalesce_mousewheel.html create mode 100644 dom/events/test/test_coalesce_touchmove.html create mode 100644 dom/events/test/test_continuous_wheel_events.html create mode 100644 dom/events/test/test_dblclick_explicit_original_target.html create mode 100644 dom/events/test/test_deltaMode_lines_always_enabled.html create mode 100644 dom/events/test/test_deviceSensor.html create mode 100644 dom/events/test/test_disabled_events.html create mode 100644 dom/events/test/test_dnd_with_modifiers.html create mode 100644 dom/events/test/test_dom_activate_event.html create mode 100644 dom/events/test/test_dom_keyboard_event.html create mode 100644 dom/events/test/test_dom_mouse_event.html create mode 100644 dom/events/test/test_dom_storage_event.html create mode 100644 dom/events/test/test_dom_wheel_event.html create mode 100644 dom/events/test/test_drag_coords.html create mode 100644 dom/events/test/test_drag_image_file.html create mode 100644 dom/events/test/test_draggableprop.html create mode 100644 dom/events/test/test_dragstart.html create mode 100644 dom/events/test/test_error_events.html create mode 100644 dom/events/test/test_eventTimeStamp.html create mode 100644 dom/events/test/test_event_handler_cc.html create mode 100644 dom/events/test/test_event_screenXY_in_cross_origin_iframe.html create mode 100644 dom/events/test/test_event_screenXY_with_zoom.html create mode 100644 dom/events/test/test_eventctors.html create mode 100644 dom/events/test/test_eventctors.xhtml create mode 100644 dom/events/test/test_eventctors_sensors.html create mode 100644 dom/events/test/test_eventhandler_scoping.html create mode 100644 dom/events/test/test_focus_abspos.html create mode 100644 dom/events/test/test_focus_blur_on_click_in_cross_origin_iframe.html create mode 100644 dom/events/test/test_focus_blur_on_click_in_deep_cross_origin_iframe.html create mode 100644 dom/events/test/test_hover_mouseleave.html create mode 100644 dom/events/test/test_legacy_event.html create mode 100644 dom/events/test/test_legacy_non-primary_click.html create mode 100644 dom/events/test/test_legacy_touch_api.html create mode 100644 dom/events/test/test_marquee_events.html create mode 100644 dom/events/test/test_messageEvent.html create mode 100644 dom/events/test/test_messageEvent_init.html create mode 100644 dom/events/test/test_mouse_capture_iframe.html create mode 100644 dom/events/test/test_mouse_enterleave_iframe.html create mode 100644 dom/events/test/test_moving_and_expanding_selection_per_page.html create mode 100644 dom/events/test/test_moz_mouse_pixel_scroll_event.html create mode 100644 dom/events/test/test_offsetxy.html create mode 100644 dom/events/test/test_onerror_handler_args.html create mode 100644 dom/events/test/test_passive_listeners.html create mode 100644 dom/events/test/test_paste_image.html create mode 100644 dom/events/test/test_scroll_per_page.html create mode 100644 dom/events/test/test_slotted_mouse_event.html create mode 100644 dom/events/test/test_slotted_text_click.html create mode 100644 dom/events/test/test_submitevent_on_form.html create mode 100644 dom/events/test/test_text_event_in_content.html create mode 100644 dom/events/test/test_unbound_before_in_active_chain.html create mode 100644 dom/events/test/test_use_conflated_keypress_event_model_on_newer_Office_Online_Server.html create mode 100644 dom/events/test/test_use_split_keypress_event_model_on_old_Confluence.html create mode 100644 dom/events/test/test_use_split_keypress_event_model_on_old_Office_Online_Server.html create mode 100644 dom/events/test/test_wheel_default_action.html create mode 100644 dom/events/test/test_wheel_zoom_on_form_controls.html create mode 100644 dom/events/test/window_bug1369072.html create mode 100644 dom/events/test/window_bug1412775.xhtml create mode 100644 dom/events/test/window_bug1429572.html create mode 100644 dom/events/test/window_bug1447993.html create mode 100644 dom/events/test/window_bug493251.html create mode 100644 dom/events/test/window_bug617528.xhtml create mode 100644 dom/events/test/window_bug659071.html create mode 100644 dom/events/test/window_empty_document.html create mode 100644 dom/events/test/window_wheel_default_action.html (limited to 'dom/events') diff --git a/dom/events/AnimationEvent.cpp b/dom/events/AnimationEvent.cpp new file mode 100644 index 0000000000..62a4c5196c --- /dev/null +++ b/dom/events/AnimationEvent.cpp @@ -0,0 +1,66 @@ +/* -*- 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/AnimationEvent.h" +#include "mozilla/ContentEvents.h" +#include "prtime.h" + +namespace mozilla::dom { + +AnimationEvent::AnimationEvent(EventTarget* aOwner, nsPresContext* aPresContext, + InternalAnimationEvent* aEvent) + : Event(aOwner, aPresContext, + aEvent ? aEvent : new InternalAnimationEvent(false, eVoidEvent)) { + if (aEvent) { + mEventIsInternal = false; + } else { + mEventIsInternal = true; + } +} + +// static +already_AddRefed AnimationEvent::Constructor( + const GlobalObject& aGlobal, const nsAString& aType, + const AnimationEventInit& aParam) { + nsCOMPtr t = do_QueryInterface(aGlobal.GetAsSupports()); + RefPtr e = new AnimationEvent(t, nullptr, nullptr); + bool trusted = e->Init(t); + + e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable); + + InternalAnimationEvent* internalEvent = e->mEvent->AsAnimationEvent(); + internalEvent->mAnimationName = aParam.mAnimationName; + internalEvent->mElapsedTime = aParam.mElapsedTime; + internalEvent->mPseudoElement = aParam.mPseudoElement; + + e->SetTrusted(trusted); + e->SetComposed(aParam.mComposed); + return e.forget(); +} + +void AnimationEvent::GetAnimationName(nsAString& aAnimationName) { + aAnimationName = mEvent->AsAnimationEvent()->mAnimationName; +} + +float AnimationEvent::ElapsedTime() { + return mEvent->AsAnimationEvent()->mElapsedTime; +} + +void AnimationEvent::GetPseudoElement(nsAString& aPseudoElement) { + aPseudoElement = mEvent->AsAnimationEvent()->mPseudoElement; +} + +} // namespace mozilla::dom + +using namespace mozilla; +using namespace mozilla::dom; + +already_AddRefed NS_NewDOMAnimationEvent( + EventTarget* aOwner, nsPresContext* aPresContext, + InternalAnimationEvent* aEvent) { + RefPtr it = new AnimationEvent(aOwner, aPresContext, aEvent); + return it.forget(); +} diff --git a/dom/events/AnimationEvent.h b/dom/events/AnimationEvent.h new file mode 100644 index 0000000000..eb40246069 --- /dev/null +++ b/dom/events/AnimationEvent.h @@ -0,0 +1,48 @@ +/* -*- 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_AnimationEvent_h_ +#define mozilla_dom_AnimationEvent_h_ + +#include "mozilla/EventForwards.h" +#include "mozilla/dom/Event.h" +#include "mozilla/dom/AnimationEventBinding.h" +#include "nsStringFwd.h" + +namespace mozilla::dom { + +class AnimationEvent : public Event { + public: + AnimationEvent(EventTarget* aOwner, nsPresContext* aPresContext, + InternalAnimationEvent* aEvent); + + NS_INLINE_DECL_REFCOUNTING_INHERITED(AnimationEvent, Event) + + static already_AddRefed Constructor( + const GlobalObject& aGlobal, const nsAString& aType, + const AnimationEventInit& aParam); + + virtual JSObject* WrapObjectInternal( + JSContext* aCx, JS::Handle aGivenProto) override { + return AnimationEvent_Binding::Wrap(aCx, this, aGivenProto); + } + + void GetAnimationName(nsAString& aAnimationName); + + float ElapsedTime(); + + void GetPseudoElement(nsAString& aPseudoElement); + + protected: + ~AnimationEvent() = default; +}; + +} // namespace mozilla::dom + +already_AddRefed NS_NewDOMAnimationEvent( + mozilla::dom::EventTarget* aOwner, nsPresContext* aPresContext, + mozilla::InternalAnimationEvent* aEvent); + +#endif // mozilla_dom_AnimationEvent_h_ diff --git a/dom/events/AsyncEventDispatcher.cpp b/dom/events/AsyncEventDispatcher.cpp new file mode 100644 index 0000000000..3c3a0a7aa3 --- /dev/null +++ b/dom/events/AsyncEventDispatcher.cpp @@ -0,0 +1,180 @@ +/* -*- 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/AsyncEventDispatcher.h" +#include "mozilla/BasicEvents.h" +#include "mozilla/EventDispatcher.h" +#include "mozilla/dom/DocumentInlines.h" +#include "mozilla/dom/Event.h" +#include "mozilla/dom/EventTarget.h" +#include "nsContentUtils.h" + +namespace mozilla { + +using namespace dom; + +/****************************************************************************** + * mozilla::AsyncEventDispatcher + ******************************************************************************/ + +AsyncEventDispatcher::AsyncEventDispatcher(EventTarget* aTarget, + WidgetEvent& aEvent) + : CancelableRunnable("AsyncEventDispatcher"), + mTarget(aTarget), + mEventMessage(eUnidentifiedEvent) { + MOZ_ASSERT(mTarget); + RefPtr event = + EventDispatcher::CreateEvent(aTarget, nullptr, &aEvent, u""_ns); + mEvent = std::move(event); + mEventType.SetIsVoid(true); + NS_ASSERTION(mEvent, "Should never fail to create an event"); + mEvent->DuplicatePrivateData(); + mEvent->SetTrusted(aEvent.IsTrusted()); +} + +NS_IMETHODIMP +AsyncEventDispatcher::Run() { + if (mCanceled) { + return NS_OK; + } + nsINode* node = nsINode::FromEventTargetOrNull(mTarget); + if (mCheckStillInDoc) { + MOZ_ASSERT(node); + if (!node->IsInComposedDoc()) { + return NS_OK; + } + } + mTarget->AsyncEventRunning(this); + if (mEventMessage != eUnidentifiedEvent) { + MOZ_ASSERT(mComposed == Composed::eDefault); + return nsContentUtils::DispatchTrustedEvent( + node->OwnerDoc(), mTarget, mEventMessage, mCanBubble, Cancelable::eNo, + nullptr /* aDefaultAction */, mOnlyChromeDispatch); + } + // MOZ_KnownLives because this instance shouldn't be touched while running. + if (mEvent) { + DispatchEventOnTarget(MOZ_KnownLive(mTarget), MOZ_KnownLive(mEvent), + mOnlyChromeDispatch, mComposed); + } else { + DispatchEventOnTarget(MOZ_KnownLive(mTarget), mEventType, mCanBubble, + mOnlyChromeDispatch, mComposed); + } + return NS_OK; +} + +// static +void AsyncEventDispatcher::DispatchEventOnTarget( + EventTarget* aTarget, const nsAString& aEventType, CanBubble aCanBubble, + ChromeOnlyDispatch aOnlyChromeDispatch, Composed aComposed) { + RefPtr event = NS_NewDOMEvent(aTarget, nullptr, nullptr); + event->InitEvent(aEventType, aCanBubble, Cancelable::eNo); + event->SetTrusted(true); + DispatchEventOnTarget(aTarget, event, aOnlyChromeDispatch, aComposed); +} + +// static +void AsyncEventDispatcher::DispatchEventOnTarget( + EventTarget* aTarget, Event* aEvent, ChromeOnlyDispatch aOnlyChromeDispatch, + Composed aComposed) { + if (aComposed != Composed::eDefault) { + aEvent->WidgetEventPtr()->mFlags.mComposed = aComposed == Composed::eYes; + } + if (aOnlyChromeDispatch == ChromeOnlyDispatch::eYes) { + MOZ_ASSERT(aEvent->IsTrusted()); + aEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true; + } + aTarget->DispatchEvent(*aEvent); +} + +nsresult AsyncEventDispatcher::Cancel() { + mCanceled = true; + return NS_OK; +} + +nsresult AsyncEventDispatcher::PostDOMEvent() { + RefPtr ensureDeletionWhenFailing = this; + if (NS_IsMainThread()) { + if (nsCOMPtr global = mTarget->GetOwnerGlobal()) { + return global->Dispatch(TaskCategory::Other, + ensureDeletionWhenFailing.forget()); + } + + // Sometimes GetOwnerGlobal returns null because it uses + // GetScriptHandlingObject rather than GetScopeObject. + if (nsINode* node = nsINode::FromEventTargetOrNull(mTarget)) { + RefPtr doc = node->OwnerDoc(); + return doc->Dispatch(TaskCategory::Other, + ensureDeletionWhenFailing.forget()); + } + } + return NS_DispatchToCurrentThread(this); +} + +void AsyncEventDispatcher::RunDOMEventWhenSafe() { + RefPtr ensureDeletionWhenFailing = this; + nsContentUtils::AddScriptRunner(this); +} + +// static +void AsyncEventDispatcher::RunDOMEventWhenSafe( + EventTarget& aTarget, const nsAString& aEventType, CanBubble aCanBubble, + ChromeOnlyDispatch aOnlyChromeDispatch /* = ChromeOnlyDispatch::eNo */, + Composed aComposed /* = Composed::eDefault */) { + if (nsContentUtils::IsSafeToRunScript()) { + OwningNonNull target = aTarget; + DispatchEventOnTarget(target, aEventType, aCanBubble, aOnlyChromeDispatch, + aComposed); + return; + } + (new AsyncEventDispatcher(&aTarget, aEventType, aCanBubble, + aOnlyChromeDispatch, aComposed)) + ->RunDOMEventWhenSafe(); +} + +void AsyncEventDispatcher::RunDOMEventWhenSafe( + EventTarget& aTarget, Event& aEvent, + ChromeOnlyDispatch aOnlyChromeDispatch /* = ChromeOnlyDispatch::eNo */) { + if (nsContentUtils::IsSafeToRunScript()) { + DispatchEventOnTarget(&aTarget, &aEvent, aOnlyChromeDispatch, + Composed::eDefault); + return; + } + (new AsyncEventDispatcher(&aTarget, &aEvent, aOnlyChromeDispatch)) + ->RunDOMEventWhenSafe(); +} + +// static +nsresult AsyncEventDispatcher::RunDOMEventWhenSafe( + nsINode& aTarget, WidgetEvent& aEvent, + nsEventStatus* aEventStatus /* = nullptr */) { + if (nsContentUtils::IsSafeToRunScript()) { + // MOZ_KnownLive due to bug 1832202 + nsPresContext* presContext = aTarget.OwnerDoc()->GetPresContext(); + return EventDispatcher::Dispatch(MOZ_KnownLive(&aTarget), + MOZ_KnownLive(presContext), &aEvent, + nullptr, aEventStatus); + } + (new AsyncEventDispatcher(&aTarget, aEvent))->RunDOMEventWhenSafe(); + return NS_OK; +} + +void AsyncEventDispatcher::RequireNodeInDocument() { + MOZ_ASSERT(mTarget); + MOZ_ASSERT(mTarget->IsNode()); + mCheckStillInDoc = true; +} + +/****************************************************************************** + * mozilla::LoadBlockingAsyncEventDispatcher + ******************************************************************************/ + +LoadBlockingAsyncEventDispatcher::~LoadBlockingAsyncEventDispatcher() { + if (mBlockedDoc) { + mBlockedDoc->UnblockOnload(true); + } +} + +} // namespace mozilla diff --git a/dom/events/AsyncEventDispatcher.h b/dom/events/AsyncEventDispatcher.h new file mode 100644 index 0000000000..671a153b41 --- /dev/null +++ b/dom/events/AsyncEventDispatcher.h @@ -0,0 +1,209 @@ +/* -*- 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_AsyncEventDispatcher_h_ +#define mozilla_AsyncEventDispatcher_h_ + +#include "mozilla/Attributes.h" +#include "mozilla/EventForwards.h" +#include "mozilla/RefPtr.h" +#include "mozilla/dom/Event.h" +#include "nsCOMPtr.h" +#include "mozilla/dom/Document.h" +#include "nsString.h" +#include "nsThreadUtils.h" + +class nsINode; + +namespace mozilla { + +/** + * Use AsyncEventDispatcher to fire a DOM event that requires safe a stable DOM. + * For example, you may need to fire an event from within layout, but + * want to ensure that the event handler doesn't mutate the DOM at + * the wrong time, in order to avoid resulting instability. + */ + +class AsyncEventDispatcher : public CancelableRunnable { + public: + /** + * If aOnlyChromeDispatch is true, the event is dispatched to only + * chrome node. In that case, if aTarget is already a chrome node, + * the event is dispatched to it, otherwise the dispatch path starts + * at the first chrome ancestor of that target. + */ + AsyncEventDispatcher( + dom::EventTarget* aTarget, const nsAString& aEventType, + CanBubble aCanBubble, + ChromeOnlyDispatch aOnlyChromeDispatch = ChromeOnlyDispatch::eNo, + Composed aComposed = Composed::eDefault) + : CancelableRunnable("AsyncEventDispatcher"), + mTarget(aTarget), + mEventType(aEventType), + mEventMessage(eUnidentifiedEvent), + mCanBubble(aCanBubble), + mOnlyChromeDispatch(aOnlyChromeDispatch), + mComposed(aComposed) {} + + /** + * If aOnlyChromeDispatch is true, the event is dispatched to only + * chrome node. In that case, if aTarget is already a chrome node, + * the event is dispatched to it, otherwise the dispatch path starts + * at the first chrome ancestor of that target. + */ + AsyncEventDispatcher(nsINode* aTarget, mozilla::EventMessage aEventMessage, + CanBubble aCanBubble, + ChromeOnlyDispatch aOnlyChromeDispatch) + : CancelableRunnable("AsyncEventDispatcher"), + mTarget(aTarget), + mEventMessage(aEventMessage), + mCanBubble(aCanBubble), + mOnlyChromeDispatch(aOnlyChromeDispatch) { + mEventType.SetIsVoid(true); + MOZ_ASSERT(mEventMessage != eUnidentifiedEvent); + } + + AsyncEventDispatcher(dom::EventTarget* aTarget, + mozilla::EventMessage aEventMessage, + CanBubble aCanBubble) + : CancelableRunnable("AsyncEventDispatcher"), + mTarget(aTarget), + mEventMessage(aEventMessage), + mCanBubble(aCanBubble) { + mEventType.SetIsVoid(true); + MOZ_ASSERT(mEventMessage != eUnidentifiedEvent); + } + + /** + * aEvent must have been created without Widget*Event and Internal*Event + * because this constructor assumes that it's safe to use aEvent + * asynchronously (i.e., after all objects allocated in the stack are + * destroyed). + */ + AsyncEventDispatcher( + dom::EventTarget* aTarget, dom::Event* aEvent, + ChromeOnlyDispatch aOnlyChromeDispatch = ChromeOnlyDispatch::eNo) + : CancelableRunnable("AsyncEventDispatcher"), + mTarget(aTarget), + mEvent(aEvent), + mEventMessage(eUnidentifiedEvent), + mOnlyChromeDispatch(aOnlyChromeDispatch) { + MOZ_ASSERT( + aEvent->IsSafeToBeDispatchedAsynchronously(), + "The DOM event should be created without Widget*Event and " + "Internal*Event " + "because if it needs to be safe to be dispatched asynchronously"); + } + + AsyncEventDispatcher(dom::EventTarget* aTarget, WidgetEvent& aEvent); + + MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override; + nsresult Cancel() override; + nsresult PostDOMEvent(); + + /** + * Dispatch event immediately if it's safe to dispatch the event. + * Otherwise, posting the event into the queue to dispatch it when it's safe. + * + * Note that this method allows callers to call itself with unsafe aTarget + * because its lifetime is guaranteed by this method (in the case of + * synchronous dispatching) or AsyncEventDispatcher (in the case of + * asynchronous dispatching). + */ + MOZ_CAN_RUN_SCRIPT_BOUNDARY static void RunDOMEventWhenSafe( + dom::EventTarget& aTarget, const nsAString& aEventType, + CanBubble aCanBubble, + ChromeOnlyDispatch aOnlyChromeDispatch = ChromeOnlyDispatch::eNo, + Composed aComposed = Composed::eDefault); + + /** + * Dispatch event immediately if it's safe to dispatch the event. + * Otherwise, posting the event into the queue to dispatch it when it's safe. + * + * NOTE: Only this is now marked as MOZ_CAN_RUN_SCRIPT because all callers + * have already had safe smart pointers for both aTarget and aEvent. + * If you need to use this in a hot path without smart pointers, you may need + * to create unsafe version of this method for avoiding the extra add/release + * refcount cost in the case of asynchronous dispatching. + */ + MOZ_CAN_RUN_SCRIPT static void RunDOMEventWhenSafe( + dom::EventTarget& aTarget, dom::Event& aEvent, + ChromeOnlyDispatch aOnlyChromeDispatch = ChromeOnlyDispatch::eNo); + + /** + * Dispatch event immediately if it's safe to dispatch the event. + * Otherwise, posting the event into the queue to dispatch it when it's safe. + * + * Note that this method allows callers to call itself with unsafe aTarget + * because its lifetime is guaranteed by EventDispatcher (in the case of + * synchronous dispatching) or AsyncEventDispatcher (in the case of + * asynchronous dispatching). + */ + MOZ_CAN_RUN_SCRIPT_BOUNDARY static nsresult RunDOMEventWhenSafe( + nsINode& aTarget, WidgetEvent& aEvent, + nsEventStatus* aEventStatus = nullptr); + + // Calling this causes the Run() method to check that + // mTarget->IsInComposedDoc(). mTarget must be an nsINode or else we'll + // assert. + void RequireNodeInDocument(); + + protected: + void RunDOMEventWhenSafe(); + MOZ_CAN_RUN_SCRIPT static void DispatchEventOnTarget( + dom::EventTarget* aTarget, dom::Event* aEvent, + ChromeOnlyDispatch aOnlyChromeDispatch, Composed aComposed); + MOZ_CAN_RUN_SCRIPT static void DispatchEventOnTarget( + dom::EventTarget* aTarget, const nsAString& aEventType, + CanBubble aCanBubble, ChromeOnlyDispatch aOnlyChromeDispatch, + Composed aComposed); + + public: + nsCOMPtr mTarget; + RefPtr mEvent; + // If mEventType is set, mEventMessage will be eUnidentifiedEvent. + // If mEventMessage is set, mEventType will be void. + // They can never both be set at the same time. + nsString mEventType; + EventMessage mEventMessage; + CanBubble mCanBubble = CanBubble::eNo; + ChromeOnlyDispatch mOnlyChromeDispatch = ChromeOnlyDispatch::eNo; + Composed mComposed = Composed::eDefault; + bool mCanceled = false; + bool mCheckStillInDoc = false; +}; + +class LoadBlockingAsyncEventDispatcher final : public AsyncEventDispatcher { + public: + LoadBlockingAsyncEventDispatcher(nsINode* aEventNode, + const nsAString& aEventType, + CanBubble aBubbles, + ChromeOnlyDispatch aDispatchChromeOnly) + : AsyncEventDispatcher(aEventNode, aEventType, aBubbles, + aDispatchChromeOnly), + mBlockedDoc(aEventNode->OwnerDoc()) { + if (mBlockedDoc) { + mBlockedDoc->BlockOnload(); + } + } + + LoadBlockingAsyncEventDispatcher(nsINode* aEventNode, dom::Event* aEvent) + : AsyncEventDispatcher(aEventNode, aEvent), + mBlockedDoc(aEventNode->OwnerDoc()) { + if (mBlockedDoc) { + mBlockedDoc->BlockOnload(); + } + } + + ~LoadBlockingAsyncEventDispatcher(); + + private: + RefPtr mBlockedDoc; +}; + +} // namespace mozilla + +#endif // mozilla_AsyncEventDispatcher_h_ diff --git a/dom/events/BeforeUnloadEvent.cpp b/dom/events/BeforeUnloadEvent.cpp new file mode 100644 index 0000000000..77f41d0010 --- /dev/null +++ b/dom/events/BeforeUnloadEvent.cpp @@ -0,0 +1,29 @@ +/* -*- 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/BeforeUnloadEvent.h" + +namespace mozilla::dom { + +void BeforeUnloadEvent::SetReturnValue(const nsAString& aReturnValue) { + mText = aReturnValue; +} + +void BeforeUnloadEvent::GetReturnValue(nsAString& aReturnValue) { + aReturnValue = mText; +} + +} // namespace mozilla::dom + +using namespace mozilla; +using namespace mozilla::dom; + +already_AddRefed NS_NewDOMBeforeUnloadEvent( + EventTarget* aOwner, nsPresContext* aPresContext, WidgetEvent* aEvent) { + RefPtr it = + new BeforeUnloadEvent(aOwner, aPresContext, aEvent); + return it.forget(); +} diff --git a/dom/events/BeforeUnloadEvent.h b/dom/events/BeforeUnloadEvent.h new file mode 100644 index 0000000000..2ffc34cfea --- /dev/null +++ b/dom/events/BeforeUnloadEvent.h @@ -0,0 +1,45 @@ +/* -*- 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_BeforeUnloadEvent_h_ +#define mozilla_dom_BeforeUnloadEvent_h_ + +#include "mozilla/dom/BeforeUnloadEventBinding.h" +#include "mozilla/dom/Event.h" + +namespace mozilla::dom { + +class BeforeUnloadEvent : public Event { + public: + BeforeUnloadEvent(EventTarget* aOwner, nsPresContext* aPresContext, + WidgetEvent* aEvent) + : Event(aOwner, aPresContext, aEvent) {} + + virtual BeforeUnloadEvent* AsBeforeUnloadEvent() override { return this; } + + virtual JSObject* WrapObjectInternal( + JSContext* aCx, JS::Handle aGivenProto) override { + return BeforeUnloadEvent_Binding::Wrap(aCx, this, aGivenProto); + } + + NS_INLINE_DECL_REFCOUNTING_INHERITED(BeforeUnloadEvent, Event) + + void GetReturnValue(nsAString& aReturnValue); + void SetReturnValue(const nsAString& aReturnValue); + + protected: + ~BeforeUnloadEvent() = default; + + nsString mText; +}; + +} // namespace mozilla::dom + +already_AddRefed NS_NewDOMBeforeUnloadEvent( + mozilla::dom::EventTarget* aOwner, nsPresContext* aPresContext, + mozilla::WidgetEvent* aEvent); + +#endif // mozilla_dom_BeforeUnloadEvent_h_ diff --git a/dom/events/Clipboard.cpp b/dom/events/Clipboard.cpp new file mode 100644 index 0000000000..090f06834b --- /dev/null +++ b/dom/events/Clipboard.cpp @@ -0,0 +1,820 @@ +/* -*- 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/Clipboard.h" + +#include + +#include "mozilla/AbstractThread.h" +#include "mozilla/BasePrincipal.h" +#include "mozilla/RefPtr.h" +#include "mozilla/Result.h" +#include "mozilla/ResultVariant.h" +#include "mozilla/dom/BlobBinding.h" +#include "mozilla/dom/ClipboardItem.h" +#include "mozilla/dom/ClipboardBinding.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/PromiseNativeHandler.h" +#include "mozilla/dom/DataTransfer.h" +#include "mozilla/dom/DataTransferItemList.h" +#include "mozilla/dom/DataTransferItem.h" +#include "mozilla/dom/Document.h" +#include "mozilla/StaticPrefs_dom.h" +#include "imgIContainer.h" +#include "imgITools.h" +#include "nsArrayUtils.h" +#include "nsComponentManagerUtils.h" +#include "nsContentUtils.h" +#include "nsIClipboard.h" +#include "nsIInputStream.h" +#include "nsIParserUtils.h" +#include "nsISupportsPrimitives.h" +#include "nsITransferable.h" +#include "nsNetUtil.h" +#include "nsServiceManagerUtils.h" +#include "nsStringStream.h" +#include "nsTArray.h" +#include "nsThreadUtils.h" +#include "nsVariant.h" + +static mozilla::LazyLogModule gClipboardLog("Clipboard"); + +namespace mozilla::dom { + +Clipboard::Clipboard(nsPIDOMWindowInner* aWindow) + : DOMEventTargetHelper(aWindow) {} + +Clipboard::~Clipboard() = default; + +// static +bool Clipboard::IsTestingPrefEnabledOrHasReadPermission( + nsIPrincipal& aSubjectPrincipal) { + return IsTestingPrefEnabled() || + nsContentUtils::PrincipalHasPermission(aSubjectPrincipal, + nsGkAtoms::clipboardRead); +} + +// @return true iff the event was dispatched successfully. +static bool MaybeCreateAndDispatchMozClipboardReadPasteEvent( + nsPIDOMWindowInner& aOwner) { + RefPtr document = aOwner.GetDoc(); + + if (!document) { + // Presumably, this shouldn't happen but to be safe, this case is handled. + MOZ_LOG(Clipboard::GetClipboardLog(), LogLevel::Debug, + ("%s: no document.", __FUNCTION__)); + return false; + } + + // Conceptionally, `ClipboardReadPasteChild` is the target of the event. + // It ensures to receive the event by declaring the event in + // . + return !NS_WARN_IF(NS_FAILED(nsContentUtils::DispatchChromeEvent( + document, ToSupports(document), u"MozClipboardReadPaste"_ns, + CanBubble::eNo, Cancelable::eNo))); +} + +void Clipboard::ReadRequest::Answer() { + RefPtr p(std::move(mPromise)); + RefPtr owner(std::move(mOwner)); + + nsresult rv; + nsCOMPtr clipboardService( + do_GetService("@mozilla.org/widget/clipboard;1", &rv)); + if (NS_FAILED(rv)) { + p->MaybeReject(NS_ERROR_UNEXPECTED); + return; + } + + switch (mType) { + case ReadRequestType::eRead: { + clipboardService + ->AsyncHasDataMatchingFlavors( + // Mandatory data types defined in + // https://w3c.github.io/clipboard-apis/#mandatory-data-types-x + AutoTArray{nsDependentCString(kHTMLMime), + nsDependentCString(kTextMime), + nsDependentCString(kPNGImageMime)}, + nsIClipboard::kGlobalClipboard) + ->Then( + GetMainThreadSerialEventTarget(), __func__, + /* resolve */ + [owner, p](nsTArray formats) { + nsCOMPtr global = do_QueryInterface(owner); + if (NS_WARN_IF(!global)) { + p->MaybeReject(NS_ERROR_UNEXPECTED); + return; + } + + AutoTArray, 3> entries; + for (const auto& format : formats) { + nsCOMPtr trans = + do_CreateInstance("@mozilla.org/widget/transferable;1"); + if (NS_WARN_IF(!trans)) { + continue; + } + + trans->Init(nullptr); + trans->AddDataFlavor(format.get()); + + RefPtr entry = + MakeRefPtr( + global, NS_ConvertUTF8toUTF16(format)); + entry->LoadDataFromSystemClipboard(*trans); + entries.AppendElement(std::move(entry)); + } + + // We currently only support one clipboard item. + AutoTArray, 1> items; + items.AppendElement(MakeRefPtr( + global, PresentationStyle::Unspecified, + std::move(entries))); + + p->MaybeResolve(std::move(items)); + }, + /* reject */ + [p](nsresult rv) { p->MaybeReject(rv); }); + break; + } + case ReadRequestType::eReadText: { + nsCOMPtr trans = + do_CreateInstance("@mozilla.org/widget/transferable;1"); + if (NS_WARN_IF(!trans)) { + p->MaybeReject(NS_ERROR_UNEXPECTED); + return; + } + + trans->Init(nullptr); + trans->AddDataFlavor(kTextMime); + clipboardService->AsyncGetData(trans, nsIClipboard::kGlobalClipboard) + ->Then( + GetMainThreadSerialEventTarget(), __func__, + /* resolve */ + [trans, p]() { + nsCOMPtr data; + nsresult rv = + trans->GetTransferData(kTextMime, getter_AddRefs(data)); + + nsAutoString str; + if (!NS_WARN_IF(NS_FAILED(rv))) { + nsCOMPtr supportsstr = + do_QueryInterface(data); + MOZ_ASSERT(supportsstr); + if (supportsstr) { + supportsstr->GetData(str); + } + } + + p->MaybeResolve(str); + }, + /* reject */ + [p](nsresult rv) { p->MaybeReject(rv); }); + break; + } + default: { + MOZ_ASSERT_UNREACHABLE("Unknown read type"); + break; + } + } +} + +static bool IsReadTextExposedToContent() { + return StaticPrefs::dom_events_asyncClipboard_readText_DoNotUseDirectly(); +} + +void Clipboard::CheckReadPermissionAndHandleRequest( + Promise& aPromise, nsIPrincipal& aSubjectPrincipal, ReadRequestType aType) { + if (IsTestingPrefEnabledOrHasReadPermission(aSubjectPrincipal)) { + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, + ("%s: testing pref enabled or has read permission", __FUNCTION__)); + nsPIDOMWindowInner* owner = GetOwner(); + if (!owner) { + aPromise.MaybeRejectWithUndefined(); + return; + } + + ReadRequest{aPromise, aType, *owner}.Answer(); + return; + } + + if (aSubjectPrincipal.GetIsAddonOrExpandedAddonPrincipal()) { + // TODO: enable showing the "Paste" button in this case; see bug 1773681. + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, + ("%s: Addon without read permssion.", __FUNCTION__)); + aPromise.MaybeRejectWithUndefined(); + return; + } + + HandleReadRequestWhichRequiresPasteButton(aPromise, aType); +} + +void Clipboard::HandleReadRequestWhichRequiresPasteButton( + Promise& aPromise, ReadRequestType aType) { + nsPIDOMWindowInner* owner = GetOwner(); + WindowContext* windowContext = owner ? owner->GetWindowContext() : nullptr; + if (!windowContext) { + MOZ_ASSERT_UNREACHABLE("There should be a WindowContext."); + aPromise.MaybeRejectWithUndefined(); + return; + } + + // If no transient user activation, reject the promise and return. + if (!windowContext->HasValidTransientUserGestureActivation()) { + aPromise.MaybeRejectWithNotAllowedError( + "Clipboard read request was blocked due to lack of " + "user activation."); + return; + } + + // TODO: when a user activation stems from a contextmenu event + // (https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event), + // forbid pasting (bug 1767941). + + switch (mTransientUserPasteState.RefreshAndGet(*windowContext)) { + case TransientUserPasteState::Value::Initial: { + MOZ_ASSERT(mReadRequests.IsEmpty()); + + if (MaybeCreateAndDispatchMozClipboardReadPasteEvent(*owner)) { + mTransientUserPasteState.OnStartWaitingForUserReactionToPasteMenuPopup( + windowContext->GetUserGestureStart()); + mReadRequests.AppendElement( + MakeUnique(aPromise, aType, *owner)); + } else { + // This shouldn't happen but let's handle this case. + aPromise.MaybeRejectWithUndefined(); + } + break; + } + case TransientUserPasteState::Value:: + WaitingForUserReactionToPasteMenuPopup: { + MOZ_ASSERT(!mReadRequests.IsEmpty()); + + mReadRequests.AppendElement( + MakeUnique(aPromise, aType, *owner)); + break; + } + case TransientUserPasteState::Value::TransientlyForbiddenByUser: { + aPromise.MaybeRejectWithNotAllowedError( + "`Clipboard read request was blocked due to the user " + "dismissing the 'Paste' button."); + break; + } + case TransientUserPasteState::Value::TransientlyAllowedByUser: { + ReadRequest{aPromise, aType, *owner}.Answer(); + break; + } + } +} + +already_AddRefed Clipboard::ReadHelper(nsIPrincipal& aSubjectPrincipal, + ReadRequestType aType, + ErrorResult& aRv) { + // Create a new promise + RefPtr p = dom::Promise::Create(GetOwnerGlobal(), aRv); + if (aRv.Failed()) { + return nullptr; + } + + CheckReadPermissionAndHandleRequest(*p, aSubjectPrincipal, aType); + return p.forget(); +} + +auto Clipboard::TransientUserPasteState::RefreshAndGet( + WindowContext& aWindowContext) -> Value { + MOZ_ASSERT(aWindowContext.HasValidTransientUserGestureActivation()); + + switch (mValue) { + case Value::Initial: { + MOZ_ASSERT(mUserGestureStart.IsNull()); + break; + } + case Value::WaitingForUserReactionToPasteMenuPopup: { + MOZ_ASSERT(!mUserGestureStart.IsNull()); + MOZ_ASSERT( + mUserGestureStart == aWindowContext.GetUserGestureStart(), + "A new transient user gesture activation should be impossible while " + "there's no response to the 'Paste' button."); + // `OnUserReactedToPasteMenuPopup` will handle the reaction. + break; + } + case Value::TransientlyForbiddenByUser: { + [[fallthrough]]; + } + case Value::TransientlyAllowedByUser: { + MOZ_ASSERT(!mUserGestureStart.IsNull()); + + if (mUserGestureStart != aWindowContext.GetUserGestureStart()) { + *this = {}; + } + break; + } + } + + return mValue; +} + +void Clipboard::TransientUserPasteState:: + OnStartWaitingForUserReactionToPasteMenuPopup( + const TimeStamp& aUserGestureStart) { + MOZ_ASSERT(mValue == Value::Initial); + MOZ_ASSERT(!aUserGestureStart.IsNull()); + + mValue = Value::WaitingForUserReactionToPasteMenuPopup; + mUserGestureStart = aUserGestureStart; +} + +void Clipboard::TransientUserPasteState::OnUserReactedToPasteMenuPopup( + const bool aAllowed) { + mValue = aAllowed ? Value::TransientlyAllowedByUser + : Value::TransientlyForbiddenByUser; +} + +already_AddRefed Clipboard::Read(nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv) { + return ReadHelper(aSubjectPrincipal, ReadRequestType::eRead, aRv); +} + +already_AddRefed Clipboard::ReadText(nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv) { + return ReadHelper(aSubjectPrincipal, ReadRequestType::eReadText, aRv); +} + +namespace { + +struct NativeEntry { + nsString mType; + nsCOMPtr mData; + + NativeEntry(const nsAString& aType, nsIVariant* aData) + : mType(aType), mData(aData) {} +}; +using NativeEntryPromise = MozPromise; + +class BlobTextHandler final : public PromiseNativeHandler { + public: + NS_DECL_THREADSAFE_ISUPPORTS + + explicit BlobTextHandler(const nsAString& aType) : mType(aType) {} + + RefPtr Promise() { return mHolder.Ensure(__func__); } + + void Reject() { + CopyableErrorResult rv; + rv.ThrowUnknownError("Unable to read blob for '"_ns + + NS_ConvertUTF16toUTF8(mType) + "' as text."_ns); + mHolder.Reject(rv, __func__); + } + + void ResolvedCallback(JSContext* aCx, JS::Handle aValue, + ErrorResult& aRv) override { + AssertIsOnMainThread(); + + nsString text; + if (!ConvertJSValueToUSVString(aCx, aValue, "ClipboardItem text", text)) { + Reject(); + return; + } + + RefPtr variant = new nsVariantCC(); + variant->SetAsAString(text); + + NativeEntry native(mType, variant); + mHolder.Resolve(std::move(native), __func__); + } + + void RejectedCallback(JSContext* aCx, JS::Handle aValue, + ErrorResult& aRv) override { + Reject(); + } + + private: + ~BlobTextHandler() = default; + + nsString mType; + MozPromiseHolder mHolder; +}; + +NS_IMPL_ISUPPORTS0(BlobTextHandler) + +static RefPtr GetStringNativeEntry( + const nsAString& aType, const OwningStringOrBlob& aData) { + if (aData.IsString()) { + RefPtr variant = new nsVariantCC(); + variant->SetAsAString(aData.GetAsString()); + NativeEntry native(aType, variant); + return NativeEntryPromise::CreateAndResolve(native, __func__); + } + + RefPtr handler = new BlobTextHandler(aType); + IgnoredErrorResult ignored; + RefPtr promise = aData.GetAsBlob()->Text(ignored); + if (ignored.Failed()) { + CopyableErrorResult rv; + rv.ThrowUnknownError("Unable to read blob for '"_ns + + NS_ConvertUTF16toUTF8(aType) + "' as text."_ns); + return NativeEntryPromise::CreateAndReject(rv, __func__); + } + promise->AppendNativeHandler(handler); + return handler->Promise(); +} + +class ImageDecodeCallback final : public imgIContainerCallback { + public: + NS_DECL_ISUPPORTS + + explicit ImageDecodeCallback(const nsAString& aType) : mType(aType) {} + + RefPtr Promise() { return mHolder.Ensure(__func__); } + + NS_IMETHOD OnImageReady(imgIContainer* aImage, nsresult aStatus) override { + // Request the image's width to force decoding the image header. + int32_t ignored; + if (NS_FAILED(aStatus) || NS_FAILED(aImage->GetWidth(&ignored))) { + CopyableErrorResult rv; + rv.ThrowDataError("Unable to decode blob for '"_ns + + NS_ConvertUTF16toUTF8(mType) + "' as image."_ns); + mHolder.Reject(rv, __func__); + return NS_OK; + } + + RefPtr variant = new nsVariantCC(); + variant->SetAsISupports(aImage); + + // Note: We always put the image as "native" on the clipboard. + NativeEntry native(NS_LITERAL_STRING_FROM_CSTRING(kNativeImageMime), + variant); + mHolder.Resolve(std::move(native), __func__); + return NS_OK; + }; + + private: + ~ImageDecodeCallback() = default; + + nsString mType; + MozPromiseHolder mHolder; +}; + +NS_IMPL_ISUPPORTS(ImageDecodeCallback, imgIContainerCallback) + +static RefPtr GetImageNativeEntry( + const nsAString& aType, const OwningStringOrBlob& aData) { + if (aData.IsString()) { + CopyableErrorResult rv; + rv.ThrowTypeError("DOMString not supported for '"_ns + + NS_ConvertUTF16toUTF8(aType) + "' as image data."_ns); + return NativeEntryPromise::CreateAndReject(rv, __func__); + } + + IgnoredErrorResult ignored; + nsCOMPtr stream; + aData.GetAsBlob()->CreateInputStream(getter_AddRefs(stream), ignored); + if (ignored.Failed()) { + CopyableErrorResult rv; + rv.ThrowUnknownError("Unable to read blob for '"_ns + + NS_ConvertUTF16toUTF8(aType) + "' as image."_ns); + return NativeEntryPromise::CreateAndReject(rv, __func__); + } + + RefPtr callback = new ImageDecodeCallback(aType); + nsCOMPtr imgtool = do_CreateInstance("@mozilla.org/image/tools;1"); + imgtool->DecodeImageAsync(stream, NS_ConvertUTF16toUTF8(aType), callback, + GetMainThreadSerialEventTarget()); + return callback->Promise(); +} + +static Result SanitizeNativeEntry( + const NativeEntry& aEntry) { + MOZ_ASSERT(aEntry.mType.EqualsLiteral(kHTMLMime)); + + nsAutoString string; + aEntry.mData->GetAsAString(string); + + nsCOMPtr parserUtils = + do_GetService(NS_PARSERUTILS_CONTRACTID); + if (!parserUtils) { + ErrorResult rv; + rv.ThrowUnknownError("Error while processing '"_ns + + NS_ConvertUTF16toUTF8(aEntry.mType) + "'."_ns); + return Err(std::move(rv)); + } + + uint32_t flags = nsIParserUtils::SanitizerAllowStyle | + nsIParserUtils::SanitizerAllowComments; + nsAutoString sanitized; + if (NS_FAILED(parserUtils->Sanitize(string, flags, sanitized))) { + ErrorResult rv; + rv.ThrowUnknownError("Error while processing '"_ns + + NS_ConvertUTF16toUTF8(aEntry.mType) + "'."_ns); + return Err(std::move(rv)); + } + + RefPtr variant = new nsVariantCC(); + variant->SetAsAString(sanitized); + return NativeEntry(aEntry.mType, variant); +} + +static RefPtr GetNativeEntry( + const nsAString& aType, const OwningStringOrBlob& aData) { + if (aType.EqualsLiteral(kPNGImageMime)) { + return GetImageNativeEntry(aType, aData); + } + + RefPtr promise = GetStringNativeEntry(aType, aData); + if (aType.EqualsLiteral(kHTMLMime)) { + promise = promise->Then( + GetMainThreadSerialEventTarget(), __func__, + [](const NativeEntryPromise::ResolveOrRejectValue& aValue) + -> RefPtr { + if (aValue.IsReject()) { + return NativeEntryPromise::CreateAndReject(aValue.RejectValue(), + __func__); + } + + auto sanitized = SanitizeNativeEntry(aValue.ResolveValue()); + if (sanitized.isErr()) { + return NativeEntryPromise::CreateAndReject( + CopyableErrorResult(sanitized.unwrapErr()), __func__); + } + return NativeEntryPromise::CreateAndResolve(sanitized.unwrap(), + __func__); + }); + } + return promise; +} + +// Restrict to types allowed by Chrome +// SVG is still disabled by default in Chrome. +static bool IsValidType(const nsAString& aType) { + return aType.EqualsLiteral(kPNGImageMime) || aType.EqualsLiteral(kTextMime) || + aType.EqualsLiteral(kHTMLMime); +} + +using NativeItemPromise = NativeEntryPromise::AllPromiseType; +static RefPtr GetClipboardNativeItem( + const ClipboardItem& aItem) { + nsTArray> promises; + for (const auto& entry : aItem.Entries()) { + const nsAString& type = entry->Type(); + if (!IsValidType(type)) { + CopyableErrorResult rv; + rv.ThrowNotAllowedError("Type '"_ns + NS_ConvertUTF16toUTF8(type) + + "' not supported for write"_ns); + return NativeItemPromise::CreateAndReject(rv, __func__); + } + + using GetDataPromise = ClipboardItem::ItemEntry::GetDataPromise; + promises.AppendElement(entry->GetData()->Then( + GetMainThreadSerialEventTarget(), __func__, + [t = nsString(type)](const GetDataPromise::ResolveOrRejectValue& aValue) + -> RefPtr { + if (aValue.IsReject()) { + return NativeEntryPromise::CreateAndReject( + CopyableErrorResult(aValue.RejectValue()), __func__); + } + + return GetNativeEntry(t, aValue.ResolveValue()); + })); + } + return NativeEntryPromise::All(GetCurrentSerialEventTarget(), promises); +} + +class ClipboardWriteCallback final : public nsIAsyncSetClipboardDataCallback { + public: + // This object will never be held by a cycle-collected object, so it doesn't + // need to be cycle-collected despite holding alive cycle-collected objects. + NS_DECL_ISUPPORTS + + explicit ClipboardWriteCallback(Promise* aPromise, + ClipboardItem* aClipboardItem) + : mPromise(aPromise), mClipboardItem(aClipboardItem) {} + + // nsIAsyncSetClipboardDataCallback + NS_IMETHOD OnComplete(nsresult aResult) override { + MOZ_ASSERT(mPromise); + + RefPtr promise = std::move(mPromise); + // XXX We need to check state here is because the promise might be rejected + // before the callback is called, we probably could wrap the promise into a + // structure to make it less confused. + if (promise->State() == Promise::PromiseState::Pending) { + if (NS_FAILED(aResult)) { + promise->MaybeRejectWithNotAllowedError( + "Clipboard write is not allowed."); + return NS_OK; + } + + promise->MaybeResolveWithUndefined(); + } + + return NS_OK; + } + + protected: + ~ClipboardWriteCallback() { + // Callback should be notified. + MOZ_ASSERT(!mPromise); + }; + + // It will be reset to nullptr once callback is notified. + RefPtr mPromise; + // Keep ClipboardItem alive until clipboard write is done. + RefPtr mClipboardItem; +}; + +NS_IMPL_ISUPPORTS(ClipboardWriteCallback, nsIAsyncSetClipboardDataCallback) + +} // namespace + +already_AddRefed Clipboard::Write( + const Sequence>& aData, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { + // Create a promise + RefPtr p = dom::Promise::Create(GetOwnerGlobal(), aRv); + if (aRv.Failed()) { + return nullptr; + } + + RefPtr owner = GetOwner(); + Document* doc = owner ? owner->GetDoc() : nullptr; + if (!doc) { + p->MaybeRejectWithUndefined(); + return p.forget(); + } + + // We want to disable security check for automated tests that have the pref + // dom.events.testing.asyncClipboard set to true + if (!IsTestingPrefEnabled() && + !nsContentUtils::IsCutCopyAllowed(doc, aSubjectPrincipal)) { + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, + ("Clipboard, Write, Not allowed to write to clipboard\n")); + p->MaybeRejectWithNotAllowedError( + "Clipboard write was blocked due to lack of user activation."); + return p.forget(); + } + + // Get the clipboard service + nsCOMPtr clipboard( + do_GetService("@mozilla.org/widget/clipboard;1")); + if (!clipboard) { + p->MaybeRejectWithUndefined(); + return p.forget(); + } + + nsCOMPtr context = doc->GetLoadContext(); + if (!context) { + p->MaybeRejectWithUndefined(); + return p.forget(); + } + + if (aData.Length() > 1) { + p->MaybeRejectWithNotAllowedError( + "Clipboard write is only supported with one ClipboardItem at the " + "moment"); + return p.forget(); + } + + if (aData.Length() == 0) { + // Nothing needs to be written to the clipboard. + p->MaybeResolveWithUndefined(); + return p.forget(); + } + + nsCOMPtr request; + RefPtr callback = + MakeRefPtr(p, aData[0]); + nsresult rv = clipboard->AsyncSetData(nsIClipboard::kGlobalClipboard, + callback, getter_AddRefs(request)); + if (NS_FAILED(rv)) { + p->MaybeReject(rv); + return p.forget(); + } + + GetClipboardNativeItem(aData[0])->Then( + GetMainThreadSerialEventTarget(), __func__, + [owner, request, context, principal = RefPtr{&aSubjectPrincipal}]( + const nsTArray& aEntries) { + RefPtr dataTransfer = + new DataTransfer(owner, eCopy, + /* is external */ true, + /* clipboard type */ -1); + + for (const auto& entry : aEntries) { + nsresult rv = dataTransfer->SetDataWithPrincipal( + entry.mType, entry.mData, 0, principal); + + if (NS_FAILED(rv)) { + request->Abort(rv); + return; + } + } + + // Get the transferable + RefPtr transferable = + dataTransfer->GetTransferable(0, context); + if (!transferable) { + request->Abort(NS_ERROR_FAILURE); + return; + } + + // Finally write data to clipboard + request->SetData(transferable, /* clipboard owner */ nullptr); + }, + [p, request](const CopyableErrorResult& aErrorResult) { + p->MaybeReject(CopyableErrorResult(aErrorResult)); + request->Abort(NS_ERROR_ABORT); + }); + + return p.forget(); +} + +already_AddRefed Clipboard::WriteText(const nsAString& aData, + nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv) { + nsCOMPtr global = GetOwnerGlobal(); + if (!global) { + aRv.ThrowInvalidStateError("Unable to get global."); + return nullptr; + } + + // Create a single-element Sequence to reuse Clipboard::Write. + nsTArray> items; + items.AppendElement(MakeRefPtr( + global, NS_LITERAL_STRING_FROM_CSTRING(kTextMime), aData)); + + nsTArray> sequence; + RefPtr item = MakeRefPtr( + GetOwner(), PresentationStyle::Unspecified, std::move(items)); + sequence.AppendElement(*item); + + return Write(std::move(sequence), aSubjectPrincipal, aRv); +} + +void Clipboard::ReadRequest::MaybeRejectWithNotAllowedError( + const nsACString& aMessage) { + mPromise->MaybeRejectWithNotAllowedError(aMessage); +} + +void Clipboard::OnUserReactedToPasteMenuPopup(const bool aAllowed) { + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, ("%s", __FUNCTION__)); + + mTransientUserPasteState.OnUserReactedToPasteMenuPopup(aAllowed); + + MOZ_ASSERT(!mReadRequests.IsEmpty()); + + for (UniquePtr& request : mReadRequests) { + if (aAllowed) { + request->Answer(); + } else { + request->MaybeRejectWithNotAllowedError( + "The user dismissed the 'Paste' button."_ns); + } + } + + mReadRequests.Clear(); +} + +JSObject* Clipboard::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return Clipboard_Binding::Wrap(aCx, this, aGivenProto); +} + +/* static */ +LogModule* Clipboard::GetClipboardLog() { return gClipboardLog; } + +/* static */ +bool Clipboard::ReadTextEnabled(JSContext* aCx, JSObject* aGlobal) { + nsIPrincipal* prin = nsContentUtils::SubjectPrincipal(aCx); + return IsReadTextExposedToContent() || + prin->GetIsAddonOrExpandedAddonPrincipal() || + prin->IsSystemPrincipal(); +} + +/* static */ +bool Clipboard::IsTestingPrefEnabled() { + bool clipboardTestingEnabled = + StaticPrefs::dom_events_testing_asyncClipboard_DoNotUseDirectly(); + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, + ("Clipboard, Is testing enabled? %d\n", clipboardTestingEnabled)); + return clipboardTestingEnabled; +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(Clipboard) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Clipboard, + DOMEventTargetHelper) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Clipboard, DOMEventTargetHelper) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Clipboard) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +NS_IMPL_ADDREF_INHERITED(Clipboard, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(Clipboard, DOMEventTargetHelper) + +} // namespace mozilla::dom diff --git a/dom/events/Clipboard.h b/dom/events/Clipboard.h new file mode 100644 index 0000000000..e4179c816f --- /dev/null +++ b/dom/events/Clipboard.h @@ -0,0 +1,133 @@ +/* -*- 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_Clipboard_h_ +#define mozilla_dom_Clipboard_h_ + +#include "nsString.h" +#include "nsStringFwd.h" +#include "mozilla/DOMEventTargetHelper.h" +#include "mozilla/Logging.h" +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/dom/DataTransfer.h" + +namespace mozilla::dom { + +class Promise; +class ClipboardItem; + +// https://www.w3.org/TR/clipboard-apis/#clipboard-interface +class Clipboard : public DOMEventTargetHelper { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Clipboard, DOMEventTargetHelper) + + IMPL_EVENT_HANDLER(message) + IMPL_EVENT_HANDLER(messageerror) + + explicit Clipboard(nsPIDOMWindowInner* aWindow); + already_AddRefed Read(nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv); + already_AddRefed ReadText(nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv); + already_AddRefed Write( + const Sequence>& aData, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); + already_AddRefed WriteText(const nsAString& aData, + nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv); + + // See documentation of the corresponding .webidl file. + void OnUserReactedToPasteMenuPopup(bool aAllowed); + + static LogModule* GetClipboardLog(); + + // Check if the Clipboard.readText API should be enabled for this context. + // This API is only enabled for Extension and System contexts, as there is no + // way to request the required permission for web content. If the clipboard + // API testing pref is enabled, ReadText is enabled for web content for + // testing purposes. + static bool ReadTextEnabled(JSContext* aCx, JSObject* aGlobal); + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + private: + enum class ReadRequestType { + eRead, + eReadText, + }; + + // Checks if dom.events.testing.asyncClipboard pref is enabled. + // The aforementioned pref allows automated tests to bypass the security + // checks when writing to + // or reading from the clipboard. + static bool IsTestingPrefEnabled(); + + static bool IsTestingPrefEnabledOrHasReadPermission( + nsIPrincipal& aSubjectPrincipal); + + void CheckReadPermissionAndHandleRequest(Promise& aPromise, + nsIPrincipal& aSubjectPrincipal, + ReadRequestType aType); + + void HandleReadRequestWhichRequiresPasteButton(Promise& aPromise, + ReadRequestType aType); + + already_AddRefed ReadHelper(nsIPrincipal& aSubjectPrincipal, + ReadRequestType aType, ErrorResult& aRv); + + ~Clipboard(); + + class ReadRequest final { + public: + ReadRequest(Promise& aPromise, ReadRequestType aType, + nsPIDOMWindowInner& aOwner) + : mType(aType), mPromise(&aPromise), mOwner(&aOwner) {} + + // Clears the request too. + void Answer(); + + void MaybeRejectWithNotAllowedError(const nsACString& aMessage); + + private: + ReadRequestType mType; + // Not cycle-collected, because it's nulled when the request is answered or + // destructed. + RefPtr mPromise; + RefPtr mOwner; + }; + + AutoTArray, 1> mReadRequests; + + class TransientUserPasteState final { + public: + enum class Value { + Initial, + WaitingForUserReactionToPasteMenuPopup, + TransientlyForbiddenByUser, + TransientlyAllowedByUser, + }; + + // @param aWindowContext requires valid transient user gesture activation. + Value RefreshAndGet(WindowContext& aWindowContext); + + void OnStartWaitingForUserReactionToPasteMenuPopup( + const TimeStamp& aUserGestureStart); + void OnUserReactedToPasteMenuPopup(bool aAllowed); + + private: + TimeStamp mUserGestureStart; + + Value mValue = Value::Initial; + }; + + TransientUserPasteState mTransientUserPasteState; +}; + +} // namespace mozilla::dom +#endif // mozilla_dom_Clipboard_h_ diff --git a/dom/events/ClipboardEvent.cpp b/dom/events/ClipboardEvent.cpp new file mode 100644 index 0000000000..e678f7c9fd --- /dev/null +++ b/dom/events/ClipboardEvent.cpp @@ -0,0 +1,90 @@ +/* -*- 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/ClipboardEvent.h" +#include "mozilla/ContentEvents.h" +#include "mozilla/ErrorResult.h" +#include "mozilla/dom/DataTransfer.h" +#include "nsIClipboard.h" + +namespace mozilla::dom { + +ClipboardEvent::ClipboardEvent(EventTarget* aOwner, nsPresContext* aPresContext, + InternalClipboardEvent* aEvent) + : Event(aOwner, aPresContext, + aEvent ? aEvent : new InternalClipboardEvent(false, eVoidEvent)) { + if (aEvent) { + mEventIsInternal = false; + } else { + mEventIsInternal = true; + } +} + +void ClipboardEvent::InitClipboardEvent(const nsAString& aType, bool aCanBubble, + bool aCancelable, + DataTransfer* aClipboardData) { + NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched); + + Event::InitEvent(aType, aCanBubble, aCancelable); + mEvent->AsClipboardEvent()->mClipboardData = aClipboardData; +} + +already_AddRefed ClipboardEvent::Constructor( + const GlobalObject& aGlobal, const nsAString& aType, + const ClipboardEventInit& aParam, ErrorResult& aRv) { + nsCOMPtr t = do_QueryInterface(aGlobal.GetAsSupports()); + RefPtr e = new ClipboardEvent(t, nullptr, nullptr); + bool trusted = e->Init(t); + + RefPtr clipboardData; + if (e->mEventIsInternal) { + InternalClipboardEvent* event = e->mEvent->AsClipboardEvent(); + if (event) { + // Always create a clipboardData for the copy event. If this is changed to + // support other types of events, make sure that read/write privileges are + // checked properly within DataTransfer. + clipboardData = new DataTransfer(ToSupports(e), eCopy, false, -1); + clipboardData->SetData(aParam.mDataType, aParam.mData, + *aGlobal.GetSubjectPrincipal(), aRv); + NS_ENSURE_TRUE(!aRv.Failed(), nullptr); + } + } + + e->InitClipboardEvent(aType, aParam.mBubbles, aParam.mCancelable, + clipboardData); + e->SetTrusted(trusted); + e->SetComposed(aParam.mComposed); + return e.forget(); +} + +DataTransfer* ClipboardEvent::GetClipboardData() { + InternalClipboardEvent* event = mEvent->AsClipboardEvent(); + + if (!event->mClipboardData) { + if (mEventIsInternal) { + event->mClipboardData = + new DataTransfer(ToSupports(this), eCopy, false, -1); + } else { + event->mClipboardData = new DataTransfer( + ToSupports(this), event->mMessage, event->mMessage == ePaste, + nsIClipboard::kGlobalClipboard); + } + } + + return event->mClipboardData; +} + +} // namespace mozilla::dom + +using namespace mozilla; +using namespace mozilla::dom; + +already_AddRefed NS_NewDOMClipboardEvent( + EventTarget* aOwner, nsPresContext* aPresContext, + InternalClipboardEvent* aEvent) { + RefPtr it = new ClipboardEvent(aOwner, aPresContext, aEvent); + return it.forget(); +} diff --git a/dom/events/ClipboardEvent.h b/dom/events/ClipboardEvent.h new file mode 100644 index 0000000000..08d96b3772 --- /dev/null +++ b/dom/events/ClipboardEvent.h @@ -0,0 +1,48 @@ +/* -*- 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_ClipboardEvent_h_ +#define mozilla_dom_ClipboardEvent_h_ + +#include "mozilla/EventForwards.h" +#include "mozilla/dom/ClipboardEventBinding.h" +#include "mozilla/dom/Event.h" + +namespace mozilla::dom { +class DataTransfer; + +class ClipboardEvent : public Event { + public: + ClipboardEvent(EventTarget* aOwner, nsPresContext* aPresContext, + InternalClipboardEvent* aEvent); + + NS_INLINE_DECL_REFCOUNTING_INHERITED(ClipboardEvent, Event) + + virtual JSObject* WrapObjectInternal( + JSContext* aCx, JS::Handle aGivenProto) override { + return ClipboardEvent_Binding::Wrap(aCx, this, aGivenProto); + } + + static already_AddRefed Constructor( + const GlobalObject& aGlobal, const nsAString& aType, + const ClipboardEventInit& aParam, ErrorResult& aRv); + + DataTransfer* GetClipboardData(); + + void InitClipboardEvent(const nsAString& aType, bool aCanBubble, + bool aCancelable, DataTransfer* aClipboardData); + + protected: + ~ClipboardEvent() = default; +}; + +} // namespace mozilla::dom + +already_AddRefed NS_NewDOMClipboardEvent( + mozilla::dom::EventTarget* aOwner, nsPresContext* aPresContext, + mozilla::InternalClipboardEvent* aEvent); + +#endif // mozilla_dom_ClipboardEvent_h_ diff --git a/dom/events/ClipboardItem.cpp b/dom/events/ClipboardItem.cpp new file mode 100644 index 0000000000..3226f40824 --- /dev/null +++ b/dom/events/ClipboardItem.cpp @@ -0,0 +1,331 @@ +/* -*- 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/ClipboardItem.h" + +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/Record.h" +#include "nsComponentManagerUtils.h" +#include "nsIClipboard.h" +#include "nsIInputStream.h" +#include "nsISupportsPrimitives.h" +#include "nsNetUtil.h" +#include "nsServiceManagerUtils.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION(ClipboardItem::ItemEntry, mGlobal, mData, + mPendingGetTypeRequests) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ClipboardItem::ItemEntry) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(ClipboardItem::ItemEntry) +NS_IMPL_CYCLE_COLLECTING_RELEASE(ClipboardItem::ItemEntry) + +void ClipboardItem::ItemEntry::ResolvedCallback(JSContext* aCx, + JS::Handle aValue, + ErrorResult& aRv) { + MOZ_ASSERT(!mLoadingPromise.Exists()); + mIsLoadingData = false; + OwningStringOrBlob clipboardData; + if (!clipboardData.Init(aCx, aValue)) { + JS_ClearPendingException(aCx); + RejectPendingPromises(NS_ERROR_DOM_DATA_ERR); + return; + } + + MaybeResolvePendingPromises(std::move(clipboardData)); +} + +void ClipboardItem::ItemEntry::RejectedCallback(JSContext* aCx, + JS::Handle aValue, + ErrorResult& aRv) { + MOZ_ASSERT(!mLoadingPromise.Exists()); + mIsLoadingData = false; + RejectPendingPromises(NS_ERROR_DOM_DATA_ERR); +} + +RefPtr +ClipboardItem::ItemEntry::GetData() { + // Data is still being loaded, either from the system clipboard or the data + // promise provided to the ClipboardItem constructor. + if (mIsLoadingData) { + MOZ_ASSERT(!mData.IsString() && !mData.IsBlob(), + "Data should be uninitialized"); + MOZ_ASSERT(mLoadResult.isNothing(), "Should have no load result"); + + MozPromiseHolder holder; + RefPtr promise = holder.Ensure(__func__); + mPendingGetDataRequests.AppendElement(std::move(holder)); + return promise.forget(); + } + + if (NS_FAILED(mLoadResult.value())) { + MOZ_ASSERT(!mData.IsString() && !mData.IsBlob(), + "Data should be uninitialized"); + // We are not able to load data, so reject the promise directly. + return GetDataPromise::CreateAndReject(mLoadResult.value(), __func__); + } + + MOZ_ASSERT(mData.IsString() || mData.IsBlob(), "Data should be initialized"); + OwningStringOrBlob data(mData); + return GetDataPromise::CreateAndResolve(std::move(data), __func__); +} + +void ClipboardItem::ItemEntry::LoadDataFromSystemClipboard( + nsITransferable& aTransferable) { + // XXX maybe we could consider adding a method to check whether the union + // object is uninitialized or initialized. + MOZ_DIAGNOSTIC_ASSERT(!mData.IsString() && !mData.IsBlob(), + "Data should be uninitialized."); + MOZ_DIAGNOSTIC_ASSERT(mLoadResult.isNothing(), "Should have no load result"); + MOZ_DIAGNOSTIC_ASSERT(!mIsLoadingData && !mLoadingPromise.Exists(), + "Should not be in the process of loading data"); + + nsresult rv; + nsCOMPtr clipboard( + do_GetService("@mozilla.org/widget/clipboard;1", &rv)); + if (NS_FAILED(rv)) { + return; + } + + mIsLoadingData = true; + nsCOMPtr trans(&aTransferable); + clipboard->AsyncGetData(trans, nsIClipboard::kGlobalClipboard) + ->Then( + GetMainThreadSerialEventTarget(), __func__, + /* resolved */ + [self = RefPtr{this}, trans]() { + self->mIsLoadingData = false; + self->mLoadingPromise.Complete(); + + nsCOMPtr data; + nsresult rv = trans->GetTransferData( + NS_ConvertUTF16toUTF8(self->Type()).get(), + getter_AddRefs(data)); + if (NS_WARN_IF(NS_FAILED(rv))) { + self->RejectPendingPromises(rv); + return; + } + + RefPtr blob; + if (nsCOMPtr supportsstr = + do_QueryInterface(data)) { + nsAutoString str; + supportsstr->GetData(str); + + blob = Blob::CreateStringBlob( + self->mGlobal, NS_ConvertUTF16toUTF8(str), self->Type()); + } else if (nsCOMPtr istream = + do_QueryInterface(data)) { + uint64_t available; + void* data = nullptr; + nsresult rv = + NS_ReadInputStreamToBuffer(istream, &data, -1, &available); + if (NS_WARN_IF(NS_FAILED(rv))) { + self->RejectPendingPromises(rv); + return; + } + + blob = Blob::CreateMemoryBlob(self->mGlobal, data, available, + self->Type()); + } else if (nsCOMPtr supportscstr = + do_QueryInterface(data)) { + nsAutoCString str; + supportscstr->GetData(str); + + blob = Blob::CreateStringBlob(self->mGlobal, str, self->Type()); + } + + if (!blob) { + self->RejectPendingPromises(NS_ERROR_DOM_DATA_ERR); + return; + } + + OwningStringOrBlob clipboardData; + clipboardData.SetAsBlob() = std::move(blob); + self->MaybeResolvePendingPromises(std::move(clipboardData)); + }, + /* rejected */ + [self = RefPtr{this}](nsresult rv) { + self->mIsLoadingData = false; + self->mLoadingPromise.Complete(); + self->RejectPendingPromises(rv); + }) + ->Track(mLoadingPromise); +} + +void ClipboardItem::ItemEntry::LoadDataFromDataPromise(Promise& aDataPromise) { + MOZ_DIAGNOSTIC_ASSERT(!mData.IsString() && !mData.IsBlob(), + "Data should be uninitialized"); + MOZ_DIAGNOSTIC_ASSERT(mLoadResult.isNothing(), "Should have no load result"); + MOZ_DIAGNOSTIC_ASSERT(!mIsLoadingData && !mLoadingPromise.Exists(), + "Should not be in the process of loading data"); + + mIsLoadingData = true; + aDataPromise.AppendNativeHandler(this); +} + +void ClipboardItem::ItemEntry::ReactGetTypePromise(Promise& aPromise) { + // Data is still being loaded, either from the system clipboard or the data + // promise provided to the ClipboardItem constructor. + if (mIsLoadingData) { + MOZ_ASSERT(!mData.IsString() && !mData.IsBlob(), + "Data should be uninitialized"); + MOZ_ASSERT(mLoadResult.isNothing(), "Should have no load result."); + mPendingGetTypeRequests.AppendElement(&aPromise); + return; + } + + if (NS_FAILED(mLoadResult.value())) { + MOZ_ASSERT(!mData.IsString() && !mData.IsBlob(), + "Data should be uninitialized"); + aPromise.MaybeRejectWithDataError("The data for type '"_ns + + NS_ConvertUTF16toUTF8(mType) + + "' was not found"_ns); + return; + } + + MaybeResolveGetTypePromise(mData, aPromise); +} + +void ClipboardItem::ItemEntry::MaybeResolveGetTypePromise( + const OwningStringOrBlob& aData, Promise& aPromise) { + if (aData.IsBlob()) { + aPromise.MaybeResolve(aData); + return; + } + + // XXX This is for the case that data is from ClipboardItem constructor, + // maybe we should also load that into a Blob earlier. But Safari returns + // different `Blob` instances for each `getTypes` call if the string is from + // ClipboardItem constructor, which is more like our current setup. + if (RefPtr blob = Blob::CreateStringBlob( + mGlobal, NS_ConvertUTF16toUTF8(aData.GetAsString()), mType)) { + aPromise.MaybeResolve(blob); + return; + } + + aPromise.MaybeRejectWithDataError("The data for type '"_ns + + NS_ConvertUTF16toUTF8(mType) + + "' was not found"_ns); +} + +void ClipboardItem::ItemEntry::RejectPendingPromises(nsresult aRv) { + MOZ_ASSERT(NS_FAILED(aRv), "Should have a failure code here"); + MOZ_DIAGNOSTIC_ASSERT(!mData.IsString() && !mData.IsBlob(), + "Data should be uninitialized"); + MOZ_DIAGNOSTIC_ASSERT(mLoadResult.isNothing(), "Should not have load result"); + MOZ_DIAGNOSTIC_ASSERT(!mIsLoadingData && !mLoadingPromise.Exists(), + "Should not be in the process of loading data"); + mLoadResult.emplace(aRv); + auto promiseHolders = std::move(mPendingGetDataRequests); + for (auto& promiseHolder : promiseHolders) { + promiseHolder.Reject(aRv, __func__); + } + auto getTypePromises = std::move(mPendingGetTypeRequests); + for (auto& promise : getTypePromises) { + promise->MaybeReject(aRv); + } +} + +void ClipboardItem::ItemEntry::MaybeResolvePendingPromises( + OwningStringOrBlob&& aData) { + MOZ_DIAGNOSTIC_ASSERT(!mData.IsString() && !mData.IsBlob(), + "Data should be uninitialized"); + MOZ_DIAGNOSTIC_ASSERT(mLoadResult.isNothing(), "Should not have load result"); + MOZ_DIAGNOSTIC_ASSERT(!mIsLoadingData && !mLoadingPromise.Exists(), + "Should not be in the process of loading data"); + mLoadResult.emplace(NS_OK); + mData = std::move(aData); + auto getDataPromiseHolders = std::move(mPendingGetDataRequests); + for (auto& promiseHolder : getDataPromiseHolders) { + OwningStringOrBlob data(mData); + promiseHolder.Resolve(std::move(data), __func__); + } + auto promises = std::move(mPendingGetTypeRequests); + for (auto& promise : promises) { + MaybeResolveGetTypePromise(mData, *promise); + } +} + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ClipboardItem, mOwner, mItems) + +ClipboardItem::ClipboardItem(nsISupports* aOwner, + const dom::PresentationStyle aPresentationStyle, + nsTArray>&& aItems) + : mOwner(aOwner), + mPresentationStyle(aPresentationStyle), + mItems(std::move(aItems)) {} + +// static +already_AddRefed ClipboardItem::Constructor( + const GlobalObject& aGlobal, + const Record>& aItems, + const ClipboardItemOptions& aOptions, ErrorResult& aRv) { + if (aItems.Entries().IsEmpty()) { + aRv.ThrowTypeError("At least one entry required"); + return nullptr; + } + + nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); + MOZ_ASSERT(global); + + nsTArray> items; + for (const auto& entry : aItems.Entries()) { + RefPtr item = MakeRefPtr(global, entry.mKey); + item->LoadDataFromDataPromise(*entry.mValue); + items.AppendElement(std::move(item)); + } + + RefPtr item = MakeRefPtr( + global, aOptions.mPresentationStyle, std::move(items)); + return item.forget(); +} + +void ClipboardItem::GetTypes(nsTArray& aTypes) const { + for (const auto& item : mItems) { + aTypes.AppendElement(item->Type()); + } +} + +already_AddRefed ClipboardItem::GetType(const nsAString& aType, + ErrorResult& aRv) { + nsCOMPtr global = do_QueryInterface(GetParentObject()); + RefPtr p = Promise::Create(global, aRv); + if (aRv.Failed()) { + return nullptr; + } + + for (auto& item : mItems) { + MOZ_ASSERT(item); + + const nsAString& type = item->Type(); + if (type == aType) { + nsCOMPtr global = do_QueryInterface(GetParentObject()); + if (NS_WARN_IF(!global)) { + p->MaybeReject(NS_ERROR_UNEXPECTED); + return p.forget(); + } + + item->ReactGetTypePromise(*p); + return p.forget(); + } + } + + p->MaybeRejectWithNotFoundError( + "The type '"_ns + NS_ConvertUTF16toUTF8(aType) + "' was not found"_ns); + return p.forget(); +} + +JSObject* ClipboardItem::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return mozilla::dom::ClipboardItem_Binding::Wrap(aCx, this, aGivenProto); +} + +} // namespace mozilla::dom diff --git a/dom/events/ClipboardItem.h b/dom/events/ClipboardItem.h new file mode 100644 index 0000000000..95fdcd6ea9 --- /dev/null +++ b/dom/events/ClipboardItem.h @@ -0,0 +1,132 @@ +/* -*- 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_ClipboardItem_h_ +#define mozilla_dom_ClipboardItem_h_ + +#include "mozilla/dom/Blob.h" +#include "mozilla/dom/ClipboardBinding.h" +#include "mozilla/dom/PromiseNativeHandler.h" +#include "mozilla/MozPromise.h" + +#include "nsWrapperCache.h" + +class nsITransferable; + +namespace mozilla::dom { + +struct ClipboardItemOptions; +template +class Record; +class Promise; + +class ClipboardItem final : public nsWrapperCache { + public: + class ItemEntry final : public PromiseNativeHandler { + public: + using GetDataPromise = + MozPromise; + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(ItemEntry) + + explicit ItemEntry(nsIGlobalObject* aGlobal, const nsAString& aType) + : mGlobal(aGlobal), mType(aType) { + MOZ_ASSERT(mGlobal); + } + ItemEntry(nsIGlobalObject* aGlobal, const nsAString& aType, + const nsAString& aData) + : ItemEntry(aGlobal, aType) { + mLoadResult.emplace(NS_OK); + mData.SetAsString() = aData; + } + + // PromiseNativeHandler + void ResolvedCallback(JSContext* aCx, JS::Handle aValue, + ErrorResult& aRv) override; + void RejectedCallback(JSContext* aCx, JS::Handle aValue, + ErrorResult& aRv) override; + + const nsString& Type() const { return mType; } + RefPtr GetData(); + + // Load data from system clipboard. + void LoadDataFromSystemClipboard(nsITransferable& aTransferable); + void LoadDataFromDataPromise(Promise& aDataPromise); + + // If clipboard data is in the process of loading from either system + // clipboard or data promise, add `aPromise` to the pending list which will + // be resolved/rejected later when process is finished. Otherwise, + // resolve/reject `aPromise` based on cached result and data. + void ReactGetTypePromise(Promise& aPromise); + + private: + ~ItemEntry() { + mLoadingPromise.DisconnectIfExists(); + if (!mPendingGetDataRequests.IsEmpty()) { + RejectPendingPromises(NS_ERROR_FAILURE); + } + }; + + void MaybeResolveGetTypePromise(const OwningStringOrBlob& aData, + Promise& aPromise); + void MaybeResolvePendingPromises(OwningStringOrBlob&& aData); + void RejectPendingPromises(nsresult rv); + + nsCOMPtr mGlobal; + + // MIME type of this entry. + nsString mType; + + // Cache the loading result. + OwningStringOrBlob mData; + Maybe mLoadResult; + + // Indicates if the data is still being loaded. + bool mIsLoadingData = false; + MozPromiseRequestHolder mLoadingPromise; + + // Pending promises for data retrieval requests. + nsTArray> mPendingGetDataRequests; + nsTArray> mPendingGetTypeRequests; + }; + + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(ClipboardItem) + NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(ClipboardItem) + + ClipboardItem(nsISupports* aOwner, dom::PresentationStyle aPresentationStyle, + nsTArray>&& aItems); + + static already_AddRefed Constructor( + const GlobalObject& aGlobal, + const Record>& aItems, + const ClipboardItemOptions& aOptions, ErrorResult& aRv); + + dom::PresentationStyle PresentationStyle() const { + return mPresentationStyle; + }; + void GetTypes(nsTArray& aTypes) const; + + already_AddRefed GetType(const nsAString& aType, ErrorResult& aRv); + + nsISupports* GetParentObject() const { return mOwner; } + + JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + const nsTArray>& Entries() const { return mItems; } + + private: + ~ClipboardItem() = default; + + nsCOMPtr mOwner; + dom::PresentationStyle mPresentationStyle; + nsTArray> mItems; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_ClipboardItem_h_ diff --git a/dom/events/CommandEvent.cpp b/dom/events/CommandEvent.cpp new file mode 100644 index 0000000000..b048a959f8 --- /dev/null +++ b/dom/events/CommandEvent.cpp @@ -0,0 +1,42 @@ +/* -*- 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/CommandEvent.h" +#include "mozilla/MiscEvents.h" +#include "prtime.h" + +namespace mozilla::dom { + +CommandEvent::CommandEvent(EventTarget* aOwner, nsPresContext* aPresContext, + WidgetCommandEvent* aEvent) + : Event(aOwner, aPresContext, aEvent ? aEvent : new WidgetCommandEvent()) { + if (aEvent) { + mEventIsInternal = false; + } else { + mEventIsInternal = true; + } +} + +void CommandEvent::GetCommand(nsAString& aCommand) { + nsAtom* command = mEvent->AsCommandEvent()->mCommand; + if (command) { + command->ToString(aCommand); + } else { + aCommand.Truncate(); + } +} + +} // namespace mozilla::dom + +using namespace mozilla; +using namespace mozilla::dom; + +already_AddRefed NS_NewDOMCommandEvent( + EventTarget* aOwner, nsPresContext* aPresContext, + WidgetCommandEvent* aEvent) { + RefPtr it = new CommandEvent(aOwner, aPresContext, aEvent); + return it.forget(); +} diff --git a/dom/events/CommandEvent.h b/dom/events/CommandEvent.h new file mode 100644 index 0000000000..944b708c3a --- /dev/null +++ b/dom/events/CommandEvent.h @@ -0,0 +1,40 @@ +/* -*- 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_CommandEvent_h_ +#define mozilla_dom_CommandEvent_h_ + +#include "mozilla/EventForwards.h" +#include "mozilla/dom/CommandEventBinding.h" +#include "mozilla/dom/Event.h" + +namespace mozilla::dom { + +class CommandEvent : public Event { + public: + CommandEvent(EventTarget* aOwner, nsPresContext* aPresContext, + WidgetCommandEvent* aEvent); + + NS_INLINE_DECL_REFCOUNTING_INHERITED(CommandEvent, Event) + + virtual JSObject* WrapObjectInternal( + JSContext* aCx, JS::Handle aGivenProto) override { + return CommandEvent_Binding::Wrap(aCx, this, aGivenProto); + } + + void GetCommand(nsAString& aCommand); + + protected: + ~CommandEvent() = default; +}; + +} // namespace mozilla::dom + +already_AddRefed NS_NewDOMCommandEvent( + mozilla::dom::EventTarget* aOwner, nsPresContext* aPresContext, + mozilla::WidgetCommandEvent* aEvent); + +#endif // mozilla_dom_CommandEvent_h_ diff --git a/dom/events/CompositionEvent.cpp b/dom/events/CompositionEvent.cpp new file mode 100644 index 0000000000..7e52b9e161 --- /dev/null +++ b/dom/events/CompositionEvent.cpp @@ -0,0 +1,108 @@ +/* -*- 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/CompositionEvent.h" +#include "mozilla/TextEvents.h" +#include "prtime.h" + +namespace mozilla::dom { + +CompositionEvent::CompositionEvent(EventTarget* aOwner, + nsPresContext* aPresContext, + WidgetCompositionEvent* aEvent) + : UIEvent(aOwner, aPresContext, + aEvent ? aEvent + : new WidgetCompositionEvent(false, eVoidEvent, nullptr)) { + NS_ASSERTION(mEvent->mClass == eCompositionEventClass, "event type mismatch"); + + if (aEvent) { + mEventIsInternal = false; + } else { + mEventIsInternal = true; + + // XXX compositionstart is cancelable in draft of DOM3 Events. + // However, it doesn't make sence for us, we cannot cancel composition + // when we sends compositionstart event. + mEvent->mFlags.mCancelable = false; + } + + // XXX Do we really need to duplicate the data value? + mData = mEvent->AsCompositionEvent()->mData; + // TODO: Native event should have locale information. +} + +// static +already_AddRefed CompositionEvent::Constructor( + const GlobalObject& aGlobal, const nsAString& aType, + const CompositionEventInit& aParam) { + nsCOMPtr t = do_QueryInterface(aGlobal.GetAsSupports()); + RefPtr e = new CompositionEvent(t, nullptr, nullptr); + bool trusted = e->Init(t); + e->InitCompositionEvent(aType, aParam.mBubbles, aParam.mCancelable, + aParam.mView, aParam.mData, u""_ns); + e->mDetail = aParam.mDetail; + e->SetTrusted(trusted); + e->SetComposed(aParam.mComposed); + return e.forget(); +} + +NS_IMPL_CYCLE_COLLECTION_INHERITED(CompositionEvent, UIEvent, mRanges) + +NS_IMPL_ADDREF_INHERITED(CompositionEvent, UIEvent) +NS_IMPL_RELEASE_INHERITED(CompositionEvent, UIEvent) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CompositionEvent) +NS_INTERFACE_MAP_END_INHERITING(UIEvent) + +void CompositionEvent::GetData(nsAString& aData) const { aData = mData; } + +void CompositionEvent::GetLocale(nsAString& aLocale) const { + aLocale = mLocale; +} + +void CompositionEvent::InitCompositionEvent(const nsAString& aType, + bool aCanBubble, bool aCancelable, + nsGlobalWindowInner* aView, + const nsAString& aData, + const nsAString& aLocale) { + NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched); + + UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, 0); + mData = aData; + mLocale = aLocale; +} + +void CompositionEvent::GetRanges(TextClauseArray& aRanges) { + // If the mRanges is not empty, we return the cached value. + if (!mRanges.IsEmpty()) { + aRanges = mRanges.Clone(); + return; + } + RefPtr textRangeArray = mEvent->AsCompositionEvent()->mRanges; + if (!textRangeArray) { + return; + } + nsCOMPtr window = do_QueryInterface(mOwner); + const TextRange* targetRange = textRangeArray->GetTargetClause(); + for (size_t i = 0; i < textRangeArray->Length(); i++) { + const TextRange& range = textRangeArray->ElementAt(i); + mRanges.AppendElement(new TextClause(window, range, targetRange)); + } + aRanges = mRanges.Clone(); +} + +} // namespace mozilla::dom + +using namespace mozilla; +using namespace mozilla::dom; + +already_AddRefed NS_NewDOMCompositionEvent( + EventTarget* aOwner, nsPresContext* aPresContext, + WidgetCompositionEvent* aEvent) { + RefPtr event = + new CompositionEvent(aOwner, aPresContext, aEvent); + return event.forget(); +} diff --git a/dom/events/CompositionEvent.h b/dom/events/CompositionEvent.h new file mode 100644 index 0000000000..400829104a --- /dev/null +++ b/dom/events/CompositionEvent.h @@ -0,0 +1,58 @@ +/* -*- 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_CompositionEvent_h_ +#define mozilla_dom_CompositionEvent_h_ + +#include "mozilla/dom/CompositionEventBinding.h" +#include "mozilla/dom/TextClause.h" +#include "mozilla/dom/TypedArray.h" +#include "mozilla/dom/UIEvent.h" +#include "mozilla/EventForwards.h" + +namespace mozilla::dom { + +using TextClauseArray = nsTArray>; + +class CompositionEvent : public UIEvent { + public: + CompositionEvent(EventTarget* aOwner, nsPresContext* aPresContext, + WidgetCompositionEvent* aEvent); + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CompositionEvent, UIEvent) + + static already_AddRefed Constructor( + const GlobalObject& aGlobal, const nsAString& aType, + const CompositionEventInit& aParam); + + virtual JSObject* WrapObjectInternal( + JSContext* aCx, JS::Handle aGivenProto) override { + return CompositionEvent_Binding::Wrap(aCx, this, aGivenProto); + } + + void InitCompositionEvent(const nsAString& aType, bool aCanBubble, + bool aCancelable, nsGlobalWindowInner* aView, + const nsAString& aData, const nsAString& aLocale); + void GetData(nsAString&) const; + void GetLocale(nsAString&) const; + void GetRanges(TextClauseArray& aRanges); + + protected: + ~CompositionEvent() = default; + + nsString mData; + nsString mLocale; + TextClauseArray mRanges; +}; + +} // namespace mozilla::dom + +already_AddRefed NS_NewDOMCompositionEvent( + mozilla::dom::EventTarget* aOwner, nsPresContext* aPresContext, + mozilla::WidgetCompositionEvent* aEvent); + +#endif // mozilla_dom_CompositionEvent_h_ diff --git a/dom/events/ConstructibleEventTarget.cpp b/dom/events/ConstructibleEventTarget.cpp new file mode 100644 index 0000000000..827b3faaa8 --- /dev/null +++ b/dom/events/ConstructibleEventTarget.cpp @@ -0,0 +1,17 @@ +/* -*- 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/ConstructibleEventTarget.h" +#include "mozilla/dom/EventTargetBinding.h" + +namespace mozilla::dom { + +JSObject* ConstructibleEventTarget::WrapObject( + JSContext* cx, JS::Handle aGivenProto) { + return EventTarget_Binding::Wrap(cx, this, aGivenProto); +} + +} // namespace mozilla::dom diff --git a/dom/events/ConstructibleEventTarget.h b/dom/events/ConstructibleEventTarget.h new file mode 100644 index 0000000000..fbaafac821 --- /dev/null +++ b/dom/events/ConstructibleEventTarget.h @@ -0,0 +1,30 @@ +/* -*- 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_ConstructibleEventTarget_h_ +#define mozilla_dom_ConstructibleEventTarget_h_ + +#include "mozilla/DOMEventTargetHelper.h" +#include "js/RootingAPI.h" + +namespace mozilla::dom { + +class ConstructibleEventTarget : public DOMEventTargetHelper { + public: + // Not worrying about isupports and cycle collection here. This does mean + // ConstructibleEventTarget will show up in CC and refcount logs as a + // DOMEventTargetHelper, but that's probably OK. + + explicit ConstructibleEventTarget(nsIGlobalObject* aGlobalObject) + : DOMEventTargetHelper(aGlobalObject) {} + + virtual JSObject* WrapObject(JSContext* cx, + JS::Handle aGivenProto) override; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_ConstructibleEventTarget_h_ diff --git a/dom/events/ContentEventHandler.cpp b/dom/events/ContentEventHandler.cpp new file mode 100644 index 0000000000..e413e70897 --- /dev/null +++ b/dom/events/ContentEventHandler.cpp @@ -0,0 +1,3307 @@ +/* -*- 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 "ContentEventHandler.h" + +#include "mozilla/Assertions.h" +#include "mozilla/CheckedInt.h" +#include "mozilla/ContentIterator.h" +#include "mozilla/IMEStateManager.h" +#include "mozilla/IntegerRange.h" +#include "mozilla/Maybe.h" +#include "mozilla/PresShell.h" +#include "mozilla/RangeBoundary.h" +#include "mozilla/RangeUtils.h" +#include "mozilla/TextComposition.h" +#include "mozilla/TextEditor.h" +#include "mozilla/TextEvents.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/HTMLBRElement.h" +#include "mozilla/dom/HTMLUnknownElement.h" +#include "mozilla/dom/Selection.h" +#include "mozilla/dom/Text.h" +#include "nsCaret.h" +#include "nsCOMPtr.h" +#include "nsContentUtils.h" +#include "nsCopySupport.h" +#include "nsElementTable.h" +#include "nsFocusManager.h" +#include "nsFontMetrics.h" +#include "nsFrameSelection.h" +#include "nsIFrame.h" +#include "nsLayoutUtils.h" +#include "nsPresContext.h" +#include "nsQueryObject.h" +#include "nsRange.h" +#include "nsTextFragment.h" +#include "nsTextFrame.h" +#include "nsView.h" +#include "mozilla/ViewportUtils.h" + +#include + +// Work around conflicting define in rpcndr.h +#if defined(small) +# undef small +#endif // defined(small) + +namespace mozilla { + +using namespace dom; +using namespace widget; + +/******************************************************************/ +/* ContentEventHandler::RawRange */ +/******************************************************************/ + +void ContentEventHandler::RawRange::AssertStartIsBeforeOrEqualToEnd() { + MOZ_ASSERT( + *nsContentUtils::ComparePoints( + mStart.Container(), + *mStart.Offset(NodePosition::OffsetFilter::kValidOrInvalidOffsets), + mEnd.Container(), + *mEnd.Offset(NodePosition::OffsetFilter::kValidOrInvalidOffsets)) <= + 0); +} + +nsresult ContentEventHandler::RawRange::SetStart( + const RawRangeBoundary& aStart) { + nsINode* newRoot = RangeUtils::ComputeRootNode(aStart.Container()); + if (!newRoot) { + return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; + } + + if (!aStart.IsSetAndValid()) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + // Collapse if not positioned yet, or if positioned in another document. + if (!IsPositioned() || newRoot != mRoot) { + mRoot = newRoot; + mStart.CopyFrom(aStart, RangeBoundaryIsMutationObserved::Yes); + mEnd.CopyFrom(aStart, RangeBoundaryIsMutationObserved::Yes); + return NS_OK; + } + + mStart.CopyFrom(aStart, RangeBoundaryIsMutationObserved::Yes); + AssertStartIsBeforeOrEqualToEnd(); + return NS_OK; +} + +nsresult ContentEventHandler::RawRange::SetEnd(const RawRangeBoundary& aEnd) { + nsINode* newRoot = RangeUtils::ComputeRootNode(aEnd.Container()); + if (!newRoot) { + return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; + } + + if (!aEnd.IsSetAndValid()) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + // Collapse if not positioned yet, or if positioned in another document. + if (!IsPositioned() || newRoot != mRoot) { + mRoot = newRoot; + mStart.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes); + mEnd.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes); + return NS_OK; + } + + mEnd.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes); + AssertStartIsBeforeOrEqualToEnd(); + return NS_OK; +} + +nsresult ContentEventHandler::RawRange::SetEndAfter(nsINode* aEndContainer) { + return SetEnd(RangeUtils::GetRawRangeBoundaryAfter(aEndContainer)); +} + +void ContentEventHandler::RawRange::SetStartAndEnd(const nsRange* aRange) { + DebugOnly rv = + SetStartAndEnd(aRange->StartRef().AsRaw(), aRange->EndRef().AsRaw()); + MOZ_ASSERT(!aRange->IsPositioned() || NS_SUCCEEDED(rv)); +} + +nsresult ContentEventHandler::RawRange::SetStartAndEnd( + const RawRangeBoundary& aStart, const RawRangeBoundary& aEnd) { + nsINode* newStartRoot = RangeUtils::ComputeRootNode(aStart.Container()); + if (!newStartRoot) { + return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; + } + if (!aStart.IsSetAndValid()) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + if (aStart.Container() == aEnd.Container()) { + if (!aEnd.IsSetAndValid()) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + MOZ_ASSERT(*aStart.Offset(RawRangeBoundary::OffsetFilter::kValidOffsets) <= + *aEnd.Offset(RawRangeBoundary::OffsetFilter::kValidOffsets)); + mRoot = newStartRoot; + mStart.CopyFrom(aStart, RangeBoundaryIsMutationObserved::Yes); + mEnd.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes); + return NS_OK; + } + + nsINode* newEndRoot = RangeUtils::ComputeRootNode(aEnd.Container()); + if (!newEndRoot) { + return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; + } + if (!aEnd.IsSetAndValid()) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + // If they have different root, this should be collapsed at the end point. + if (newStartRoot != newEndRoot) { + mRoot = newEndRoot; + mStart.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes); + mEnd.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes); + return NS_OK; + } + + // Otherwise, set the range as specified. + mRoot = newStartRoot; + mStart.CopyFrom(aStart, RangeBoundaryIsMutationObserved::Yes); + mEnd.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes); + AssertStartIsBeforeOrEqualToEnd(); + return NS_OK; +} + +nsresult ContentEventHandler::RawRange::SelectNodeContents( + const nsINode* aNodeToSelectContents) { + nsINode* const newRoot = + RangeUtils::ComputeRootNode(const_cast(aNodeToSelectContents)); + if (!newRoot) { + return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; + } + mRoot = newRoot; + mStart = RangeBoundary(const_cast(aNodeToSelectContents), nullptr); + mEnd = RangeBoundary(const_cast(aNodeToSelectContents), + aNodeToSelectContents->GetLastChild()); + return NS_OK; +} + +/******************************************************************/ +/* ContentEventHandler */ +/******************************************************************/ + +// NOTE +// +// ContentEventHandler *creates* ranges as following rules: +// 1. Start of range: +// 1.1. Cases: [textNode or text[Node or textNode[ +// When text node is start of a range, start node is the text node and +// start offset is any number between 0 and the length of the text. +// 1.2. Case: [: +// When start of an element node is start of a range, start node is +// parent of the element and start offset is the element's index in the +// parent. +// 1.3. Case: [ +// When after an empty element node is start of a range, start node is +// parent of the element and start offset is the element's index in the +// parent + 1. +// 1.4. Case: [ +// When start of a non-empty element is start of a range, start node is +// the element and start offset is 0. +// 1.5. Case: [ +// When start of a range is 0 and there are no nodes causing text, +// start node is the root node and start offset is 0. +// 1.6. Case: [ +// When start of a range is out of bounds, start node is the root node +// and start offset is number of the children. +// 2. End of range: +// 2.1. Cases: ]textNode or text]Node or textNode] +// When a text node is end of a range, end node is the text node and +// end offset is any number between 0 and the length of the text. +// 2.2. Case: ] +// When before an element node (meaning before the open tag of the +// element) is end of a range, end node is previous node causing text. +// Note that this case shouldn't be handled directly. If rule 2.1 and +// 2.3 are handled correctly, the loop with ContentIterator shouldn't +// reach the element node since the loop should've finished already at +// handling the last node which caused some text. +// 2.3. Case: ] +// When a line break is caused before a non-empty element node and it's +// end of a range, end node is the element and end offset is 0. +// (i.e., including open tag of the element) +// 2.4. Cases: ] +// When after an empty element node is end of a range, end node is +// parent of the element node and end offset is the element's index in +// the parent + 1. (i.e., including close tag of the element or empty +// element) +// 2.5. Case: ] +// When end of a range is out of bounds, end node is the root node and +// end offset is number of the children. +// +// ContentEventHandler *treats* ranges as following additional rules: +// 1. When the start node is an element node which doesn't have children, +// it includes a line break caused before itself (i.e., includes its open +// tag). For example, if start position is {
, 0 }, the line break +// caused by
should be included into the flatten text. +// 2. When the end node is an element node which doesn't have children, +// it includes the end (i.e., includes its close tag except empty element). +// Although, currently, any close tags don't cause line break, this also +// includes its open tag. For example, if end position is {
, 0 }, the +// line break caused by the
should be included into the flatten text. + +ContentEventHandler::ContentEventHandler(nsPresContext* aPresContext) + : mDocument(aPresContext->Document()) {} + +nsresult ContentEventHandler::InitBasic(bool aRequireFlush) { + NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); + if (aRequireFlush) { + // If text frame which has overflowing selection underline is dirty, + // we need to flush the pending reflow here. + mDocument->FlushPendingNotifications(FlushType::Layout); + } + return NS_OK; +} + +nsresult ContentEventHandler::InitRootContent( + const Selection& aNormalSelection) { + // Root content should be computed with normal selection because normal + // selection is typically has at least one range but the other selections + // not so. If there is a range, computing its root is easy, but if + // there are no ranges, we need to use ancestor limit instead. + MOZ_ASSERT(aNormalSelection.Type() == SelectionType::eNormal); + + if (!aNormalSelection.RangeCount()) { + // If there is no selection range, we should compute the selection root + // from ancestor limiter or root content of the document. + mRootElement = + Element::FromNodeOrNull(aNormalSelection.GetAncestorLimiter()); + if (!mRootElement) { + mRootElement = mDocument->GetRootElement(); + if (NS_WARN_IF(!mRootElement)) { + return NS_ERROR_NOT_AVAILABLE; + } + } + return NS_OK; + } + + RefPtr range(aNormalSelection.GetRangeAt(0)); + if (NS_WARN_IF(!range)) { + return NS_ERROR_UNEXPECTED; + } + + // If there is a selection, we should retrieve the selection root from + // the range since when the window is inactivated, the ancestor limiter + // of selection was cleared by blur event handler of EditorBase but the + // selection range still keeps storing the nodes. If the active element of + // the deactive window is or + + + + + diff --git a/dom/events/test/test_addEventListenerExtraArg.html b/dom/events/test/test_addEventListenerExtraArg.html new file mode 100644 index 0000000000..58b18545de --- /dev/null +++ b/dom/events/test/test_addEventListenerExtraArg.html @@ -0,0 +1,31 @@ + + + + + + Test for Bug 828554 + + + + + +Mozilla Bug 828554 +

+ +
+
+ + diff --git a/dom/events/test/test_all_synthetic_events.html b/dom/events/test/test_all_synthetic_events.html new file mode 100644 index 0000000000..cd9eab3e33 --- /dev/null +++ b/dom/events/test/test_all_synthetic_events.html @@ -0,0 +1,479 @@ + + + + Test all synthetic events + + + + + +

+ +
+
+
+ + diff --git a/dom/events/test/test_bug1003432.html b/dom/events/test/test_bug1003432.html new file mode 100644 index 0000000000..d74aefb886 --- /dev/null +++ b/dom/events/test/test_bug1003432.html @@ -0,0 +1,45 @@ + + + + + Test for Bug 1003432 + + + + +Mozilla Bug 1003432 +

+ +
+
+
+ + diff --git a/dom/events/test/test_bug1003432.js b/dom/events/test/test_bug1003432.js new file mode 100644 index 0000000000..2f92ebf8da --- /dev/null +++ b/dom/events/test/test_bug1003432.js @@ -0,0 +1,31 @@ +addEventListener( + "foobar", + function (evt) { + postMessage({ + type: evt.type, + bubbles: evt.bubbles, + cancelable: evt.cancelable, + detail: evt.detail, + }); + }, + true +); + +addEventListener( + "message", + function (evt) { + // Test the constructor of CustomEvent + var e = new CustomEvent("foobar", { + bubbles: true, + cancelable: true, + detail: "test", + }); + dispatchEvent(e); + + // Test initCustomEvent + e = new CustomEvent("foobar"); + e.initCustomEvent("foobar", true, true, "test"); + dispatchEvent(e); + }, + true +); diff --git a/dom/events/test/test_bug1013412.html b/dom/events/test/test_bug1013412.html new file mode 100644 index 0000000000..03730b09b4 --- /dev/null +++ b/dom/events/test/test_bug1013412.html @@ -0,0 +1,116 @@ + + + + + Test for Bug 1013412 and 1168182 + + + + + + + +Mozilla Bug 1013412 +Mozilla Bug 1168182 +

+
+

Scrolling the page should be async and scrolling over the dark circle should scroll the page and avoid rotating the white ball.

+
+
+
+
+
+
+
+
+
+ + + diff --git a/dom/events/test/test_bug1017086_enable.html b/dom/events/test/test_bug1017086_enable.html new file mode 100644 index 0000000000..e7e6097c63 --- /dev/null +++ b/dom/events/test/test_bug1017086_enable.html @@ -0,0 +1,35 @@ + + + + + + Test for Bug 1017086 + + + + + + + + + diff --git a/dom/events/test/test_bug1037990.html b/dom/events/test/test_bug1037990.html new file mode 100644 index 0000000000..c148debcf7 --- /dev/null +++ b/dom/events/test/test_bug1037990.html @@ -0,0 +1,61 @@ + + + + + + Test for Bug 1037990 + + + + +Mozilla Bug 1037990 +

+ +
+
+ + + diff --git a/dom/events/test/test_bug1079236.html b/dom/events/test/test_bug1079236.html new file mode 100644 index 0000000000..4c89101574 --- /dev/null +++ b/dom/events/test/test_bug1079236.html @@ -0,0 +1,66 @@ + + + + + + Test for Bug 1079236 + + + + + + +Mozilla Bug 1079236 +

+
+ +
+
+
+ + diff --git a/dom/events/test/test_bug1127588.html b/dom/events/test/test_bug1127588.html new file mode 100644 index 0000000000..7d00a68eee --- /dev/null +++ b/dom/events/test/test_bug1127588.html @@ -0,0 +1,61 @@ + + + + + + + + +Mozilla Bug 1127588 +

+